svn commit: trunk/busybox: editors include libbb miscutils

vda at busybox.net vda at busybox.net
Sat Oct 25 23:27:29 UTC 2008


Author: vda
Date: 2008-10-25 16:27:29 -0700 (Sat, 25 Oct 2008)
New Revision: 23788

Log:
less: reuse former vi's key reading code. Improve SIGWINCH handling.

function                                             old     new   delta
less_main                                           2056    2097     +41
getch_nowait                                         248     273     +25
read_key                                             310     321     +11
static.esccmds                                        61      69      +8
count_lines                                           72      74      +2
less_gets                                            166     142     -24
less_getch                                           172      43    -129
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 6/5 up/down: 91/-170)           Total: -79 bytes
   text    data     bss     dec     hex filename



Modified:
   trunk/busybox/editors/vi.c
   trunk/busybox/include/libbb.h
   trunk/busybox/libbb/read_key.c
   trunk/busybox/miscutils/less.c


Changeset:
Modified: trunk/busybox/editors/vi.c
===================================================================
--- trunk/busybox/editors/vi.c	2008-10-25 23:23:32 UTC (rev 23787)
+++ trunk/busybox/editors/vi.c	2008-10-25 23:27:29 UTC (rev 23788)
@@ -193,7 +193,7 @@
 #if ENABLE_FEATURE_VI_CRASHME
 	char readbuffer[128];
 #else
-	char readbuffer[8];
+	char readbuffer[KEYCODE_BUFFER_SIZE];
 #endif
 #define STATUS_BUFFER_LEN  200
 	char status_buffer[STATUS_BUFFER_LEN]; // messages to the user

Modified: trunk/busybox/include/libbb.h
===================================================================
--- trunk/busybox/include/libbb.h	2008-10-25 23:23:32 UTC (rev 23787)
+++ trunk/busybox/include/libbb.h	2008-10-25 23:27:29 UTC (rev 23788)
@@ -950,6 +950,8 @@
 	KEYCODE_FUN11    = -22,
 	KEYCODE_FUN12    = -23,
 #endif
+	/* How long the longest ESC sequence we know? */
+	KEYCODE_BUFFER_SIZE = 4
 };
 int read_key(int fd, smalluint *nbuffered, char *buffer) FAST_FUNC;
 

Modified: trunk/busybox/libbb/read_key.c
===================================================================
--- trunk/busybox/libbb/read_key.c	2008-10-25 23:23:32 UTC (rev 23787)
+++ trunk/busybox/libbb/read_key.c	2008-10-25 23:27:29 UTC (rev 23788)
@@ -33,14 +33,16 @@
 		'[','B'        |0x80,KEYCODE_DOWN    ,
 		'[','C'        |0x80,KEYCODE_RIGHT   ,
 		'[','D'        |0x80,KEYCODE_LEFT    ,
-		'[','H'        |0x80,KEYCODE_HOME    ,
-		'[','F'        |0x80,KEYCODE_END     ,
-		'[','1','~'    |0x80,KEYCODE_HOME    ,
+		'[','H'        |0x80,KEYCODE_HOME    , /* xterm */
+		'[','F'        |0x80,KEYCODE_END     , /* xterm */
+		'[','1','~'    |0x80,KEYCODE_HOME    , /* vt100? linux vt? or what? */
 		'[','2','~'    |0x80,KEYCODE_INSERT  ,
 		'[','3','~'    |0x80,KEYCODE_DELETE  ,
-		'[','4','~'    |0x80,KEYCODE_END     ,
+		'[','4','~'    |0x80,KEYCODE_END     , /* vt100? linux vt? or what? */
 		'[','5','~'    |0x80,KEYCODE_PAGEUP  ,
 		'[','6','~'    |0x80,KEYCODE_PAGEDOWN,
+		'[','7','~'    |0x80,KEYCODE_HOME    , /* vt100? linux vt? or what? */
+		'[','8','~'    |0x80,KEYCODE_END     , /* vt100? linux vt? or what? */
 #if 0
 		'[','1','1','~'|0x80,KEYCODE_FUN1    ,
 		'[','1','2','~'|0x80,KEYCODE_FUN2    ,
