diff options
author | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2010-09-14 11:41:16 +1000 |
---|---|---|
committer | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2010-09-14 11:41:16 +1000 |
commit | 743d85e7d1c2a721baf020b9d79f45f0df2420a9 (patch) | |
tree | 9e551b726ac2bf9fd8eafb2764e7237f352bb429 /libbb | |
parent | 87911f4fcd86f7abc0aefba8e9cbec2ac9d127e4 (diff) | |
parent | c7f95d23f6bc7e17a3b79decf83eb362b389e53a (diff) | |
download | busybox-w32-743d85e7d1c2a721baf020b9d79f45f0df2420a9.tar.gz busybox-w32-743d85e7d1c2a721baf020b9d79f45f0df2420a9.tar.bz2 busybox-w32-743d85e7d1c2a721baf020b9d79f45f0df2420a9.zip |
Merge branch 'origin/master' (early part)
Diffstat (limited to 'libbb')
-rw-r--r-- | libbb/appletlib.c | 73 | ||||
-rw-r--r-- | libbb/lineedit.c | 320 | ||||
-rw-r--r-- | libbb/read.c | 103 | ||||
-rw-r--r-- | libbb/read_key.c | 2 | ||||
-rw-r--r-- | libbb/time.c | 10 | ||||
-rw-r--r-- | libbb/unicode.c | 40 | ||||
-rw-r--r-- | libbb/xfuncs.c | 54 |
7 files changed, 380 insertions, 222 deletions
diff --git a/libbb/appletlib.c b/libbb/appletlib.c index f287e4522..f6dc1f171 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c | |||
@@ -105,7 +105,9 @@ static const char *unpack_usage_messages(void) | |||
105 | 105 | ||
106 | static void full_write2_str(const char *str) | 106 | static void full_write2_str(const char *str) |
107 | { | 107 | { |
108 | xwrite_str(STDERR_FILENO, str); | 108 | // This uses stdio: |
109 | //xwrite_str(STDERR_FILENO, str); | ||
110 | write(STDERR_FILENO, str, strlen(str)); | ||
109 | } | 111 | } |
110 | 112 | ||
111 | void FAST_FUNC bb_show_usage(void) | 113 | void FAST_FUNC bb_show_usage(void) |
@@ -593,6 +595,17 @@ static void check_suid(int applet_no) | |||
593 | 595 | ||
594 | 596 | ||
595 | #if ENABLE_FEATURE_INSTALLER | 597 | #if ENABLE_FEATURE_INSTALLER |
598 | static const char usr_bin [] ALIGN1 = "/usr/bin/"; | ||
599 | static const char usr_sbin[] ALIGN1 = "/usr/sbin/"; | ||
600 | static const char *const install_dir[] = { | ||
601 | &usr_bin [8], /* "/" */ | ||
602 | &usr_bin [4], /* "/bin/" */ | ||
603 | &usr_sbin[4], /* "/sbin/" */ | ||
604 | usr_bin, | ||
605 | usr_sbin | ||
606 | }; | ||
607 | |||
608 | |||
596 | /* create (sym)links for each applet */ | 609 | /* create (sym)links for each applet */ |
597 | static void install_links(const char *busybox, int use_symbolic_links, | 610 | static void install_links(const char *busybox, int use_symbolic_links, |
598 | char *custom_install_dir) | 611 | char *custom_install_dir) |
@@ -600,16 +613,6 @@ static void install_links(const char *busybox, int use_symbolic_links, | |||
600 | /* directory table | 613 | /* directory table |
601 | * this should be consistent w/ the enum, | 614 | * this should be consistent w/ the enum, |
602 | * busybox.h::bb_install_loc_t, or else... */ | 615 | * busybox.h::bb_install_loc_t, or else... */ |
603 | static const char usr_bin [] ALIGN1 = "/usr/bin"; | ||
604 | static const char usr_sbin[] ALIGN1 = "/usr/sbin"; | ||
605 | static const char *const install_dir[] = { | ||
606 | &usr_bin [8], /* "", equivalent to "/" for concat_path_file() */ | ||
607 | &usr_bin [4], /* "/bin" */ | ||
608 | &usr_sbin[4], /* "/sbin" */ | ||
609 | usr_bin, | ||
610 | usr_sbin | ||
611 | }; | ||
612 | |||
613 | int (*lf)(const char *, const char *); | 616 | int (*lf)(const char *, const char *); |
614 | char *fpc; | 617 | char *fpc; |
615 | unsigned i; | 618 | unsigned i; |
@@ -633,8 +636,8 @@ static void install_links(const char *busybox, int use_symbolic_links, | |||
633 | } | 636 | } |
634 | } | 637 | } |
635 | #else | 638 | #else |
636 | #define install_links(x,y,z) ((void)0) | 639 | # define install_links(x,y,z) ((void)0) |
637 | #endif /* FEATURE_INSTALLER */ | 640 | #endif |
638 | 641 | ||
639 | /* If we were called as "busybox..." */ | 642 | /* If we were called as "busybox..." */ |
640 | static int busybox_main(char **argv) | 643 | static int busybox_main(char **argv) |
@@ -655,19 +658,20 @@ static int busybox_main(char **argv) | |||
655 | full_write2_str(bb_banner); /* reuse const string */ | 658 | full_write2_str(bb_banner); /* reuse const string */ |
656 | full_write2_str(" multi-call binary.\n"); /* reuse */ | 659 | full_write2_str(" multi-call binary.\n"); /* reuse */ |
657 | full_write2_str( | 660 | full_write2_str( |
658 | "Copyright (C) 1998-2009 Erik Andersen, Rob Landley, Denys Vlasenko\n" | 661 | "Copyright (C) 1998-2009 Erik Andersen, Rob Landley, Denys Vlasenko\n" |
659 | "and others. Licensed under GPLv2.\n" | 662 | "and others. Licensed under GPLv2.\n" |
660 | "See source distribution for full notice.\n" | 663 | "See source distribution for full notice.\n" |
661 | "\n" | 664 | "\n" |
662 | "Usage: busybox [function] [arguments]...\n" | 665 | "Usage: busybox [function] [arguments]...\n" |
663 | " or: function [arguments]...\n" | 666 | " or: function [arguments]...\n" |
664 | "\n" | 667 | "\n" |
665 | "\tBusyBox is a multi-call binary that combines many common Unix\n" | 668 | "\tBusyBox is a multi-call binary that combines many common Unix\n" |
666 | "\tutilities into a single executable. Most people will create a\n" | 669 | "\tutilities into a single executable. Most people will create a\n" |
667 | "\tlink to busybox for each function they wish to use and BusyBox\n" | 670 | "\tlink to busybox for each function they wish to use and BusyBox\n" |
668 | "\twill act like whatever it was invoked as.\n" | 671 | "\twill act like whatever it was invoked as.\n" |
669 | "\n" | 672 | "\n" |
670 | "Currently defined functions:\n"); | 673 | "Currently defined functions:\n" |
674 | ); | ||
671 | col = 0; | 675 | col = 0; |
672 | a = applet_names; | 676 | a = applet_names; |
673 | /* prevent last comma to be in the very last pos */ | 677 | /* prevent last comma to be in the very last pos */ |
@@ -692,6 +696,23 @@ static int busybox_main(char **argv) | |||
692 | return 0; | 696 | return 0; |
693 | } | 697 | } |
694 | 698 | ||
699 | if (strncmp(argv[1], "--list", 6) == 0) { | ||
700 | unsigned i = 0; | ||
701 | const char *a = applet_names; | ||
702 | dup2(1, 2); | ||
703 | while (*a) { | ||
704 | #if ENABLE_FEATURE_INSTALLER | ||
705 | if (argv[1][6]) /* --list-path? */ | ||
706 | full_write2_str(install_dir[APPLET_INSTALL_LOC(i)] + 1); | ||
707 | #endif | ||
708 | full_write2_str(a); | ||
709 | full_write2_str("\n"); | ||
710 | i++; | ||
711 | a += strlen(a) + 1; | ||
712 | } | ||
713 | return 0; | ||
714 | } | ||
715 | |||
695 | if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) { | 716 | if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) { |
696 | int use_symbolic_links; | 717 | int use_symbolic_links; |
697 | const char *busybox; | 718 | const char *busybox; |
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 9a04c38bf..f7faf4639 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 | ||
@@ -66,9 +62,13 @@ | |||
66 | #endif | 62 | #endif |
67 | 63 | ||
68 | 64 | ||
65 | #define SEQ_CLEAR_TILL_END_OF_SCREEN "\033[J" | ||
66 | //#define SEQ_CLEAR_TILL_END_OF_LINE "\033[K" | ||
67 | |||
68 | |||
69 | #undef CHAR_T | 69 | #undef CHAR_T |
70 | #if ENABLE_UNICODE_SUPPORT | 70 | #if ENABLE_UNICODE_SUPPORT |
71 | # define BB_NUL L'\0' | 71 | # define BB_NUL ((wchar_t)0) |
72 | # define CHAR_T wchar_t | 72 | # define CHAR_T wchar_t |
73 | static bool BB_isspace(CHAR_T c) { return ((unsigned)c < 256 && isspace(c)); } | 73 | static bool BB_isspace(CHAR_T c) { return ((unsigned)c < 256 && isspace(c)); } |
74 | # if ENABLE_FEATURE_EDITING_VI | 74 | # if ENABLE_FEATURE_EDITING_VI |
@@ -92,6 +92,14 @@ static bool BB_ispunct(CHAR_T c) { return ((unsigned)c < 256 && ispunct(c)); } | |||
92 | #endif | 92 | #endif |
93 | 93 | ||
94 | 94 | ||
95 | # if ENABLE_UNICODE_PRESERVE_BROKEN | ||
96 | # define unicode_mark_raw_byte(wc) ((wc) | 0x20000000) | ||
97 | # define unicode_is_raw_byte(wc) ((wc) & 0x20000000) | ||
98 | # else | ||
99 | # define unicode_is_raw_byte(wc) 0 | ||
100 | # endif | ||
101 | |||
102 | |||
95 | enum { | 103 | enum { |
96 | /* We use int16_t for positions, need to limit line len */ | 104 | /* We use int16_t for positions, need to limit line len */ |
97 | MAX_LINELEN = CONFIG_FEATURE_EDITING_MAX_LEN < 0x7ff0 | 105 | MAX_LINELEN = CONFIG_FEATURE_EDITING_MAX_LEN < 0x7ff0 |
@@ -208,42 +216,107 @@ static size_t load_string(const char *src, int maxsize) | |||
208 | ssize_t len = mbstowcs(command_ps, src, maxsize - 1); | 216 | ssize_t len = mbstowcs(command_ps, src, maxsize - 1); |
209 | if (len < 0) | 217 | if (len < 0) |
210 | len = 0; | 218 | len = 0; |
211 | command_ps[len] = L'\0'; | 219 | command_ps[len] = 0; |
212 | return len; | 220 | return len; |
213 | } | 221 | } |
214 | static size_t save_string(char *dst, int maxsize) | 222 | static unsigned save_string(char *dst, unsigned maxsize) |
215 | { | 223 | { |
224 | # if !ENABLE_UNICODE_PRESERVE_BROKEN | ||
216 | ssize_t len = wcstombs(dst, command_ps, maxsize - 1); | 225 | ssize_t len = wcstombs(dst, command_ps, maxsize - 1); |
217 | if (len < 0) | 226 | if (len < 0) |
218 | len = 0; | 227 | len = 0; |
219 | dst[len] = '\0'; | 228 | dst[len] = '\0'; |
220 | return len; | 229 | return len; |
230 | # else | ||
231 | unsigned dstpos = 0; | ||
232 | unsigned srcpos = 0; | ||
233 | |||
234 | maxsize--; | ||
235 | while (dstpos < maxsize) { | ||
236 | wchar_t wc; | ||
237 | int n = srcpos; | ||
238 | while ((wc = command_ps[srcpos]) != 0 | ||
239 | && !unicode_is_raw_byte(wc) | ||
240 | ) { | ||
241 | srcpos++; | ||
242 | } | ||
243 | command_ps[srcpos] = 0; | ||
244 | n = wcstombs(dst + dstpos, command_ps + n, maxsize - dstpos); | ||
245 | if (n < 0) /* should not happen */ | ||
246 | break; | ||
247 | dstpos += n; | ||
248 | if (wc == 0) /* usually is */ | ||
249 | break; | ||
250 | /* We do have invalid byte here! */ | ||
251 | command_ps[srcpos] = wc; /* restore it */ | ||
252 | srcpos++; | ||
253 | if (dstpos == maxsize) | ||
254 | break; | ||
255 | dst[dstpos++] = (char) wc; | ||
256 | } | ||
257 | dst[dstpos] = '\0'; | ||
258 | return dstpos; | ||
259 | # endif | ||
221 | } | 260 | } |
222 | /* I thought just fputwc(c, stdout) would work. But no... */ | 261 | /* I thought just fputwc(c, stdout) would work. But no... */ |
223 | static void BB_PUTCHAR(wchar_t c) | 262 | static void BB_PUTCHAR(wchar_t c) |
224 | { | 263 | { |
225 | char buf[MB_CUR_MAX + 1]; | 264 | char buf[MB_CUR_MAX + 1]; |
226 | mbstate_t mbst = { 0 }; | 265 | mbstate_t mbst = { 0 }; |
227 | ssize_t len = wcrtomb(buf, c, &mbst); | 266 | ssize_t len; |
228 | 267 | ||
268 | len = wcrtomb(buf, c, &mbst); | ||
229 | if (len > 0) { | 269 | if (len > 0) { |
230 | buf[len] = '\0'; | 270 | buf[len] = '\0'; |
231 | fputs(buf, stdout); | 271 | fputs(buf, stdout); |
232 | } | 272 | } |
233 | } | 273 | } |
234 | #else | 274 | # if ENABLE_UNICODE_COMBINING_WCHARS || ENABLE_UNICODE_WIDE_WCHARS |
275 | static wchar_t adjust_width_and_validate_wc(unsigned *width_adj, wchar_t wc) | ||
276 | # else | ||
277 | static 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 (wc > CONFIG_LAST_SUPPORTED_WCHAR) { | ||
286 | /* note: also true for unicode_is_raw_byte(wc) */ | ||
287 | goto subst; | ||
288 | } | ||
289 | w = wcwidth(wc); | ||
290 | if ((ENABLE_UNICODE_COMBINING_WCHARS && w < 0) | ||
291 | || (!ENABLE_UNICODE_COMBINING_WCHARS && w <= 0) | ||
292 | || (!ENABLE_UNICODE_WIDE_WCHARS && w > 1) | ||
293 | ) { | ||
294 | subst: | ||
295 | w = 1; | ||
296 | wc = CONFIG_SUBST_WCHAR; | ||
297 | } | ||
298 | } | ||
299 | |||
300 | # if ENABLE_UNICODE_COMBINING_WCHARS || ENABLE_UNICODE_WIDE_WCHARS | ||
301 | *width_adj += w; | ||
302 | #endif | ||
303 | return wc; | ||
304 | } | ||
305 | #else /* !UNICODE */ | ||
235 | static size_t load_string(const char *src, int maxsize) | 306 | static size_t load_string(const char *src, int maxsize) |
236 | { | 307 | { |
237 | safe_strncpy(command_ps, src, maxsize); | 308 | safe_strncpy(command_ps, src, maxsize); |
238 | return strlen(command_ps); | 309 | return strlen(command_ps); |
239 | } | 310 | } |
240 | # if ENABLE_FEATURE_TAB_COMPLETION | 311 | # if ENABLE_FEATURE_TAB_COMPLETION |
241 | static void save_string(char *dst, int maxsize) | 312 | static void save_string(char *dst, unsigned maxsize) |
242 | { | 313 | { |
243 | safe_strncpy(dst, command_ps, maxsize); | 314 | safe_strncpy(dst, command_ps, maxsize); |
244 | } | 315 | } |
245 | # endif | 316 | # endif |
246 | # define BB_PUTCHAR(c) bb_putchar(c) | 317 | # define BB_PUTCHAR(c) bb_putchar(c) |
318 | /* Should never be called: */ | ||
319 | int adjust_width_and_validate_wc(unsigned *width_adj, int wc); | ||
247 | #endif | 320 | #endif |
248 | 321 | ||
249 | 322 | ||
@@ -251,38 +324,35 @@ static void save_string(char *dst, int maxsize) | |||
251 | * Advance cursor on screen. If we reached right margin, scroll text up | 324 | * Advance cursor on screen. If we reached right margin, scroll text up |
252 | * and remove terminal margin effect by printing 'next_char' */ | 325 | * and remove terminal margin effect by printing 'next_char' */ |
253 | #define HACK_FOR_WRONG_WIDTH 1 | 326 | #define HACK_FOR_WRONG_WIDTH 1 |
254 | #if HACK_FOR_WRONG_WIDTH | 327 | static void put_cur_glyph_and_inc_cursor(void) |
255 | static void cmdedit_set_out_char(void) | ||
256 | #define cmdedit_set_out_char(next_char) cmdedit_set_out_char() | ||
257 | #else | ||
258 | static void cmdedit_set_out_char(int next_char) | ||
259 | #endif | ||
260 | { | 328 | { |
261 | CHAR_T c = command_ps[cursor]; | 329 | CHAR_T c = command_ps[cursor]; |
330 | unsigned width = 0; | ||
331 | int ofs_to_right; | ||
262 | 332 | ||
263 | if (c == BB_NUL) { | 333 | if (c == BB_NUL) { |
264 | /* erase character after end of input string */ | 334 | /* erase character after end of input string */ |
265 | c = ' '; | 335 | c = ' '; |
336 | } else { | ||
337 | /* advance cursor only if we aren't at the end yet */ | ||
338 | cursor++; | ||
339 | if (unicode_status == UNICODE_ON) { | ||
340 | IF_UNICODE_WIDE_WCHARS(width = cmdedit_x;) | ||
341 | c = adjust_width_and_validate_wc(&cmdedit_x, c); | ||
342 | IF_UNICODE_WIDE_WCHARS(width = cmdedit_x - width;) | ||
343 | } else { | ||
344 | cmdedit_x++; | ||
345 | } | ||
266 | } | 346 | } |
267 | #if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT | 347 | |
268 | /* Display non-printable characters in reverse */ | 348 | ofs_to_right = cmdedit_x - cmdedit_termw; |
269 | if (!BB_isprint(c)) { | 349 | if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right <= 0) { |
270 | if (c >= 128) | 350 | /* c fits on this line */ |
271 | c -= 128; | ||
272 | if (c < ' ') | ||
273 | c += '@'; | ||
274 | if (c == 127) | ||
275 | c = '?'; | ||
276 | printf("\033[7m%c\033[0m", c); | ||
277 | } else | ||
278 | #endif | ||
279 | { | ||
280 | BB_PUTCHAR(c); | 351 | BB_PUTCHAR(c); |
281 | } | 352 | } |
282 | if (++cmdedit_x >= cmdedit_termw) { | 353 | |
283 | /* terminal is scrolled down */ | 354 | if (ofs_to_right >= 0) { |
284 | cmdedit_y++; | 355 | /* we go to the next line */ |
285 | cmdedit_x = 0; | ||
286 | #if HACK_FOR_WRONG_WIDTH | 356 | #if HACK_FOR_WRONG_WIDTH |
287 | /* This works better if our idea of term width is wrong | 357 | /* This works better if our idea of term width is wrong |
288 | * and it is actually wider (often happens on serial lines). | 358 | * and it is actually wider (often happens on serial lines). |
@@ -293,55 +363,83 @@ static void cmdedit_set_out_char(int next_char) | |||
293 | * this will break things: there will be one extra empty line */ | 363 | * this will break things: there will be one extra empty line */ |
294 | puts("\r"); /* + implicit '\n' */ | 364 | puts("\r"); /* + implicit '\n' */ |
295 | #else | 365 | #else |
296 | /* Works ok only if cmdedit_termw is correct */ | 366 | /* VT-10x terminals don't wrap cursor to next line when last char |
297 | /* destroy "(auto)margin" */ | 367 | * on the line is printed - cursor stays "over" this char. |
298 | bb_putchar(next_char); | 368 | * Need to print _next_ char too (first one to appear on next line) |
369 | * to make cursor move down to next line. | ||
370 | */ | ||
371 | /* Works ok only if cmdedit_termw is correct. */ | ||
372 | c = command_ps[cursor]; | ||
373 | if (c == BB_NUL) | ||
374 | c = ' '; | ||
375 | BB_PUTCHAR(c); | ||
299 | bb_putchar('\b'); | 376 | bb_putchar('\b'); |
300 | #endif | 377 | #endif |
378 | cmdedit_y++; | ||
379 | if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right == 0) { | ||
380 | width = 0; | ||
381 | } else { /* ofs_to_right > 0 */ | ||
382 | /* wide char c didn't fit on prev line */ | ||
383 | BB_PUTCHAR(c); | ||
384 | } | ||
385 | cmdedit_x = width; | ||
301 | } | 386 | } |
302 | // Huh? What if command_ps[cursor] == BB_NUL (we are at the end already?) | ||
303 | cursor++; | ||
304 | } | 387 | } |
305 | 388 | ||
306 | /* Move to end of line (by printing all chars till the end) */ | 389 | /* Move to end of line (by printing all chars till the end) */ |
307 | static void input_end(void) | 390 | static void put_till_end_and_adv_cursor(void) |
308 | { | 391 | { |
309 | while (cursor < command_len) | 392 | while (cursor < command_len) |
310 | cmdedit_set_out_char(' '); | 393 | put_cur_glyph_and_inc_cursor(); |
311 | } | 394 | } |
312 | 395 | ||
313 | /* Go to the next line */ | 396 | /* Go to the next line */ |
314 | static void goto_new_line(void) | 397 | static void goto_new_line(void) |
315 | { | 398 | { |
316 | input_end(); | 399 | put_till_end_and_adv_cursor(); |
317 | if (cmdedit_x) | 400 | if (cmdedit_x != 0) |
318 | bb_putchar('\n'); | 401 | bb_putchar('\n'); |
319 | } | 402 | } |
320 | 403 | ||
321 | 404 | static void beep(void) | |
322 | static void out1str(const char *s) | ||
323 | { | 405 | { |
324 | if (s) | 406 | bb_putchar('\007'); |
325 | fputs(s, stdout); | ||
326 | } | 407 | } |
327 | 408 | ||
328 | static void beep(void) | 409 | static void put_prompt(void) |
329 | { | 410 | { |
330 | bb_putchar('\007'); | 411 | unsigned w; |
412 | |||
413 | fputs(cmdedit_prompt, stdout); | ||
414 | fflush_all(); | ||
415 | cursor = 0; | ||
416 | w = cmdedit_termw; /* read volatile var once */ | ||
417 | cmdedit_y = cmdedit_prmt_len / w; /* new quasireal y */ | ||
418 | cmdedit_x = cmdedit_prmt_len % w; | ||
331 | } | 419 | } |
332 | 420 | ||
333 | /* Move back one character */ | 421 | /* Move back one character */ |
334 | /* (optimized for slow terminals) */ | 422 | /* (optimized for slow terminals) */ |
335 | static void input_backward(unsigned num) | 423 | static void input_backward(unsigned num) |
336 | { | 424 | { |
337 | int count_y; | ||
338 | |||
339 | if (num > cursor) | 425 | if (num > cursor) |
340 | num = cursor; | 426 | num = cursor; |
341 | if (!num) | 427 | if (num == 0) |
342 | return; | 428 | return; |
343 | cursor -= num; | 429 | cursor -= num; |
344 | 430 | ||
431 | if ((ENABLE_UNICODE_COMBINING_WCHARS || ENABLE_UNICODE_WIDE_WCHARS) | ||
432 | && unicode_status == UNICODE_ON | ||
433 | ) { | ||
434 | /* correct NUM to be equal to _screen_ width */ | ||
435 | int n = num; | ||
436 | num = 0; | ||
437 | while (--n >= 0) | ||
438 | adjust_width_and_validate_wc(&num, command_ps[cursor + n]); | ||
439 | if (num == 0) | ||
440 | return; | ||
441 | } | ||
442 | |||
345 | if (cmdedit_x >= num) { | 443 | if (cmdedit_x >= num) { |
346 | cmdedit_x -= num; | 444 | cmdedit_x -= num; |
347 | if (num <= 4) { | 445 | if (num <= 4) { |
@@ -361,38 +459,61 @@ static void input_backward(unsigned num) | |||
361 | } | 459 | } |
362 | 460 | ||
363 | /* Need to go one or more lines up */ | 461 | /* Need to go one or more lines up */ |
364 | num -= cmdedit_x; | 462 | if (ENABLE_UNICODE_WIDE_WCHARS) { |
365 | { | 463 | /* With wide chars, it is hard to "backtrack" |
366 | unsigned w = cmdedit_termw; /* volatile var */ | 464 | * and reliably figure out where to put cursor. |
367 | count_y = 1 + (num / w); | 465 | * Example (<> is a wide char; # is an ordinary char, _ cursor): |
368 | cmdedit_y -= count_y; | 466 | * |prompt: <><> | |
369 | cmdedit_x = w * count_y - num; | 467 | * |<><><><><><> | |
468 | * |_ | | ||
469 | * and user presses left arrow. num = 1, cmdedit_x = 0, | ||
470 | * We need to go up one line, and then - how do we know that | ||
471 | * we need to go *10* positions to the right? Because | ||
472 | * |prompt: <>#<>| | ||
473 | * |<><><>#<><><>| | ||
474 | * |_ | | ||
475 | * in this situation we need to go *11* positions to the right. | ||
476 | * | ||
477 | * A simpler thing to do is to redraw everything from the start | ||
478 | * up to new cursor position (which is already known): | ||
479 | */ | ||
480 | unsigned sv_cursor; | ||
481 | /* go to 1st column; go up to first line */ | ||
482 | printf("\r" "\033[%uA", cmdedit_y); | ||
483 | cmdedit_y = 0; | ||
484 | sv_cursor = cursor; | ||
485 | put_prompt(); /* sets cursor to 0 */ | ||
486 | while (cursor < sv_cursor) | ||
487 | put_cur_glyph_and_inc_cursor(); | ||
488 | } else { | ||
489 | int lines_up; | ||
490 | unsigned width; | ||
491 | /* num = chars to go back from the beginning of current line: */ | ||
492 | num -= cmdedit_x; | ||
493 | width = cmdedit_termw; /* read volatile var once */ | ||
494 | /* num=1...w: one line up, w+1...2w: two, etc: */ | ||
495 | lines_up = 1 + (num - 1) / width; | ||
496 | cmdedit_x = (width * cmdedit_y - num) % width; | ||
497 | cmdedit_y -= lines_up; | ||
498 | /* go to 1st column; go up */ | ||
499 | printf("\r" "\033[%uA", lines_up); | ||
500 | /* go to correct column. | ||
501 | * xterm, konsole, Linux VT interpret 0 as 1 below! wow. | ||
502 | * need to *make sure* we skip it if cmdedit_x == 0 */ | ||
503 | if (cmdedit_x) | ||
504 | printf("\033[%uC", cmdedit_x); | ||
370 | } | 505 | } |
371 | /* go to 1st column; go up; go to correct column */ | ||
372 | printf("\r" "\033[%dA" "\033[%dC", count_y, cmdedit_x); | ||
373 | } | ||
374 | |||
375 | static void put_prompt(void) | ||
376 | { | ||
377 | unsigned w; | ||
378 | |||
379 | out1str(cmdedit_prompt); | ||
380 | fflush_all(); | ||
381 | cursor = 0; | ||
382 | w = cmdedit_termw; /* read volatile var once */ | ||
383 | cmdedit_y = cmdedit_prmt_len / w; /* new quasireal y */ | ||
384 | cmdedit_x = cmdedit_prmt_len % w; | ||
385 | } | 506 | } |
386 | 507 | ||
387 | /* draw prompt, editor line, and clear tail */ | 508 | /* draw prompt, editor line, and clear tail */ |
388 | static void redraw(int y, int back_cursor) | 509 | static void redraw(int y, int back_cursor) |
389 | { | 510 | { |
390 | if (y > 0) /* up to start y */ | 511 | if (y > 0) /* up y lines */ |
391 | printf("\033[%uA", y); | 512 | printf("\033[%uA", y); |
392 | bb_putchar('\r'); | 513 | bb_putchar('\r'); |
393 | put_prompt(); | 514 | put_prompt(); |
394 | input_end(); /* rewrite */ | 515 | put_till_end_and_adv_cursor(); |
395 | printf("\033[J"); /* erase after cursor */ | 516 | printf(SEQ_CLEAR_TILL_END_OF_SCREEN); |
396 | input_backward(back_cursor); | 517 | input_backward(back_cursor); |
397 | } | 518 | } |
398 | 519 | ||
@@ -426,8 +547,9 @@ static void input_delete(int save) | |||
426 | * simplified into (command_len - j) */ | 547 | * simplified into (command_len - j) */ |
427 | (command_len - j) * sizeof(command_ps[0])); | 548 | (command_len - j) * sizeof(command_ps[0])); |
428 | command_len--; | 549 | command_len--; |
429 | input_end(); /* rewrite new line */ | 550 | put_till_end_and_adv_cursor(); |
430 | cmdedit_set_out_char(' '); /* erase char */ | 551 | /* Last char is still visible, erase it (and more) */ |
552 | printf(SEQ_CLEAR_TILL_END_OF_SCREEN); | ||
431 | input_backward(cursor - j); /* back to old pos cursor */ | 553 | input_backward(cursor - j); /* back to old pos cursor */ |
432 | } | 554 | } |
433 | 555 | ||
@@ -445,7 +567,7 @@ static void put(void) | |||
445 | (command_len - cursor + 1) * sizeof(command_ps[0])); | 567 | (command_len - cursor + 1) * sizeof(command_ps[0])); |
446 | memcpy(command_ps + cursor, delbuf, j * sizeof(command_ps[0])); | 568 | memcpy(command_ps + cursor, delbuf, j * sizeof(command_ps[0])); |
447 | command_len += j; | 569 | command_len += j; |
448 | input_end(); /* rewrite new line */ | 570 | put_till_end_and_adv_cursor(); |
449 | input_backward(cursor - ocursor - j + 1); /* at end of new text */ | 571 | input_backward(cursor - ocursor - j + 1); /* at end of new text */ |
450 | } | 572 | } |
451 | #endif | 573 | #endif |
@@ -463,7 +585,7 @@ static void input_backspace(void) | |||
463 | static void input_forward(void) | 585 | static void input_forward(void) |
464 | { | 586 | { |
465 | if (cursor < command_len) | 587 | if (cursor < command_len) |
466 | cmdedit_set_out_char(command_ps[cursor + 1]); | 588 | put_cur_glyph_and_inc_cursor(); |
467 | } | 589 | } |
468 | 590 | ||
469 | #if ENABLE_FEATURE_TAB_COMPLETION | 591 | #if ENABLE_FEATURE_TAB_COMPLETION |
@@ -721,21 +843,13 @@ static NOINLINE int find_match(char *matchBuf, int *len_with_quotes) | |||
721 | } | 843 | } |
722 | 844 | ||
723 | /* mask \+symbol and convert '\t' to ' ' */ | 845 | /* mask \+symbol and convert '\t' to ' ' */ |
724 | for (i = j = 0; matchBuf[i]; i++, j++) | 846 | for (i = j = 0; matchBuf[i]; i++, j++) { |
725 | if (matchBuf[i] == '\\') { | 847 | if (matchBuf[i] == '\\') { |
726 | collapse_pos(j, j + 1); | 848 | collapse_pos(j, j + 1); |
727 | int_buf[j] |= QUOT; | 849 | int_buf[j] |= QUOT; |
728 | i++; | 850 | i++; |
729 | #if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT | ||
730 | if (matchBuf[i] == '\t') /* algorithm equivalent */ | ||
731 | int_buf[j] = ' ' | QUOT; | ||
732 | #endif | ||
733 | } | 851 | } |
734 | #if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT | 852 | } |
735 | else if (matchBuf[i] == '\t') | ||
736 | int_buf[j] = ' '; | ||
737 | #endif | ||
738 | |||
739 | /* mask "symbols" or 'symbols' */ | 853 | /* mask "symbols" or 'symbols' */ |
740 | c2 = 0; | 854 | c2 = 0; |
741 | for (i = 0; int_buf[i]; i++) { | 855 | for (i = 0; int_buf[i]; i++) { |
@@ -1509,7 +1623,7 @@ static void ask_terminal(void) | |||
1509 | pfd.events = POLLIN; | 1623 | pfd.events = POLLIN; |
1510 | if (safe_poll(&pfd, 1, 0) == 0) { | 1624 | if (safe_poll(&pfd, 1, 0) == 0) { |
1511 | S.sent_ESC_br6n = 1; | 1625 | S.sent_ESC_br6n = 1; |
1512 | out1str("\033" "[6n"); | 1626 | fputs("\033" "[6n", stdout); |
1513 | fflush_all(); /* make terminal see it ASAP! */ | 1627 | fflush_all(); /* make terminal see it ASAP! */ |
1514 | } | 1628 | } |
1515 | } | 1629 | } |
@@ -1727,13 +1841,11 @@ static int lineedit_read_key(char *read_key_buffer) | |||
1727 | pushback: | 1841 | pushback: |
1728 | /* Invalid sequence. Save all "bad bytes" except first */ | 1842 | /* Invalid sequence. Save all "bad bytes" except first */ |
1729 | read_key_ungets(read_key_buffer, unicode_buf + 1, unicode_idx - 1); | 1843 | read_key_ungets(read_key_buffer, unicode_buf + 1, unicode_idx - 1); |
1730 | /* | 1844 | # if !ENABLE_UNICODE_PRESERVE_BROKEN |
1731 | * ic = unicode_buf[0] sounds even better, but currently | ||
1732 | * this does not work: wchar_t[] -> char[] conversion | ||
1733 | * when lineedit finishes mangles such "raw bytes" | ||
1734 | * (by misinterpreting them as unicode chars): | ||
1735 | */ | ||
1736 | ic = CONFIG_SUBST_WCHAR; | 1845 | ic = CONFIG_SUBST_WCHAR; |
1846 | # else | ||
1847 | ic = unicode_mark_raw_byte(unicode_buf[0]); | ||
1848 | # endif | ||
1737 | } else { | 1849 | } else { |
1738 | /* Valid unicode char, return its code */ | 1850 | /* Valid unicode char, return its code */ |
1739 | ic = wc; | 1851 | ic = wc; |
@@ -1925,7 +2037,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li | |||
1925 | case CTRL('E'): | 2037 | case CTRL('E'): |
1926 | vi_case('$'|VI_CMDMODE_BIT:) | 2038 | vi_case('$'|VI_CMDMODE_BIT:) |
1927 | /* Control-e -- End of line */ | 2039 | /* Control-e -- End of line */ |
1928 | input_end(); | 2040 | put_till_end_and_adv_cursor(); |
1929 | break; | 2041 | break; |
1930 | case CTRL('F'): | 2042 | case CTRL('F'): |
1931 | vi_case('l'|VI_CMDMODE_BIT:) | 2043 | vi_case('l'|VI_CMDMODE_BIT:) |
@@ -1954,12 +2066,12 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li | |||
1954 | /* Control-k -- clear to end of line */ | 2066 | /* Control-k -- clear to end of line */ |
1955 | command_ps[cursor] = BB_NUL; | 2067 | command_ps[cursor] = BB_NUL; |
1956 | command_len = cursor; | 2068 | command_len = cursor; |
1957 | printf("\033[J"); | 2069 | printf(SEQ_CLEAR_TILL_END_OF_SCREEN); |
1958 | break; | 2070 | break; |
1959 | case CTRL('L'): | 2071 | case CTRL('L'): |
1960 | vi_case(CTRL('L')|VI_CMDMODE_BIT:) | 2072 | vi_case(CTRL('L')|VI_CMDMODE_BIT:) |
1961 | /* Control-l -- clear screen */ | 2073 | /* Control-l -- clear screen */ |
1962 | printf("\033[H"); | 2074 | printf("\033[H"); /* cursor to top,left */ |
1963 | redraw(0, command_len - cursor); | 2075 | redraw(0, command_len - cursor); |
1964 | break; | 2076 | break; |
1965 | #if MAX_HISTORY > 0 | 2077 | #if MAX_HISTORY > 0 |
@@ -2010,7 +2122,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li | |||
2010 | vi_cmdmode = 0; | 2122 | vi_cmdmode = 0; |
2011 | break; | 2123 | break; |
2012 | case 'A'|VI_CMDMODE_BIT: | 2124 | case 'A'|VI_CMDMODE_BIT: |
2013 | input_end(); | 2125 | put_till_end_and_adv_cursor(); |
2014 | vi_cmdmode = 0; | 2126 | vi_cmdmode = 0; |
2015 | break; | 2127 | break; |
2016 | case 'x'|VI_CMDMODE_BIT: | 2128 | case 'x'|VI_CMDMODE_BIT: |
@@ -2170,7 +2282,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li | |||
2170 | input_backward(cursor); | 2282 | input_backward(cursor); |
2171 | break; | 2283 | break; |
2172 | case KEYCODE_END: | 2284 | case KEYCODE_END: |
2173 | input_end(); | 2285 | put_till_end_and_adv_cursor(); |
2174 | break; | 2286 | break; |
2175 | 2287 | ||
2176 | default: | 2288 | default: |
@@ -2230,7 +2342,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li | |||
2230 | /* We are at the end, append */ | 2342 | /* We are at the end, append */ |
2231 | command_ps[cursor] = ic; | 2343 | command_ps[cursor] = ic; |
2232 | command_ps[cursor + 1] = BB_NUL; | 2344 | command_ps[cursor + 1] = BB_NUL; |
2233 | cmdedit_set_out_char(' '); | 2345 | put_cur_glyph_and_inc_cursor(); |
2234 | if (unicode_bidi_isrtl(ic)) | 2346 | if (unicode_bidi_isrtl(ic)) |
2235 | input_backward(1); | 2347 | input_backward(1); |
2236 | } else { | 2348 | } else { |
@@ -2243,8 +2355,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li | |||
2243 | /* is right-to-left char, or neutral one (e.g. comma) was just added to rtl text? */ | 2355 | /* is right-to-left char, or neutral one (e.g. comma) was just added to rtl text? */ |
2244 | if (!isrtl_str()) | 2356 | if (!isrtl_str()) |
2245 | sc++; /* no */ | 2357 | sc++; /* no */ |
2246 | /* rewrite from cursor */ | 2358 | put_till_end_and_adv_cursor(); |
2247 | input_end(); | ||
2248 | /* to prev x pos + 1 */ | 2359 | /* to prev x pos + 1 */ |
2249 | input_backward(cursor - sc); | 2360 | input_backward(cursor - sc); |
2250 | } | 2361 | } |
@@ -2345,9 +2456,6 @@ int main(int argc, char **argv) | |||
2345 | "% "; | 2456 | "% "; |
2346 | #endif | 2457 | #endif |
2347 | 2458 | ||
2348 | #if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT | ||
2349 | setlocale(LC_ALL, ""); | ||
2350 | #endif | ||
2351 | while (1) { | 2459 | while (1) { |
2352 | int l; | 2460 | int l; |
2353 | l = read_line_input(prompt, buff); | 2461 | l = read_line_input(prompt, buff); |
diff --git a/libbb/read.c b/libbb/read.c index 06ce29718..f3af144f0 100644 --- a/libbb/read.c +++ b/libbb/read.c | |||
@@ -6,7 +6,6 @@ | |||
6 | * | 6 | * |
7 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | 7 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
8 | */ | 8 | */ |
9 | |||
10 | #include "libbb.h" | 9 | #include "libbb.h" |
11 | 10 | ||
12 | #define ZIPPED (ENABLE_FEATURE_SEAMLESS_LZMA \ | 11 | #define ZIPPED (ENABLE_FEATURE_SEAMLESS_LZMA \ |
@@ -16,7 +15,7 @@ | |||
16 | ) | 15 | ) |
17 | 16 | ||
18 | #if ZIPPED | 17 | #if ZIPPED |
19 | #include "unarchive.h" | 18 | # include "unarchive.h" |
20 | #endif | 19 | #endif |
21 | 20 | ||
22 | ssize_t FAST_FUNC safe_read(int fd, void *buf, size_t count) | 21 | ssize_t FAST_FUNC safe_read(int fd, void *buf, size_t count) |
@@ -306,14 +305,11 @@ void* FAST_FUNC xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p) | |||
306 | return buf; | 305 | return buf; |
307 | } | 306 | } |
308 | 307 | ||
309 | int FAST_FUNC open_zipped(const char *fname) | 308 | #if ZIPPED |
309 | int FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) | ||
310 | { | 310 | { |
311 | #if !ZIPPED | 311 | const int fail_if_not_detected = 1; |
312 | return open(fname, O_RDONLY); | ||
313 | #else | ||
314 | unsigned char magic[2]; | 312 | unsigned char magic[2]; |
315 | char *sfx; | ||
316 | int fd; | ||
317 | #if BB_MMU | 313 | #if BB_MMU |
318 | IF_DESKTOP(long long) int FAST_FUNC (*xformer)(int src_fd, int dst_fd); | 314 | IF_DESKTOP(long long) int FAST_FUNC (*xformer)(int src_fd, int dst_fd); |
319 | enum { xformer_prog = 0 }; | 315 | enum { xformer_prog = 0 }; |
@@ -322,6 +318,62 @@ int FAST_FUNC open_zipped(const char *fname) | |||
322 | const char *xformer_prog; | 318 | const char *xformer_prog; |
323 | #endif | 319 | #endif |
324 | 320 | ||
321 | /* .gz and .bz2 both have 2-byte signature, and their | ||
322 | * unpack_XXX_stream wants this header skipped. */ | ||
323 | xread(fd, &magic, 2); | ||
324 | if (ENABLE_FEATURE_SEAMLESS_GZ | ||
325 | && magic[0] == 0x1f && magic[1] == 0x8b | ||
326 | ) { | ||
327 | # if BB_MMU | ||
328 | xformer = unpack_gz_stream; | ||
329 | # else | ||
330 | xformer_prog = "gunzip"; | ||
331 | # endif | ||
332 | goto found_magic; | ||
333 | } | ||
334 | if (ENABLE_FEATURE_SEAMLESS_BZ2 | ||
335 | && magic[0] == 'B' && magic[1] == 'Z' | ||
336 | ) { | ||
337 | # if BB_MMU | ||
338 | xformer = unpack_bz2_stream; | ||
339 | # else | ||
340 | xformer_prog = "bunzip2"; | ||
341 | # endif | ||
342 | goto found_magic; | ||
343 | } | ||
344 | // TODO: xz format support. rpm adopted it, "rpm -i FILE.rpm" badly needs this. | ||
345 | // Signature: 0xFD, '7', 'z', 'X', 'Z', 0x00 | ||
346 | // More info at: http://tukaani.org/xz/xz-file-format.txt | ||
347 | |||
348 | /* No known magic seen */ | ||
349 | if (fail_if_not_detected) | ||
350 | bb_error_msg_and_die("no gzip" | ||
351 | IF_FEATURE_SEAMLESS_BZ2("/bzip2") | ||
352 | " magic"); | ||
353 | xlseek(fd, -2, SEEK_CUR); | ||
354 | return fd; | ||
355 | |||
356 | found_magic: | ||
357 | # if !BB_MMU | ||
358 | /* NOMMU version of open_transformer execs | ||
359 | * an external unzipper that wants | ||
360 | * file position at the start of the file */ | ||
361 | xlseek(fd, -2, SEEK_CUR); | ||
362 | # endif | ||
363 | open_transformer(fd, xformer, xformer_prog); | ||
364 | |||
365 | return fd; | ||
366 | } | ||
367 | #endif /* ZIPPED */ | ||
368 | |||
369 | int FAST_FUNC open_zipped(const char *fname) | ||
370 | { | ||
371 | #if !ZIPPED | ||
372 | return open(fname, O_RDONLY); | ||
373 | #else | ||
374 | char *sfx; | ||
375 | int fd; | ||
376 | |||
325 | fd = open(fname, O_RDONLY); | 377 | fd = open(fname, O_RDONLY); |
326 | if (fd < 0) | 378 | if (fd < 0) |
327 | return fd; | 379 | return fd; |
@@ -335,40 +387,7 @@ int FAST_FUNC open_zipped(const char *fname) | |||
335 | if ((ENABLE_FEATURE_SEAMLESS_GZ && strcmp(sfx, ".gz") == 0) | 387 | if ((ENABLE_FEATURE_SEAMLESS_GZ && strcmp(sfx, ".gz") == 0) |
336 | || (ENABLE_FEATURE_SEAMLESS_BZ2 && strcmp(sfx, ".bz2") == 0) | 388 | || (ENABLE_FEATURE_SEAMLESS_BZ2 && strcmp(sfx, ".bz2") == 0) |
337 | ) { | 389 | ) { |
338 | /* .gz and .bz2 both have 2-byte signature, and their | 390 | setup_unzip_on_fd(fd /*, fail_if_not_detected: 1*/); |
339 | * unpack_XXX_stream wants this header skipped. */ | ||
340 | xread(fd, &magic, 2); | ||
341 | #if ENABLE_FEATURE_SEAMLESS_GZ | ||
342 | #if BB_MMU | ||
343 | xformer = unpack_gz_stream; | ||
344 | #else | ||
345 | xformer_prog = "gunzip"; | ||
346 | #endif | ||
347 | #endif | ||
348 | if (!ENABLE_FEATURE_SEAMLESS_GZ | ||
349 | || magic[0] != 0x1f || magic[1] != 0x8b | ||
350 | ) { | ||
351 | if (!ENABLE_FEATURE_SEAMLESS_BZ2 | ||
352 | || magic[0] != 'B' || magic[1] != 'Z' | ||
353 | ) { | ||
354 | bb_error_msg_and_die("no gzip" | ||
355 | IF_FEATURE_SEAMLESS_BZ2("/bzip2") | ||
356 | " magic"); | ||
357 | } | ||
358 | #if BB_MMU | ||
359 | xformer = unpack_bz2_stream; | ||
360 | #else | ||
361 | xformer_prog = "bunzip2"; | ||
362 | #endif | ||
363 | } else { | ||
364 | #if !BB_MMU | ||
365 | /* NOMMU version of open_transformer execs | ||
366 | * an external unzipper that wants | ||
367 | * file position at the start of the file */ | ||
368 | xlseek(fd, 0, SEEK_SET); | ||
369 | #endif | ||
370 | } | ||
371 | open_transformer(fd, xformer, xformer_prog); | ||
372 | } | 391 | } |
373 | } | 392 | } |
374 | 393 | ||
diff --git a/libbb/read_key.c b/libbb/read_key.c index 8422976c9..64557ab14 100644 --- a/libbb/read_key.c +++ b/libbb/read_key.c | |||
@@ -214,7 +214,7 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) | |||
214 | } | 214 | } |
215 | n++; | 215 | n++; |
216 | /* Try to decipher "ESC [ NNN ; NNN R" sequence */ | 216 | /* Try to decipher "ESC [ NNN ; NNN R" sequence */ |
217 | if (ENABLE_FEATURE_EDITING_ASK_TERMINAL | 217 | if ((ENABLE_FEATURE_EDITING_ASK_TERMINAL || ENABLE_FEATURE_VI_ASK_TERMINAL) |
218 | && n >= 5 | 218 | && n >= 5 |
219 | && buffer[0] == '[' | 219 | && buffer[0] == '[' |
220 | && buffer[n-1] == 'R' | 220 | && buffer[n-1] == 'R' |
diff --git a/libbb/time.c b/libbb/time.c index 5cd04268c..8d176e52e 100644 --- a/libbb/time.c +++ b/libbb/time.c | |||
@@ -68,6 +68,16 @@ void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm) | |||
68 | end = '\0'; | 68 | end = '\0'; |
69 | /* else end != NUL and we error out */ | 69 | /* else end != NUL and we error out */ |
70 | } | 70 | } |
71 | } else if (date_str[0] == '@') { | ||
72 | time_t t = bb_strtol(date_str + 1, NULL, 10); | ||
73 | if (!errno) { | ||
74 | struct tm *lt = localtime(&t); | ||
75 | if (lt) { | ||
76 | *ptm = *lt; | ||
77 | return; | ||
78 | } | ||
79 | } | ||
80 | end = '1'; | ||
71 | } else { | 81 | } else { |
72 | /* Googled the following on an old date manpage: | 82 | /* Googled the following on an old date manpage: |
73 | * | 83 | * |
diff --git a/libbb/unicode.c b/libbb/unicode.c index 83e70b412..b2c28239b 100644 --- a/libbb/unicode.c +++ b/libbb/unicode.c | |||
@@ -240,7 +240,7 @@ int FAST_FUNC iswpunct(wint_t wc) | |||
240 | } | 240 | } |
241 | 241 | ||
242 | 242 | ||
243 | # if LAST_SUPPORTED_WCHAR >= 0x300 | 243 | # if CONFIG_LAST_SUPPORTED_WCHAR >= 0x300 |
244 | struct interval { | 244 | struct interval { |
245 | uint16_t first; | 245 | uint16_t first; |
246 | uint16_t last; | 246 | uint16_t last; |
@@ -418,12 +418,11 @@ 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 | */ |
421 | static int wcwidth(unsigned ucs) | 421 | int FAST_FUNC wcwidth(unsigned ucs) |
422 | { | 422 | { |
423 | # if LAST_SUPPORTED_WCHAR >= 0x300 | 423 | # if CONFIG_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 */ |
425 | /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */ | 425 | /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */ |
426 | static const struct interval combining[] = { | ||
427 | # define BIG_(a,b) { a, b }, | 426 | # define BIG_(a,b) { a, b }, |
428 | # define PAIR(a,b) | 427 | # define PAIR(a,b) |
429 | # define ARRAY /* PAIR if < 0x4000 and no more than 4 chars big */ \ | 428 | # define ARRAY /* PAIR if < 0x4000 and no more than 4 chars big */ \ |
@@ -557,10 +556,9 @@ static int wcwidth(unsigned ucs) | |||
557 | BIG_(0xFE20, 0xFE23) \ | 556 | BIG_(0xFE20, 0xFE23) \ |
558 | BIG_(0xFEFF, 0xFEFF) \ | 557 | BIG_(0xFEFF, 0xFEFF) \ |
559 | BIG_(0xFFF9, 0xFFFB) | 558 | BIG_(0xFFF9, 0xFFFB) |
560 | ARRAY | 559 | static const struct interval combining[] = { ARRAY }; |
561 | # undef BIG_ | 560 | # undef BIG_ |
562 | # undef PAIR | 561 | # undef PAIR |
563 | }; | ||
564 | # define BIG_(a,b) | 562 | # define BIG_(a,b) |
565 | # define PAIR(a,b) (a << 2) | (b-a), | 563 | # define PAIR(a,b) (a << 2) | (b-a), |
566 | static const uint16_t combining1[] = { ARRAY }; | 564 | static const uint16_t combining1[] = { ARRAY }; |
@@ -581,14 +579,14 @@ static int wcwidth(unsigned ucs) | |||
581 | if ((ucs & ~0x80) < 0x20 || ucs == 0x7f) | 579 | if ((ucs & ~0x80) < 0x20 || ucs == 0x7f) |
582 | return -1; | 580 | return -1; |
583 | /* Quick abort if it is an obviously invalid char */ | 581 | /* Quick abort if it is an obviously invalid char */ |
584 | if (ucs > LAST_SUPPORTED_WCHAR) | 582 | if (ucs > CONFIG_LAST_SUPPORTED_WCHAR) |
585 | return -1; | 583 | return -1; |
586 | 584 | ||
587 | /* Optimization: no combining chars below 0x300 */ | 585 | /* Optimization: no combining chars below 0x300 */ |
588 | if (LAST_SUPPORTED_WCHAR < 0x300 || ucs < 0x300) | 586 | if (CONFIG_LAST_SUPPORTED_WCHAR < 0x300 || ucs < 0x300) |
589 | return 1; | 587 | return 1; |
590 | 588 | ||
591 | # if LAST_SUPPORTED_WCHAR >= 0x300 | 589 | # if CONFIG_LAST_SUPPORTED_WCHAR >= 0x300 |
592 | /* Binary search in table of non-spacing characters */ | 590 | /* Binary search in table of non-spacing characters */ |
593 | if (in_interval_table(ucs, combining, ARRAY_SIZE(combining) - 1)) | 591 | if (in_interval_table(ucs, combining, ARRAY_SIZE(combining) - 1)) |
594 | return 0; | 592 | return 0; |
@@ -596,25 +594,25 @@ static int wcwidth(unsigned ucs) | |||
596 | return 0; | 594 | return 0; |
597 | 595 | ||
598 | /* Optimization: all chars below 0x1100 are not double-width */ | 596 | /* Optimization: all chars below 0x1100 are not double-width */ |
599 | if (LAST_SUPPORTED_WCHAR < 0x1100 || ucs < 0x1100) | 597 | if (CONFIG_LAST_SUPPORTED_WCHAR < 0x1100 || ucs < 0x1100) |
600 | return 1; | 598 | return 1; |
601 | 599 | ||
602 | # if LAST_SUPPORTED_WCHAR >= 0x1100 | 600 | # if CONFIG_LAST_SUPPORTED_WCHAR >= 0x1100 |
603 | /* Invalid code points: */ | 601 | /* Invalid code points: */ |
604 | /* High (d800..dbff) and low (dc00..dfff) surrogates (valid only in UTF16) */ | 602 | /* High (d800..dbff) and low (dc00..dfff) surrogates (valid only in UTF16) */ |
605 | /* Private Use Area (e000..f8ff) */ | 603 | /* Private Use Area (e000..f8ff) */ |
606 | /* Noncharacters fdd0..fdef */ | 604 | /* Noncharacters fdd0..fdef */ |
607 | if ((LAST_SUPPORTED_WCHAR >= 0xd800 && ucs >= 0xd800 && ucs <= 0xf8ff) | 605 | if ((CONFIG_LAST_SUPPORTED_WCHAR >= 0xd800 && ucs >= 0xd800 && ucs <= 0xf8ff) |
608 | || (LAST_SUPPORTED_WCHAR >= 0xfdd0 && ucs >= 0xfdd0 && ucs <= 0xfdef) | 606 | || (CONFIG_LAST_SUPPORTED_WCHAR >= 0xfdd0 && ucs >= 0xfdd0 && ucs <= 0xfdef) |
609 | ) { | 607 | ) { |
610 | return -1; | 608 | return -1; |
611 | } | 609 | } |
612 | /* 0xfffe and 0xffff in every plane are invalid */ | 610 | /* 0xfffe and 0xffff in every plane are invalid */ |
613 | if (LAST_SUPPORTED_WCHAR >= 0xfffe && ((ucs & 0xfffe) == 0xfffe)) { | 611 | if (CONFIG_LAST_SUPPORTED_WCHAR >= 0xfffe && ((ucs & 0xfffe) == 0xfffe)) { |
614 | return -1; | 612 | return -1; |
615 | } | 613 | } |
616 | 614 | ||
617 | # if LAST_SUPPORTED_WCHAR >= 0x10000 | 615 | # if CONFIG_LAST_SUPPORTED_WCHAR >= 0x10000 |
618 | if (ucs >= 0x10000) { | 616 | if (ucs >= 0x10000) { |
619 | /* Combining chars in Supplementary Multilingual Plane 0x1xxxx */ | 617 | /* Combining chars in Supplementary Multilingual Plane 0x1xxxx */ |
620 | static const struct interval combining0x10000[] = { | 618 | static const struct interval combining0x10000[] = { |
@@ -627,7 +625,7 @@ static int wcwidth(unsigned ucs) | |||
627 | if (in_interval_table(ucs ^ 0x10000, combining0x10000, ARRAY_SIZE(combining0x10000) - 1)) | 625 | if (in_interval_table(ucs ^ 0x10000, combining0x10000, ARRAY_SIZE(combining0x10000) - 1)) |
628 | return 0; | 626 | return 0; |
629 | /* Check a few non-spacing chars in Supplementary Special-purpose Plane 0xExxxx */ | 627 | /* Check a few non-spacing chars in Supplementary Special-purpose Plane 0xExxxx */ |
630 | if (LAST_SUPPORTED_WCHAR >= 0xE0001 | 628 | if (CONFIG_LAST_SUPPORTED_WCHAR >= 0xE0001 |
631 | && ( ucs == 0xE0001 | 629 | && ( ucs == 0xE0001 |
632 | || (ucs >= 0xE0020 && ucs <= 0xE007F) | 630 | || (ucs >= 0xE0020 && ucs <= 0xE007F) |
633 | || (ucs >= 0xE0100 && ucs <= 0xE01EF) | 631 | || (ucs >= 0xE0100 && ucs <= 0xE01EF) |
@@ -646,7 +644,7 @@ static int wcwidth(unsigned ucs) | |||
646 | || ucs == 0x2329 /* left-pointing angle bracket; also CJK punct. char */ | 644 | || ucs == 0x2329 /* left-pointing angle bracket; also CJK punct. char */ |
647 | || ucs == 0x232a /* right-pointing angle bracket; also CJK punct. char */ | 645 | || ucs == 0x232a /* right-pointing angle bracket; also CJK punct. char */ |
648 | || (ucs >= 0x2e80 && ucs <= 0xa4cf && ucs != 0x303f) /* CJK ... Yi */ | 646 | || (ucs >= 0x2e80 && ucs <= 0xa4cf && ucs != 0x303f) /* CJK ... Yi */ |
649 | # if LAST_SUPPORTED_WCHAR >= 0xac00 | 647 | # if CONFIG_LAST_SUPPORTED_WCHAR >= 0xac00 |
650 | || (ucs >= 0xac00 && ucs <= 0xd7a3) /* Hangul Syllables */ | 648 | || (ucs >= 0xac00 && ucs <= 0xd7a3) /* Hangul Syllables */ |
651 | || (ucs >= 0xf900 && ucs <= 0xfaff) /* CJK Compatibility Ideographs */ | 649 | || (ucs >= 0xf900 && ucs <= 0xfaff) /* CJK Compatibility Ideographs */ |
652 | || (ucs >= 0xfe10 && ucs <= 0xfe19) /* Vertical forms */ | 650 | || (ucs >= 0xfe10 && ucs <= 0xfe19) /* Vertical forms */ |
@@ -668,7 +666,6 @@ int FAST_FUNC unicode_bidi_isrtl(wint_t wc) | |||
668 | * http://www.unicode.org/Public/5.2.0/ucd/extracted/DerivedBidiClass.txt | 666 | * http://www.unicode.org/Public/5.2.0/ucd/extracted/DerivedBidiClass.txt |
669 | * Bidi_Class=Left_To_Right | Bidi_Class=Arabic_Letter | 667 | * Bidi_Class=Left_To_Right | Bidi_Class=Arabic_Letter |
670 | */ | 668 | */ |
671 | static const struct interval rtl_b[] = { | ||
672 | # define BIG_(a,b) { a, b }, | 669 | # define BIG_(a,b) { a, b }, |
673 | # define PAIR(a,b) | 670 | # define PAIR(a,b) |
674 | # define ARRAY \ | 671 | # define ARRAY \ |
@@ -723,10 +720,9 @@ int FAST_FUNC unicode_bidi_isrtl(wint_t wc) | |||
723 | {0x10E7F, 0x10FFF}, | 720 | {0x10E7F, 0x10FFF}, |
724 | {0x1E800, 0x1EFFF} | 721 | {0x1E800, 0x1EFFF} |
725 | */ | 722 | */ |
726 | ARRAY | 723 | static const struct interval rtl_b[] = { ARRAY }; |
727 | # undef BIG_ | 724 | # undef BIG_ |
728 | # undef PAIR | 725 | # undef PAIR |
729 | }; | ||
730 | # define BIG_(a,b) | 726 | # define BIG_(a,b) |
731 | # define PAIR(a,b) (a << 2) | (b-a), | 727 | # define PAIR(a,b) (a << 2) | (b-a), |
732 | static const uint16_t rtl_p[] = { ARRAY }; | 728 | static const uint16_t rtl_p[] = { ARRAY }; |
@@ -755,7 +751,6 @@ int FAST_FUNC unicode_bidi_is_neutral_wchar(wint_t wc) | |||
755 | * White_Space, Other_Neutral, European_Number, European_Separator, | 751 | * White_Space, Other_Neutral, European_Number, European_Separator, |
756 | * European_Terminator, Arabic_Number, Common_Separator | 752 | * European_Terminator, Arabic_Number, Common_Separator |
757 | */ | 753 | */ |
758 | static const struct interval neutral_b[] = { | ||
759 | # define BIG_(a,b) { a, b }, | 754 | # define BIG_(a,b) { a, b }, |
760 | # define PAIR(a,b) | 755 | # define PAIR(a,b) |
761 | # define ARRAY \ | 756 | # define ARRAY \ |
@@ -929,10 +924,9 @@ int FAST_FUNC unicode_bidi_is_neutral_wchar(wint_t wc) | |||
929 | {0x1F030, 0x1F093}, | 924 | {0x1F030, 0x1F093}, |
930 | {0x1F100, 0x1F10A} | 925 | {0x1F100, 0x1F10A} |
931 | */ | 926 | */ |
932 | ARRAY | 927 | static const struct interval neutral_b[] = { ARRAY }; |
933 | # undef BIG_ | 928 | # undef BIG_ |
934 | # undef PAIR | 929 | # undef PAIR |
935 | }; | ||
936 | # define BIG_(a,b) | 930 | # define BIG_(a,b) |
937 | # define PAIR(a,b) (a << 2) | (b-a), | 931 | # define PAIR(a,b) (a << 2) | (b-a), |
938 | static const uint16_t neutral_p[] = { ARRAY }; | 932 | static const uint16_t neutral_p[] = { ARRAY }; |
diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c index aec165f06..d93dd2af9 100644 --- a/libbb/xfuncs.c +++ b/libbb/xfuncs.c | |||
@@ -210,34 +210,40 @@ char* FAST_FUNC xmalloc_ttyname(int fd) | |||
210 | return buf; | 210 | return buf; |
211 | } | 211 | } |
212 | 212 | ||
213 | /* It is perfectly ok to pass in a NULL for either width or for | 213 | static int wh_helper(int value, int def_val, const char *env_name, int *err) |
214 | * height, in which case that value will not be set. */ | ||
215 | int FAST_FUNC get_terminal_width_height(int fd, unsigned *width, unsigned *height) | ||
216 | { | 214 | { |
217 | struct winsize win = { 0, 0, 0, 0 }; | 215 | if (value == 0) { |
218 | int ret = ioctl(fd, TIOCGWINSZ, &win); | 216 | char *s = getenv(env_name); |
219 | 217 | if (s) { | |
220 | if (height) { | 218 | value = atoi(s); |
221 | if (!win.ws_row) { | 219 | /* If LINES/COLUMNS are set, pretent that there is |
222 | char *s = getenv("LINES"); | 220 | * no error getting w/h, this prevents some ugly |
223 | if (s) win.ws_row = atoi(s); | 221 | * cursor tricks by our callers */ |
224 | } | 222 | *err = 0; |
225 | if (win.ws_row <= 1 || win.ws_row >= 30000) | ||
226 | win.ws_row = 24; | ||
227 | *height = (int) win.ws_row; | ||
228 | } | ||
229 | |||
230 | if (width) { | ||
231 | if (!win.ws_col) { | ||
232 | char *s = getenv("COLUMNS"); | ||
233 | if (s) win.ws_col = atoi(s); | ||
234 | } | 223 | } |
235 | if (win.ws_col <= 1 || win.ws_col >= 30000) | ||
236 | win.ws_col = 80; | ||
237 | *width = (int) win.ws_col; | ||
238 | } | 224 | } |
225 | if (value <= 1 || value >= 30000) | ||
226 | value = def_val; | ||
227 | return value; | ||
228 | } | ||
239 | 229 | ||
240 | return ret; | 230 | /* It is perfectly ok to pass in a NULL for either width or for |
231 | * height, in which case that value will not be set. */ | ||
232 | int FAST_FUNC get_terminal_width_height(int fd, unsigned *width, unsigned *height) | ||
233 | { | ||
234 | struct winsize win; | ||
235 | int err; | ||
236 | |||
237 | win.ws_row = 0; | ||
238 | win.ws_col = 0; | ||
239 | /* I've seen ioctl returning 0, but row/col is (still?) 0. | ||
240 | * We treat that as an error too. */ | ||
241 | err = ioctl(fd, TIOCGWINSZ, &win) != 0 || win.ws_row == 0; | ||
242 | if (height) | ||
243 | *height = wh_helper(win.ws_row, 24, "LINES", &err); | ||
244 | if (width) | ||
245 | *width = wh_helper(win.ws_col, 80, "COLUMNS", &err); | ||
246 | return err; | ||
241 | } | 247 | } |
242 | 248 | ||
243 | int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp) | 249 | int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp) |