Magellan Linux

Diff of /trunk/mkinitrd-magellan/busybox/libbb/read_key.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 983 by niro, Fri Apr 24 18:33:46 2009 UTC revision 984 by niro, Sun May 30 11:32:42 2010 UTC
# Line 9  Line 9 
9   */   */
10  #include "libbb.h"  #include "libbb.h"
11    
12  int FAST_FUNC read_key(int fd, smalluint *nbuffered, char *buffer)  int64_t FAST_FUNC read_key(int fd, char *buffer)
13  {  {
14   struct pollfd pfd;   struct pollfd pfd;
15   const char *seq;   const char *seq;
16   int n;   int n;
  int c;  
17    
18   /* Known escape sequences for cursor and function keys */   /* Known escape sequences for cursor and function keys */
19   static const char esccmds[] ALIGN1 = {   static const char esccmds[] ALIGN1 = {
# Line 27  int FAST_FUNC read_key(int fd, smalluint Line 26  int FAST_FUNC read_key(int fd, smalluint
26  #if 0  #if 0
27   'O','P'        |0x80,KEYCODE_FUN1    ,   'O','P'        |0x80,KEYCODE_FUN1    ,
28   /* [ESC] ESC O [2] P - [Alt-][Shift-]F1 */   /* [ESC] ESC O [2] P - [Alt-][Shift-]F1 */
29   /* Ctrl- seems to not affect sequences */   /* ESC [ O 1 ; 2 P - Shift-F1 */
30     /* ESC [ O 1 ; 3 P - Alt-F1 */
31     /* ESC [ O 1 ; 4 P - Alt-Shift-F1 */
32     /* ESC [ O 1 ; 5 P - Ctrl-F1 */
33     /* ESC [ O 1 ; 6 P - Ctrl-Shift-F1 */
34   'O','Q'        |0x80,KEYCODE_FUN2    ,   'O','Q'        |0x80,KEYCODE_FUN2    ,
35   'O','R'        |0x80,KEYCODE_FUN3    ,   'O','R'        |0x80,KEYCODE_FUN3    ,
36   'O','S'        |0x80,KEYCODE_FUN4    ,   'O','S'        |0x80,KEYCODE_FUN4    ,
# Line 36  int FAST_FUNC read_key(int fd, smalluint Line 39  int FAST_FUNC read_key(int fd, smalluint
39   '[','B'        |0x80,KEYCODE_DOWN    ,   '[','B'        |0x80,KEYCODE_DOWN    ,
40   '[','C'        |0x80,KEYCODE_RIGHT   ,   '[','C'        |0x80,KEYCODE_RIGHT   ,
41   '[','D'        |0x80,KEYCODE_LEFT    ,   '[','D'        |0x80,KEYCODE_LEFT    ,
42     /* ESC [ 1 ; 2 x, where x = A/B/C/D: Shift-<arrow> */
43     /* ESC [ 1 ; 3 x, where x = A/B/C/D: Alt-<arrow> */
44     /* ESC [ 1 ; 4 x, where x = A/B/C/D: Alt-Shift-<arrow> */
45     /* ESC [ 1 ; 5 x, where x = A/B/C/D: Ctrl-<arrow> - implemented below */
46     /* ESC [ 1 ; 6 x, where x = A/B/C/D: Ctrl-Shift-<arrow> */
47   '[','H'        |0x80,KEYCODE_HOME    , /* xterm */   '[','H'        |0x80,KEYCODE_HOME    , /* xterm */
48   /* [ESC] ESC [ [2] H - [Alt-][Shift-]Home */   /* [ESC] ESC [ [2] H - [Alt-][Shift-]Home */
49   '[','F'        |0x80,KEYCODE_END     , /* xterm */   '[','F'        |0x80,KEYCODE_END     , /* xterm */
50   '[','1','~'    |0x80,KEYCODE_HOME    , /* vt100? linux vt? or what? */   '[','1','~'    |0x80,KEYCODE_HOME    , /* vt100? linux vt? or what? */
51   '[','2','~'    |0x80,KEYCODE_INSERT  ,   '[','2','~'    |0x80,KEYCODE_INSERT  ,
52     /* ESC [ 2 ; 3 ~ - Alt-Insert */
53   '[','3','~'    |0x80,KEYCODE_DELETE  ,   '[','3','~'    |0x80,KEYCODE_DELETE  ,
54   /* [ESC] ESC [ 3 [;2] ~ - [Alt-][Shift-]Delete */   /* [ESC] ESC [ 3 [;2] ~ - [Alt-][Shift-]Delete */
55     /* ESC [ 3 ; 3 ~ - Alt-Delete */
56     /* ESC [ 3 ; 5 ~ - Ctrl-Delete */
57   '[','4','~'    |0x80,KEYCODE_END     , /* vt100? linux vt? or what? */   '[','4','~'    |0x80,KEYCODE_END     , /* vt100? linux vt? or what? */
58   '[','5','~'    |0x80,KEYCODE_PAGEUP  ,   '[','5','~'    |0x80,KEYCODE_PAGEUP  ,
59     /* ESC [ 5 ; 3 ~ - Alt-PgUp */
60     /* ESC [ 5 ; 5 ~ - Ctrl-PgUp */
61     /* ESC [ 5 ; 7 ~ - Ctrl-Alt-PgUp */
62   '[','6','~'    |0x80,KEYCODE_PAGEDOWN,   '[','6','~'    |0x80,KEYCODE_PAGEDOWN,
63   '[','7','~'    |0x80,KEYCODE_HOME    , /* vt100? linux vt? or what? */   '[','7','~'    |0x80,KEYCODE_HOME    , /* vt100? linux vt? or what? */
64   '[','8','~'    |0x80,KEYCODE_END     , /* vt100? linux vt? or what? */   '[','8','~'    |0x80,KEYCODE_END     , /* vt100? linux vt? or what? */
# Line 62  int FAST_FUNC read_key(int fd, smalluint Line 76  int FAST_FUNC read_key(int fd, smalluint
76   '[','2','1','~'|0x80,KEYCODE_FUN10   ,   '[','2','1','~'|0x80,KEYCODE_FUN10   ,
77   '[','2','3','~'|0x80,KEYCODE_FUN11   ,   '[','2','3','~'|0x80,KEYCODE_FUN11   ,
78   '[','2','4','~'|0x80,KEYCODE_FUN12   ,   '[','2','4','~'|0x80,KEYCODE_FUN12   ,
79     /* ESC [ 2 4 ; 2 ~ - Shift-F12 */
80     /* ESC [ 2 4 ; 3 ~ - Alt-F12 */
81     /* ESC [ 2 4 ; 4 ~ - Alt-Shift-F12 */
82     /* ESC [ 2 4 ; 5 ~ - Ctrl-F12 */
83     /* ESC [ 2 4 ; 6 ~ - Ctrl-Shift-F12 */
84  #endif  #endif
85     /* '[','1',';','5','A' |0x80,KEYCODE_CTRL_UP   , - unused */
86     /* '[','1',';','5','B' |0x80,KEYCODE_CTRL_DOWN , - unused */
87     '[','1',';','5','C' |0x80,KEYCODE_CTRL_RIGHT,
88     '[','1',';','5','D' |0x80,KEYCODE_CTRL_LEFT ,
89   0   0
90     /* ESC [ Z - Shift-Tab */
91   };   };
92    
93   n = 0;   buffer++; /* saved chars counter is in buffer[-1] now */
94   if (nbuffered)  
95   n = *nbuffered;   start_over:
96     errno = 0;
97     n = (unsigned char)buffer[-1];
98   if (n == 0) {   if (n == 0) {
99   /* If no data, block waiting for input. If we read more   /* If no data, block waiting for input.
100   * than the minimal ESC sequence size, the "n=0" below   * It is tempting to read more than one byte here,
101   * would instead have to figure out how much to keep,   * but it breaks pasting. Example: at shell prompt,
102   * resulting in larger code. */   * user presses "c","a","t" and then pastes "\nline\n".
103   n = safe_read(fd, buffer, 3);   * When we were reading 3 bytes here, we were eating
104     * "li" too, and cat was getting wrong input.
105     */
106     n = safe_read(fd, buffer, 1);
107   if (n <= 0)   if (n <= 0)
108   return -1;   return -1;
109   }   }
110    
111   /* Grab character to return from buffer */   {
112   c = (unsigned char)buffer[0];   unsigned char c = buffer[0];
113   n--;   n--;
114   if (n)   if (n)
115   memmove(buffer, buffer + 1, n);   memmove(buffer, buffer + 1, n);
116     /* Only ESC starts ESC sequences */
117   /* Only ESC starts ESC sequences */   if (c != 27) {
118   if (c != 27)   buffer[-1] = n;
119   goto ret;   return c;
120     }
121     }
122    
123   /* Loop through known ESC sequences */   /* Loop through known ESC sequences */
124   pfd.fd = fd;   pfd.fd = fd;
# Line 109  int FAST_FUNC read_key(int fd, smalluint Line 140  int FAST_FUNC read_key(int fd, smalluint
140   if (safe_poll(&pfd, 1, 50) == 0) {   if (safe_poll(&pfd, 1, 50) == 0) {
141   /* No more data!   /* No more data!
142   * Array is sorted from shortest to longest,   * Array is sorted from shortest to longest,
143   * we can't match anything later in array,   * we can't match anything later in array -
144   * break out of both loops. */   * anything later is longer than this seq.
145   goto ret;   * Break out of both loops. */
146     goto got_all;
147   }   }
148   errno = 0;   errno = 0;
149   if (safe_read(fd, buffer + n, 1) <= 0) {   if (safe_read(fd, buffer + n, 1) <= 0) {
150   /* If EAGAIN, then fd is O_NONBLOCK and poll lied:   /* If EAGAIN, then fd is O_NONBLOCK and poll lied:
151   * in fact, there is no data. */   * in fact, there is no data. */
152   if (errno != EAGAIN)   if (errno != EAGAIN) {
153   c = -1; /* otherwise it's EOF/error */   /* otherwise: it's EOF/error */
154   goto ret;   buffer[-1] = 0;
155     return -1;
156     }
157     goto got_all;
158   }   }
159   n++;   n++;
160   }   }
# Line 135  int FAST_FUNC read_key(int fd, smalluint Line 170  int FAST_FUNC read_key(int fd, smalluint
170   }   }
171   if (seq[i] & 0x80) {   if (seq[i] & 0x80) {
172   /* Entire seq matched */   /* Entire seq matched */
  c = (signed char)seq[i+1];  
173   n = 0;   n = 0;
174   /* n -= i; memmove(...);   /* n -= i; memmove(...);
175   * would be more correct,   * would be more correct,
176   * but we never read ahead that much,   * but we never read ahead that much,
177   * and n == i here. */   * and n == i here. */
178   goto ret;   buffer[-1] = 0;
179     return (signed char)seq[i+1];
180   }   }
181   i++;   i++;
182   }   }
183   }   }
184   /* We did not find matching sequence, it was a bare ESC.   /* We did not find matching sequence.
185   * We possibly read and stored more input in buffer[]   * We possibly read and stored more input in buffer[] by now.
186   * by now. */   * n = bytes read. Try to read more until we time out.
187     */
188   ret:   while (n < KEYCODE_BUFFER_SIZE-1) { /* 1 for count byte at buffer[-1] */
189   if (nbuffered)   if (safe_poll(&pfd, 1, 50) == 0) {
190   *nbuffered = n;   /* No more data! */
191   return c;   break;
192     }
193     errno = 0;
194     if (safe_read(fd, buffer + n, 1) <= 0) {
195     /* If EAGAIN, then fd is O_NONBLOCK and poll lied:
196     * in fact, there is no data. */
197     if (errno != EAGAIN) {
198     /* otherwise: it's EOF/error */
199     buffer[-1] = 0;
200     return -1;
201     }
202     break;
203     }
204     n++;
205     /* Try to decipher "ESC [ NNN ; NNN R" sequence */
206     if (ENABLE_FEATURE_EDITING_ASK_TERMINAL
207     && n >= 5
208     && buffer[0] == '['
209     && buffer[n-1] == 'R'
210     && isdigit(buffer[1])
211     ) {
212     char *end;
213     unsigned long row, col;
214    
215     row = strtoul(buffer + 1, &end, 10);
216     if (*end != ';' || !isdigit(end[1]))
217     continue;
218     col = strtoul(end + 1, &end, 10);
219     if (*end != 'R')
220     continue;
221     if (row < 1 || col < 1 || (row | col) > 0x7fff)
222     continue;
223    
224     buffer[-1] = 0;
225     /* Pack into "1 <row15bits> <col16bits>" 32-bit sequence */
226     col |= (((-1 << 15) | row) << 16);
227     /* Return it in high-order word */
228     return ((int64_t) col << 32) | (uint32_t)KEYCODE_CURSOR_POS;
229     }
230     }
231     got_all:
232    
233     if (n <= 1) {
234     /* Alt-x is usually returned as ESC x.
235     * Report ESC, x is remembered for the next call.
236     */
237     buffer[-1] = n;
238     return 27;
239     }
240    
241     /* We were doing "buffer[-1] = n; return c;" here, but this results
242     * in unknown key sequences being interpreted as ESC + garbage.
243     * This was not useful. Pretend there was no key pressed,
244     * go and wait for a new keypress:
245     */
246     buffer[-1] = 0;
247     goto start_over;
248  }  }

Legend:
Removed from v.983  
changed lines
  Added in v.984