diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2009-10-26 12:09:06 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2009-10-26 12:09:06 +0100 |
commit | 0f91b3d0dc85af558306f65666779c9deae5fe4a (patch) | |
tree | 578923e04741a505e389efd16086b2f38a486b64 | |
parent | 180f585ac379d9eb2250d8cc4c11fbea38a1b844 (diff) | |
download | busybox-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.c | 124 |
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 | } |