aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomas Heinrich <heinrich.tomas@gmail.com>2010-05-16 20:46:53 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2010-05-16 20:46:53 +0200
commitb8909c52fe850d2731326534822164c2f5258bf5 (patch)
tree2e33d71a3caf8861b2380d8e07841dd0eab09a8a
parent0b7412e66b3d702557a2bf214752ff68d80fcda3 (diff)
downloadbusybox-w32-b8909c52fe850d2731326534822164c2f5258bf5.tar.gz
busybox-w32-b8909c52fe850d2731326534822164c2f5258bf5.tar.bz2
busybox-w32-b8909c52fe850d2731326534822164c2f5258bf5.zip
lineedit: partially fix wide and combining chars editing
Signed-off-by: Tomas Heinrich <heinrich.tomas@gmail.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--include/unicode.h11
-rw-r--r--libbb/lineedit.c124
-rw-r--r--libbb/unicode.c2
3 files changed, 92 insertions, 45 deletions
diff --git a/include/unicode.h b/include/unicode.h
index 4e2927297..747026abe 100644
--- a/include/unicode.h
+++ b/include/unicode.h
@@ -35,6 +35,16 @@ enum {
35# define LAST_SUPPORTED_WCHAR CONFIG_LAST_SUPPORTED_WCHAR 35# define LAST_SUPPORTED_WCHAR CONFIG_LAST_SUPPORTED_WCHAR
36# endif 36# endif
37 37
38# if LAST_SUPPORTED_WCHAR < 0x300
39# undef ENABLE_UNICODE_COMBINING_WCHARS
40# define ENABLE_UNICODE_COMBINING_WCHARS 0
41# endif
42
43# if LAST_SUPPORTED_WCHAR < 0x1100
44# undef ENABLE_UNICODE_WIDE_WCHARS
45# define ENABLE_UNICODE_WIDE_WCHARS 0
46# endif
47
38# if LAST_SUPPORTED_WCHAR < 0x590 48# if LAST_SUPPORTED_WCHAR < 0x590
39# undef ENABLE_UNICODE_BIDI_SUPPORT 49# undef ENABLE_UNICODE_BIDI_SUPPORT
40# define ENABLE_UNICODE_BIDI_SUPPORT 0 50# define ENABLE_UNICODE_BIDI_SUPPORT 0
@@ -92,6 +102,7 @@ size_t wcrtomb(char *s, wchar_t wc, mbstate_t *ps) FAST_FUNC;
92int iswspace(wint_t wc) FAST_FUNC; 102int iswspace(wint_t wc) FAST_FUNC;
93int iswalnum(wint_t wc) FAST_FUNC; 103int iswalnum(wint_t wc) FAST_FUNC;
94int iswpunct(wint_t wc) FAST_FUNC; 104int iswpunct(wint_t wc) FAST_FUNC;
105int wcwidth(unsigned ucs) FAST_FUNC;
95# if ENABLE_UNICODE_BIDI_SUPPORT 106# if ENABLE_UNICODE_BIDI_SUPPORT
96# undef unicode_bidi_isrtl 107# undef unicode_bidi_isrtl
97int unicode_bidi_isrtl(wint_t wc) FAST_FUNC; 108int unicode_bidi_isrtl(wint_t wc) FAST_FUNC;
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 7fffe7ba2..9f2d65717 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -42,14 +42,10 @@
42#include "libbb.h" 42#include "libbb.h"
43#include "unicode.h" 43#include "unicode.h"
44 44
45/* FIXME: obsolete CONFIG item? */
46#define ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 0
47
48#ifdef TEST 45#ifdef TEST
49# define ENABLE_FEATURE_EDITING 0 46# define ENABLE_FEATURE_EDITING 0
50# define ENABLE_FEATURE_TAB_COMPLETION 0 47# define ENABLE_FEATURE_TAB_COMPLETION 0
51# define ENABLE_FEATURE_USERNAME_COMPLETION 0 48# define ENABLE_FEATURE_USERNAME_COMPLETION 0
52# define ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 0
53#endif 49#endif
54 50
55 51
@@ -97,10 +93,10 @@ static bool BB_ispunct(CHAR_T c) { return ((unsigned)c < 256 && ispunct(c)); }
97 93
98 94
99# if ENABLE_UNICODE_PRESERVE_BROKEN 95# if ENABLE_UNICODE_PRESERVE_BROKEN
100# define unicode_mark_inv_wchar(wc) ((wc) | 0x20000000) 96# define unicode_mark_raw_byte(wc) ((wc) | 0x20000000)
101# define unicode_is_inv_wchar(wc) ((wc) & 0x20000000) 97# define unicode_is_raw_byte(wc) ((wc) & 0x20000000)
102# else 98# else
103# define unicode_is_inv_wchar(wc) 0 99# define unicode_is_raw_byte(wc) 0
104# endif 100# endif
105 101
106 102
@@ -240,7 +236,7 @@ static unsigned save_string(char *dst, unsigned maxsize)
240 wchar_t wc; 236 wchar_t wc;
241 int n = srcpos; 237 int n = srcpos;
242 while ((wc = command_ps[srcpos]) != 0 238 while ((wc = command_ps[srcpos]) != 0
243 && !unicode_is_inv_wchar(wc) 239 && !unicode_is_raw_byte(wc)
244 ) { 240 ) {
245 srcpos++; 241 srcpos++;
246 } 242 }
@@ -269,15 +265,45 @@ static void BB_PUTCHAR(wchar_t c)
269 mbstate_t mbst = { 0 }; 265 mbstate_t mbst = { 0 };
270 ssize_t len; 266 ssize_t len;
271 267
272 if (unicode_is_inv_wchar(c))
273 c = CONFIG_SUBST_WCHAR;
274 len = wcrtomb(buf, c, &mbst); 268 len = wcrtomb(buf, c, &mbst);
275 if (len > 0) { 269 if (len > 0) {
276 buf[len] = '\0'; 270 buf[len] = '\0';
277 fputs(buf, stdout); 271 fputs(buf, stdout);
278 } 272 }
279} 273}
280#else 274# if ENABLE_UNICODE_COMBINING_WCHARS || ENABLE_UNICODE_WIDE_WCHARS
275static wchar_t adjust_width_and_validate_wc(unsigned *width_adj, wchar_t wc)
276# else
277static wchar_t adjust_width_and_validate_wc(wchar_t wc)
278# define adjust_width_and_validate_wc(width_adj, wc) \
279 ((*(width_adj))++, adjust_width_and_validate_wc(wc))
280# endif
281{
282 int w = 1;
283
284 if (unicode_status == UNICODE_ON) {
285 if (unicode_is_raw_byte(wc)
286 || (CONFIG_LAST_SUPPORTED_WCHAR && wc > CONFIG_LAST_SUPPORTED_WCHAR)
287 ) {
288 goto subst;
289 }
290 w = wcwidth(wc);
291 if ((ENABLE_UNICODE_COMBINING_WCHARS && w < 0)
292 || (!ENABLE_UNICODE_COMBINING_WCHARS && w <= 0)
293 || (!ENABLE_UNICODE_WIDE_WCHARS && w > 1)
294 ) {
295 subst:
296 w = 1;
297 wc = CONFIG_SUBST_WCHAR;
298 }
299 }
300
301# if ENABLE_UNICODE_COMBINING_WCHARS || ENABLE_UNICODE_WIDE_WCHARS
302 *width_adj += w;
303#endif
304 return wc;
305}
306#else /* !UNICODE */
281static size_t load_string(const char *src, int maxsize) 307static size_t load_string(const char *src, int maxsize)
282{ 308{
283 safe_strncpy(command_ps, src, maxsize); 309 safe_strncpy(command_ps, src, maxsize);
@@ -290,6 +316,8 @@ static void save_string(char *dst, unsigned maxsize)
290} 316}
291# endif 317# endif
292# define BB_PUTCHAR(c) bb_putchar(c) 318# define BB_PUTCHAR(c) bb_putchar(c)
319/* Should never be called: */
320int adjust_width_and_validate_wc(unsigned *width_adj, int wc);
293#endif 321#endif
294 322
295 323
@@ -300,6 +328,8 @@ static void save_string(char *dst, unsigned maxsize)
300static void put_cur_glyph_and_inc_cursor(void) 328static void put_cur_glyph_and_inc_cursor(void)
301{ 329{
302 CHAR_T c = command_ps[cursor]; 330 CHAR_T c = command_ps[cursor];
331 unsigned width = 0;
332 int ofs_to_right;
303 333
304 if (c == BB_NUL) { 334 if (c == BB_NUL) {
305 /* erase character after end of input string */ 335 /* erase character after end of input string */
@@ -307,28 +337,23 @@ static void put_cur_glyph_and_inc_cursor(void)
307 } else { 337 } else {
308 /* advance cursor only if we aren't at the end yet */ 338 /* advance cursor only if we aren't at the end yet */
309 cursor++; 339 cursor++;
310 cmdedit_x++; 340 if (unicode_status == UNICODE_ON) {
341 IF_UNICODE_WIDE_WCHARS(width = cmdedit_x;)
342 c = adjust_width_and_validate_wc(&cmdedit_x, c);
343 IF_UNICODE_WIDE_WCHARS(width = cmdedit_x - width;)
344 } else {
345 cmdedit_x++;
346 }
311 } 347 }
312 348
313#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 349 ofs_to_right = cmdedit_x - cmdedit_termw;
314 /* Display non-printable characters in reverse */ 350 if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right <= 0) {
315 if (!BB_isprint(c)) { 351 /* c fits on this line */
316 if (c >= 128)
317 c -= 128;
318 if (c < ' ')
319 c += '@';
320 if (c == 127)
321 c = '?';
322 printf("\033[7m%c\033[0m", c);
323 } else
324#endif
325 {
326 BB_PUTCHAR(c); 352 BB_PUTCHAR(c);
327 } 353 }
328 if (cmdedit_x >= cmdedit_termw) { 354
329 /* terminal is scrolled down */ 355 if (ofs_to_right >= 0) {
330 cmdedit_y++; 356 /* we go to the next line */
331 cmdedit_x = 0;
332#if HACK_FOR_WRONG_WIDTH 357#if HACK_FOR_WRONG_WIDTH
333 /* This works better if our idea of term width is wrong 358 /* This works better if our idea of term width is wrong
334 * and it is actually wider (often happens on serial lines). 359 * and it is actually wider (often happens on serial lines).
@@ -351,6 +376,14 @@ static void put_cur_glyph_and_inc_cursor(void)
351 BB_PUTCHAR(c); 376 BB_PUTCHAR(c);
352 bb_putchar('\b'); 377 bb_putchar('\b');
353#endif 378#endif
379 cmdedit_y++;
380 if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right == 0) {
381 width = 0;
382 } else { /* ofs_to_right > 0 */
383 /* wide char c didn't fit on prev line */
384 BB_PUTCHAR(c);
385 }
386 cmdedit_x = width;
354 } 387 }
355} 388}
356 389
@@ -389,10 +422,22 @@ static void input_backward(unsigned num)
389 422
390 if (num > cursor) 423 if (num > cursor)
391 num = cursor; 424 num = cursor;
392 if (!num) 425 if (num == 0)
393 return; 426 return;
394 cursor -= num; 427 cursor -= num;
395 428
429 if ((ENABLE_UNICODE_COMBINING_WCHARS || ENABLE_UNICODE_WIDE_WCHARS)
430 && unicode_status == UNICODE_ON
431 ) {
432 /* correct NUM to be equal to _screen_ width */
433 int n = num;
434 num = 0;
435 while (--n >= 0)
436 adjust_width_and_validate_wc(&num, command_ps[cursor + n]);
437 if (num == 0)
438 return;
439 }
440
396 if (cmdedit_x >= num) { 441 if (cmdedit_x >= num) {
397 cmdedit_x -= num; 442 cmdedit_x -= num;
398 if (num <= 4) { 443 if (num <= 4) {
@@ -412,6 +457,8 @@ static void input_backward(unsigned num)
412 } 457 }
413 458
414 /* Need to go one or more lines up */ 459 /* Need to go one or more lines up */
460//FIXME: this does not work correctly if prev line has one "unfilled" screen position
461//caused by wide unicode char not fitting in that one screen position.
415 num -= cmdedit_x; 462 num -= cmdedit_x;
416 { 463 {
417 unsigned w = cmdedit_termw; /* volatile var */ 464 unsigned w = cmdedit_termw; /* volatile var */
@@ -765,21 +812,13 @@ static NOINLINE int find_match(char *matchBuf, int *len_with_quotes)
765 } 812 }
766 813
767 /* mask \+symbol and convert '\t' to ' ' */ 814 /* mask \+symbol and convert '\t' to ' ' */
768 for (i = j = 0; matchBuf[i]; i++, j++) 815 for (i = j = 0; matchBuf[i]; i++, j++) {
769 if (matchBuf[i] == '\\') { 816 if (matchBuf[i] == '\\') {
770 collapse_pos(j, j + 1); 817 collapse_pos(j, j + 1);
771 int_buf[j] |= QUOT; 818 int_buf[j] |= QUOT;
772 i++; 819 i++;
773#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
774 if (matchBuf[i] == '\t') /* algorithm equivalent */
775 int_buf[j] = ' ' | QUOT;
776#endif
777 } 820 }
778#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 821 }
779 else if (matchBuf[i] == '\t')
780 int_buf[j] = ' ';
781#endif
782
783 /* mask "symbols" or 'symbols' */ 822 /* mask "symbols" or 'symbols' */
784 c2 = 0; 823 c2 = 0;
785 for (i = 0; int_buf[i]; i++) { 824 for (i = 0; int_buf[i]; i++) {
@@ -1774,7 +1813,7 @@ static int lineedit_read_key(char *read_key_buffer)
1774# if !ENABLE_UNICODE_PRESERVE_BROKEN 1813# if !ENABLE_UNICODE_PRESERVE_BROKEN
1775 ic = CONFIG_SUBST_WCHAR; 1814 ic = CONFIG_SUBST_WCHAR;
1776# else 1815# else
1777 ic = unicode_mark_inv_wchar(unicode_buf[0]); 1816 ic = unicode_mark_raw_byte(unicode_buf[0]);
1778# endif 1817# endif
1779 } else { 1818 } else {
1780 /* Valid unicode char, return its code */ 1819 /* Valid unicode char, return its code */
@@ -2384,9 +2423,6 @@ int main(int argc, char **argv)
2384 "% "; 2423 "% ";
2385#endif 2424#endif
2386 2425
2387#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
2388 setlocale(LC_ALL, "");
2389#endif
2390 while (1) { 2426 while (1) {
2391 int l; 2427 int l;
2392 l = read_line_input(prompt, buff); 2428 l = read_line_input(prompt, buff);
diff --git a/libbb/unicode.c b/libbb/unicode.c
index d1c6167c7..eb0ea6129 100644
--- a/libbb/unicode.c
+++ b/libbb/unicode.c
@@ -418,7 +418,7 @@ static int in_uint16_table(unsigned ucs, const uint16_t *table, unsigned max)
418 * This implementation assumes that wchar_t characters are encoded 418 * This implementation assumes that wchar_t characters are encoded
419 * in ISO 10646. 419 * in ISO 10646.
420 */ 420 */
421static int wcwidth(unsigned ucs) 421int FAST_FUNC wcwidth(unsigned ucs)
422{ 422{
423# if LAST_SUPPORTED_WCHAR >= 0x300 423# if LAST_SUPPORTED_WCHAR >= 0x300
424 /* sorted list of non-overlapping intervals of non-spacing characters */ 424 /* sorted list of non-overlapping intervals of non-spacing characters */