diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2010-03-11 21:17:55 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-03-11 21:17:55 +0100 |
commit | 58f108eb339957f58d5a6034d82b09c4d50b53e3 (patch) | |
tree | 4fdfae71136811f3b9c8ffd56656b78da19739da /libbb/lineedit.c | |
parent | b0a57abb79001b994115d2c96a7d9e1f2f511430 (diff) | |
download | busybox-w32-58f108eb339957f58d5a6034d82b09c4d50b53e3.tar.gz busybox-w32-58f108eb339957f58d5a6034d82b09c4d50b53e3.tar.bz2 busybox-w32-58f108eb339957f58d5a6034d82b09c4d50b53e3.zip |
lineedit: fix another corner case with bad unicode input
function old new delta
read_key 607 646 +39
readit 50 55 +5
getch_nowait 290 295 +5
hash_find 233 234 +1
xstrtoul_range_sfx 231 230 -1
passwd_main 1058 1056 -2
builtin_exit 45 43 -2
cmp_main 649 645 -4
lineedit_read_key 257 245 -12
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 4/5 up/down: 50/-21) Total: 29 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'libbb/lineedit.c')
-rw-r--r-- | libbb/lineedit.c | 45 |
1 files changed, 24 insertions, 21 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 8e339da53..7c0eef90d 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c | |||
@@ -1658,27 +1658,28 @@ static void win_changed(int nsig) | |||
1658 | static int lineedit_read_key(char *read_key_buffer) | 1658 | static int lineedit_read_key(char *read_key_buffer) |
1659 | { | 1659 | { |
1660 | int64_t ic; | 1660 | int64_t ic; |
1661 | struct pollfd pfd; | 1661 | int timeout = -1; |
1662 | int delay = -1; | ||
1663 | #if ENABLE_FEATURE_ASSUME_UNICODE | 1662 | #if ENABLE_FEATURE_ASSUME_UNICODE |
1664 | char unicode_buf[MB_CUR_MAX + 1]; | 1663 | char unicode_buf[MB_CUR_MAX + 1]; |
1665 | int unicode_idx = 0; | 1664 | int unicode_idx = 0; |
1666 | #endif | 1665 | #endif |
1667 | 1666 | ||
1668 | pfd.fd = STDIN_FILENO; | 1667 | while (1) { |
1669 | pfd.events = POLLIN; | 1668 | /* Wait for input. TIMEOUT = -1 makes read_key wait even |
1670 | do { | 1669 | * on nonblocking stdin, TIMEOUT = 50 makes sure we won't |
1671 | #if ENABLE_FEATURE_EDITING_ASK_TERMINAL || ENABLE_FEATURE_ASSUME_UNICODE | 1670 | * insist on full MB_CUR_MAX buffer to declare input like |
1672 | poll_again: | 1671 | * "\xff\n",pause,"ls\n" invalid and thus won't lose "ls". |
1672 | * | ||
1673 | * Note: read_key sets errno to 0 on success. | ||
1674 | */ | ||
1675 | ic = read_key(STDIN_FILENO, read_key_buffer, timeout); | ||
1676 | if (errno) { | ||
1677 | #if ENABLE_FEATURE_ASSUME_UNICODE | ||
1678 | if (errno == EAGAIN && unicode_idx != 0) | ||
1679 | goto pushback; | ||
1673 | #endif | 1680 | #endif |
1674 | if (read_key_buffer[0] == 0) { | 1681 | break; |
1675 | /* Wait for input. Can't just call read_key, | ||
1676 | * it returns at once if stdin | ||
1677 | * is in non-blocking mode. */ | ||
1678 | safe_poll(&pfd, 1, delay); | ||
1679 | } | 1682 | } |
1680 | /* Note: read_key sets errno to 0 on success: */ | ||
1681 | ic = read_key(STDIN_FILENO, read_key_buffer); | ||
1682 | 1683 | ||
1683 | #if ENABLE_FEATURE_EDITING_ASK_TERMINAL | 1684 | #if ENABLE_FEATURE_EDITING_ASK_TERMINAL |
1684 | if ((int32_t)ic == KEYCODE_CURSOR_POS | 1685 | if ((int32_t)ic == KEYCODE_CURSOR_POS |
@@ -1695,7 +1696,7 @@ static int lineedit_read_key(char *read_key_buffer) | |||
1695 | } | 1696 | } |
1696 | } | 1697 | } |
1697 | } | 1698 | } |
1698 | goto poll_again; | 1699 | continue; |
1699 | } | 1700 | } |
1700 | #endif | 1701 | #endif |
1701 | 1702 | ||
@@ -1704,19 +1705,20 @@ static int lineedit_read_key(char *read_key_buffer) | |||
1704 | wchar_t wc; | 1705 | wchar_t wc; |
1705 | 1706 | ||
1706 | if ((int32_t)ic < 0) /* KEYCODE_xxx */ | 1707 | if ((int32_t)ic < 0) /* KEYCODE_xxx */ |
1707 | return ic; | 1708 | break; |
1708 | // TODO: imagine sequence like: 0xff, <left-arrow>: we are currently losing 0xff... | 1709 | // TODO: imagine sequence like: 0xff,<left-arrow>: we are currently losing 0xff... |
1709 | 1710 | ||
1710 | unicode_buf[unicode_idx++] = ic; | 1711 | unicode_buf[unicode_idx++] = ic; |
1711 | unicode_buf[unicode_idx] = '\0'; | 1712 | unicode_buf[unicode_idx] = '\0'; |
1712 | if (mbstowcs(&wc, unicode_buf, 1) != 1) { | 1713 | if (mbstowcs(&wc, unicode_buf, 1) != 1) { |
1713 | /* Not (yet?) a valid unicode char */ | 1714 | /* Not (yet?) a valid unicode char */ |
1714 | if (unicode_idx < MB_CUR_MAX) { | 1715 | if (unicode_idx < MB_CUR_MAX) { |
1715 | delay = 50; | 1716 | timeout = 50; |
1716 | goto poll_again; | 1717 | continue; |
1717 | } | 1718 | } |
1719 | pushback: | ||
1718 | /* Invalid sequence. Save all "bad bytes" except first */ | 1720 | /* Invalid sequence. Save all "bad bytes" except first */ |
1719 | read_key_ungets(read_key_buffer, unicode_buf + 1, MB_CUR_MAX - 1); | 1721 | read_key_ungets(read_key_buffer, unicode_buf + 1, unicode_idx - 1); |
1720 | /* | 1722 | /* |
1721 | * ic = unicode_buf[0] sounds even better, but currently | 1723 | * ic = unicode_buf[0] sounds even better, but currently |
1722 | * this does not work: wchar_t[] -> char[] conversion | 1724 | * this does not work: wchar_t[] -> char[] conversion |
@@ -1730,7 +1732,8 @@ static int lineedit_read_key(char *read_key_buffer) | |||
1730 | } | 1732 | } |
1731 | } | 1733 | } |
1732 | #endif | 1734 | #endif |
1733 | } while (errno == EAGAIN); | 1735 | break; |
1736 | } | ||
1734 | 1737 | ||
1735 | return ic; | 1738 | return ic; |
1736 | } | 1739 | } |