@@ -58,7 +60,9 @@
 		0
 	};
 
-	n = *nbuffered;
+	n = 0;
+	if (nbuffered)
+		n = *nbuffered;
 	if (n == 0) {
 		/* If no data, block waiting for input. If we read more
 		 * than the minimal ESC sequence size, the "n=0" below
@@ -141,6 +145,7 @@
 	 * by now. */
 
  ret:
-	*nbuffered = n;
+	if (nbuffered)
+		*nbuffered = n;
 	return c;
 }

Modified: trunk/busybox/miscutils/less.c
===================================================================
--- trunk/busybox/miscutils/less.c	2008-10-25 23:23:32 UTC (rev 23787)
+++ trunk/busybox/miscutils/less.c	2008-10-25 23:27:29 UTC (rev 23788)
@@ -36,34 +36,9 @@
 /* The escape code to clear to end of line */
 #define CLEAR_2_EOL "\033[K"
 
-/* These are the escape sequences corresponding to special keys */
 enum {
-	REAL_KEY_UP = 'A',
-	REAL_KEY_DOWN = 'B',
-	REAL_KEY_RIGHT = 'C',
-	REAL_KEY_LEFT = 'D',
-	REAL_PAGE_UP = '5',
-	REAL_PAGE_DOWN = '6',
-	REAL_KEY_HOME = '7', // vt100? linux vt? or what?
-	REAL_KEY_END = '8',
-	REAL_KEY_HOME_ALT = '1', // ESC [1~ (vt100? linux vt? or what?)
-	REAL_KEY_END_ALT = '4', // ESC [4~
-	REAL_KEY_HOME_XTERM = 'H',
-	REAL_KEY_END_XTERM = 'F',
-
-/* These are the special codes assigned by this program to the special keys */
-	KEY_UP = 20,
-	KEY_DOWN = 21,
-	KEY_RIGHT = 22,
-	KEY_LEFT = 23,
-	PAGE_UP = 24,
-	PAGE_DOWN = 25,
-	KEY_HOME = 26,
-	KEY_END = 27,
-
 /* Absolute max of lines eaten */
 	MAXLINES = CONFIG_FEATURE_LESS_MAXLINES,
-
 /* This many "after the end" lines we will show (at max) */
 	TILDES = 1,
 };
@@ -133,6 +108,8 @@
 #define max_displayed_line  (G.max_displayed_line)
 #define width               (G.width             )
 #define winch_counter       (G.winch_counter     )
+/* This one is 100% not cached by compiler on read access */
+#define WINCH_COUNTER (*(volatile unsigned *)&winch_counter)
 #define eof_error           (G.eof_error         )
 #define readpos             (G.readpos           )
 #define readeof             (G.readeof           )
@@ -824,9 +801,10 @@
 	buffer_fill_and_print();
 }
 
