kern/48599: [PATCH] syscons cut-n-paste logic is broken

Eugene Grosbein eugen at grosbein.pp.ru
Sun Jun 5 16:40:05 GMT 2005


The following reply was made to PR kern/48599; it has been noted by GNATS.

From: Eugene Grosbein <eugen at grosbein.pp.ru>
To: bug-followup at freebsd.org
Cc: Gleb Smirnoff <glebius at freebsd.org>
Subject: Re: kern/48599: [PATCH] syscons cut-n-paste logic is broken
Date: Mon, 6 Jun 2005 00:36:48 +0800

 Hi!
 
 Here is a merge to RELENG_4 of sys/dev/syscons/scmouse.c rev. 1.20, 1.27-1.29
 and corresponding revisions of sys/conf/options.i386, sys/i386/conf/LINT
 and share/man/man4/syscons.4.
 
 1.20 is needed for 1.27 to apply cleanly.
 
 This patch fixes the problem and follows current codebase.
 
 --- sys/dev/syscons/scmouse.c.orig	Mon Jun  6 00:10:21 2005
 +++ sys/dev/syscons/scmouse.c	Mon Jun  6 00:10:12 2005
 @@ -280,6 +280,18 @@
  
  #define IS_SPACE_CHAR(c)	(((c) & 0xff) == ' ')
  
 +#ifdef SC_CUT_SPACES2TABS
 +#define IS_BLANK_CHAR(c)	(((c) & 0xff) == ' ' || ((c) & 0xff) == '\t')
 +#else
 +#define IS_BLANK_CHAR(c)	IS_SPACE_CHAR(c)
 +#endif /* SC_CUT_SPACES2TABS */
 +
 +#ifdef SC_CUT_SEPCHARS
 +#define IS_SEP_CHAR(c)		(index(SC_CUT_SEPCHARS, (c) & 0xff) != NULL)
 +#else
 +#define IS_SEP_CHAR(c)		IS_SPACE_CHAR(c)
 +#endif /* SC_CUT_SEPCHARS */
 +
  /* skip spaces to right */
  static int
  skip_spc_right(scr_stat *scp, int p)
 @@ -312,6 +324,66 @@
      return i;
  }
  
 +static void
 +mouse_do_cut(scr_stat *scp, int from, int to)
 +{
 +    int blank;
 +    int i;
 +    int leadspaces;
 +    int p;
 +    int s;
 +
 +    for (p = from, i = blank = leadspaces = 0; p <= to; ++p) {
 +	cut_buffer[i] = sc_vtb_getc(&scp->vtb, p);
 +	/* Be prepared that sc_vtb_getc() can return '\0' */
 +	if (cut_buffer[i] == '\0')
 +	    cut_buffer[i] = ' ';
 +#ifdef SC_CUT_SPACES2TABS
 +	if (leadspaces != -1) {
 +	    if (IS_SPACE_CHAR(cut_buffer[i])) {
 +		leadspaces++;
 +		/* Check that we are at tabstop position */
 +		if ((p % scp->xsize) % 8 == 7) {
 +		    i -= leadspaces - 1;
 +		    cut_buffer[i] = '\t';
 +		    leadspaces = 0;
 +		}
 +	    } else {
 +		leadspaces = -1;
 +	    }
 +	}
 +#endif /* SC_CUT_SPACES2TABS */
 +	/* remember the position of the last non-space char */
 +	if (!IS_BLANK_CHAR(cut_buffer[i]))
 +	    blank = i + 1;	/* the first space after the last non-space */
 +	++i;
 +	/* trim trailing blank when crossing lines */
 +	if ((p % scp->xsize) == (scp->xsize - 1)) {
 +	    cut_buffer[blank++] = '\r';
 +	    i = blank;
 +	    leadspaces = 0;
 +	}
 +    }
 +    cut_buffer[i] = '\0';
 +
 +    /* remove the current marking */
 +    s = spltty();
 +    if (scp->mouse_cut_start <= scp->mouse_cut_end) {
 +	mark_for_update(scp, scp->mouse_cut_start);
 +	mark_for_update(scp, scp->mouse_cut_end);
 +    } else if (scp->mouse_cut_end >= 0) {
 +	mark_for_update(scp, scp->mouse_cut_end);
 +	mark_for_update(scp, scp->mouse_cut_start);
 +    }
 +
 +    /* mark the new region */
 +    scp->mouse_cut_start = from;
 +    scp->mouse_cut_end = to;
 +    mark_for_update(scp, from);
 +    mark_for_update(scp, to);
 +    splx(s);
 +}
 +
  /* copy marked region to the cut buffer */
  static void
  mouse_cut(scr_stat *scp)
 @@ -320,7 +392,6 @@
      int end;
      int from;
      int to;
 -    int blank;
      int c;
      int p;
      int s;
 @@ -335,21 +406,7 @@
  	from = end = scp->mouse_pos;
  	to = start - 1;
      }
 -    for (p = from, i = blank = 0; p <= to; ++p) {
 -	cut_buffer[i] = sc_vtb_getc(&scp->vtb, p);
 -	/* remember the position of the last non-space char */
 -	if (!IS_SPACE_CHAR(cut_buffer[i++]))
 -	    blank = i;		/* the first space after the last non-space */
 -	/* trim trailing blank when crossing lines */
 -	if ((p % scp->xsize) == (scp->xsize - 1)) {
 -	    cut_buffer[blank] = '\r';
 -	    i = blank + 1;
 -	}
 -    }
 -    cut_buffer[i] = '\0';
 -
 -    /* scan towards the end of the last line */
 -    --p;
 +    p = to;
      for (i = p % scp->xsize; i < scp->xsize; ++i) {
  	c = sc_vtb_getc(&scp->vtb, p);
  	if (!IS_SPACE_CHAR(c))
 @@ -357,47 +414,31 @@
  	++p;
      }
      /* if there is nothing but blank chars, trim them, but mark towards eol */
 -    if (i >= scp->xsize) {
 +    if (i == scp->xsize) {
  	if (end >= start)
  	    to = end = p - 1;
  	else
  	    to = start = p;
 -	cut_buffer[blank++] = '\r';
 -	cut_buffer[blank] = '\0';
      }
 -
 -    /* remove the current marking */
 +    mouse_do_cut(scp, from, to);
      s = spltty();
 -    if (scp->mouse_cut_start <= scp->mouse_cut_end) {
 -	mark_for_update(scp, scp->mouse_cut_start);
 -	mark_for_update(scp, scp->mouse_cut_end);
 -    } else if (scp->mouse_cut_end >= 0) {
 -	mark_for_update(scp, scp->mouse_cut_end);
 -	mark_for_update(scp, scp->mouse_cut_start);
 -    }
 -
 -    /* mark the new region */
      scp->mouse_cut_start = start;
      scp->mouse_cut_end = end;
 -    mark_for_update(scp, from);
 -    mark_for_update(scp, to);
      splx(s);
  }
  
  /* a mouse button is pressed, start cut operation */
  static void
 -mouse_cut_start(scr_stat *scp) 
 +mouse_cut_start(scr_stat *scp)
  {
      int i;
 -    int j;
      int s;
  
      if (scp->status & MOUSE_VISIBLE) {
 -	i = scp->mouse_cut_start;
 -	j = scp->mouse_cut_end;
  	sc_remove_all_cutmarkings(scp->sc);
 -	if (scp->mouse_pos == i && i == j) {
 +	if (scp->mouse_pos == scp->mouse_cut_start == scp->mouse_cut_end) {
  	    cut_buffer[0] = '\0';
 +	    return;
  	} else if (skip_spc_right(scp, scp->mouse_pos) >= scp->xsize) {
  	    /* if the pointer is on trailing blank chars, mark towards eol */
  	    i = skip_spc_left(scp, scp->mouse_pos) + 1;
 @@ -408,17 +449,15 @@
  	        (scp->mouse_pos / scp->xsize + 1) * scp->xsize - 1;
  	    splx(s);
  	    cut_buffer[0] = '\r';
 -	    cut_buffer[1] = '\0';
 -	    scp->status |= MOUSE_CUTTING;
  	} else {
  	    s = spltty();
  	    scp->mouse_cut_start = scp->mouse_pos;
  	    scp->mouse_cut_end = scp->mouse_cut_start;
  	    splx(s);
  	    cut_buffer[0] = sc_vtb_getc(&scp->vtb, scp->mouse_cut_start);
 -	    cut_buffer[1] = '\0';
 -	    scp->status |= MOUSE_CUTTING;
  	}
 +	cut_buffer[1] = '\0';
 +	scp->status |= MOUSE_CUTTING;
      	mark_all(scp);	/* this is probably overkill XXX */
      }
  }
 @@ -440,43 +479,30 @@
      int sol;
      int eol;
      int c;
 -    int s;
 -    int i;
      int j;
 +    int len;
  
      /*
       * Because we don't have locale information in the kernel,
       * we only distinguish space char and non-space chars.  Punctuation
 -     * chars, symbols and other regular chars are all treated alike.
 +     * chars, symbols and other regular chars are all treated alike
 +     * unless user specified SC_CUT_SEPCHARS in his kernel config file.
       */
      if (scp->status & MOUSE_VISIBLE) {
 -	/* remove the current cut mark */
 -	s = spltty();
 -	if (scp->mouse_cut_start <= scp->mouse_cut_end) {
 -	    mark_for_update(scp, scp->mouse_cut_start);
 -	    mark_for_update(scp, scp->mouse_cut_end);
 -	} else if (scp->mouse_cut_end >= 0) {
 -	    mark_for_update(scp, scp->mouse_cut_end);
 -	    mark_for_update(scp, scp->mouse_cut_start);
 -	}
 -	scp->mouse_cut_start = scp->xsize*scp->ysize;
 -	scp->mouse_cut_end = -1;
 -	splx(s);
 -
  	sol = (scp->mouse_pos / scp->xsize) * scp->xsize;
  	eol = sol + scp->xsize;
  	c = sc_vtb_getc(&scp->vtb, scp->mouse_pos);
 -	if (IS_SPACE_CHAR(c)) {
 +	if (IS_SEP_CHAR(c)) {
  	    /* blank space */
  	    for (j = scp->mouse_pos; j >= sol; --j) {
  		c = sc_vtb_getc(&scp->vtb, j);
 -	        if (!IS_SPACE_CHAR(c))
 +	        if (!IS_SEP_CHAR(c))
  		    break;
  	    }
  	    start = ++j;
  	    for (j = scp->mouse_pos; j < eol; ++j) {
  		c = sc_vtb_getc(&scp->vtb, j);
 -	        if (!IS_SPACE_CHAR(c))
 +	        if (!IS_SEP_CHAR(c))
  		    break;
  	    }
  	    end = j - 1;
 @@ -484,31 +510,23 @@
  	    /* non-space word */
  	    for (j = scp->mouse_pos; j >= sol; --j) {
  		c = sc_vtb_getc(&scp->vtb, j);
 -	        if (IS_SPACE_CHAR(c))
 +	        if (IS_SEP_CHAR(c))
  		    break;
  	    }
  	    start = ++j;
  	    for (j = scp->mouse_pos; j < eol; ++j) {
  		c = sc_vtb_getc(&scp->vtb, j);
 -	        if (IS_SPACE_CHAR(c))
 +	        if (IS_SEP_CHAR(c))
  		    break;
  	    }
  	    end = j - 1;
  	}
  
  	/* copy the found word */
 -	for (i = 0, j = start; j <= end; ++j)
 -	    cut_buffer[i++] = sc_vtb_getc(&scp->vtb, j);
 -	cut_buffer[i] = '\0';
 -	scp->status |= MOUSE_CUTTING;
 -
 -	/* mark the region */
 -	s = spltty();
 -	scp->mouse_cut_start = start;
 -	scp->mouse_cut_end = end;
 -	mark_for_update(scp, start);
 -	mark_for_update(scp, end);
 -	splx(s);
 +	mouse_do_cut(scp, start, end);
 +	len = strlen(cut_buffer);
 +	if (cut_buffer[len - 1] == '\r')
 +	    cut_buffer[len - 1] = '\0';
      }
  }
  
 @@ -516,34 +534,15 @@
  static void
  mouse_cut_line(scr_stat *scp)
  {
 -    int s;
 -    int i;
 -    int j;
 +    int len;
 +    int from;
  
      if (scp->status & MOUSE_VISIBLE) {
 -	/* remove the current cut mark */
 -	s = spltty();
 -	if (scp->mouse_cut_start <= scp->mouse_cut_end) {
 -	    mark_for_update(scp, scp->mouse_cut_start);
 -	    mark_for_update(scp, scp->mouse_cut_end);
 -	} else if (scp->mouse_cut_end >= 0) {
 -	    mark_for_update(scp, scp->mouse_cut_end);
 -	    mark_for_update(scp, scp->mouse_cut_start);
 -	}
 -
 -	/* mark the entire line */
 -	scp->mouse_cut_start =
 -	    (scp->mouse_pos / scp->xsize) * scp->xsize;
 -	scp->mouse_cut_end = scp->mouse_cut_start + scp->xsize - 1;
 -	mark_for_update(scp, scp->mouse_cut_start);
 -	mark_for_update(scp, scp->mouse_cut_end);
 -	splx(s);
 -
 -	/* copy the line into the cut buffer */
 -	for (i = 0, j = scp->mouse_cut_start; j <= scp->mouse_cut_end; ++j)
 -	    cut_buffer[i++] = sc_vtb_getc(&scp->vtb, j);
 -	cut_buffer[i++] = '\r';
 -	cut_buffer[i] = '\0';
 +	from = (scp->mouse_pos / scp->xsize) * scp->xsize;
 +	mouse_do_cut(scp, from, from + scp->xsize - 1);
 +	len = strlen(cut_buffer);
 +	if (cut_buffer[len - 1] == '\r')
 +	    cut_buffer[len - 1] = '\0';
  	scp->status |= MOUSE_CUTTING;
      }
  }
 --- sys/conf/options.i386.orig	Fri Apr  2 00:40:28 2004
 +++ sys/conf/options.i386	Sun Jun  5 23:14:08 2005
 @@ -77,6 +77,8 @@
  
  MAXCONS			opt_syscons.h
  SC_ALT_MOUSE_IMAGE	opt_syscons.h
 +SC_CUT_SPACES2TABS	opt_syscons.h
 +SC_CUT_SEPCHARS		opt_syscons.h
  SC_DEBUG_LEVEL		opt_syscons.h
  SC_DFLT_FONT		opt_syscons.h
  SC_DISABLE_DDBKEY	opt_syscons.h
 --- sys/i386/conf/LINT.orig	Mon Jan 17 16:37:27 2005
 +++ sys/i386/conf/LINT	Sun Jun  5 23:16:23 2005
 @@ -1186,6 +1186,12 @@
  options 	SC_KERNEL_CONS_ATTR="(FG_RED|BG_BLACK)"
  options 	SC_KERNEL_CONS_REV_ATTR="(FG_BLACK|BG_RED)"
  
 +# The following options will let you change the default behaviour of
 +# cut-n-paste feature
 +options		SC_CUT_SPACES2TABS	# convert leading spaces into tabs
 +options		SC_CUT_SEPCHARS="\x20"	# set of characters that delimit words
 +					# (default is single space - "\x20")
 +
  # If you have a two button mouse, you may want to add the following option
  # to use the right button of the mouse to paste text.
  options 	SC_TWOBUTTON_MOUSE
 --- share/man/man4/syscons.4.orig	Sat Apr 26 05:21:36 2003
 +++ share/man/man4/syscons.4	Sun Jun  5 23:11:56 2005
 @@ -261,6 +261,16 @@
  .Dv SC_NO_FONT_LOADING
  option then you must also use this option if you wish to be able to use
  the mouse.
 +.It Dv SC_CUT_SEPCHARS=_characters_
 +This options specifies characters that will be looked for when the
 +driver searches for words boundaries when doing cut operation.  By
 +default its value is
 +.Dq \e\\&x20
 +- a space character.
 +.It Dv SC_CUT_SPACES2TABS
 +This options instructs the driver to convert leading spaces into tabs
 +when copying data into cut buffer.  This might be useful to preserve
 +identation when copying tab-idented text.
  .It Dv SC_DISABLE_DDBKEY
  This option disables the ``debug'' key combination (by default, it is
  .Dv Alt-Esc ,


More information about the freebsd-bugs mailing list