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>
This commit is contained in:
Denys Vlasenko 2009-10-26 12:09:06 +01:00
parent 180f585ac3
commit 0f91b3d0dc

View File

@ -14,7 +14,6 @@ int64_t FAST_FUNC read_key(int fd, char *buffer)
struct pollfd pfd;
const char *seq;
int n;
int c;
/* Known escape sequences for cursor and function keys */
static const char esccmds[] ALIGN1 = {
@ -91,8 +90,11 @@ int64_t FAST_FUNC read_key(int fd, char *buffer)
/* ESC [ Z - Shift-Tab */
};
buffer++; /* saved chars counter is in buffer[-1] now */
start_over:
errno = 0;
n = (unsigned char) *buffer++;
n = (unsigned char)buffer[-1];
if (n == 0) {
/* If no data, block waiting for input.
* It is tempting to read more than one byte here,
@ -106,15 +108,17 @@ int64_t FAST_FUNC read_key(int fd, char *buffer)
return -1;
}
/* Grab character to return from buffer */
c = (unsigned char)buffer[0];
{
unsigned char c = buffer[0];
n--;
if (n)
memmove(buffer, buffer + 1, n);
/* Only ESC starts ESC sequences */
if (c != 27)
goto ret;
if (c != 27) {
buffer[-1] = n;
return c;
}
}
/* Loop through known ESC sequences */
pfd.fd = fd;
@ -136,17 +140,21 @@ int64_t FAST_FUNC read_key(int fd, char *buffer)
if (safe_poll(&pfd, 1, 50) == 0) {
/* No more data!
* Array is sorted from shortest to longest,
* we can't match anything later in array,
* break out of both loops. */
goto ret;
* we can't match anything later in array -
* anything later is longer than this seq.
* Break out of both loops. */
goto got_all;
}
errno = 0;
if (safe_read(fd, buffer + n, 1) <= 0) {
/* If EAGAIN, then fd is O_NONBLOCK and poll lied:
* in fact, there is no data. */
if (errno != EAGAIN)
c = -1; /* otherwise it's EOF/error */
goto ret;
if (errno != EAGAIN) {
/* otherwise: it's EOF/error */
buffer[-1] = 0;
return -1;
}
goto got_all;
}
n++;
}
@ -162,29 +170,22 @@ int64_t FAST_FUNC read_key(int fd, char *buffer)
}
if (seq[i] & 0x80) {
/* Entire seq matched */
c = (signed char)seq[i+1];
n = 0;
/* n -= i; memmove(...);
* would be more correct,
* but we never read ahead that much,
* and n == i here. */
goto ret;
buffer[-1] = 0;
return (signed char)seq[i+1];
}
i++;
}
}
/* We did not find matching sequence, it was a bare ESC.
* We possibly read and stored more input in buffer[] by now. */
/* Try to decipher "ESC [ NNN ; NNN R" sequence */
if (ENABLE_FEATURE_EDITING_ASK_TERMINAL
&& n != 0
&& buffer[0] == '['
) {
char *end;
unsigned long row, col;
while (n < KEYCODE_BUFFER_SIZE-1) { /* 1 for cnt */
/* We did not find matching sequence.
* We possibly read and stored more input in buffer[] by now.
* n = bytes read. Try to read more until we time out.
*/
while (n < KEYCODE_BUFFER_SIZE-1) { /* 1 for count byte at buffer[-1] */
if (safe_poll(&pfd, 1, 50) == 0) {
/* No more data! */
break;
@ -193,35 +194,58 @@ int64_t FAST_FUNC read_key(int fd, char *buffer)
if (safe_read(fd, buffer + n, 1) <= 0) {
/* If EAGAIN, then fd is O_NONBLOCK and poll lied:
* in fact, there is no data. */
if (errno != EAGAIN)
c = -1; /* otherwise it's EOF/error */
goto ret;
if (errno != EAGAIN) {
/* otherwise: it's EOF/error */
buffer[-1] = 0;
return -1;
}
if (buffer[n++] == 'R')
goto got_R;
break;
}
goto ret;
got_R:
if (!isdigit(buffer[1]))
goto ret;
n++;
}
got_all:
if (n <= 1) {
/* Alt-x is usually returned as ESC x.
* Report ESC, x is remembered for the next call.
*/
buffer[-1] = n;
return 27;
}
/* Try to decipher "ESC [ NNN ; NNN R" sequence */
if (ENABLE_FEATURE_EDITING_ASK_TERMINAL
&& n >= 5
&& buffer[0] == '['
&& isdigit(buffer[1])
&& buffer[n-1] == 'R'
) {
char *end;
unsigned long row, col;
row = strtoul(buffer + 1, &end, 10);
if (*end != ';' || !isdigit(end[1]))
goto ret;
goto not_R;
col = strtoul(end + 1, &end, 10);
if (*end != 'R')
goto ret;
goto not_R;
if (row < 1 || col < 1 || (row | col) > 0x7fff)
goto ret;
goto not_R;
buffer[-1] = 0;
/* Pack into "1 <row15bits> <col16bits>" 32-bit sequence */
c = (((-1 << 15) | row) << 16) | col;
col |= (((-1 << 15) | row) << 16);
/* Return it in high-order word */
return ((int64_t) c << 32) | (uint32_t)KEYCODE_CURSOR_POS;
return ((int64_t) col << 32) | (uint32_t)KEYCODE_CURSOR_POS;
}
not_R:
ret:
buffer[-1] = n;
return c;
/* We were doing "buffer[-1] = n; return c;" here, but this results
* in unknown key sequences being interpreted as ESC + garbage.
* This was not useful. Pretend there was no key pressed,
* go and wait for a new keypress:
*/
buffer[-1] = 0;
goto start_over;
}