-static ssize_t getch_nowait(char* input, int sz)
+static ssize_t getch_nowait(void)
 {
-	ssize_t rd;
+	char input[KEYCODE_BUFFER_SIZE];
+	int rd;
 	struct pollfd pfd[2];
 
 	pfd[0].fd = STDIN_FILENO;
@@ -842,34 +820,39 @@
 	 * (switch fd into O_NONBLOCK'ed mode to avoid it)
 	 */
 	rd = 1;
-	if (max_fline <= cur_fline + max_displayed_line
-	 && eof_error > 0 /* did NOT reach eof yet */
+	/* Are we interested in stdin? */
+//TODO: reuse code for determining this
+	if (!(option_mask32 & FLAG_S)
+	   ? !(max_fline > cur_fline + max_displayed_line)
+	   : !(max_fline >= cur_fline
+	       && max_lineno > LINENO(flines[cur_fline]) + max_displayed_line)
 	) {
-		/* We are interested in stdin */
-		rd = 0;
+		if (eof_error > 0) /* did NOT reach eof yet */
+			rd = 0; /* yes, we are interested in stdin */
 	}
-	/* position cursor if line input is done */
+	/* Position cursor if line input is done */
 	if (less_gets_pos >= 0)
 		move_cursor(max_displayed_line + 2, less_gets_pos + 1);
 	fflush(stdout);
 #if ENABLE_FEATURE_LESS_WINCH
 	while (1) {
 		int r;
+		/* NB: SIGWINCH interrupts poll() */
 		r = poll(pfd + rd, 2 - rd, -1);
-		if (/*r < 0 && errno == EINTR &&*/ winch_counter) {
-			input[0] = '\\'; /* anything which has no defined function */
-			return 1;
-		}
+		if (/*r < 0 && errno == EINTR &&*/ winch_counter)
+			return '\\'; /* anything which has no defined function */
 		if (r) break;
 	}
 #else
 	safe_poll(pfd + rd, 2 - rd, -1);
 #endif
 
-	input[0] = '\0';
-	rd = safe_read(kbd_fd, input, sz); /* NB: kbd_fd is in O_NONBLOCK mode */
-	if (rd < 0 && errno == EAGAIN) {
-		/* No keyboard input -> we have input on stdin! */
+	/* We have kbd_fd in O_NONBLOCK mode, read inside read_key()
+	 * would not block even if there is no input available */
+	rd = read_key(kbd_fd, NULL, input);
+	if (rd == -1 && errno == EAGAIN) {
+		/* No keyboard input available. Since poll() did return,
+		 * we should have input on stdin */
 		read_lines();
 		buffer_fill_and_print();
 		goto again;
@@ -883,51 +866,29 @@
  * special return codes. Note that this function works best with raw input. */
 static int less_getch(int pos)
 {
-	unsigned char input[16];
-	unsigned i;
+	int i;
 
  again:
 	less_gets_pos = pos;
-	memset(input, 0, sizeof(input));
-	getch_nowait((char *)input, sizeof(input));
+	i = getch_nowait();
 	less_gets_pos = -1;
 
-	/* Detect escape sequences (i.e. arrow keys) and handle
-	 * them accordingly */
-	if (input[0] == '\033' && input[1] == '[') {
-		i = input[2] - REAL_KEY_UP;
-		if (i < 4)
-			return 20 + i;
-		i = input[2] - REAL_PAGE_UP;
-		if (i < 4)
-			return 24 + i;
-		if (input[2] == REAL_KEY_HOME_XTERM)
-			return KEY_HOME;
-		if (input[2] == REAL_KEY_HOME_ALT)
-			return KEY_HOME;
-		if (input[2] == REAL_KEY_END_XTERM)
-			return KEY_END;
-		if (input[2] == REAL_KEY_END_ALT)
-			return KEY_END;
-		return 0;
-	}
-	/* Reject almost all control chars */
-	i = input[0];
-	if (i < ' ' && i != 0x0d && i != 8)
+	/* Discard Ctrl-something chars */
+	if (i >= 0 && i < ' ' && i != 0x0d && i != 8)
 		goto again;
 	return i;
 }
 
 static char* less_gets(int sz)
 {
-	char c;
+	int c;
 	unsigned i = 0;
 	char *result = xzalloc(1);
 
 	while (1) {
 		c = '\0';
 		less_gets_pos = sz + i;
-		getch_nowait(&c, 1);
+		c = getch_nowait();
 		if (c == 0x0d) {
 			result[i] = '\0';
 			less_gets_pos = -1;
@@ -939,7 +900,7 @@
 			printf("\x8 \x8");
 			i--;
 		}
-		if (c < ' ')
+		if (c < ' ') /* filters out KEYCODE_xxx too (<0) */
 			continue;
 		if (i >= width - sz - 1)
 			continue; /* len limit */
@@ -1151,8 +1112,8 @@
 {
 	unsigned i;
 	int num;
+	int keypress;
 	char num_input[sizeof(int)*4]; /* more than enough */
-	char keypress;
 
 	num_input[0] = first_digit;
 
@@ -1163,15 +1124,14 @@
 	/* Receive input until a letter is given */
 	i = 1;
 	while (i < sizeof(num_input)-1) {
-		num_input[i] = less_getch(i + 1);
-		if (!num_input[i] || !isdigit(num_input[i]))
+		keypress = less_getch(i + 1);
+		if ((unsigned)keypress > 255 || !isdigit(num_input[i]))
 			break;
-		bb_putchar(num_input[i]);
+		num_input[i] = keypress;
+		bb_putchar(keypress);
 		i++;
 	}
 
-	/* Take the final letter out of the digits string */
-	keypress = num_input[i];
 	num_input[i] = '\0';
 	num = bb_strtou(num_input, NULL, 10);
 	/* on format error, num == -1 */
@@ -1182,10 +1142,10 @@
 
 	/* We now know the number and the letter entered, so we process them */
 	switch (keypress) {
-	case KEY_DOWN: case 'z': case 'd': case 'e': case ' ': case '\015':
+	case KEYCODE_DOWN: case 'z': case 'd': case 'e': case ' ': case '\015':
 		buffer_down(num);
 		break;
-	case KEY_UP: case 'b': case 'w': case 'y': case 'u':
+	case KEYCODE_UP: case 'b': case 'w': case 'y': case 'u':
 		buffer_up(num);
 		break;
 	case 'g': case '<': case 'G': case '>':
@@ -1413,16 +1373,16 @@
 static void keypress_process(int keypress)
 {
 	switch (keypress) {
-	case KEY_DOWN: case 'e': case 'j': case 0x0d:
+	case KEYCODE_DOWN: case 'e': case 'j': case 0x0d:
 		buffer_down(1);
 		break;
-	case KEY_UP: case 'y': case 'k':
+	case KEYCODE_UP: case 'y': case 'k':
 		buffer_up(1);
 		break;
-	case PAGE_DOWN: case ' ': case 'z': case 'f':
+	case KEYCODE_PAGEDOWN: case ' ': case 'z': case 'f':
 		buffer_down(max_displayed_line + 1);
 		break;
-	case PAGE_UP: case 'w': case 'b':
+	case KEYCODE_PAGEUP: case 'w': case 'b':
 		buffer_up(max_displayed_line + 1);
 		break;
 	case 'd':
@@ -1431,10 +1391,10 @@
 	case 'u':
 		buffer_up((max_displayed_line + 1) / 2);
 		break;
-	case KEY_HOME: case 'g': case 'p': case '<': case '%':
+	case KEYCODE_HOME: case 'g': case 'p': case '<': case '%':
 		buffer_line(0);
 		break;
-	case KEY_END: case 'G': case '>':
+	case KEYCODE_END: case 'G': case '>':
 		cur_fline = MAXLINES;
 		read_lines();
 		buffer_line(cur_fline);
@@ -1586,7 +1546,8 @@
 	reinitialize();
 	while (1) {
 #if ENABLE_FEATURE_LESS_WINCH
-		if (winch_counter) {
+		while (WINCH_COUNTER) {
+ again:
 			winch_counter--;
 			get_terminal_width_height(kbd_fd, &width, &max_displayed_line);
 			/* 20: two tabstops + 4 */
@@ -1597,8 +1558,16 @@
 			max_displayed_line -= 2;
 			free(buffer);
 			buffer = xmalloc((max_displayed_line+1) * sizeof(char *));
+			/* Avoid re-wrap and/or redraw if we already know
+			 * we need to do it again. These ops are expensive */
+			if (WINCH_COUNTER)
+				goto again;
 			re_wrap();
+			if (WINCH_COUNTER)
+				goto again;
 			buffer_fill_and_print();
+			/* This took some time. Loop back and check,
+			 * were there another SIGWINCH? */
 		}
 #endif
 		keypress = less_getch(-1); /* -1: do not position cursor */




More information about the busybox-cvs mailing list