X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=toys%2Fposix%2Fls.c;h=6b181c0afb50c54189b9332af4d3cbf5fb543142;hb=a0637cef8f;hp=7d15935c8434c66d37ce39adef82ea07715394fe;hpb=55aa28467914463e9c6869cd3c8b7264f7e6e695;p=android-x86%2Fexternal-toybox.git diff --git a/toys/posix/ls.c b/toys/posix/ls.c index 7d15935c..6b181c0a 100644 --- a/toys/posix/ls.c +++ b/toys/posix/ls.c @@ -5,34 +5,35 @@ * * See http://opengroup.org/onlinepubs/9699919799/utilities/ls.html -USE_LS(NEWTOY(ls, USE_LS_COLOR("(color):;")"ZgoACFHLRSacdfhiklmnpqrstux1[-Cxm1][-Cxml][-Cxmo][-Cxmg][-cu][-ftS][-HL]", TOYFLAG_BIN|TOYFLAG_LOCALE)) +USE_LS(NEWTOY(ls, USE_LS_COLOR("(color):;")"ZgoACFHLRSabcdfhiklmnpqrstux1[-Cxm1][-Cxml][-Cxmo][-Cxmg][-cu][-ftS][-HL][!qb]", TOYFLAG_BIN|TOYFLAG_LOCALE)) config LS bool "ls" default y help usage: ls [-ACFHLRSZacdfhiklmnpqrstux1] [directory...] + list files what to show: - -a all files including .hidden -c use ctime for timestamps - -d directory, not contents -i inode number - -k block sizes in kilobytes -p put a '/' after dir names - -q unprintable chars as '?' -s size (in blocks) - -u use access time for timestamps -A list all files but . and .. - -H follow command line symlinks -L follow symlinks - -R recursively list files in subdirs -F append /dir *exe @sym |FIFO - -Z security context + -a all files including .hidden -b escape nongraphic chars + -c use ctime for timestamps -d directory, not contents + -i inode number -k block sizes in kilobytes + -p put a '/' after dir names -q unprintable chars as '?' + -s size (in blocks) -u use access time for timestamps + -A list all files but . and .. -H follow command line symlinks + -L follow symlinks -R recursively list files in subdirs + -F append /dir *exe @sym |FIFO -Z security context output formats: - -1 list one file per line -C columns (sorted vertically) - -g like -l but no owner -h human readable sizes - -l long (show full details) -m comma separated - -n like -l but numeric uid/gid -o like -l but no group - -x columns (horizontal sort) + -1 list one file per line -C columns (sorted vertically) + -g like -l but no owner -h human readable sizes + -l long (show full details) -m comma separated + -n like -l but numeric uid/gid -o like -l but no group + -x columns (horizontal sort) sorting (default is alphabetical): - -f unsorted -r reverse -t timestamp -S size + -f unsorted -r reverse -t timestamp -S size config LS_COLOR bool "ls --color" @@ -60,34 +61,53 @@ GLOBALS( unsigned screen_width; int nl_title; - char uid_buf[12], gid_buf[12]; + char *escmore; ) -// Does two things: 1) Returns wcwidth(utf8) version of strlen, -// 2) replaces unprintable characters input string with '?' wildcard char. -int strwidth(char *s) +// Callback from crunch_str to represent unprintable chars +int crunch_qb(FILE *out, int cols, int wc) { - int total = 0, width, len; - wchar_t c; - - if (!CFG_TOYBOX_I18N) { - total = strlen(s); - if (toys.optflags & FLAG_q) for (; *s; s++) if (!isprint(*s)) *s = '?'; - } else while (*s) { - len = mbrtowc(&c, s, MB_CUR_MAX, 0); - if (len < 1 || (width = wcwidth(c)) < 0) { - total++; - if (toys.optflags & FLAG_q) *s = '?'; - s++; - } else { - s += len; - total += width; + unsigned len = 1; + char buf[32]; + + if (toys.optflags&FLAG_q) *buf = '?'; + else { + if (wc<256) *buf = wc; + // scrute the inscrutable, eff the ineffable, print the unprintable + else len = wcrtomb(buf, wc, 0); + if (toys.optflags&FLAG_b) { + char *to = buf, *from = buf+24; + int i, j; + + memcpy(from, to, 8); + for (i = 0; ist_mode; @@ -101,22 +121,6 @@ static char endtype(struct stat *st) return 0; } -static char *getusername(uid_t uid) -{ - struct passwd *pw = getpwuid(uid); - - sprintf(TT.uid_buf, "%u", (unsigned)uid); - return pw ? pw->pw_name : TT.uid_buf; -} - -static char *getgroupname(gid_t gid) -{ - struct group *gr = getgrgid(gid); - - sprintf(TT.gid_buf, "%u", (unsigned)gid); - return gr ? gr->gr_name : TT.gid_buf; -} - static int numlen(long long ll) { return snprintf(0, 0, "%llu", ll); @@ -143,7 +147,7 @@ static void entrylen(struct dirtree *dt, unsigned *len) if (S_ISBLK(st->st_mode) || S_ISCHR(st->st_mode)) { // cheating slightly here: assuming minor is always 3 digits to avoid // tracking another column - len[5] = numlen(major(st->st_rdev))+5; + len[5] = numlen(dev_major(st->st_rdev))+5; } else if (flags & FLAG_h) { human_readable(tmp, st->st_size, 0); len[5] = strwidth(tmp); @@ -191,7 +195,7 @@ static int filter(struct dirtree *new) // fchmodat(), mknodat(), readlinkat() so we could do this without // even O_PATH? But no, this is 1990's tech.) int fd = openat(dirtree_parentfd(new), new->name, - O_PATH|(O_NOFOLLOW*!!(toys.optflags&FLAG_L))); + O_PATH|(O_NOFOLLOW*!(toys.optflags&FLAG_L))); if (fd != -1) { if (-1 == lsm_fget_context(fd, (char **)&new->extra) && errno == EBADF) @@ -291,13 +295,13 @@ static void listfiles(int dirfd, struct dirtree *indir) char tmp[64]; if (-1 == dirfd) { - strwidth(indir->name); - perror_msg("%s", indir->name); + perror_msg_raw(indir->name); return; } memset(totals, 0, sizeof(totals)); + if (CFG_TOYBOX_ON_ANDROID || CFG_TOYBOX_DEBUG) memset(len, 0, sizeof(len)); // Top level directory was already populated by main() if (!indir->parent) { @@ -314,12 +318,10 @@ static void listfiles(int dirfd, struct dirtree *indir) // Do preprocessing (Dirtree didn't populate, so callback wasn't called.) for (;dt; dt = dt->next) filter(dt); if (flags == (FLAG_1|FLAG_f)) return; - } else { - // Read directory contents. We dup() the fd because this will close it. - // This reads/saves contents to display later, except for in "ls -1f" mode. - indir->data = dup(dirfd); - dirtree_recurse(indir, filter, DIRTREE_SYMFOLLOW*!!(flags&FLAG_L)); - } + // Read directory contents. We dup() the fd because this will close it. + // This reads/saves contents to display later, except for in "ls -1f" mode. + } else dirtree_recurse(indir, filter, dup(dirfd), + DIRTREE_SYMFOLLOW*!!(flags&FLAG_L)); // Copy linked list to array and sort it. Directories go in array because // we visit them in sorted order too. (The nested loops let us measure and @@ -393,11 +395,12 @@ static void listfiles(int dirfd, struct dirtree *indir) memset(toybuf, ' ', 256); width = 0; for (ul = 0; ulst); mode_t mode = st->st_mode; - char et = endtype(st); + char et = endtype(st), *ss; // Skip directories at the top of the tree when -d isn't set if (S_ISDIR(mode) && !indir->parent && !(flags & FLAG_d)) continue; @@ -426,7 +429,6 @@ static void listfiles(int dirfd, struct dirtree *indir) if (flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g)) { struct tm *tm; - char *ss; // (long) is to coerce the st types into something we know we can print. mode_to_string(mode, tmp); @@ -434,16 +436,20 @@ static void listfiles(int dirfd, struct dirtree *indir) // print user if (!(flags&FLAG_g)) { - if (flags&FLAG_n) sprintf(ss = tmp, "%u", (unsigned)st->st_uid); - else strwidth(ss = getusername(st->st_uid)); - printf(" %-*s", (int)totals[3], ss); + putchar(' '); + ii = -totals[3]; + if (flags&FLAG_n) printf("%*u", ii, (unsigned)st->st_uid); + else draw_trim_esc(getusername(st->st_uid), ii, abs(ii), TT.escmore, + crunch_qb); } // print group if (!(flags&FLAG_o)) { - if (flags&FLAG_n) sprintf(ss = tmp, "%u", (unsigned)st->st_gid); - else strwidth(ss = getgroupname(st->st_gid)); - printf(" %-*s", (int)totals[4], ss); + putchar(' '); + ii = -totals[4]; + if (flags&FLAG_n) printf("%*u", ii, (unsigned)st->st_gid); + else draw_trim_esc(getgroupname(st->st_gid), ii, abs(ii), TT.escmore, + crunch_qb); } if (flags & FLAG_Z) @@ -451,7 +457,8 @@ static void listfiles(int dirfd, struct dirtree *indir) // print major/minor, or size if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) - printf("% *d,% 4d", totals[5]-4, major(st->st_rdev),minor(st->st_rdev)); + printf("% *d,% 4d", totals[5]-4, dev_major(st->st_rdev), + dev_minor(st->st_rdev)); else if (flags&FLAG_h) { human_readable(tmp, st->st_size, 0); xprintf("%*s", totals[5]+1, tmp); @@ -469,10 +476,8 @@ static void listfiles(int dirfd, struct dirtree *indir) if (color) printf("\033[%d;%dm", color>>8, color&255); } - if (flags & FLAG_q) { - char *p; - for (p=sort[next]->name; *p; p++) fputc(isprint(*p) ? *p : '?', stdout); - } else xprintf("%s", sort[next]->name); + ss = sort[next]->name; + crunch_str(&ss, INT_MAX, stdout, TT.escmore, crunch_qb); if (color) xprintf("\033[0m"); if ((flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g)) && S_ISLNK(mode)) { @@ -523,10 +528,11 @@ void ls_main(void) TT.screen_width = 80; terminal_size(&TT.screen_width, NULL); if (TT.screen_width<2) TT.screen_width = 2; + if (toys.optflags&FLAG_b) TT.escmore = " \\"; // Do we have an implied -1 if (!isatty(1)) { - toys.optflags |= FLAG_1; + if (!(toys.optflags & FLAG_m)) toys.optflags |= FLAG_1; if (TT.color) toys.optflags ^= FLAG_color; } else if (toys.optflags&(FLAG_l|FLAG_o|FLAG_n|FLAG_g)) toys.optflags |= FLAG_1; @@ -537,11 +543,15 @@ void ls_main(void) if (toys.optflags & FLAG_d) toys.optflags &= ~FLAG_R; // Iterate through command line arguments, collecting directories and files. - // Non-absolute paths are relative to current directory. - TT.files = dirtree_start(0, 0); + // Non-absolute paths are relative to current directory. Top of tree is + // a dummy node to collect command line arguments into pseudo-directory. + TT.files = dirtree_add_node(0, 0, 0); + TT.files->dirfd = AT_FDCWD; for (s = *toys.optargs ? toys.optargs : noargs; *s; s++) { - dt = dirtree_start(*s, !(toys.optflags&(FLAG_l|FLAG_d|FLAG_F)) || - (toys.optflags&(FLAG_L|FLAG_H))); + int sym = !(toys.optflags&(FLAG_l|FLAG_d|FLAG_F)) + || (toys.optflags&(FLAG_L|FLAG_H)); + + dt = dirtree_add_node(0, *s, DIRTREE_SYMFOLLOW*sym); // note: double_list->prev temporarirly goes in dirtree->parent if (dt) dlist_add_nomalloc((void *)&TT.files->child, (void *)dt);