From 43b094b584d8e24406bb819e056c9ce618167ee8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 18 Apr 2010 20:16:11 -0700 Subject: remove stdio from allnoconfig build Signed-off-by: Denys Vlasenko --- libbb/appletlib.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'libbb') diff --git a/libbb/appletlib.c b/libbb/appletlib.c index 2d52c3db9..7a5e7ae4d 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -105,7 +105,9 @@ static const char *unpack_usage_messages(void) static void full_write2_str(const char *str) { - xwrite_str(STDERR_FILENO, str); + // This uses stdio: + //xwrite_str(STDERR_FILENO, str); + write(STDERR_FILENO, str, strlen(str)); } void FAST_FUNC bb_show_usage(void) -- cgit v1.2.3-55-g6feb From c175c4664734e5a363d8cc8668c08f551eff1485 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 18 Apr 2010 22:09:30 -0700 Subject: vi: discover window size even on serial consoles. optional function old new delta edit_file 671 761 +90 wh_helper - 57 +57 query_screen_dimensions 54 63 +9 ar_main 533 542 +9 refresh 767 773 +6 vi_main 242 243 +1 text_yank 56 54 -2 get_terminal_width_height 180 135 -45 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 5/2 up/down: 172/-47) Total: 125 bytes Signed-off-by: Denys Vlasenko --- editors/Config.in | 12 ++++++++++++ editors/vi.c | 23 ++++++++++++++++++++++- libbb/read_key.c | 2 +- libbb/xfuncs.c | 54 ++++++++++++++++++++++++++++++------------------------ 4 files changed, 65 insertions(+), 26 deletions(-) (limited to 'libbb') diff --git a/editors/Config.in b/editors/Config.in index e4fdd0f38..5f9566f0a 100644 --- a/editors/Config.in +++ b/editors/Config.in @@ -168,6 +168,18 @@ config FEATURE_VI_WIN_RESIZE help Make busybox vi behave nicely with terminals that get resized. +config FEATURE_VI_ASK_TERMINAL + bool "Use 'tell me cursor position' ESC sequence to measure window" + default n + depends on VI + help + If terminal size can't be retrieved and $LINES/$COLUMNS are not set, + this option makes vi perform a last-ditch effort to find it: + vi positions cursor to 999,999 and asks terminal to report real + cursor position using "ESC [ 6 n" escape sequence, then reads stdin. + + This is not clean but helps a lot on serial lines and such. + config FEATURE_VI_OPTIMIZE_CURSOR bool "Optimize cursor movement" default y diff --git a/editors/vi.c b/editors/vi.c index f925984ba..d3a35e781 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -138,6 +138,9 @@ struct globals { int save_argc; // how many file names on cmd line int cmdcnt; // repetition count unsigned rows, columns; // the terminal screen is this size +#if ENABLE_FEATURE_VI_ASK_TERMINAL + int get_rowcol_error; +#endif int crow, ccol; // cursor is on Crow x Ccol int offset; // chars scrolled off the screen to the left int have_status_msg; // is default edit status needed? @@ -503,7 +506,11 @@ static int init_text_buffer(char *fn) #if ENABLE_FEATURE_VI_WIN_RESIZE static void query_screen_dimensions(void) { - get_terminal_width_height(STDIN_FILENO, &columns, &rows); +# if ENABLE_FEATURE_VI_ASK_TERMINAL + if (!G.get_rowcol_error) + G.get_rowcol_error = +# endif + get_terminal_width_height(STDIN_FILENO, &columns, &rows); if (rows > MAX_SCR_ROWS) rows = MAX_SCR_ROWS; if (columns > MAX_SCR_COLS) @@ -530,6 +537,20 @@ static void edit_file(char *fn) columns = 80; size = 0; query_screen_dimensions(); +#if ENABLE_FEATURE_VI_ASK_TERMINAL + if (G.get_rowcol_error /* TODO? && no input on stdin */) { + uint64_t k; + write1("\033[999;999H" "\033[6n"); + fflush_all(); + k = read_key(STDIN_FILENO, readbuffer, /*timeout_ms:*/ 100); + if ((int32_t)k == KEYCODE_CURSOR_POS) { + uint32_t rc = (k >> 32); + columns = (rc & 0x7fff); + rows = ((rc >> 16) & 0x7fff); + } + query_screen_dimensions(); + } +#endif new_screen(rows, columns); // get memory for virtual screen init_text_buffer(fn); 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) } n++; /* Try to decipher "ESC [ NNN ; NNN R" sequence */ - if (ENABLE_FEATURE_EDITING_ASK_TERMINAL + if ((ENABLE_FEATURE_EDITING_ASK_TERMINAL || ENABLE_FEATURE_VI_ASK_TERMINAL) && n >= 5 && buffer[0] == '[' && buffer[n-1] == 'R' 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) return buf; } -/* It is perfectly ok to pass in a NULL for either width or for - * height, in which case that value will not be set. */ -int FAST_FUNC get_terminal_width_height(int fd, unsigned *width, unsigned *height) +static int wh_helper(int value, int def_val, const char *env_name, int *err) { - struct winsize win = { 0, 0, 0, 0 }; - int ret = ioctl(fd, TIOCGWINSZ, &win); - - if (height) { - if (!win.ws_row) { - char *s = getenv("LINES"); - if (s) win.ws_row = atoi(s); - } - if (win.ws_row <= 1 || win.ws_row >= 30000) - win.ws_row = 24; - *height = (int) win.ws_row; - } - - if (width) { - if (!win.ws_col) { - char *s = getenv("COLUMNS"); - if (s) win.ws_col = atoi(s); + if (value == 0) { + char *s = getenv(env_name); + if (s) { + value = atoi(s); + /* If LINES/COLUMNS are set, pretent that there is + * no error getting w/h, this prevents some ugly + * cursor tricks by our callers */ + *err = 0; } - if (win.ws_col <= 1 || win.ws_col >= 30000) - win.ws_col = 80; - *width = (int) win.ws_col; } + if (value <= 1 || value >= 30000) + value = def_val; + return value; +} - return ret; +/* It is perfectly ok to pass in a NULL for either width or for + * height, in which case that value will not be set. */ +int FAST_FUNC get_terminal_width_height(int fd, unsigned *width, unsigned *height) +{ + struct winsize win; + int err; + + win.ws_row = 0; + win.ws_col = 0; + /* I've seen ioctl returning 0, but row/col is (still?) 0. + * We treat that as an error too. */ + err = ioctl(fd, TIOCGWINSZ, &win) != 0 || win.ws_row == 0; + if (height) + *height = wh_helper(win.ws_row, 24, "LINES", &err); + if (width) + *width = wh_helper(win.ws_col, 80, "COLUMNS", &err); + return err; } int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp) -- cgit v1.2.3-55-g6feb From 5a7c72015c0562dbe19f1e493b54b4c9db7f6f3a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 20 Apr 2010 21:02:57 -0400 Subject: busybox --list option. +140 bytes. Rob wanted it. Signed-off-by: Denys Vlasenko --- libbb/appletlib.c | 69 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 25 deletions(-) (limited to 'libbb') diff --git a/libbb/appletlib.c b/libbb/appletlib.c index 7a5e7ae4d..a8cd8e65f 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -595,6 +595,17 @@ static void check_suid(int applet_no) #if ENABLE_FEATURE_INSTALLER +static const char usr_bin [] ALIGN1 = "/usr/bin/"; +static const char usr_sbin[] ALIGN1 = "/usr/sbin/"; +static const char *const install_dir[] = { + &usr_bin [8], /* "/" */ + &usr_bin [4], /* "/bin/" */ + &usr_sbin[4], /* "/sbin/" */ + usr_bin, + usr_sbin +}; + + /* create (sym)links for each applet */ static void install_links(const char *busybox, int use_symbolic_links, char *custom_install_dir) @@ -602,16 +613,6 @@ static void install_links(const char *busybox, int use_symbolic_links, /* directory table * this should be consistent w/ the enum, * busybox.h::bb_install_loc_t, or else... */ - static const char usr_bin [] ALIGN1 = "/usr/bin"; - static const char usr_sbin[] ALIGN1 = "/usr/sbin"; - static const char *const install_dir[] = { - &usr_bin [8], /* "", equivalent to "/" for concat_path_file() */ - &usr_bin [4], /* "/bin" */ - &usr_sbin[4], /* "/sbin" */ - usr_bin, - usr_sbin - }; - int (*lf)(const char *, const char *); char *fpc; unsigned i; @@ -635,8 +636,8 @@ static void install_links(const char *busybox, int use_symbolic_links, } } #else -#define install_links(x,y,z) ((void)0) -#endif /* FEATURE_INSTALLER */ +# define install_links(x,y,z) ((void)0) +#endif /* If we were called as "busybox..." */ static int busybox_main(char **argv) @@ -657,19 +658,20 @@ static int busybox_main(char **argv) full_write2_str(bb_banner); /* reuse const string */ full_write2_str(" multi-call binary.\n"); /* reuse */ full_write2_str( - "Copyright (C) 1998-2009 Erik Andersen, Rob Landley, Denys Vlasenko\n" - "and others. Licensed under GPLv2.\n" - "See source distribution for full notice.\n" - "\n" - "Usage: busybox [function] [arguments]...\n" - " or: function [arguments]...\n" - "\n" - "\tBusyBox is a multi-call binary that combines many common Unix\n" - "\tutilities into a single executable. Most people will create a\n" - "\tlink to busybox for each function they wish to use and BusyBox\n" - "\twill act like whatever it was invoked as.\n" - "\n" - "Currently defined functions:\n"); + "Copyright (C) 1998-2009 Erik Andersen, Rob Landley, Denys Vlasenko\n" + "and others. Licensed under GPLv2.\n" + "See source distribution for full notice.\n" + "\n" + "Usage: busybox [function] [arguments]...\n" + " or: function [arguments]...\n" + "\n" + "\tBusyBox is a multi-call binary that combines many common Unix\n" + "\tutilities into a single executable. Most people will create a\n" + "\tlink to busybox for each function they wish to use and BusyBox\n" + "\twill act like whatever it was invoked as.\n" + "\n" + "Currently defined functions:\n" + ); col = 0; a = applet_names; /* prevent last comma to be in the very last pos */ @@ -694,6 +696,23 @@ static int busybox_main(char **argv) return 0; } + if (strncmp(argv[1], "--list", 6) == 0) { + unsigned i = 0; + const char *a = applet_names; + dup2(1, 2); + while (*a) { +#if ENABLE_FEATURE_INSTALLER + if (argv[1][6]) /* --list-path? */ + full_write2_str(install_dir[APPLET_INSTALL_LOC(i)] + 1); +#endif + full_write2_str(a); + full_write2_str("\n"); + i++; + a += strlen(a) + 1; + } + return 0; + } + if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) { int use_symbolic_links; const char *busybox; -- cgit v1.2.3-55-g6feb From 5f94346f7387cb5e33cf202dd3306f062bb22052 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 22 Apr 2010 00:45:28 -0400 Subject: date: support -d @SECONDS_SINCE_1970 function old new delta parse_datestr 647 721 +74 Signed-off-by: Denys Vlasenko --- libbb/time.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'libbb') 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) end = '\0'; /* else end != NUL and we error out */ } + } else if (date_str[0] == '@') { + time_t t = bb_strtol(date_str + 1, NULL, 10); + if (!errno) { + struct tm *lt = localtime(&t); + if (lt) { + *ptm = *lt; + return; + } + } + end = '1'; } else { /* Googled the following on an old date manpage: * -- cgit v1.2.3-55-g6feb From a659b81dfa435aa19130a8c7dd1bfe8fa9a22131 Mon Sep 17 00:00:00 2001 From: Tomas Heinrich Date: Thu, 29 Apr 2010 13:43:39 +0200 Subject: libbb/lineedit: add support for preserving "broken" (non-unicode) chars Signed-off-by: Tomas Heinrich Signed-off-by: Denys Vlasenko --- Config.in | 11 ++++++++++ libbb/lineedit.c | 62 +++++++++++++++++++++++++++++++++++++++++++---------- libbb/unicode.c | 12 +++-------- testsuite/ash.tests | 24 +++++++++++++++++++++ 4 files changed, 89 insertions(+), 20 deletions(-) (limited to 'libbb') diff --git a/Config.in b/Config.in index 40af9115d..a5d20038a 100644 --- a/Config.in +++ b/Config.in @@ -223,6 +223,17 @@ config UNICODE_NEUTRAL_TABLE With this option on, more extensive (and bigger) table of neutral chars will be used. +config UNICODE_PRESERVE_BROKEN + bool "Make it possible to enter sequences of chars which are not Unicode" + default n + depends on UNICODE_SUPPORT + help + With this option on, invalid UTF-8 bytes are not substituted + with the selected substitution character. + For example, this means that entering 'l', 's', ' ', 0xff, [Enter] + at shell prompt will list file named 0xff (single char name + with char value 255), not file named '?'. + config LONG_OPTS bool "Support for --long-options" default y diff --git a/libbb/lineedit.c b/libbb/lineedit.c index dc90846f9..622f9ddfc 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -68,7 +68,7 @@ #undef CHAR_T #if ENABLE_UNICODE_SUPPORT -# define BB_NUL L'\0' +# define BB_NUL ((wchar_t)0) # define CHAR_T wchar_t static bool BB_isspace(CHAR_T c) { return ((unsigned)c < 256 && isspace(c)); } # if ENABLE_FEATURE_EDITING_VI @@ -92,6 +92,14 @@ static bool BB_ispunct(CHAR_T c) { return ((unsigned)c < 256 && ispunct(c)); } #endif +# if ENABLE_UNICODE_PRESERVE_BROKEN +# define unicode_mark_inv_wchar(wc) ((wc) | 0x20000000) +# define unicode_is_inv_wchar(wc) ((wc) & 0x20000000) +# else +# define unicode_is_inv_wchar(wc) 0 +# endif + + enum { /* We use int16_t for positions, need to limit line len */ MAX_LINELEN = CONFIG_FEATURE_EDITING_MAX_LEN < 0x7ff0 @@ -208,24 +216,58 @@ static size_t load_string(const char *src, int maxsize) ssize_t len = mbstowcs(command_ps, src, maxsize - 1); if (len < 0) len = 0; - command_ps[len] = L'\0'; + command_ps[len] = 0; return len; } -static size_t save_string(char *dst, int maxsize) +static unsigned save_string(char *dst, unsigned maxsize) { +#if !ENABLE_UNICODE_PRESERVE_BROKEN ssize_t len = wcstombs(dst, command_ps, maxsize - 1); if (len < 0) len = 0; dst[len] = '\0'; return len; +#else + unsigned dstpos = 0; + unsigned srcpos = 0; + + maxsize--; + while (dstpos < maxsize) { + wchar_t wc; + int n = srcpos; + while ((wc = command_ps[srcpos]) != 0 + && !unicode_is_inv_wchar(wc) + ) { + srcpos++; + } + command_ps[srcpos] = 0; + n = wcstombs(dst + dstpos, command_ps + n, maxsize - dstpos); + if (n < 0) /* should not happen */ + break; + dstpos += n; + if (wc == 0) /* usually is */ + break; + /* We do have invalid byte here! */ + command_ps[srcpos] = wc; /* restore it */ + srcpos++; + if (dstpos == maxsize) + break; + dst[dstpos++] = (char) wc; + } + dst[dstpos] = '\0'; + return dstpos; +#endif } /* I thought just fputwc(c, stdout) would work. But no... */ static void BB_PUTCHAR(wchar_t c) { char buf[MB_CUR_MAX + 1]; mbstate_t mbst = { 0 }; - ssize_t len = wcrtomb(buf, c, &mbst); + ssize_t len; + if (unicode_is_inv_wchar(c)) + c = CONFIG_SUBST_WCHAR; + len = wcrtomb(buf, c, &mbst); if (len > 0) { buf[len] = '\0'; fputs(buf, stdout); @@ -238,7 +280,7 @@ static size_t load_string(const char *src, int maxsize) return strlen(command_ps); } # if ENABLE_FEATURE_TAB_COMPLETION -static void save_string(char *dst, int maxsize) +static void save_string(char *dst, unsigned maxsize) { safe_strncpy(dst, command_ps, maxsize); } @@ -1719,13 +1761,11 @@ static int lineedit_read_key(char *read_key_buffer) pushback: /* Invalid sequence. Save all "bad bytes" except first */ read_key_ungets(read_key_buffer, unicode_buf + 1, unicode_idx - 1); - /* - * ic = unicode_buf[0] sounds even better, but currently - * this does not work: wchar_t[] -> char[] conversion - * when lineedit finishes mangles such "raw bytes" - * (by misinterpreting them as unicode chars): - */ +# if !ENABLE_UNICODE_PRESERVE_BROKEN ic = CONFIG_SUBST_WCHAR; +# else + ic = unicode_mark_inv_wchar(unicode_buf[0]); +# endif } else { /* Valid unicode char, return its code */ ic = wc; diff --git a/libbb/unicode.c b/libbb/unicode.c index 83e70b412..d1c6167c7 100644 --- a/libbb/unicode.c +++ b/libbb/unicode.c @@ -423,7 +423,6 @@ static int wcwidth(unsigned ucs) # if LAST_SUPPORTED_WCHAR >= 0x300 /* sorted list of non-overlapping intervals of non-spacing characters */ /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */ - static const struct interval combining[] = { # define BIG_(a,b) { a, b }, # define PAIR(a,b) # define ARRAY /* PAIR if < 0x4000 and no more than 4 chars big */ \ @@ -557,10 +556,9 @@ static int wcwidth(unsigned ucs) BIG_(0xFE20, 0xFE23) \ BIG_(0xFEFF, 0xFEFF) \ BIG_(0xFFF9, 0xFFFB) - ARRAY + static const struct interval combining[] = { ARRAY }; # undef BIG_ # undef PAIR - }; # define BIG_(a,b) # define PAIR(a,b) (a << 2) | (b-a), static const uint16_t combining1[] = { ARRAY }; @@ -668,7 +666,6 @@ int FAST_FUNC unicode_bidi_isrtl(wint_t wc) * http://www.unicode.org/Public/5.2.0/ucd/extracted/DerivedBidiClass.txt * Bidi_Class=Left_To_Right | Bidi_Class=Arabic_Letter */ - static const struct interval rtl_b[] = { # define BIG_(a,b) { a, b }, # define PAIR(a,b) # define ARRAY \ @@ -723,10 +720,9 @@ int FAST_FUNC unicode_bidi_isrtl(wint_t wc) {0x10E7F, 0x10FFF}, {0x1E800, 0x1EFFF} */ - ARRAY + static const struct interval rtl_b[] = { ARRAY }; # undef BIG_ # undef PAIR - }; # define BIG_(a,b) # define PAIR(a,b) (a << 2) | (b-a), static const uint16_t rtl_p[] = { ARRAY }; @@ -755,7 +751,6 @@ int FAST_FUNC unicode_bidi_is_neutral_wchar(wint_t wc) * White_Space, Other_Neutral, European_Number, European_Separator, * European_Terminator, Arabic_Number, Common_Separator */ - static const struct interval neutral_b[] = { # define BIG_(a,b) { a, b }, # define PAIR(a,b) # define ARRAY \ @@ -929,10 +924,9 @@ int FAST_FUNC unicode_bidi_is_neutral_wchar(wint_t wc) {0x1F030, 0x1F093}, {0x1F100, 0x1F10A} */ - ARRAY + static const struct interval neutral_b[] = { ARRAY }; # undef BIG_ # undef PAIR - }; # define BIG_(a,b) # define PAIR(a,b) (a << 2) | (b-a), static const uint16_t neutral_p[] = { ARRAY }; diff --git a/testsuite/ash.tests b/testsuite/ash.tests index 6b2caf316..ce585beb1 100755 --- a/testsuite/ash.tests +++ b/testsuite/ash.tests @@ -7,8 +7,30 @@ . ./testing.sh +test -f "$bindir/.config" && . "$bindir/.config" + # testing "test name" "options" "expected result" "file input" "stdin" +if test x"$CONFIG_UNICODE_PRESERVE_BROKEN" = x"y"; then +testing "One byte which is not valid unicode char followed by valid input" \ + "script -q -c 'ash' /dev/null >/dev/null; cat ash.output" \ + "\ +00000000 ff 2d 0a |.-.| +00000003 +" \ + "" \ + "echo \xff- | hexdump -C >ash.output; exit; exit; exit; exit\n" + +testing "30 bytes which are not valid unicode chars followed by valid input" \ + "script -q -c 'ash' /dev/null >/dev/null; cat ash.output" \ + "\ +00000000 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| +00000010 ff ff ff ff ff ff ff ff ff ff ff ff ff ff 2d 0a |..............-.| +00000020 +" \ + "" \ + "echo \xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff- | hexdump -C >ash.output; exit; exit; exit; exit\n" +else testing "One byte which is not valid unicode char followed by valid input" \ "script -q -c 'ash' /dev/null >/dev/null; cat ash.output" \ "\ @@ -27,6 +49,8 @@ testing "30 bytes which are not valid unicode chars followed by valid input" \ " \ "" \ "echo \xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff- | hexdump -C >ash.output; exit; exit; exit; exit\n" +fi + # Not sure this behavior is perfect: we lose all invalid input which precedes # arrow keys and such. In this example, \xff\xff are lost -- cgit v1.2.3-55-g6feb From 27653adc8b7ebe44bd357511de53d0c14eef0894 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 6 May 2010 14:19:19 +0000 Subject: rpm: code shrink. Now uses open_zipped's logic (factored out into setup_unzip_on_fd()) function old new delta setup_unzip_on_fd - 80 +80 open_zipped 176 113 -63 rpm_main 1672 1355 -317 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 0/2 up/down: 80/-380) Total: -300 bytes Signed-off-by: Denys Vlasenko --- archival/rpm.c | 97 +++++++++++++++++------------------------------------ archival/rpm.h | 38 +++++++++++++++++++++ archival/rpm2cpio.c | 69 ++++++++++++++++--------------------- include/libbb.h | 9 +++++ libbb/read.c | 97 ++++++++++++++++++++++++++++++----------------------- 5 files changed, 161 insertions(+), 149 deletions(-) create mode 100644 archival/rpm.h (limited to 'libbb') diff --git a/archival/rpm.c b/archival/rpm.c index 6c1e341cd..77679c275 100644 --- a/archival/rpm.c +++ b/archival/rpm.c @@ -9,8 +9,8 @@ #include "libbb.h" #include "unarchive.h" +#include "rpm.h" -#define RPM_HEADER_MAGIC "\216\255\350" #define RPM_CHAR_TYPE 1 #define RPM_INT8_TYPE 2 #define RPM_INT16_TYPE 3 @@ -46,6 +46,7 @@ #define TAG_DIRINDEXES 1116 #define TAG_BASENAMES 1117 #define TAG_DIRNAMES 1118 + #define RPMFILE_CONFIG (1 << 0) #define RPMFILE_DOC (1 << 1) @@ -147,8 +148,14 @@ int rpm_main(int argc, char **argv) time_t bdate_time; struct tm *bdate_ptm; char bdatestring[50]; - printf("Name : %-29sRelocations: %s\n", rpm_getstr(TAG_NAME, 0), rpm_getstr(TAG_PREFIXS, 0) ? rpm_getstr(TAG_PREFIXS, 0) : "(not relocateable)"); - printf("Version : %-34sVendor: %s\n", rpm_getstr(TAG_VERSION, 0), rpm_getstr(TAG_VENDOR, 0) ? rpm_getstr(TAG_VENDOR, 0) : "(none)"); + const char *p; + + p = rpm_getstr(TAG_PREFIXS, 0); + if (!p) p = "(not relocateable)"; + printf("Name : %-29sRelocations: %s\n", rpm_getstr(TAG_NAME, 0), p); + p = rpm_getstr(TAG_VENDOR, 0); + if (!p) p = "(none)"; + printf("Version : %-34sVendor: %s\n", rpm_getstr(TAG_VERSION, 0), p); bdate_time = rpm_getint(TAG_BUILDTIME, 0); bdate_ptm = localtime(&bdate_time); strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate_ptm); @@ -190,20 +197,15 @@ int rpm_main(int argc, char **argv) static void extract_cpio_gz(int fd) { archive_handle_t *archive_handle; - unsigned char magic[2]; -#if BB_MMU - IF_DESKTOP(long long) int FAST_FUNC (*xformer)(int src_fd, int dst_fd); - enum { xformer_prog = 0 }; -#else - enum { xformer = 0 }; - const char *xformer_prog; -#endif /* Initialize */ archive_handle = init_handle(); archive_handle->seek = seek_by_read; - //archive_handle->action_header = header_list; archive_handle->action_data = data_extract_all; +#if 0 /* For testing (rpm -i only lists the files in internal cpio): */ + archive_handle->action_header = header_list; + archive_handle->action_data = data_skip; +#endif archive_handle->ah_flags = ARCHIVE_RESTORE_DATE | ARCHIVE_CREATE_LEADING_DIRS /* compat: overwrite existing files. * try "rpm -i foo.src.rpm" few times in a row - @@ -213,46 +215,15 @@ static void extract_cpio_gz(int fd) archive_handle->src_fd = fd; /*archive_handle->offset = 0; - init_handle() did it */ -// TODO: open_zipped does the same - - xread(archive_handle->src_fd, &magic, 2); -#if BB_MMU - xformer = unpack_gz_stream; -#else - xformer_prog = "gunzip"; -#endif - if (magic[0] != 0x1f || magic[1] != 0x8b) { - if (!ENABLE_FEATURE_SEAMLESS_BZ2 - || magic[0] != 'B' || magic[1] != 'Z' - ) { - bb_error_msg_and_die("no gzip" - IF_FEATURE_SEAMLESS_BZ2("/bzip2") - " magic"); - } -#if BB_MMU - xformer = unpack_bz2_stream; -#else - xformer_prog = "bunzip2"; -#endif - } else { -#if !BB_MMU - /* NOMMU version of open_transformer execs an external unzipper that should - * have the file position at the start of the file */ - xlseek(archive_handle->src_fd, 0, SEEK_SET); -#endif - } - xchdir("/"); /* Install RPM's to root */ - open_transformer(archive_handle->src_fd, xformer, xformer_prog); - archive_handle->offset = 0; + setup_unzip_on_fd(archive_handle->src_fd /*, fail_if_not_detected: 1*/); while (get_header_cpio(archive_handle) == EXIT_SUCCESS) continue; } - static rpm_index **rpm_gettags(int fd, int *num_tags) { - /* We should never need mode than 200, and realloc later */ + /* We should never need more than 200 (shrink via realloc later) */ rpm_index **tags = xzalloc(200 * sizeof(tags[0])); int pass, tagindex = 0; @@ -260,27 +231,16 @@ static rpm_index **rpm_gettags(int fd, int *num_tags) /* 1st pass is the signature headers, 2nd is the main stuff */ for (pass = 0; pass < 2; pass++) { - struct { - char magic[3]; /* 3 byte magic: 0x8e 0xad 0xe8 */ - uint8_t version; /* 1 byte version number */ - uint32_t reserved; /* 4 bytes reserved */ - uint32_t entries; /* Number of entries in header (4 bytes) */ - uint32_t size; /* Size of store (4 bytes) */ - } header; - struct BUG_header { - char BUG_header[sizeof(header) == 16 ? 1 : -1]; - }; + struct rpm_header header; rpm_index *tmpindex; int storepos; xread(fd, &header, sizeof(header)); - if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC, 3) != 0) - return NULL; /* Invalid magic */ - if (header.version != 1) - return NULL; /* This program only supports v1 headers */ + if (header.magic_and_ver != htonl(RPM_HEADER_MAGICnVER)) + return NULL; /* Invalid magic, or not version 1 */ header.size = ntohl(header.size); header.entries = ntohl(header.entries); - storepos = xlseek(fd,0,SEEK_CUR) + header.entries * 16; + storepos = xlseek(fd, 0, SEEK_CUR) + header.entries * 16; while (header.entries--) { tmpindex = tags[tagindex++] = xmalloc(sizeof(*tmpindex)); @@ -292,14 +252,16 @@ static rpm_index **rpm_gettags(int fd, int *num_tags) if (pass == 0) tmpindex->tag -= 743; } - xlseek(fd, header.size, SEEK_CUR); /* Seek past store */ + storepos = xlseek(fd, header.size, SEEK_CUR); /* Seek past store */ /* Skip padding to 8 byte boundary after reading signature headers */ if (pass == 0) - xlseek(fd, (8 - (xlseek(fd,0,SEEK_CUR) % 8)) % 8, SEEK_CUR); + xlseek(fd, (-storepos) & 0x7, SEEK_CUR); } - tags = xrealloc(tags, tagindex * sizeof(tags[0])); /* realloc tags to save space */ + /* realloc tags to save space */ + tags = xrealloc(tags, tagindex * sizeof(tags[0])); *num_tags = tagindex; - return tags; /* All done, leave the file at the start of the gzipped cpio archive */ + /* All done, leave the file at the start of the gzipped cpio archive */ + return tags; } static int bsearch_rpmtag(const void *key, const void *item) @@ -324,10 +286,13 @@ static char *rpm_getstr(int tag, int itemindex) found = bsearch(&tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); if (!found || itemindex >= found[0]->count) return NULL; - if (found[0]->type == RPM_STRING_TYPE || found[0]->type == RPM_I18NSTRING_TYPE || found[0]->type == RPM_STRING_ARRAY_TYPE) { + if (found[0]->type == RPM_STRING_TYPE + || found[0]->type == RPM_I18NSTRING_TYPE + || found[0]->type == RPM_STRING_ARRAY_TYPE + ) { int n; char *tmpstr = (char *) map + found[0]->offset; - for (n=0; n < itemindex; n++) + for (n = 0; n < itemindex; n++) tmpstr = tmpstr + strlen(tmpstr) + 1; return tmpstr; } diff --git a/archival/rpm.h b/archival/rpm.h new file mode 100644 index 000000000..f7c6fc2fa --- /dev/null +++ b/archival/rpm.h @@ -0,0 +1,38 @@ +/* vi: set sw=4 ts=4: */ +/* + * RPM structs and consts + * + * Copyright (C) 2001 by Laurence Anderson + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +/* RPM file starts with this struct: */ +struct rpm_lead { + uint32_t magic; + uint8_t major, minor; + uint16_t type; + uint16_t archnum; + char name[66]; + uint16_t osnum; + uint16_t signature_type; + char reserved[16]; +}; +struct BUG_rpm_lead { + char bug[sizeof(struct rpm_lead) == 96 ? 1 : -1]; +}; +#define RPM_LEAD_MAGIC 0xedabeedb +#define RPM_LEAD_MAGIC_STR "\355\253\356\333" + +/* Then follows the header: */ +struct rpm_header { + uint32_t magic_and_ver; /* 3 byte magic: 0x8e 0xad 0xe8; 1 byte version: 0x01 */ + uint32_t reserved; /* 4 bytes reserved */ + uint32_t entries; /* Number of entries in header (4 bytes) */ + uint32_t size; /* Size of store (4 bytes) */ +}; +struct BUG_rpm_header { + char bug[sizeof(struct rpm_header) == 16 ? 1 : -1]; +}; +#define RPM_HEADER_MAGICnVER 0x8eade801 +#define RPM_HEADER_MAGIC_STR "\216\255\350" diff --git a/archival/rpm2cpio.c b/archival/rpm2cpio.c index 5403aee02..4ed5b023b 100644 --- a/archival/rpm2cpio.c +++ b/archival/rpm2cpio.c @@ -8,30 +8,7 @@ */ #include "libbb.h" #include "unarchive.h" - -#define RPM_MAGIC 0xedabeedb -#define RPM_MAGIC_STR "\355\253\356\333" - -struct rpm_lead { - uint32_t magic; - uint8_t major, minor; - uint16_t type; - uint16_t archnum; - char name[66]; - uint16_t osnum; - uint16_t signature_type; - char reserved[16]; -}; - -#define RPM_HEADER_MAGICnVER 0x8eade801 -#define RPM_HEADER_MAGIC_STR "\216\255\350" - -struct rpm_header { - uint32_t magic_and_ver; /* 3 byte magic: 0x8e 0xad 0xe8; 1 byte version */ - uint32_t reserved; /* 4 bytes reserved */ - uint32_t entries; /* Number of entries in header (4 bytes) */ - uint32_t size; /* Size of store (4 bytes) */ -}; +#include "rpm.h" enum { rpm_fd = STDIN_FILENO }; @@ -65,8 +42,6 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) { struct rpm_lead lead; unsigned pos; - unsigned char magic[2]; - IF_DESKTOP(long long) int FAST_FUNC (*unpack)(int src_fd, int dst_fd); if (argv[1]) { xmove_fd(xopen(argv[1], O_RDONLY), rpm_fd); @@ -74,33 +49,45 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) xread(rpm_fd, &lead, sizeof(lead)); /* Just check the magic, the rest is irrelevant */ - if (lead.magic != htonl(RPM_MAGIC)) { + if (lead.magic != htonl(RPM_LEAD_MAGIC)) { bb_error_msg_and_die("invalid RPM magic"); } /* Skip the signature header, align to 8 bytes */ pos = skip_header(); - seek_by_jump(rpm_fd, (8 - pos) & 7); + seek_by_jump(rpm_fd, (-(int)pos) & 7); /* Skip the main header */ skip_header(); - xread(rpm_fd, &magic, 2); - unpack = unpack_gz_stream; - if (magic[0] != 0x1f || magic[1] != 0x8b) { - if (!ENABLE_FEATURE_SEAMLESS_BZ2 - || magic[0] != 'B' || magic[1] != 'Z' - ) { - bb_error_msg_and_die("invalid gzip" - IF_FEATURE_SEAMLESS_BZ2("/bzip2") - " magic"); +#if 0 + /* This works, but doesn't report uncompress errors (they happen in child) */ + setup_unzip_on_fd(rpm_fd /*fail_if_not_detected: 1*/); + if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0) + bb_error_msg_and_die("error unpacking"); +#else + /* BLOAT */ + { + unsigned char magic[2]; + IF_DESKTOP(long long) int FAST_FUNC (*unpack)(int src_fd, int dst_fd); + + xread(rpm_fd, &magic, 2); + unpack = unpack_gz_stream; + if (magic[0] != 0x1f || magic[1] != 0x8b) { + if (!ENABLE_FEATURE_SEAMLESS_BZ2 + || magic[0] != 'B' || magic[1] != 'Z' + ) { + bb_error_msg_and_die("invalid gzip" + IF_FEATURE_SEAMLESS_BZ2("/bzip2") + " magic"); + } + unpack = unpack_bz2_stream; } - unpack = unpack_bz2_stream; - } - if (unpack(rpm_fd, STDOUT_FILENO) < 0) { - bb_error_msg_and_die("error unpacking"); + if (unpack(rpm_fd, STDOUT_FILENO) < 0) + bb_error_msg_and_die("error unpacking"); } +#endif if (ENABLE_FEATURE_CLEAN_UP) { close(rpm_fd); diff --git a/include/libbb.h b/include/libbb.h index 976120e72..2f67c7f72 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -651,6 +651,15 @@ extern char *xmalloc_reads(int fd, char *pfx, size_t *maxsz_p) FAST_FUNC; extern void *xmalloc_read(int fd, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; /* Returns NULL if file can't be opened (default max size: INT_MAX - 4095) */ extern void *xmalloc_open_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; +/* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */ +#if ENABLE_FEATURE_SEAMLESS_LZMA \ + || ENABLE_FEATURE_SEAMLESS_BZ2 \ + || ENABLE_FEATURE_SEAMLESS_GZ \ + /* || ENABLE_FEATURE_SEAMLESS_Z */ +extern int setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) FAST_FUNC; +#else +# define setup_unzip_on_fd(...) ((void)0) +#endif /* Autodetects .gz etc */ extern int open_zipped(const char *fname) FAST_FUNC; extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; diff --git a/libbb/read.c b/libbb/read.c index 06ce29718..503216eb5 100644 --- a/libbb/read.c +++ b/libbb/read.c @@ -6,7 +6,6 @@ * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ - #include "libbb.h" #define ZIPPED (ENABLE_FEATURE_SEAMLESS_LZMA \ @@ -16,7 +15,7 @@ ) #if ZIPPED -#include "unarchive.h" +# include "unarchive.h" #endif 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) return buf; } -int FAST_FUNC open_zipped(const char *fname) +#if ZIPPED +int FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) { -#if !ZIPPED - return open(fname, O_RDONLY); -#else + const int fail_if_not_detected = 1; unsigned char magic[2]; - char *sfx; - int fd; #if BB_MMU IF_DESKTOP(long long) int FAST_FUNC (*xformer)(int src_fd, int dst_fd); enum { xformer_prog = 0 }; @@ -322,6 +318,56 @@ int FAST_FUNC open_zipped(const char *fname) const char *xformer_prog; #endif + /* .gz and .bz2 both have 2-byte signature, and their + * unpack_XXX_stream wants this header skipped. */ + xread(fd, &magic, 2); +#if ENABLE_FEATURE_SEAMLESS_GZ +# if BB_MMU + xformer = unpack_gz_stream; +# else + xformer_prog = "gunzip"; +# endif +#endif + if (!ENABLE_FEATURE_SEAMLESS_GZ + || magic[0] != 0x1f || magic[1] != 0x8b + ) { + if (!ENABLE_FEATURE_SEAMLESS_BZ2 + || magic[0] != 'B' || magic[1] != 'Z' + ) { + if (fail_if_not_detected) + bb_error_msg_and_die("no gzip" + IF_FEATURE_SEAMLESS_BZ2("/bzip2") + " magic"); + xlseek(fd, -2, SEEK_CUR); + return fd; + } +#if BB_MMU + xformer = unpack_bz2_stream; +#else + xformer_prog = "bunzip2"; +#endif + } else { +#if !BB_MMU + /* NOMMU version of open_transformer execs + * an external unzipper that wants + * file position at the start of the file */ + xlseek(fd, -2, SEEK_CUR); +#endif + } + open_transformer(fd, xformer, xformer_prog); + + return fd; +} +#endif /* ZIPPED */ + +int FAST_FUNC open_zipped(const char *fname) +{ +#if !ZIPPED + return open(fname, O_RDONLY); +#else + char *sfx; + int fd; + fd = open(fname, O_RDONLY); if (fd < 0) return fd; @@ -335,40 +381,7 @@ int FAST_FUNC open_zipped(const char *fname) if ((ENABLE_FEATURE_SEAMLESS_GZ && strcmp(sfx, ".gz") == 0) || (ENABLE_FEATURE_SEAMLESS_BZ2 && strcmp(sfx, ".bz2") == 0) ) { - /* .gz and .bz2 both have 2-byte signature, and their - * unpack_XXX_stream wants this header skipped. */ - xread(fd, &magic, 2); -#if ENABLE_FEATURE_SEAMLESS_GZ -#if BB_MMU - xformer = unpack_gz_stream; -#else - xformer_prog = "gunzip"; -#endif -#endif - if (!ENABLE_FEATURE_SEAMLESS_GZ - || magic[0] != 0x1f || magic[1] != 0x8b - ) { - if (!ENABLE_FEATURE_SEAMLESS_BZ2 - || magic[0] != 'B' || magic[1] != 'Z' - ) { - bb_error_msg_and_die("no gzip" - IF_FEATURE_SEAMLESS_BZ2("/bzip2") - " magic"); - } -#if BB_MMU - xformer = unpack_bz2_stream; -#else - xformer_prog = "bunzip2"; -#endif - } else { -#if !BB_MMU - /* NOMMU version of open_transformer execs - * an external unzipper that wants - * file position at the start of the file */ - xlseek(fd, 0, SEEK_SET); -#endif - } - open_transformer(fd, xformer, xformer_prog); + setup_unzip_on_fd(fd /*, fail_if_not_detected: 1*/); } } -- cgit v1.2.3-55-g6feb From c2345fa2d410a3b1bc2797dae246fcbcb23ef17e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 6 May 2010 17:05:22 +0200 Subject: add comment about xz format support Signed-off-by: Denys Vlasenko --- libbb/read.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'libbb') diff --git a/libbb/read.c b/libbb/read.c index 503216eb5..21e005c6f 100644 --- a/libbb/read.c +++ b/libbb/read.c @@ -334,6 +334,11 @@ int FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) if (!ENABLE_FEATURE_SEAMLESS_BZ2 || magic[0] != 'B' || magic[1] != 'Z' ) { + +// TODO: xz format support. rpm adopted it, "rpm -i FILE.rpm" badly needs this. +// Signature: 0xFD, '7', 'z', 'X', 'Z', 0x00 +// More info at: http://tukaani.org/xz/xz-file-format.txt + if (fail_if_not_detected) bb_error_msg_and_die("no gzip" IF_FEATURE_SEAMLESS_BZ2("/bzip2") -- cgit v1.2.3-55-g6feb From bfa1b2e8e8aaddcf849011a12cb2ac634b27f339 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 11 May 2010 03:53:57 +0200 Subject: randomtest fixes Signed-off-by: Denys Vlasenko --- libbb/read.c | 61 ++++++++++++------------ testsuite/ar.tests | 4 +- testsuite/awk.tests | 2 + testsuite/busybox.tests | 7 +-- testsuite/cpio.tests | 2 + testsuite/diff.tests | 10 ++++ testsuite/du/du-h-works | 2 + testsuite/du/du-l-works | 2 + testsuite/du/du-m-works | 2 + testsuite/du/du-s-works | 2 + testsuite/du/du-works | 2 + testsuite/echo/echo-does-not-print-newline | 2 + testsuite/echo/echo-prints-slash-zero | 2 + testsuite/find/find-supports-minus-xdev | 2 + testsuite/ls/ls-1-works | 2 + testsuite/ls/ls-h-works | 2 + testsuite/makedevs.tests | 2 +- testsuite/md5sum/md5sum-verifies-non-binary-file | 2 + testsuite/mdev.tests | 22 ++++----- testsuite/mount.tests | 15 +++--- testsuite/od.tests | 2 + testsuite/patch.tests | 2 + testsuite/pidof.tests | 4 +- testsuite/sort.tests | 2 +- testsuite/tail/tail-works | 2 + testsuite/tar.tests | 6 +-- testsuite/tar/tar_with_prefix_fields | 1 + testsuite/tr.tests | 6 +++ testsuite/tr/tr-d-alnum-works | 2 + testsuite/tr/tr-rejects-wrong-class | 2 + testsuite/tr/tr-works | 2 + 31 files changed, 120 insertions(+), 58 deletions(-) (limited to 'libbb') diff --git a/libbb/read.c b/libbb/read.c index 21e005c6f..f3af144f0 100644 --- a/libbb/read.c +++ b/libbb/read.c @@ -321,44 +321,45 @@ int FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) /* .gz and .bz2 both have 2-byte signature, and their * unpack_XXX_stream wants this header skipped. */ xread(fd, &magic, 2); -#if ENABLE_FEATURE_SEAMLESS_GZ + if (ENABLE_FEATURE_SEAMLESS_GZ + && magic[0] == 0x1f && magic[1] == 0x8b + ) { # if BB_MMU - xformer = unpack_gz_stream; + xformer = unpack_gz_stream; # else - xformer_prog = "gunzip"; + xformer_prog = "gunzip"; # endif -#endif - if (!ENABLE_FEATURE_SEAMLESS_GZ - || magic[0] != 0x1f || magic[1] != 0x8b + goto found_magic; + } + if (ENABLE_FEATURE_SEAMLESS_BZ2 + && magic[0] == 'B' && magic[1] == 'Z' ) { - if (!ENABLE_FEATURE_SEAMLESS_BZ2 - || magic[0] != 'B' || magic[1] != 'Z' - ) { - +# if BB_MMU + xformer = unpack_bz2_stream; +# else + xformer_prog = "bunzip2"; +# endif + goto found_magic; + } // TODO: xz format support. rpm adopted it, "rpm -i FILE.rpm" badly needs this. // Signature: 0xFD, '7', 'z', 'X', 'Z', 0x00 // More info at: http://tukaani.org/xz/xz-file-format.txt - if (fail_if_not_detected) - bb_error_msg_and_die("no gzip" - IF_FEATURE_SEAMLESS_BZ2("/bzip2") - " magic"); - xlseek(fd, -2, SEEK_CUR); - return fd; - } -#if BB_MMU - xformer = unpack_bz2_stream; -#else - xformer_prog = "bunzip2"; -#endif - } else { -#if !BB_MMU - /* NOMMU version of open_transformer execs - * an external unzipper that wants - * file position at the start of the file */ - xlseek(fd, -2, SEEK_CUR); -#endif - } + /* No known magic seen */ + if (fail_if_not_detected) + bb_error_msg_and_die("no gzip" + IF_FEATURE_SEAMLESS_BZ2("/bzip2") + " magic"); + xlseek(fd, -2, SEEK_CUR); + return fd; + + found_magic: +# if !BB_MMU + /* NOMMU version of open_transformer execs + * an external unzipper that wants + * file position at the start of the file */ + xlseek(fd, -2, SEEK_CUR); +# endif open_transformer(fd, xformer, xformer_prog); return fd; diff --git a/testsuite/ar.tests b/testsuite/ar.tests index f112eb64a..4630d08a4 100755 --- a/testsuite/ar.tests +++ b/testsuite/ar.tests @@ -18,10 +18,10 @@ testing "ar creates archives" \ rm test.a testing "ar replaces things in archives" \ - "echo 'blah!' >file1 && echo 'blast!'> file2 && ar cr test.a README file1 file2 && mv file2 file1 && ar cr test.a file1 && ar p test.a file1" \ + "echo 'blah!' >file1 && echo 'blast!' >file2 && ar cr test.a README file1 file2 && mv file2 file1 && ar cr test.a file1 && ar p test.a file1" \ "blast!\n" \ "" \ "" -rm test.a +rm test.a file1 file1 2>/dev/null exit $FAILCOUNT diff --git a/testsuite/awk.tests b/testsuite/awk.tests index efa03a79a..0691a7972 100755 --- a/testsuite/awk.tests +++ b/testsuite/awk.tests @@ -18,9 +18,11 @@ testing "awk -F case 7" "awk -F '[#]' '{ print NF }'" "5\n" "" "z##abc##zz\n" # 4294967295 = 0xffffffff testing "awk bitwise op" "awk '{ print or(4294967295,1) }'" "4.29497e+09\n" "" "\n" +optional DESKTOP testing "awk hex const 1" "awk '{ print or(0xffffffff,1) }'" "4.29497e+09\n" "" "\n" testing "awk hex const 2" "awk '{ print or(0x80000000,1) }'" "2.14748e+09\n" "" "\n" testing "awk oct const" "awk '{ print or(01234,1) }'" "669\n" "" "\n" +SKIP= # long field seps requiring regex testing "awk long field sep" "awk -F-- '{ print NF, length(\$NF), \$NF }'" \ diff --git a/testsuite/busybox.tests b/testsuite/busybox.tests index 6eeb3251d..18ac36fc4 100755 --- a/testsuite/busybox.tests +++ b/testsuite/busybox.tests @@ -10,8 +10,9 @@ HELPDUMP=`true | busybox 2>&1 | cat` # We need to test under calling the binary under other names. - +optional SHOW_USAGE testing "busybox --help busybox" "true | busybox --help busybox 2>&1 | cat" "$HELPDUMP\n\n" "" "" +SKIP= ln -s `which busybox` busybox-suffix for i in busybox ./busybox-suffix @@ -26,11 +27,11 @@ do testing "$i --help" "$i --help 2>&1" "$HELPDUMP\n\n" "" "" - optional CAT + optional SHOW_USAGE CAT testing "" "$i cat" "moo" "" "moo" testing "$i --help cat" "$i --help cat 2>&1 | grep print" \ "Concatenate FILEs and print them to stdout\n" "" "" - optional "" + SKIP= testing "$i --help unknown" "$i --help unknown 2>&1" \ "unknown: applet not found\n" "" "" diff --git a/testsuite/cpio.tests b/testsuite/cpio.tests index b4c41dd9a..8cb8b787b 100755 --- a/testsuite/cpio.tests +++ b/testsuite/cpio.tests @@ -31,6 +31,7 @@ rm -rf cpio.testdir cpio.testdir2 2>/dev/null # testing "test name" "command" "expected result" "file input" "stdin" +optional FEATURE_LS_SORTFILES testing "cpio extracts zero-sized hardlinks" \ "$ECHO -ne '$hexdump' | bzcat | cpio -i 2>&1; echo \$?; ls -ln cpio.testdir | $FILTER_LS" \ @@ -41,6 +42,7 @@ ls -ln cpio.testdir | $FILTER_LS" \ -rw-r--r-- 2 $user $group 0 y " \ "" "" +SKIP= test x"$SKIP_KNOWN_BUGS" = x"" && { diff --git a/testsuite/diff.tests b/testsuite/diff.tests index 72ebb6c4c..06d5a4fd7 100755 --- a/testsuite/diff.tests +++ b/testsuite/diff.tests @@ -106,6 +106,7 @@ rm -rf diff1 diff2 mkdir diff1 diff2 diff2/subdir echo qwe >diff1/- echo asd >diff2/subdir/- +optional FEATURE_DIFF_DIR testing "diff diff1 diff2/subdir" \ "diff -ur diff1 diff2/subdir | $TRIM_TAB" \ "\ @@ -116,8 +117,10 @@ testing "diff diff1 diff2/subdir" \ +asd " \ "" "" +SKIP= # using directory structure from prev test... +optional FEATURE_DIFF_DIR testing "diff dir dir2/file/-" \ "diff -ur diff1 diff2/subdir/- | $TRIM_TAB" \ "\ @@ -128,10 +131,12 @@ testing "diff dir dir2/file/-" \ +asd " \ "" "" +SKIP= # using directory structure from prev test... mkdir diff1/test mkfifo diff2/subdir/test +optional FEATURE_DIFF_DIR testing "diff of dir and fifo" \ "diff -ur diff1 diff2/subdir | $TRIM_TAB" \ "\ @@ -143,10 +148,12 @@ testing "diff of dir and fifo" \ Only in diff2/subdir: test " \ "" "" +SKIP= # using directory structure from prev test... rmdir diff1/test echo >diff1/test +optional FEATURE_DIFF_DIR testing "diff of file and fifo" \ "diff -ur diff1 diff2/subdir | $TRIM_TAB" \ "\ @@ -158,9 +165,11 @@ testing "diff of file and fifo" \ File diff2/subdir/test is not a regular file or directory and was skipped " \ "" "" +SKIP= # using directory structure from prev test... mkfifo diff1/test2 +optional FEATURE_DIFF_DIR testing "diff -rN does not read non-regular files" \ "diff -urN diff1 diff2/subdir | $TRIM_TAB" \ "\ @@ -173,6 +182,7 @@ File diff2/subdir/test is not a regular file or directory and was skipped File diff1/test2 is not a regular file or directory and was skipped " \ "" "" +SKIP= # clean up rm -rf diff1 diff2 diff --git a/testsuite/du/du-h-works b/testsuite/du/du-h-works index 3f8ff3d0b..a1b4b4905 100644 --- a/testsuite/du/du-h-works +++ b/testsuite/du/du-h-works @@ -1,3 +1,5 @@ +# FEATURE: CONFIG_FEATURE_HUMAN_READABLE + d=/bin du -h "$d" > logfile.gnu busybox du -h "$d" > logfile.bb diff --git a/testsuite/du/du-l-works b/testsuite/du/du-l-works index c3d2ec0c1..64dcf8726 100644 --- a/testsuite/du/du-l-works +++ b/testsuite/du/du-l-works @@ -1,3 +1,5 @@ +# FEATURE: CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K + d=/bin du -l "$d" > logfile.gnu busybox du -l "$d" > logfile.bb diff --git a/testsuite/du/du-m-works b/testsuite/du/du-m-works index bf0a90e1b..6e733c016 100644 --- a/testsuite/du/du-m-works +++ b/testsuite/du/du-m-works @@ -1,3 +1,5 @@ +# FEATURE: CONFIG_FEATURE_HUMAN_READABLE + d=/bin du -m "$d" > logfile.gnu busybox du -m "$d" > logfile.bb diff --git a/testsuite/du/du-s-works b/testsuite/du/du-s-works index ae970772a..0c870ceb5 100644 --- a/testsuite/du/du-s-works +++ b/testsuite/du/du-s-works @@ -1,3 +1,5 @@ +# FEATURE: CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K + d=/bin du -s "$d" > logfile.gnu busybox du -s "$d" > logfile.bb diff --git a/testsuite/du/du-works b/testsuite/du/du-works index 46a336dc3..4db684a9b 100644 --- a/testsuite/du/du-works +++ b/testsuite/du/du-works @@ -1,3 +1,5 @@ +# FEATURE: CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K + d=/bin du "$d" > logfile.gnu busybox du "$d" > logfile.bb diff --git a/testsuite/echo/echo-does-not-print-newline b/testsuite/echo/echo-does-not-print-newline index 2ed03caf5..2857c0d13 100644 --- a/testsuite/echo/echo-does-not-print-newline +++ b/testsuite/echo/echo-does-not-print-newline @@ -1 +1,3 @@ +# FEATURE: CONFIG_FEATURE_FANCY_ECHO + test `busybox echo -n word | wc -c` -eq 4 diff --git a/testsuite/echo/echo-prints-slash-zero b/testsuite/echo/echo-prints-slash-zero index d2466326f..d97ed8e66 100644 --- a/testsuite/echo/echo-prints-slash-zero +++ b/testsuite/echo/echo-prints-slash-zero @@ -1 +1,3 @@ +# FEATURE: CONFIG_FEATURE_FANCY_ECHO + test "`busybox echo -e -n 'msg\n\0' | od -t x1 | head -n 1`" = "0000000 6d 73 67 0a 00" diff --git a/testsuite/find/find-supports-minus-xdev b/testsuite/find/find-supports-minus-xdev index 4c559a1f4..c807fc8f2 100644 --- a/testsuite/find/find-supports-minus-xdev +++ b/testsuite/find/find-supports-minus-xdev @@ -1 +1,3 @@ +# FEATURE: CONFIG_FEATURE_FIND_XDEV + busybox find . -xdev >/dev/null 2>&1 diff --git a/testsuite/ls/ls-1-works b/testsuite/ls/ls-1-works index 885694920..71ab9a66b 100644 --- a/testsuite/ls/ls-1-works +++ b/testsuite/ls/ls-1-works @@ -1,3 +1,5 @@ +# FEATURE: CONFIG_FEATURE_LS_SORTFILES + [ -n "$d" ] || d=.. LC_ALL=C ls -1 "$d" > logfile.gnu LC_ALL=C busybox ls -1 "$d" > logfile.bb diff --git a/testsuite/ls/ls-h-works b/testsuite/ls/ls-h-works index 0c83f7cc5..60016bac1 100644 --- a/testsuite/ls/ls-h-works +++ b/testsuite/ls/ls-h-works @@ -1,3 +1,5 @@ +# FEATURE: CONFIG_FEATURE_LS_SORTFILES CONFIG_FEATURE_HUMAN_READABLE + [ -n "$d" ] || d=.. LC_ALL=C ls -h "$d" > logfile.gnu LC_ALL=C busybox ls -h "$d" > logfile.bb diff --git a/testsuite/makedevs.tests b/testsuite/makedevs.tests index 72fc933d3..f69b4a6b1 100755 --- a/testsuite/makedevs.tests +++ b/testsuite/makedevs.tests @@ -16,7 +16,7 @@ FILTER_LS2="sed -e 's/, */,/g' -e 's/ */ /g' | cut -d' ' -f 1-4,9-" rm -rf makedevs.testdir mkdir makedevs.testdir -optional FEATURE_MAKEDEVS_TABLE FEATURE_FIND_NOT FEATURE_FIND_TYPE FEATURE_LS_RECURSIVE +optional FEATURE_MAKEDEVS_TABLE FEATURE_FIND_NOT FEATURE_FIND_TYPE FEATURE_LS_RECURSIVE FEATURE_LS_SORTFILES testing "makedevs -d ../makedevs.device_table.txt ." \ "(cd makedevs.testdir && makedevs -d ../makedevs.device_table.txt . 2>&1); find makedevs.testdir ! -type d | sort | xargs ls -lnR | $FILTER_LS" \ diff --git a/testsuite/md5sum/md5sum-verifies-non-binary-file b/testsuite/md5sum/md5sum-verifies-non-binary-file index 8566a234d..1df818eb5 100644 --- a/testsuite/md5sum/md5sum-verifies-non-binary-file +++ b/testsuite/md5sum/md5sum-verifies-non-binary-file @@ -1,3 +1,5 @@ +# FEATURE: CONFIG_FEATURE_MD5_SHA1_SUM_CHECK + touch foo md5sum foo > bar busybox md5sum -c bar diff --git a/testsuite/mdev.tests b/testsuite/mdev.tests index 270f6292e..0b4525483 100755 --- a/testsuite/mdev.tests +++ b/testsuite/mdev.tests @@ -27,7 +27,7 @@ echo "8:0" >mdev.testdir/sys/block/sda/dev # env - PATH=$PATH: on some systems chroot binary won't otherwise be found -optional STATIC +optional STATIC FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME testing "mdev add /block/sda" \ "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; ls -ln mdev.testdir/dev | $FILTER_LS" \ @@ -41,7 +41,7 @@ SKIP= rm -rf mdev.testdir/dev/* echo ".* 1:1 666" >mdev.testdir/etc/mdev.conf echo "sda 2:2 444" >>mdev.testdir/etc/mdev.conf -optional STATIC FEATURE_MDEV_CONF +optional STATIC FEATURE_MDEV_CONF FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME testing "mdev stops on first rule" \ "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; ls -ln mdev.testdir/dev | $FILTER_LS" \ @@ -55,7 +55,7 @@ SKIP= rm -rf mdev.testdir/dev/* echo "-.* 1:1 666" >mdev.testdir/etc/mdev.conf echo "sda 2:2 444" >>mdev.testdir/etc/mdev.conf -optional STATIC FEATURE_MDEV_CONF +optional STATIC FEATURE_MDEV_CONF FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME testing "mdev does not stop on dash-rule" \ "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; ls -ln mdev.testdir/dev | $FILTER_LS" \ @@ -70,7 +70,7 @@ rm -rf mdev.testdir/dev/* echo "\$MODALIAS=qw 1:1 666" >mdev.testdir/etc/mdev.conf echo "\$MODALIAS=qw. 2:2 444" >>mdev.testdir/etc/mdev.conf echo "\$MODALIAS=qw. 3:3 400" >>mdev.testdir/etc/mdev.conf -optional STATIC FEATURE_MDEV_CONF +optional STATIC FEATURE_MDEV_CONF FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME testing "mdev \$ENVVAR=regex match" \ "env - PATH=$PATH ACTION=add DEVPATH=/block/sda MODALIAS=qwe chroot mdev.testdir /mdev 2>&1; ls -ln mdev.testdir/dev | $FILTER_LS" \ @@ -83,7 +83,7 @@ SKIP= # continuing to use directory structure from prev test rm -rf mdev.testdir/dev/* echo "sda 0:0 444 >disk/scsiA" >mdev.testdir/etc/mdev.conf -optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_LS_RECURSIVE +optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME testing "mdev move/symlink rule '>bar/baz'" \ "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; ls -lnR mdev.testdir/dev | $FILTER_LS2" \ @@ -101,7 +101,7 @@ SKIP= # continuing to use directory structure from prev test rm -rf mdev.testdir/dev/* echo "sda 0:0 444 >disk/" >mdev.testdir/etc/mdev.conf -optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_LS_RECURSIVE +optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME testing "mdev move/symlink rule '>bar/'" \ "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; ls -lnR mdev.testdir/dev | $FILTER_LS2" \ @@ -120,7 +120,7 @@ SKIP= rm -rf mdev.testdir/dev/* # here we complicate things by having non-matching group 1 and using %0 echo "s([0-9])*d([a-z]+) 0:0 644 >sd/%2_%0" >mdev.testdir/etc/mdev.conf -optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_MDEV_RENAME_REGEXP FEATURE_LS_RECURSIVE +optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_MDEV_RENAME_REGEXP FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME testing "mdev regexp substring match + replace" \ "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; ls -lnR mdev.testdir/dev | $FILTER_LS2" \ @@ -138,7 +138,7 @@ SKIP= # continuing to use directory structure from prev test rm -rf mdev.testdir/dev/* echo "sda 0:0 644 @echo @echo TEST" >mdev.testdir/etc/mdev.conf -optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_EXEC FEATURE_LS_RECURSIVE +optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_EXEC FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME testing "mdev command" \ "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; ls -lnR mdev.testdir/dev | $FILTER_LS" \ @@ -153,7 +153,7 @@ SKIP= # continuing to use directory structure from prev test rm -rf mdev.testdir/dev/* echo "sda 0:0 644 =block/ @echo @echo TEST:\$MDEV" >mdev.testdir/etc/mdev.conf -optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_MDEV_EXEC FEATURE_LS_RECURSIVE +optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_MDEV_EXEC FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME testing "mdev move and command" \ "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; ls -lnR mdev.testdir/dev | $FILTER_LS2" \ @@ -171,7 +171,7 @@ SKIP= # continuing to use directory structure from prev test rm -rf mdev.testdir/dev/* echo "@8,0 0:1 644" >mdev.testdir/etc/mdev.conf -optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_MDEV_RENAME_REGEXP FEATURE_LS_RECURSIVE +optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_MDEV_RENAME_REGEXP FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME testing "mdev #maj,min and no explicit uid" \ "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; ls -lnR mdev.testdir/dev | $FILTER_LS" \ @@ -194,7 +194,7 @@ echo "capi 0:0 0660 =capi20" >mdev.testdir/etc/mdev.conf echo "capi([0-9]) 0:0 0660 =capi20.0%1" >>mdev.testdir/etc/mdev.conf echo "capi([0-9]*) 0:0 0660 =capi20.%1" >>mdev.testdir/etc/mdev.conf # mdev invocation with DEVPATH=/class/tty/capi20 was deleting /dev/capi20 -optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_MDEV_RENAME_REGEXP FEATURE_LS_RECURSIVE +optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_MDEV_RENAME_REGEXP FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME testing "move rule does not delete node with name == device_name" \ "\ env - PATH=$PATH ACTION=add DEVPATH=/class/tty/capi chroot mdev.testdir /mdev 2>&1; diff --git a/testsuite/mount.tests b/testsuite/mount.tests index 043586f05..ee13ec285 100755 --- a/testsuite/mount.tests +++ b/testsuite/mount.tests @@ -4,16 +4,19 @@ . ./testing.sh +test -f "$bindir/.config" && . "$bindir/.config" + test "`id -u`" = 0 || { - echo "SKIPPED: must be root to test this" + echo "SKIPPED: mount (must be root to test this)" exit 0 } -optional MKFS_MINIX -if [ -n "$SKIP" ] -then - echo "SKIPPED: mount" - exit 0 +if test x"$CONFIG_MKFS_MINIX" != x"y" \ +|| test x"$CONFIG_FEATURE_MINIX2" != x"y" \ +|| test x"$CONFIG_FEATURE_DEVFS" = x"y" \ +; then + echo "SKIPPED: mount" + exit 0 fi testdir=$PWD/testdir diff --git a/testsuite/od.tests b/testsuite/od.tests index 0bf1f4c54..a2d015ad7 100755 --- a/testsuite/od.tests +++ b/testsuite/od.tests @@ -6,6 +6,7 @@ # testing "test name" "options" "expected result" "file input" "stdin" +optional DESKTOP testing "od -b" \ "od -b" \ "\ @@ -13,5 +14,6 @@ testing "od -b" \ 0000005 " \ "" "HELLO" +SKIP= exit $FAILCOUNT diff --git a/testsuite/patch.tests b/testsuite/patch.tests index f3e607186..749d936ea 100755 --- a/testsuite/patch.tests +++ b/testsuite/patch.tests @@ -123,4 +123,6 @@ abc +456 " \ +rm input.orig 2>/dev/null + exit $FAILCOUNT diff --git a/testsuite/pidof.tests b/testsuite/pidof.tests index 45df1a958..624b0a720 100755 --- a/testsuite/pidof.tests +++ b/testsuite/pidof.tests @@ -20,12 +20,14 @@ testing "pidof this" "pidof pidof.tests | grep -o -w $$" "$$\n" "" "" optional FEATURE_PIDOF_SINGLE testing "pidof -s" "pidof -s init" "1\n" "" "" +SKIP= -optional FEATURE_PIDOF_OMIT +optional FEATURE_PIDOF_OMIT FEATURE_PIDOF_SINGLE # This test fails now because process name matching logic has changed, # but new logic is not "wrong" either... see find_pid_by_name.c comments #testing "pidof -o %PPID" "pidof -o %PPID pidof.tests | grep -o -w $$" "" "" "" testing "pidof -o %PPID NOP" "pidof -o %PPID -s init" "1\n" "" "" testing "pidof -o init" "pidof -o 1 init | grep -o -w 1" "" "" "" +SKIP= exit $FAILCOUNT diff --git a/testsuite/sort.tests b/testsuite/sort.tests index 72df80b1f..8a810f8d4 100755 --- a/testsuite/sort.tests +++ b/testsuite/sort.tests @@ -118,7 +118,7 @@ testing "sort key doesn't strip leading blanks, disables fallback global sort" \ "sort -n -k2 -t ' '" " a \n 1 \n 2 \n" "" " 2 \n 1 \n a \n" testing "sort file in place" \ -"strace -oZZZ sort -o input input && cat input" "\ +"sort -o input input && cat input" "\ 111 222 " "\ diff --git a/testsuite/tail/tail-works b/testsuite/tail/tail-works index f3434d1a9..50eca136e 100644 --- a/testsuite/tail/tail-works +++ b/testsuite/tail/tail-works @@ -1,3 +1,5 @@ +# FEATURE: CONFIG_INCLUDE_SUSv2 + $ECHO -ne "abc\ndef\n123\n" >input $ECHO -ne "def\n123\n" >logfile.ok busybox tail -2 input > logfile.bb diff --git a/testsuite/tar.tests b/testsuite/tar.tests index ecd212fbf..8599b79fc 100755 --- a/testsuite/tar.tests +++ b/testsuite/tar.tests @@ -9,7 +9,7 @@ mkdir tar.tempdir && cd tar.tempdir || exit 1 # testing "test name" "script" "expected result" "file input" "stdin" -optional FEATURE_TAR_CREATE +optional FEATURE_TAR_CREATE FEATURE_LS_SORTFILES testing "tar hardlinks and repeated files" '\ rm -rf input_* test.tar 2>/dev/null >input_hard1 @@ -42,7 +42,7 @@ drwxr-xr-x input_dir "" "" SKIP= -optional FEATURE_TAR_CREATE +optional FEATURE_TAR_CREATE FEATURE_LS_SORTFILES testing "tar hardlinks mode" '\ rm -rf input_* test.tar 2>/dev/null >input_hard1 @@ -73,7 +73,7 @@ dr-xr-x--- input_dir "" "" SKIP= -optional FEATURE_TAR_CREATE +optional FEATURE_TAR_CREATE FEATURE_LS_SORTFILES testing "tar symlinks mode" '\ rm -rf input_* test.tar 2>/dev/null >input_file diff --git a/testsuite/tar/tar_with_prefix_fields b/testsuite/tar/tar_with_prefix_fields index 56dcac59d..8c1fda795 100644 --- a/testsuite/tar/tar_with_prefix_fields +++ b/testsuite/tar/tar_with_prefix_fields @@ -1,4 +1,5 @@ # FEATURE: CONFIG_FEATURE_TAR_UNAME_GNAME +# FEATURE: CONFIG_DESKTOP tar1_bz2() { diff --git a/testsuite/tr.tests b/testsuite/tr.tests index 9706056c9..a1f83bfc6 100755 --- a/testsuite/tr.tests +++ b/testsuite/tr.tests @@ -15,17 +15,23 @@ testing "tr understands 0-9A-F" \ "tr -cd '[0-9A-F]'" \ "19AF" "" "19AFH\n" +optional CONFIG_FEATURE_TR_CLASSES testing "tr understands [:xdigit:]" \ "tr -cd '[:xdigit:]'" \ "19AF" "" "19AFH\n" +SKIP= +optional CONFIG_FEATURE_TR_CLASSES testing "tr does not stop after [:digit:]" \ "tr '[:digit:]y-z' 111111111123" \ "111abcx23\n" "" "789abcxyz\n" +SKIP= +optional CONFIG_FEATURE_TR_CLASSES testing "tr has correct xdigit sequence" \ "tr '[:xdigit:]Gg' 1111111151242222333330xX" \ "#1111111151242222x333330X\n" "" \ "#0123456789ABCDEFGabcdefg\n" +SKIP= exit $FAILCOUNT diff --git a/testsuite/tr/tr-d-alnum-works b/testsuite/tr/tr-d-alnum-works index d440f8f3b..6540ea527 100644 --- a/testsuite/tr/tr-d-alnum-works +++ b/testsuite/tr/tr-d-alnum-works @@ -1,3 +1,5 @@ +# FEATURE: CONFIG_FEATURE_TR_CLASSES + echo testing | tr -d '[[:alnum:]]' > logfile.gnu echo testing | busybox tr -d '[[:alnum:]]' > logfile.bb diff --git a/testsuite/tr/tr-rejects-wrong-class b/testsuite/tr/tr-rejects-wrong-class index 97539360d..1d488a3df 100644 --- a/testsuite/tr/tr-rejects-wrong-class +++ b/testsuite/tr/tr-rejects-wrong-class @@ -1,3 +1,5 @@ +# FEATURE: CONFIG_FEATURE_TR_CLASSES + echo t12esting | tr -d '[[:alpha:]]' > logfile.gnu echo t12esting | tr -d '[:alpha:]' >> logfile.gnu echo t12esting | tr -d '[[:alpha:]' >> logfile.gnu diff --git a/testsuite/tr/tr-works b/testsuite/tr/tr-works index 2c0a9d196..3783971ce 100644 --- a/testsuite/tr/tr-works +++ b/testsuite/tr/tr-works @@ -1,3 +1,5 @@ +# FEATURE: CONFIG_FEATURE_TR_CLASSES + run_tr () { echo -n "echo '$1' | tr '$2' '$3': " -- cgit v1.2.3-55-g6feb From 94043e8ad2d30cc2199b35d18c853314ade174a3 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 11 May 2010 14:49:13 +0200 Subject: lineedit: change how cmdedit_set_out_char works Rename two badly names functions, use "clear to end of screen" to eliminate annoying problems with clearing wide/combining chars, and such. Run tested. function old new delta put_cur_glyph_and_inc_cursor - 124 +124 put_till_end_and_adv_cursor - 24 +24 input_delete 125 130 +5 Ceos 5 4 -1 Ceol 5 4 -1 input_end 24 - -24 cmdedit_set_out_char 122 - -122 ------------------------------------------------------------------------------ (add/remove: 2/2 grow/shrink: 1/2 up/down: 153/-148) Total: 5 bytes Signed-off-by: Denys Vlasenko --- editors/vi.c | 4 ++-- libbb/lineedit.c | 73 +++++++++++++++++++++++++++++++------------------------- 2 files changed, 43 insertions(+), 34 deletions(-) (limited to 'libbb') diff --git a/editors/vi.c b/editors/vi.c index d3a35e781..b8cacb43f 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -65,8 +65,8 @@ static const char SOn[] ALIGN1 = "\033[0m"; /* terminal bell sequence */ static const char bell[] ALIGN1 = "\007"; /* Clear-end-of-line and Clear-end-of-screen ESC sequence */ -static const char Ceol[] ALIGN1 = "\033[0K"; -static const char Ceos[] ALIGN1 = "\033[0J"; +static const char Ceol[] ALIGN1 = "\033[K"; +static const char Ceos[] ALIGN1 = "\033[J"; /* Cursor motion arbitrary destination ESC sequence */ static const char CMrc[] ALIGN1 = "\033[%d;%dH"; /* Cursor motion up and down ESC sequence */ diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 622f9ddfc..7fffe7ba2 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -66,6 +66,10 @@ #endif +#define SEQ_CLEAR_TILL_END_OF_SCREEN "\033[J" +//#define SEQ_CLEAR_TILL_END_OF_LINE "\033[K" + + #undef CHAR_T #if ENABLE_UNICODE_SUPPORT # define BB_NUL ((wchar_t)0) @@ -221,13 +225,13 @@ static size_t load_string(const char *src, int maxsize) } static unsigned save_string(char *dst, unsigned maxsize) { -#if !ENABLE_UNICODE_PRESERVE_BROKEN +# if !ENABLE_UNICODE_PRESERVE_BROKEN ssize_t len = wcstombs(dst, command_ps, maxsize - 1); if (len < 0) len = 0; dst[len] = '\0'; return len; -#else +# else unsigned dstpos = 0; unsigned srcpos = 0; @@ -256,7 +260,7 @@ static unsigned save_string(char *dst, unsigned maxsize) } dst[dstpos] = '\0'; return dstpos; -#endif +# endif } /* I thought just fputwc(c, stdout) would work. But no... */ static void BB_PUTCHAR(wchar_t c) @@ -293,19 +297,19 @@ static void save_string(char *dst, unsigned maxsize) * Advance cursor on screen. If we reached right margin, scroll text up * and remove terminal margin effect by printing 'next_char' */ #define HACK_FOR_WRONG_WIDTH 1 -#if HACK_FOR_WRONG_WIDTH -static void cmdedit_set_out_char(void) -#define cmdedit_set_out_char(next_char) cmdedit_set_out_char() -#else -static void cmdedit_set_out_char(int next_char) -#endif +static void put_cur_glyph_and_inc_cursor(void) { CHAR_T c = command_ps[cursor]; if (c == BB_NUL) { /* erase character after end of input string */ c = ' '; + } else { + /* advance cursor only if we aren't at the end yet */ + cursor++; + cmdedit_x++; } + #if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT /* Display non-printable characters in reverse */ if (!BB_isprint(c)) { @@ -321,7 +325,7 @@ static void cmdedit_set_out_char(int next_char) { BB_PUTCHAR(c); } - if (++cmdedit_x >= cmdedit_termw) { + if (cmdedit_x >= cmdedit_termw) { /* terminal is scrolled down */ cmdedit_y++; cmdedit_x = 0; @@ -335,27 +339,32 @@ static void cmdedit_set_out_char(int next_char) * this will break things: there will be one extra empty line */ puts("\r"); /* + implicit '\n' */ #else - /* Works ok only if cmdedit_termw is correct */ - /* destroy "(auto)margin" */ - bb_putchar(next_char); + /* VT-10x terminals don't wrap cursor to next line when last char + * on the line is printed - cursor stays "over" this char. + * Need to print _next_ char too (first one to appear on next line) + * to make cursor move down to next line. + */ + /* Works ok only if cmdedit_termw is correct. */ + c = command_ps[cursor]; + if (c == BB_NUL) + c = ' '; + BB_PUTCHAR(c); bb_putchar('\b'); #endif } -// Huh? What if command_ps[cursor] == BB_NUL (we are at the end already?) - cursor++; } /* Move to end of line (by printing all chars till the end) */ -static void input_end(void) +static void put_till_end_and_adv_cursor(void) { while (cursor < command_len) - cmdedit_set_out_char(' '); + put_cur_glyph_and_inc_cursor(); } /* Go to the next line */ static void goto_new_line(void) { - input_end(); + put_till_end_and_adv_cursor(); if (cmdedit_x) bb_putchar('\n'); } @@ -433,8 +442,8 @@ static void redraw(int y, int back_cursor) printf("\033[%uA", y); bb_putchar('\r'); put_prompt(); - input_end(); /* rewrite */ - printf("\033[J"); /* erase after cursor */ + put_till_end_and_adv_cursor(); + printf(SEQ_CLEAR_TILL_END_OF_SCREEN); input_backward(back_cursor); } @@ -468,8 +477,9 @@ static void input_delete(int save) * simplified into (command_len - j) */ (command_len - j) * sizeof(command_ps[0])); command_len--; - input_end(); /* rewrite new line */ - cmdedit_set_out_char(' '); /* erase char */ + put_till_end_and_adv_cursor(); + /* Last char is still visible, erase it (and more) */ + printf(SEQ_CLEAR_TILL_END_OF_SCREEN); input_backward(cursor - j); /* back to old pos cursor */ } @@ -487,7 +497,7 @@ static void put(void) (command_len - cursor + 1) * sizeof(command_ps[0])); memcpy(command_ps + cursor, delbuf, j * sizeof(command_ps[0])); command_len += j; - input_end(); /* rewrite new line */ + put_till_end_and_adv_cursor(); input_backward(cursor - ocursor - j + 1); /* at end of new text */ } #endif @@ -505,7 +515,7 @@ static void input_backspace(void) static void input_forward(void) { if (cursor < command_len) - cmdedit_set_out_char(command_ps[cursor + 1]); + put_cur_glyph_and_inc_cursor(); } #if ENABLE_FEATURE_TAB_COMPLETION @@ -1955,7 +1965,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li case CTRL('E'): vi_case('$'|VI_CMDMODE_BIT:) /* Control-e -- End of line */ - input_end(); + put_till_end_and_adv_cursor(); break; case CTRL('F'): vi_case('l'|VI_CMDMODE_BIT:) @@ -1984,12 +1994,12 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li /* Control-k -- clear to end of line */ command_ps[cursor] = BB_NUL; command_len = cursor; - printf("\033[J"); + printf(SEQ_CLEAR_TILL_END_OF_SCREEN); break; case CTRL('L'): vi_case(CTRL('L')|VI_CMDMODE_BIT:) /* Control-l -- clear screen */ - printf("\033[H"); + printf("\033[H"); /* cursor to top,left */ redraw(0, command_len - cursor); break; #if MAX_HISTORY > 0 @@ -2040,7 +2050,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li vi_cmdmode = 0; break; case 'A'|VI_CMDMODE_BIT: - input_end(); + put_till_end_and_adv_cursor(); vi_cmdmode = 0; break; case 'x'|VI_CMDMODE_BIT: @@ -2200,7 +2210,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li input_backward(cursor); break; case KEYCODE_END: - input_end(); + put_till_end_and_adv_cursor(); break; default: @@ -2260,7 +2270,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li /* We are at the end, append */ command_ps[cursor] = ic; command_ps[cursor + 1] = BB_NUL; - cmdedit_set_out_char(' '); + put_cur_glyph_and_inc_cursor(); if (unicode_bidi_isrtl(ic)) input_backward(1); } else { @@ -2273,8 +2283,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li /* is right-to-left char, or neutral one (e.g. comma) was just added to rtl text? */ if (!isrtl_str()) sc++; /* no */ - /* rewrite from cursor */ - input_end(); + put_till_end_and_adv_cursor(); /* to prev x pos + 1 */ input_backward(cursor - sc); } -- cgit v1.2.3-55-g6feb From b8909c52fe850d2731326534822164c2f5258bf5 Mon Sep 17 00:00:00 2001 From: Tomas Heinrich Date: Sun, 16 May 2010 20:46:53 +0200 Subject: lineedit: partially fix wide and combining chars editing Signed-off-by: Tomas Heinrich Signed-off-by: Denys Vlasenko --- include/unicode.h | 11 +++++ libbb/lineedit.c | 124 +++++++++++++++++++++++++++++++++++------------------- libbb/unicode.c | 2 +- 3 files changed, 92 insertions(+), 45 deletions(-) (limited to 'libbb') diff --git a/include/unicode.h b/include/unicode.h index 4e2927297..747026abe 100644 --- a/include/unicode.h +++ b/include/unicode.h @@ -35,6 +35,16 @@ enum { # define LAST_SUPPORTED_WCHAR CONFIG_LAST_SUPPORTED_WCHAR # endif +# if LAST_SUPPORTED_WCHAR < 0x300 +# undef ENABLE_UNICODE_COMBINING_WCHARS +# define ENABLE_UNICODE_COMBINING_WCHARS 0 +# endif + +# if LAST_SUPPORTED_WCHAR < 0x1100 +# undef ENABLE_UNICODE_WIDE_WCHARS +# define ENABLE_UNICODE_WIDE_WCHARS 0 +# endif + # if LAST_SUPPORTED_WCHAR < 0x590 # undef ENABLE_UNICODE_BIDI_SUPPORT # define ENABLE_UNICODE_BIDI_SUPPORT 0 @@ -92,6 +102,7 @@ size_t wcrtomb(char *s, wchar_t wc, mbstate_t *ps) FAST_FUNC; int iswspace(wint_t wc) FAST_FUNC; int iswalnum(wint_t wc) FAST_FUNC; int iswpunct(wint_t wc) FAST_FUNC; +int wcwidth(unsigned ucs) FAST_FUNC; # if ENABLE_UNICODE_BIDI_SUPPORT # undef unicode_bidi_isrtl int unicode_bidi_isrtl(wint_t wc) FAST_FUNC; diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 7fffe7ba2..9f2d65717 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -42,14 +42,10 @@ #include "libbb.h" #include "unicode.h" -/* FIXME: obsolete CONFIG item? */ -#define ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 0 - #ifdef TEST # define ENABLE_FEATURE_EDITING 0 # define ENABLE_FEATURE_TAB_COMPLETION 0 # define ENABLE_FEATURE_USERNAME_COMPLETION 0 -# define ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 0 #endif @@ -97,10 +93,10 @@ static bool BB_ispunct(CHAR_T c) { return ((unsigned)c < 256 && ispunct(c)); } # if ENABLE_UNICODE_PRESERVE_BROKEN -# define unicode_mark_inv_wchar(wc) ((wc) | 0x20000000) -# define unicode_is_inv_wchar(wc) ((wc) & 0x20000000) +# define unicode_mark_raw_byte(wc) ((wc) | 0x20000000) +# define unicode_is_raw_byte(wc) ((wc) & 0x20000000) # else -# define unicode_is_inv_wchar(wc) 0 +# define unicode_is_raw_byte(wc) 0 # endif @@ -240,7 +236,7 @@ static unsigned save_string(char *dst, unsigned maxsize) wchar_t wc; int n = srcpos; while ((wc = command_ps[srcpos]) != 0 - && !unicode_is_inv_wchar(wc) + && !unicode_is_raw_byte(wc) ) { srcpos++; } @@ -269,15 +265,45 @@ static void BB_PUTCHAR(wchar_t c) mbstate_t mbst = { 0 }; ssize_t len; - if (unicode_is_inv_wchar(c)) - c = CONFIG_SUBST_WCHAR; len = wcrtomb(buf, c, &mbst); if (len > 0) { buf[len] = '\0'; fputs(buf, stdout); } } -#else +# if ENABLE_UNICODE_COMBINING_WCHARS || ENABLE_UNICODE_WIDE_WCHARS +static wchar_t adjust_width_and_validate_wc(unsigned *width_adj, wchar_t wc) +# else +static wchar_t adjust_width_and_validate_wc(wchar_t wc) +# define adjust_width_and_validate_wc(width_adj, wc) \ + ((*(width_adj))++, adjust_width_and_validate_wc(wc)) +# endif +{ + int w = 1; + + if (unicode_status == UNICODE_ON) { + if (unicode_is_raw_byte(wc) + || (CONFIG_LAST_SUPPORTED_WCHAR && wc > CONFIG_LAST_SUPPORTED_WCHAR) + ) { + goto subst; + } + w = wcwidth(wc); + if ((ENABLE_UNICODE_COMBINING_WCHARS && w < 0) + || (!ENABLE_UNICODE_COMBINING_WCHARS && w <= 0) + || (!ENABLE_UNICODE_WIDE_WCHARS && w > 1) + ) { + subst: + w = 1; + wc = CONFIG_SUBST_WCHAR; + } + } + +# if ENABLE_UNICODE_COMBINING_WCHARS || ENABLE_UNICODE_WIDE_WCHARS + *width_adj += w; +#endif + return wc; +} +#else /* !UNICODE */ static size_t load_string(const char *src, int maxsize) { safe_strncpy(command_ps, src, maxsize); @@ -290,6 +316,8 @@ static void save_string(char *dst, unsigned maxsize) } # endif # define BB_PUTCHAR(c) bb_putchar(c) +/* Should never be called: */ +int adjust_width_and_validate_wc(unsigned *width_adj, int wc); #endif @@ -300,6 +328,8 @@ static void save_string(char *dst, unsigned maxsize) static void put_cur_glyph_and_inc_cursor(void) { CHAR_T c = command_ps[cursor]; + unsigned width = 0; + int ofs_to_right; if (c == BB_NUL) { /* erase character after end of input string */ @@ -307,28 +337,23 @@ static void put_cur_glyph_and_inc_cursor(void) } else { /* advance cursor only if we aren't at the end yet */ cursor++; - cmdedit_x++; + if (unicode_status == UNICODE_ON) { + IF_UNICODE_WIDE_WCHARS(width = cmdedit_x;) + c = adjust_width_and_validate_wc(&cmdedit_x, c); + IF_UNICODE_WIDE_WCHARS(width = cmdedit_x - width;) + } else { + cmdedit_x++; + } } -#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT - /* Display non-printable characters in reverse */ - if (!BB_isprint(c)) { - if (c >= 128) - c -= 128; - if (c < ' ') - c += '@'; - if (c == 127) - c = '?'; - printf("\033[7m%c\033[0m", c); - } else -#endif - { + ofs_to_right = cmdedit_x - cmdedit_termw; + if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right <= 0) { + /* c fits on this line */ BB_PUTCHAR(c); } - if (cmdedit_x >= cmdedit_termw) { - /* terminal is scrolled down */ - cmdedit_y++; - cmdedit_x = 0; + + if (ofs_to_right >= 0) { + /* we go to the next line */ #if HACK_FOR_WRONG_WIDTH /* This works better if our idea of term width is wrong * and it is actually wider (often happens on serial lines). @@ -351,6 +376,14 @@ static void put_cur_glyph_and_inc_cursor(void) BB_PUTCHAR(c); bb_putchar('\b'); #endif + cmdedit_y++; + if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right == 0) { + width = 0; + } else { /* ofs_to_right > 0 */ + /* wide char c didn't fit on prev line */ + BB_PUTCHAR(c); + } + cmdedit_x = width; } } @@ -389,10 +422,22 @@ static void input_backward(unsigned num) if (num > cursor) num = cursor; - if (!num) + if (num == 0) return; cursor -= num; + if ((ENABLE_UNICODE_COMBINING_WCHARS || ENABLE_UNICODE_WIDE_WCHARS) + && unicode_status == UNICODE_ON + ) { + /* correct NUM to be equal to _screen_ width */ + int n = num; + num = 0; + while (--n >= 0) + adjust_width_and_validate_wc(&num, command_ps[cursor + n]); + if (num == 0) + return; + } + if (cmdedit_x >= num) { cmdedit_x -= num; if (num <= 4) { @@ -412,6 +457,8 @@ static void input_backward(unsigned num) } /* Need to go one or more lines up */ +//FIXME: this does not work correctly if prev line has one "unfilled" screen position +//caused by wide unicode char not fitting in that one screen position. num -= cmdedit_x; { unsigned w = cmdedit_termw; /* volatile var */ @@ -765,21 +812,13 @@ static NOINLINE int find_match(char *matchBuf, int *len_with_quotes) } /* mask \+symbol and convert '\t' to ' ' */ - for (i = j = 0; matchBuf[i]; i++, j++) + for (i = j = 0; matchBuf[i]; i++, j++) { if (matchBuf[i] == '\\') { collapse_pos(j, j + 1); int_buf[j] |= QUOT; i++; -#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT - if (matchBuf[i] == '\t') /* algorithm equivalent */ - int_buf[j] = ' ' | QUOT; -#endif } -#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT - else if (matchBuf[i] == '\t') - int_buf[j] = ' '; -#endif - + } /* mask "symbols" or 'symbols' */ c2 = 0; for (i = 0; int_buf[i]; i++) { @@ -1774,7 +1813,7 @@ static int lineedit_read_key(char *read_key_buffer) # if !ENABLE_UNICODE_PRESERVE_BROKEN ic = CONFIG_SUBST_WCHAR; # else - ic = unicode_mark_inv_wchar(unicode_buf[0]); + ic = unicode_mark_raw_byte(unicode_buf[0]); # endif } else { /* Valid unicode char, return its code */ @@ -2384,9 +2423,6 @@ int main(int argc, char **argv) "% "; #endif -#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT - setlocale(LC_ALL, ""); -#endif while (1) { int l; l = read_line_input(prompt, buff); diff --git a/libbb/unicode.c b/libbb/unicode.c index d1c6167c7..eb0ea6129 100644 --- a/libbb/unicode.c +++ b/libbb/unicode.c @@ -418,7 +418,7 @@ static int in_uint16_table(unsigned ucs, const uint16_t *table, unsigned max) * This implementation assumes that wchar_t characters are encoded * in ISO 10646. */ -static int wcwidth(unsigned ucs) +int FAST_FUNC wcwidth(unsigned ucs) { # if LAST_SUPPORTED_WCHAR >= 0x300 /* sorted list of non-overlapping intervals of non-spacing characters */ -- cgit v1.2.3-55-g6feb From 26e2c1db0df35df1affa558efc12d2bcfd7718e2 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 16 May 2010 21:15:03 +0200 Subject: stop using LAST_SUPPORTED_WCHAR and CONFIG_LAST_SUPPORTED_WCHAR, it's confusing Signed-off-by: Denys Vlasenko --- include/unicode.h | 11 +++++------ libbb/lineedit.c | 5 ++--- libbb/unicode.c | 26 +++++++++++++------------- 3 files changed, 20 insertions(+), 22 deletions(-) (limited to 'libbb') diff --git a/include/unicode.h b/include/unicode.h index 747026abe..eaf67c833 100644 --- a/include/unicode.h +++ b/include/unicode.h @@ -30,22 +30,21 @@ enum { #else # if CONFIG_LAST_SUPPORTED_WCHAR < 126 || CONFIG_LAST_SUPPORTED_WCHAR >= 0x30000 -# define LAST_SUPPORTED_WCHAR 0x2ffff -# else -# define LAST_SUPPORTED_WCHAR CONFIG_LAST_SUPPORTED_WCHAR +# undef CONFIG_LAST_SUPPORTED_WCHAR +# define CONFIG_LAST_SUPPORTED_WCHAR 0x2ffff # endif -# if LAST_SUPPORTED_WCHAR < 0x300 +# if CONFIG_LAST_SUPPORTED_WCHAR < 0x300 # undef ENABLE_UNICODE_COMBINING_WCHARS # define ENABLE_UNICODE_COMBINING_WCHARS 0 # endif -# if LAST_SUPPORTED_WCHAR < 0x1100 +# if CONFIG_LAST_SUPPORTED_WCHAR < 0x1100 # undef ENABLE_UNICODE_WIDE_WCHARS # define ENABLE_UNICODE_WIDE_WCHARS 0 # endif -# if LAST_SUPPORTED_WCHAR < 0x590 +# if CONFIG_LAST_SUPPORTED_WCHAR < 0x590 # undef ENABLE_UNICODE_BIDI_SUPPORT # define ENABLE_UNICODE_BIDI_SUPPORT 0 # endif diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 9f2d65717..72a1786ff 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -282,9 +282,8 @@ static wchar_t adjust_width_and_validate_wc(wchar_t wc) int w = 1; if (unicode_status == UNICODE_ON) { - if (unicode_is_raw_byte(wc) - || (CONFIG_LAST_SUPPORTED_WCHAR && wc > CONFIG_LAST_SUPPORTED_WCHAR) - ) { + if (wc > CONFIG_LAST_SUPPORTED_WCHAR) { + /* note: also true for unicode_is_raw_byte(wc) */ goto subst; } w = wcwidth(wc); diff --git a/libbb/unicode.c b/libbb/unicode.c index eb0ea6129..b2c28239b 100644 --- a/libbb/unicode.c +++ b/libbb/unicode.c @@ -240,7 +240,7 @@ int FAST_FUNC iswpunct(wint_t wc) } -# if LAST_SUPPORTED_WCHAR >= 0x300 +# if CONFIG_LAST_SUPPORTED_WCHAR >= 0x300 struct interval { uint16_t first; uint16_t last; @@ -420,7 +420,7 @@ static int in_uint16_table(unsigned ucs, const uint16_t *table, unsigned max) */ int FAST_FUNC wcwidth(unsigned ucs) { -# if LAST_SUPPORTED_WCHAR >= 0x300 +# if CONFIG_LAST_SUPPORTED_WCHAR >= 0x300 /* sorted list of non-overlapping intervals of non-spacing characters */ /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */ # define BIG_(a,b) { a, b }, @@ -579,14 +579,14 @@ int FAST_FUNC wcwidth(unsigned ucs) if ((ucs & ~0x80) < 0x20 || ucs == 0x7f) return -1; /* Quick abort if it is an obviously invalid char */ - if (ucs > LAST_SUPPORTED_WCHAR) + if (ucs > CONFIG_LAST_SUPPORTED_WCHAR) return -1; /* Optimization: no combining chars below 0x300 */ - if (LAST_SUPPORTED_WCHAR < 0x300 || ucs < 0x300) + if (CONFIG_LAST_SUPPORTED_WCHAR < 0x300 || ucs < 0x300) return 1; -# if LAST_SUPPORTED_WCHAR >= 0x300 +# if CONFIG_LAST_SUPPORTED_WCHAR >= 0x300 /* Binary search in table of non-spacing characters */ if (in_interval_table(ucs, combining, ARRAY_SIZE(combining) - 1)) return 0; @@ -594,25 +594,25 @@ int FAST_FUNC wcwidth(unsigned ucs) return 0; /* Optimization: all chars below 0x1100 are not double-width */ - if (LAST_SUPPORTED_WCHAR < 0x1100 || ucs < 0x1100) + if (CONFIG_LAST_SUPPORTED_WCHAR < 0x1100 || ucs < 0x1100) return 1; -# if LAST_SUPPORTED_WCHAR >= 0x1100 +# if CONFIG_LAST_SUPPORTED_WCHAR >= 0x1100 /* Invalid code points: */ /* High (d800..dbff) and low (dc00..dfff) surrogates (valid only in UTF16) */ /* Private Use Area (e000..f8ff) */ /* Noncharacters fdd0..fdef */ - if ((LAST_SUPPORTED_WCHAR >= 0xd800 && ucs >= 0xd800 && ucs <= 0xf8ff) - || (LAST_SUPPORTED_WCHAR >= 0xfdd0 && ucs >= 0xfdd0 && ucs <= 0xfdef) + if ((CONFIG_LAST_SUPPORTED_WCHAR >= 0xd800 && ucs >= 0xd800 && ucs <= 0xf8ff) + || (CONFIG_LAST_SUPPORTED_WCHAR >= 0xfdd0 && ucs >= 0xfdd0 && ucs <= 0xfdef) ) { return -1; } /* 0xfffe and 0xffff in every plane are invalid */ - if (LAST_SUPPORTED_WCHAR >= 0xfffe && ((ucs & 0xfffe) == 0xfffe)) { + if (CONFIG_LAST_SUPPORTED_WCHAR >= 0xfffe && ((ucs & 0xfffe) == 0xfffe)) { return -1; } -# if LAST_SUPPORTED_WCHAR >= 0x10000 +# if CONFIG_LAST_SUPPORTED_WCHAR >= 0x10000 if (ucs >= 0x10000) { /* Combining chars in Supplementary Multilingual Plane 0x1xxxx */ static const struct interval combining0x10000[] = { @@ -625,7 +625,7 @@ int FAST_FUNC wcwidth(unsigned ucs) if (in_interval_table(ucs ^ 0x10000, combining0x10000, ARRAY_SIZE(combining0x10000) - 1)) return 0; /* Check a few non-spacing chars in Supplementary Special-purpose Plane 0xExxxx */ - if (LAST_SUPPORTED_WCHAR >= 0xE0001 + if (CONFIG_LAST_SUPPORTED_WCHAR >= 0xE0001 && ( ucs == 0xE0001 || (ucs >= 0xE0020 && ucs <= 0xE007F) || (ucs >= 0xE0100 && ucs <= 0xE01EF) @@ -644,7 +644,7 @@ int FAST_FUNC wcwidth(unsigned ucs) || ucs == 0x2329 /* left-pointing angle bracket; also CJK punct. char */ || ucs == 0x232a /* right-pointing angle bracket; also CJK punct. char */ || (ucs >= 0x2e80 && ucs <= 0xa4cf && ucs != 0x303f) /* CJK ... Yi */ -# if LAST_SUPPORTED_WCHAR >= 0xac00 +# if CONFIG_LAST_SUPPORTED_WCHAR >= 0xac00 || (ucs >= 0xac00 && ucs <= 0xd7a3) /* Hangul Syllables */ || (ucs >= 0xf900 && ucs <= 0xfaff) /* CJK Compatibility Ideographs */ || (ucs >= 0xfe10 && ucs <= 0xfe19) /* Vertical forms */ -- cgit v1.2.3-55-g6feb From d9a3e89f501800c3e7c779b7e9545a5c80134593 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 16 May 2010 23:42:13 +0200 Subject: consolidate ESC sequences function old new delta bell 2 - -2 CMdown 2 - -2 Ceos 4 - -4 Ceol 4 - -4 CMup 4 - -4 SOs 5 - -5 SOn 5 - -5 CMrc 9 - -9 Signed-off-by: Denys Vlasenko --- console-tools/clear.c | 3 ++- console-tools/reset.c | 10 +++++----- editors/vi.c | 16 ++++++++-------- libbb/lineedit.c | 2 +- miscutils/fbsplash.c | 4 ++-- miscutils/less.c | 10 +++++----- procps/top.c | 8 ++++---- procps/watch.c | 3 ++- 8 files changed, 29 insertions(+), 27 deletions(-) (limited to 'libbb') diff --git a/console-tools/clear.c b/console-tools/clear.c index 8b727b39b..b0c6d65d2 100644 --- a/console-tools/clear.c +++ b/console-tools/clear.c @@ -15,5 +15,6 @@ int clear_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int clear_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) { - return printf("\033[H\033[J") != 6; + /* home; clear to the end of screen */ + return printf("\033[H""\033[J") != 6; } diff --git a/console-tools/reset.c b/console-tools/reset.c index 6917eda42..f0ea5cb20 100644 --- a/console-tools/reset.c +++ b/console-tools/reset.c @@ -28,11 +28,11 @@ int reset_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { /* See 'man 4 console_codes' for details: - * "ESC c" -- Reset - * "ESC ( K" -- Select user mapping - * "ESC [ J" -- Erase display - * "ESC [ 0 m" -- Reset all display attributes - * "ESC [ ? 25 h" -- Make cursor visible. + * "ESC c" -- Reset + * "ESC ( K" -- Select user mapping + * "ESC [ J" -- Erase to the end of screen + * "ESC [ 0 m" -- Reset all display attributes + * "ESC [ ? 25 h" -- Make cursor visible */ printf("\033c\033(K\033[J\033[0m\033[?25h"); /* http://bugs.busybox.net/view.php?id=1414: diff --git a/editors/vi.c b/editors/vi.c index b8cacb43f..d9124fd76 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -60,18 +60,18 @@ enum { /* vt102 typical ESC sequence */ /* terminal standout start/normal ESC sequence */ -static const char SOs[] ALIGN1 = "\033[7m"; -static const char SOn[] ALIGN1 = "\033[0m"; +#define SOs "\033[7m" +#define SOn "\033[0m" /* terminal bell sequence */ -static const char bell[] ALIGN1 = "\007"; +#define bell "\007" /* Clear-end-of-line and Clear-end-of-screen ESC sequence */ -static const char Ceol[] ALIGN1 = "\033[K"; -static const char Ceos[] ALIGN1 = "\033[J"; +#define Ceol "\033[K" +#define Ceos "\033[J" /* Cursor motion arbitrary destination ESC sequence */ -static const char CMrc[] ALIGN1 = "\033[%d;%dH"; +#define CMrc "\033[%u;%uH" /* Cursor motion up and down ESC sequence */ -static const char CMup[] ALIGN1 = "\033[A"; -static const char CMdown[] ALIGN1 = "\n"; +#define CMup "\033[A" +#define CMdown "\n" #if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK // cmds modifying text[] diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 72a1786ff..bc089ab1c 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -466,7 +466,7 @@ static void input_backward(unsigned num) cmdedit_x = w * count_y - num; } /* go to 1st column; go up; go to correct column */ - printf("\r" "\033[%dA" "\033[%dC", count_y, cmdedit_x); + printf("\r" "\033[%uA" "\033[%uC", count_y, cmdedit_x); } static void put_prompt(void) diff --git a/miscutils/fbsplash.c b/miscutils/fbsplash.c index 5974006bb..e370d207b 100644 --- a/miscutils/fbsplash.c +++ b/miscutils/fbsplash.c @@ -359,7 +359,7 @@ int fbsplash_main(int argc UNUSED_PARAM, char **argv) if (fifo_filename && bCursorOff) { // hide cursor (BEFORE any fb ops) - full_write(STDOUT_FILENO, "\x1b" "[?25l", 6); + full_write(STDOUT_FILENO, "\033[?25l", 6); } fb_drawimage(); @@ -404,7 +404,7 @@ int fbsplash_main(int argc UNUSED_PARAM, char **argv) } if (bCursorOff) // restore cursor - full_write(STDOUT_FILENO, "\x1b" "[?25h", 6); + full_write(STDOUT_FILENO, "\033[?25h", 6); return EXIT_SUCCESS; } diff --git a/miscutils/less.c b/miscutils/less.c index e4f8ab979..848266212 100644 --- a/miscutils/less.c +++ b/miscutils/less.c @@ -29,11 +29,11 @@ #endif /* The escape codes for highlighted and normal text */ -#define HIGHLIGHT "\033[7m" -#define NORMAL "\033[0m" -/* The escape code to clear the screen */ -#define CLEAR "\033[H\033[J" -/* The escape code to clear to end of line */ +#define HIGHLIGHT "\033[7m" +#define NORMAL "\033[0m" +/* The escape code to home and clear to the end of screen */ +#define CLEAR "\033[H\033[J" +/* The escape code to clear to the end of line */ #define CLEAR_2_EOL "\033[K" enum { diff --git a/procps/top.c b/procps/top.c index f5c0a123f..e4afafc4c 100644 --- a/procps/top.c +++ b/procps/top.c @@ -478,8 +478,8 @@ static unsigned long display_header(int scr_width, int *lines_rem_p) snprintf(scrbuf, scr_width, "Mem: %luK used, %luK free, %luK shrd, %luK buff, %luK cached", used, mfree, shared, buffers, cached); - /* clear screen & go to top */ - printf(OPT_BATCH_MODE ? "%s\n" : "\e[H\e[J%s\n", scrbuf); + /* go to top & clear to the end of screen */ + printf(OPT_BATCH_MODE ? "%s\n" : "\033[H\033[J%s\n", scrbuf); (*lines_rem_p)--; /* Display CPU time split as percentage of total time @@ -518,7 +518,7 @@ static NOINLINE void display_process_list(int lines_rem, int scr_width) #endif /* what info of the processes is shown */ - printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width, + printf(OPT_BATCH_MODE ? "%.*s" : "\033[7m%.*s\033[0m", scr_width, " PID PPID USER STAT VSZ %MEM" IF_FEATURE_TOP_SMP_PROCESS(" CPU") IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE(" %CPU") @@ -772,7 +772,7 @@ static void display_topmem_header(int scr_width, int *lines_rem_p) snprintf(linebuf, sizeof(linebuf), "Mem total:%s anon:%s map:%s free:%s", S(total), S(anon), S(map), S(mfree)); - printf(OPT_BATCH_MODE ? "%.*s\n" : "\e[H\e[J%.*s\n", scr_width, linebuf); + printf(OPT_BATCH_MODE ? "%.*s\n" : "\033[H\033[J%.*s\n", scr_width, linebuf); snprintf(linebuf, sizeof(linebuf), " slab:%s buf:%s cache:%s dirty:%s write:%s", diff --git a/procps/watch.c b/procps/watch.c index 126945c40..a1cde9ea0 100644 --- a/procps/watch.c +++ b/procps/watch.c @@ -52,7 +52,8 @@ int watch_main(int argc UNUSED_PARAM, char **argv) width = (unsigned)-1; // make sure first time new_width != width header = NULL; while (1) { - printf("\033[H\033[J"); + /* home; clear to the end of screen */ + printf("\033[H""\033[J"); if (!(opt & 0x2)) { // no -t const unsigned time_len = sizeof("1234-67-90 23:56:89"); time_t t; -- cgit v1.2.3-55-g6feb From 248c324f7c6d407467ab3ad9057dfe33fb2723d8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 17 May 2010 00:45:44 +0200 Subject: lineedit: fix moving backwards across lines with wide chars function old new delta input_backward 212 208 -4 Signed-off-by: Denys Vlasenko --- libbb/lineedit.c | 67 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 21 deletions(-) (limited to 'libbb') diff --git a/libbb/lineedit.c b/libbb/lineedit.c index bc089ab1c..836fc0089 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -413,12 +413,22 @@ static void beep(void) bb_putchar('\007'); } +static void put_prompt(void) +{ + unsigned w; + + out1str(cmdedit_prompt); + fflush_all(); + cursor = 0; + w = cmdedit_termw; /* read volatile var once */ + cmdedit_y = cmdedit_prmt_len / w; /* new quasireal y */ + cmdedit_x = cmdedit_prmt_len % w; +} + /* Move back one character */ /* (optimized for slow terminals) */ static void input_backward(unsigned num) { - int count_y; - if (num > cursor) num = cursor; if (num == 0) @@ -456,29 +466,44 @@ static void input_backward(unsigned num) } /* Need to go one or more lines up */ -//FIXME: this does not work correctly if prev line has one "unfilled" screen position -//caused by wide unicode char not fitting in that one screen position. - num -= cmdedit_x; - { - unsigned w = cmdedit_termw; /* volatile var */ + if (ENABLE_UNICODE_WIDE_WCHARS) { + /* With wide chars, it is hard to "backtrack" + * and reliably figure out where to put cursor. + * Example (<> is a wide char; # is an ordinary char, _ cursor): + * |prompt: <><> | + * |<><><><><><> | + * |_ | + * and user presses left arrow. num = 1, cmdedit_x = 0, + * We need to go up one line, and then - how do we know that + * we need to go *10* positions to the right? Because + * |prompt: <>#<>| + * |<><><>#<><><>| + * |_ | + * in this situation we need to go *11* positions to the right. + * + * A simpler thing to do is to redraw everything from the start + * up to new cursor position (which is already known): + */ + unsigned sv_cursor; + if (cmdedit_y > 0) /* up to start y */ + printf("\033[%uA", cmdedit_y); + bb_putchar('\r'); + cmdedit_y = 0; + sv_cursor = cursor; + put_prompt(); /* sets cursor to 0 */ + while (cursor < sv_cursor) + put_cur_glyph_and_inc_cursor(); + } else { + int count_y; + unsigned w; + num -= cmdedit_x; + w = cmdedit_termw; /* read volatile var once */ count_y = 1 + (num / w); cmdedit_y -= count_y; cmdedit_x = w * count_y - num; + /* go to 1st column; go up; go to correct column */ + printf("\r" "\033[%uA" "\033[%uC", count_y, cmdedit_x); } - /* go to 1st column; go up; go to correct column */ - printf("\r" "\033[%uA" "\033[%uC", count_y, cmdedit_x); -} - -static void put_prompt(void) -{ - unsigned w; - - out1str(cmdedit_prompt); - fflush_all(); - cursor = 0; - w = cmdedit_termw; /* read volatile var once */ - cmdedit_y = cmdedit_prmt_len / w; /* new quasireal y */ - cmdedit_x = cmdedit_prmt_len % w; } /* draw prompt, editor line, and clear tail */ -- cgit v1.2.3-55-g6feb From 9963fe36c2af2bf99fcbd2eae6e9e050c8cf779b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 17 May 2010 04:05:53 +0200 Subject: lineedit: trivial simplifications. -7 bytes Signed-off-by: Denys Vlasenko --- libbb/lineedit.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) (limited to 'libbb') diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 836fc0089..36d057bbb 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -397,17 +397,10 @@ static void put_till_end_and_adv_cursor(void) static void goto_new_line(void) { put_till_end_and_adv_cursor(); - if (cmdedit_x) + if (cmdedit_x != 0) bb_putchar('\n'); } - -static void out1str(const char *s) -{ - if (s) - fputs(s, stdout); -} - static void beep(void) { bb_putchar('\007'); @@ -417,7 +410,7 @@ static void put_prompt(void) { unsigned w; - out1str(cmdedit_prompt); + fputs(cmdedit_prompt, stdout); fflush_all(); cursor = 0; w = cmdedit_termw; /* read volatile var once */ @@ -485,9 +478,8 @@ static void input_backward(unsigned num) * up to new cursor position (which is already known): */ unsigned sv_cursor; - if (cmdedit_y > 0) /* up to start y */ - printf("\033[%uA", cmdedit_y); - bb_putchar('\r'); + /* go to 1st column; go up to first line */ + printf("\r" "\033[%uA", cmdedit_y); cmdedit_y = 0; sv_cursor = cursor; put_prompt(); /* sets cursor to 0 */ @@ -509,7 +501,7 @@ static void input_backward(unsigned num) /* draw prompt, editor line, and clear tail */ static void redraw(int y, int back_cursor) { - if (y > 0) /* up to start y */ + if (y > 0) /* up y lines */ printf("\033[%uA", y); bb_putchar('\r'); put_prompt(); @@ -1616,7 +1608,7 @@ static void ask_terminal(void) pfd.events = POLLIN; if (safe_poll(&pfd, 1, 0) == 0) { S.sent_ESC_br6n = 1; - out1str("\033" "[6n"); + fputs("\033" "[6n", stdout); fflush_all(); /* make terminal see it ASAP! */ } } -- cgit v1.2.3-55-g6feb From 1118d9b213e4cad56e6f79c1753e0a52defadaa5 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 17 May 2010 12:30:44 +0200 Subject: lineedit: fix insertion deep inside line (*several lines* before end) function old new delta input_backward 212 229 +17 Signed-off-by: Denys Vlasenko --- libbb/lineedit.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'libbb') diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 36d057bbb..f7d3ffed8 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -486,15 +486,22 @@ static void input_backward(unsigned num) while (cursor < sv_cursor) put_cur_glyph_and_inc_cursor(); } else { - int count_y; - unsigned w; + int lines_up; + unsigned width; + /* num = chars to go back from the beginning of current line: */ num -= cmdedit_x; - w = cmdedit_termw; /* read volatile var once */ - count_y = 1 + (num / w); - cmdedit_y -= count_y; - cmdedit_x = w * count_y - num; - /* go to 1st column; go up; go to correct column */ - printf("\r" "\033[%uA" "\033[%uC", count_y, cmdedit_x); + width = cmdedit_termw; /* read volatile var once */ + /* num=1...w: one line up, w+1...2w: two, etc: */ + lines_up = 1 + (num - 1) / width; + cmdedit_x = (width * cmdedit_y - num) % width; + cmdedit_y -= lines_up; + /* go to 1st column; go up */ + printf("\r" "\033[%uA", lines_up); + /* go to correct column. + * xtarm, konsole, Linux VT interpret 0 as 1 below! wow. + * Need to *make sure* we skip it if cmdedit_x == 0 */ + if (cmdedit_x) + printf("\033[%uC", cmdedit_x); } } -- cgit v1.2.3-55-g6feb From bbf1aa1eaf6278e23ae75914c8d9b9be4d0e28f5 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 17 May 2010 12:33:13 +0200 Subject: typo fix Signed-off-by: Denys Vlasenko --- libbb/lineedit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libbb') diff --git a/libbb/lineedit.c b/libbb/lineedit.c index f7d3ffed8..18664b8c1 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -498,8 +498,8 @@ static void input_backward(unsigned num) /* go to 1st column; go up */ printf("\r" "\033[%uA", lines_up); /* go to correct column. - * xtarm, konsole, Linux VT interpret 0 as 1 below! wow. - * Need to *make sure* we skip it if cmdedit_x == 0 */ + * xterm, konsole, Linux VT interpret 0 as 1 below! wow. + * need to *make sure* we skip it if cmdedit_x == 0 */ if (cmdedit_x) printf("\033[%uC", cmdedit_x); } -- cgit v1.2.3-55-g6feb