From c7497ea31b84eb3261a64a2e1a8e80643c26fd9d Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Fri, 13 Jun 2008 11:16:09 +0000 Subject: [PATCH] build system: introduce FEATURE_ASSUME_UNICODE ls: use it. also do G trick. with UNICODE off: function old new delta ls_main 843 871 +28 show_color 1 - -1 showdirs 500 497 -3 my_stat 100 97 -3 terminal_width 4 - -4 tabstops 4 - -4 status 122 118 -4 static.dotdir 4 - -4 current_time_t 4 - -4 all_fmt 4 - -4 ------------------------------------------------------------------------------ (add/remove: 0/6 grow/shrink: 1/3 up/down: 28/-31) Total: -3 bytes Also was tested with UNICODE on with glibc. --- Config.in | 12 +++++ coreutils/ls.c | 149 +++++++++++++++++++++++++++++++++------------------------ 2 files changed, 99 insertions(+), 62 deletions(-) diff --git a/Config.in b/Config.in index 0a7edf8..e70caf5 100644 --- a/Config.in +++ b/Config.in @@ -21,6 +21,18 @@ config DESKTOP Select this only if you plan to use busybox on full-blown desktop machine with common Linux distro, not on an embedded box. +config FEATURE_ASSUME_UNICODE + bool "Assume that 1:1 char/glyph correspondence is not true" + default n + help + This makes various applets aware that one byte is not + one character on screen. + + Busybox aims to eventually work correctly with Unicode displays. + Any older encodings are not guaranteed to work. + Probably by the time when busybox will be fully Unicode-clean, + other encodings will be mainly of historic interest. + choice prompt "Buffer allocation policy" default FEATURE_BUFFERS_USE_MALLOC diff --git a/coreutils/ls.c b/coreutils/ls.c index 9850866..7d33eae 100644 --- a/coreutils/ls.c +++ b/coreutils/ls.c @@ -31,6 +31,10 @@ #include "libbb.h" +#if ENABLE_FEATURE_ASSUME_UNICODE +#include +#endif + /* This is a NOEXEC applet. Be very careful! */ @@ -114,18 +118,6 @@ SPLIT_SUBDIR = 2, #define ATTR(mode) ("\00\00\01\00\01\00\01\00"\ "\00\00\01\00\01\00\00\01" [TYPEINDEX(mode)]) -/* colored LS support by JaWi, janwillem.janssen@lxtreme.nl */ -#if ENABLE_FEATURE_LS_COLOR -static smallint show_color; -/* long option entry used only for --color, which has no short option - * equivalent */ -static const char ls_color_opt[] ALIGN1 = - "color\0" Optional_argument "\xff" /* no short equivalent */ - ; -#else -enum { show_color = 0 }; -#endif - /* * a directory entry and its stat info are stored here */ @@ -137,25 +129,68 @@ struct dnode { /* the basic node */ USE_SELINUX(security_context_t sid;) struct dnode *next; /* point at the next node */ }; -typedef struct dnode dnode_t; static struct dnode **list_dir(const char *); static struct dnode **dnalloc(int); -static int list_single(struct dnode *); +static int list_single(const struct dnode *); -static unsigned all_fmt; +struct globals { +#if ENABLE_FEATURE_LS_COLOR + smallint show_color; +#endif + smallint exit_failure; + unsigned all_fmt; +#if ENABLE_FEATURE_AUTOWIDTH + unsigned tabstops; // = COLUMN_GAP; + unsigned terminal_width; // = TERMINAL_WIDTH; +#endif +#if ENABLE_FEATURE_LS_TIMESTAMPS + /* Do time() just once. Saves one syscall per file for "ls -l" */ + time_t current_time_t; +#endif +}; +#define G (*(struct globals*)&bb_common_bufsiz1) +#if ENABLE_FEATURE_LS_COLOR +#define show_color (G.show_color ) +#else +enum { show_color = 0 }; +#endif +#define exit_failure (G.exit_failure ) +#define all_fmt (G.all_fmt ) #if ENABLE_FEATURE_AUTOWIDTH -static unsigned tabstops = COLUMN_GAP; -static unsigned terminal_width = TERMINAL_WIDTH; +#define tabstops (G.tabstops ) +#define terminal_width (G.terminal_width) #else enum { tabstops = COLUMN_GAP, terminal_width = TERMINAL_WIDTH, }; #endif +#define current_time_t (G.current_time_t) +/* memset: we have to zero it out because of NOEXEC */ +#define INIT_G() { \ + memset(&G, 0, sizeof(G)); \ + tabstops = COLUMN_GAP; \ + terminal_width = TERMINAL_WIDTH; \ + USE_FEATURE_LS_TIMESTAMPS(time(¤t_time_t);) \ +} + + +#if ENABLE_FEATURE_ASSUME_UNICODE +/* libbb candidate */ +static size_t mbstrlen(const char *string) +{ + size_t width = mbsrtowcs(NULL /*dest*/, &string, + MAXINT(size_t) /*len*/, NULL /*state*/); + if (width == (size_t)-1) + return strlen(string); + return width; +} +#else +#define mbstrlen(string) strlen(string) +#endif -static int status = EXIT_SUCCESS; static struct dnode *my_stat(const char *fullname, const char *name, int force_follow) { @@ -171,7 +206,7 @@ static struct dnode *my_stat(const char *fullname, const char *name, int force_f #endif if (stat(fullname, &dstat)) { bb_simple_perror_msg(fullname); - status = EXIT_FAILURE; + exit_failure = 1; return 0; } } else { @@ -182,7 +217,7 @@ static struct dnode *my_stat(const char *fullname, const char *name, int force_f #endif if (lstat(fullname, &dstat)) { bb_simple_perror_msg(fullname); - status = EXIT_FAILURE; + exit_failure = 1; return 0; } } @@ -395,7 +430,7 @@ static void showfiles(struct dnode **dn, int nfiles) } else { /* find the longest file name, use that as the column width */ for (i = 0; i < nfiles; i++) { - int len = strlen(dn[i]->name); + int len = mbstrlen(dn[i]->name); if (column_width < len) column_width = len; } @@ -494,7 +529,7 @@ static struct dnode **list_dir(const char *path) nfiles = 0; dir = warn_opendir(path); if (dir == NULL) { - status = EXIT_FAILURE; + exit_failure = 1; return NULL; /* could not open the dir */ } while ((entry = readdir(dir)) != NULL) { @@ -538,13 +573,7 @@ static struct dnode **list_dir(const char *path) } -#if ENABLE_FEATURE_LS_TIMESTAMPS -/* Do time() just once. Saves one syscall per file for "ls -l" */ -/* Initialized in main() */ -static time_t current_time_t; -#endif - -static int list_single(struct dnode *dn) +static int list_single(const struct dnode *dn) { int i, column = 0; @@ -658,7 +687,12 @@ static int list_single(struct dnode *dn) fgcolor(info.st_mode)); } #endif +#if ENABLE_FEATURE_ASSUME_UNICODE + printf("%s", dn->name); + column += mbstrlen(dn->name); +#else column += printf("%s", dn->name); +#endif if (show_color) { printf("\033[0m"); } @@ -701,6 +735,7 @@ static int list_single(struct dnode *dn) return column; } + /* "[-]Cadil1", POSIX mandated options, busybox always supports */ /* "[-]gnsx", POSIX non-mandated options, busybox always supports */ /* "[-]Ak" GNU options, busybox always supports */ @@ -779,11 +814,18 @@ static const unsigned opt_flags[] = { }; -/* THIS IS A "SAFE" APPLET, main() MAY BE CALLED INTERNALLY FROM SHELL */ -/* BE CAREFUL! */ +/* colored LS support by JaWi, janwillem.janssen@lxtreme.nl */ +#if ENABLE_FEATURE_LS_COLOR +/* long option entry used only for --color, which has no short option + * equivalent */ +static const char ls_color_opt[] ALIGN1 = + "color\0" Optional_argument "\xff" /* no short equivalent */ + ; +#endif + int ls_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int ls_main(int argc, char **argv) +int ls_main(int argc ATTRIBUTE_UNUSED, char **argv) { struct dnode **dnd; struct dnode **dnf; @@ -791,18 +833,13 @@ int ls_main(int argc, char **argv) struct dnode *dn; struct dnode *cur; unsigned opt; - int nfiles = 0; + int nfiles; int dnfiles; int dndirs; - int oi; - int ac; int i; - char **av; USE_FEATURE_LS_COLOR(char *color_opt;) -#if ENABLE_FEATURE_LS_TIMESTAMPS - time(¤t_time_t); -#endif + INIT_G(); all_fmt = LIST_SHORT | (ENABLE_FEATURE_LS_SORTFILES * (SORT_NAME | SORT_FORWARD)); @@ -883,39 +920,27 @@ int ls_main(int argc, char **argv) if (!(all_fmt & STYLE_MASK)) all_fmt |= (isatty(STDOUT_FILENO) ? STYLE_COLUMNS : STYLE_SINGLE); - /* - * when there are no cmd line args we have to supply a default "." arg. - * we will create a second argv array, "av" that will hold either - * our created "." arg, or the real cmd line args. The av array - * just holds the pointers- we don't move the date the pointers - * point to. - */ - ac = argc - optind; /* how many cmd line args are left */ - if (ac < 1) { - static const char *const dotdir[] = { "." }; - - av = (char **) dotdir; - ac = 1; - } else { - av = argv + optind; - } + argv += optind; + if (!argv[0]) + *--argv = (char*)"."; - /* now, everything is in the av array */ - if (ac > 1) - all_fmt |= DISP_DIRNAME; /* 2 or more items? label directories */ + if (argv[1]) + all_fmt |= DISP_DIRNAME; /* 2 or more items? label directories */ /* stuff the command line file names into a dnode array */ dn = NULL; - for (oi = 0; oi < ac; oi++) { + nfiles = 0; + do { /* ls w/o -l follows links on command line */ - cur = my_stat(av[oi], av[oi], !(all_fmt & STYLE_LONG)); + cur = my_stat(*argv, *argv, !(all_fmt & STYLE_LONG)); + argv++; if (!cur) continue; cur->allocated = 0; cur->next = dn; dn = cur; nfiles++; - } + } while (*argv); /* now that we know how many files there are * allocate memory for an array to hold dnode pointers @@ -950,5 +975,5 @@ int ls_main(int argc, char **argv) } if (ENABLE_FEATURE_CLEAN_UP) dfree(dnp, nfiles); - return status; + return (exit_failure == 0); } -- 2.7.4