aboutsummaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>2010-09-14 11:41:16 +1000
committerNguyễn Thái Ngọc Duy <pclouds@gmail.com>2010-09-14 11:41:16 +1000
commit743d85e7d1c2a721baf020b9d79f45f0df2420a9 (patch)
tree9e551b726ac2bf9fd8eafb2764e7237f352bb429 /libbb
parent87911f4fcd86f7abc0aefba8e9cbec2ac9d127e4 (diff)
parentc7f95d23f6bc7e17a3b79decf83eb362b389e53a (diff)
downloadbusybox-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.c73
-rw-r--r--libbb/lineedit.c320
-rw-r--r--libbb/read.c103
-rw-r--r--libbb/read_key.c2
-rw-r--r--libbb/time.c10
-rw-r--r--libbb/unicode.c40
-rw-r--r--libbb/xfuncs.c54
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
106static void full_write2_str(const char *str) 106static 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
111void FAST_FUNC bb_show_usage(void) 113void 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
598static const char usr_bin [] ALIGN1 = "/usr/bin/";
599static const char usr_sbin[] ALIGN1 = "/usr/sbin/";
600static 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 */
597static void install_links(const char *busybox, int use_symbolic_links, 610static 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..." */
640static int busybox_main(char **argv) 643static 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
73static bool BB_isspace(CHAR_T c) { return ((unsigned)c < 256 && isspace(c)); } 73static 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
95enum { 103enum {
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}
214static size_t save_string(char *dst, int maxsize) 222static 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... */
223static void BB_PUTCHAR(wchar_t c) 262static 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
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 (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 */
235static size_t load_string(const char *src, int maxsize) 306static 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
241static void save_string(char *dst, int maxsize) 312static 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: */
319int 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 327static void put_cur_glyph_and_inc_cursor(void)
255static void cmdedit_set_out_char(void)
256#define cmdedit_set_out_char(next_char) cmdedit_set_out_char()
257#else
258static 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) */
307static void input_end(void) 390static 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 */
314static void goto_new_line(void) 397static 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 404static void beep(void)
322static void out1str(const char *s)
323{ 405{
324 if (s) 406 bb_putchar('\007');
325 fputs(s, stdout);
326} 407}
327 408
328static void beep(void) 409static 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) */
335static void input_backward(unsigned num) 423static 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
375static 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 */
388static void redraw(int y, int back_cursor) 509static 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)
463static void input_forward(void) 585static 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
22ssize_t FAST_FUNC safe_read(int fd, void *buf, size_t count) 21ssize_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
309int FAST_FUNC open_zipped(const char *fname) 308#if ZIPPED
309int 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
369int 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
244struct interval { 244struct 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 */
421static int wcwidth(unsigned ucs) 421int 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 213static 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. */
215int 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. */
232int 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
243int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp) 249int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp)