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.
This commit is contained in:
Denis Vlasenko 2008-06-13 11:16:09 +00:00
parent 25b463079d
commit c7497ea31b
2 changed files with 99 additions and 62 deletions

View File

@ -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

View File

@ -31,6 +31,10 @@
#include "libbb.h"
#if ENABLE_FEATURE_ASSUME_UNICODE
#include <wchar.h>
#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
static unsigned tabstops = COLUMN_GAP;
static unsigned terminal_width = TERMINAL_WIDTH;
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
#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(&current_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(&current_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[] = { "." };
argv += optind;
if (!argv[0])
*--argv = (char*)".";
av = (char **) dotdir;
ac = 1;
} else {
av = argv + optind;
}
/* 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);
}