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