aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2009-10-26 12:09:06 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2009-10-26 12:09:06 +0100
commit0f91b3d0dc85af558306f65666779c9deae5fe4a (patch)
tree578923e04741a505e389efd16086b2f38a486b64
parent180f585ac379d9eb2250d8cc4c11fbea38a1b844 (diff)
downloadbusybox-w32-0f91b3d0dc85af558306f65666779c9deae5fe4a.tar.gz
busybox-w32-0f91b3d0dc85af558306f65666779c9deae5fe4a.tar.bz2
busybox-w32-0f91b3d0dc85af558306f65666779c9deae5fe4a.zip
read_key: ignore unknown keys (do not return them to caller byte-by-byte)
function old new delta read_key 568 601 +33 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--libbb/read_key.c124
1 files changed, 74 insertions, 50 deletions
diff --git a/libbb/read_key.c b/libbb/read_key.c
index 02c381dd5..ec1b3a4a8 100644
--- a/libbb/read_key.c
+++ b/libbb/read_key.c
@@ -14,7 +14,6 @@ int64_t FAST_FUNC read_key(int fd, char *buffer)
14 struct pollfd pfd; 14 struct pollfd pfd;
15 const char *seq; 15 const char *seq;
16 int n; 16 int n;
17 int c;
18 17
19 /* Known escape sequences for cursor and function keys */ 18 /* Known escape sequences for cursor and function keys */
20 static const char esccmds[] ALIGN1 = { 19 static const char esccmds[] ALIGN1 = {
@@ -91,8 +90,11 @@ int64_t FAST_FUNC read_key(int fd, char *buffer)
91 /* ESC [ Z - Shift-Tab */ 90 /* ESC [ Z - Shift-Tab */
92 }; 91 };
93 92
93 buffer++; /* saved chars counter is in buffer[-1] now */
94
95 start_over:
94 errno = 0; 96 errno = 0;
95 n = (unsigned char) *buffer++; 97 n = (unsigned char)buffer[-1];
96 if (n == 0) { 98 if (n == 0) {
97 /* If no data, block waiting for input. 99 /* If no data, block waiting for input.
98 * It is tempting to read more than one byte here, 100 * It is tempting to read more than one byte here,
@@ -106,15 +108,17 @@ int64_t FAST_FUNC read_key(int fd, char *buffer)
106 return -1; 108 return -1;
107 } 109 }
108 110
109 /* Grab character to return from buffer */ 111 {
110 c = (unsigned char)buffer[0]; 112 unsigned char c = buffer[0];
111 n--; 113 n--;
112 if (n) 114 if (n)
113 memmove(buffer, buffer + 1, n); 115 memmove(buffer, buffer + 1, n);
114 116 /* Only ESC starts ESC sequences */
115 /* Only ESC starts ESC sequences */ 117 if (c != 27) {
116 if (c != 27) 118 buffer[-1] = n;
117 goto ret; 119 return c;
120 }
121 }
118 122
119 /* Loop through known ESC sequences */ 123 /* Loop through known ESC sequences */
120 pfd.fd = fd; 124 pfd.fd = fd;
@@ -136,17 +140,21 @@ int64_t FAST_FUNC read_key(int fd, char *buffer)
136 if (safe_poll(&pfd, 1, 50) == 0) { 140 if (safe_poll(&pfd, 1, 50) == 0) {
137 /* No more data! 141 /* No more data!
138 * Array is sorted from shortest to longest, 142 * Array is sorted from shortest to longest,
139 * we can't match anything later in array, 143 * we can't match anything later in array -
140 * break out of both loops. */ 144 * anything later is longer than this seq.
141 goto ret; 145 * Break out of both loops. */
146 goto got_all;
142 } 147 }
143 errno = 0; 148 errno = 0;
144 if (safe_read(fd, buffer + n, 1) <= 0) { 149 if (safe_read(fd, buffer + n, 1) <= 0) {
145 /* If EAGAIN, then fd is O_NONBLOCK and poll lied: 150 /* If EAGAIN, then fd is O_NONBLOCK and poll lied:
146 * in fact, there is no data. */ 151 * in fact, there is no data. */
147 if (errno != EAGAIN) 152 if (errno != EAGAIN) {
148 c = -1; /* otherwise it's EOF/error */ 153 /* otherwise: it's EOF/error */
149 goto ret; 154 buffer[-1] = 0;
155 return -1;
156 }
157 goto got_all;
150 } 158 }
151 n++; 159 n++;
152 } 160 }
@@ -162,66 +170,82 @@ int64_t FAST_FUNC read_key(int fd, char *buffer)
162 } 170 }
163 if (seq[i] & 0x80) { 171 if (seq[i] & 0x80) {
164 /* Entire seq matched */ 172 /* Entire seq matched */
165 c = (signed char)seq[i+1];
166 n = 0; 173 n = 0;
167 /* n -= i; memmove(...); 174 /* n -= i; memmove(...);
168 * would be more correct, 175 * would be more correct,
169 * but we never read ahead that much, 176 * but we never read ahead that much,
170 * and n == i here. */ 177 * and n == i here. */
171 goto ret; 178 buffer[-1] = 0;
179 return (signed char)seq[i+1];
172 } 180 }
173 i++; 181 i++;
174 } 182 }
175 } 183 }
176 /* We did not find matching sequence, it was a bare ESC. 184 /* We did not find matching sequence.
177 * We possibly read and stored more input in buffer[] by now. */ 185 * We possibly read and stored more input in buffer[] by now.
186 * n = bytes read. Try to read more until we time out.
187 */
188 while (n < KEYCODE_BUFFER_SIZE-1) { /* 1 for count byte at buffer[-1] */
189 if (safe_poll(&pfd, 1, 50) == 0) {
190 /* No more data! */
191 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 }
206 got_all:
207
208 if (n <= 1) {
209 /* Alt-x is usually returned as ESC x.
210 * Report ESC, x is remembered for the next call.
211 */
212 buffer[-1] = n;
213 return 27;
214 }
178 215
179 /* Try to decipher "ESC [ NNN ; NNN R" sequence */ 216 /* Try to decipher "ESC [ NNN ; NNN R" sequence */
180 if (ENABLE_FEATURE_EDITING_ASK_TERMINAL 217 if (ENABLE_FEATURE_EDITING_ASK_TERMINAL
181 && n != 0 218 && n >= 5
182 && buffer[0] == '[' 219 && buffer[0] == '['
220 && isdigit(buffer[1])
221 && buffer[n-1] == 'R'
183 ) { 222 ) {
184 char *end; 223 char *end;
185 unsigned long row, col; 224 unsigned long row, col;
186 225
187 while (n < KEYCODE_BUFFER_SIZE-1) { /* 1 for cnt */
188 if (safe_poll(&pfd, 1, 50) == 0) {
189 /* No more data! */
190 break;
191 }
192 errno = 0;
193 if (safe_read(fd, buffer + n, 1) <= 0) {
194 /* If EAGAIN, then fd is O_NONBLOCK and poll lied:
195 * in fact, there is no data. */
196 if (errno != EAGAIN)
197 c = -1; /* otherwise it's EOF/error */
198 goto ret;
199 }
200 if (buffer[n++] == 'R')
201 goto got_R;
202 }
203 goto ret;
204 got_R:
205 if (!isdigit(buffer[1]))
206 goto ret;
207 row = strtoul(buffer + 1, &end, 10); 226 row = strtoul(buffer + 1, &end, 10);
208 if (*end != ';' || !isdigit(end[1])) 227 if (*end != ';' || !isdigit(end[1]))
209 goto ret; 228 goto not_R;
210 col = strtoul(end + 1, &end, 10); 229 col = strtoul(end + 1, &end, 10);
211 if (*end != 'R') 230 if (*end != 'R')
212 goto ret; 231 goto not_R;
213 if (row < 1 || col < 1 || (row | col) > 0x7fff) 232 if (row < 1 || col < 1 || (row | col) > 0x7fff)
214 goto ret; 233 goto not_R;
215 234
216 buffer[-1] = 0; 235 buffer[-1] = 0;
217 236
218 /* Pack into "1 <row15bits> <col16bits>" 32-bit sequence */ 237 /* Pack into "1 <row15bits> <col16bits>" 32-bit sequence */
219 c = (((-1 << 15) | row) << 16) | col; 238 col |= (((-1 << 15) | row) << 16);
220 /* Return it in high-order word */ 239 /* Return it in high-order word */
221 return ((int64_t) c << 32) | (uint32_t)KEYCODE_CURSOR_POS; 240 return ((int64_t) col << 32) | (uint32_t)KEYCODE_CURSOR_POS;
222 } 241 }
242 not_R:
223 243
224 ret: 244 /* We were doing "buffer[-1] = n; return c;" here, but this results
225 buffer[-1] = n; 245 * in unknown key sequences being interpreted as ESC + garbage.
226 return c; 246 * This was not useful. Pretend there was no key pressed,
247 * go and wait for a new keypress:
248 */
249 buffer[-1] = 0;
250 goto start_over;
227} 251}