# HG changeset patch # User Rob Landley # Date 1335488378 18000 # Node ID c42ed3601b357f5ffc783bdf6c4ec69379d466ed # Parent 8a88a9e3c30b469122cdc03d27bd395a9794bedd Simplify/unify listfiles recursion: populate directory node (and detect top of tree) at start of function rather than end (and redundantly in main). Move title printing down next to total printing. diff -r 8a88a9e3c30b -r c42ed3601b35 toys/ls.c --- a/toys/ls.c Tue Apr 24 23:09:27 2012 +0200 +++ b/toys/ls.c Thu Apr 26 19:59:38 2012 -0500 @@ -58,7 +58,7 @@ struct dirtree *files; unsigned width; - int again; + int nl_title; ) #define TT this.ls @@ -149,30 +149,26 @@ // Display a list of dirtree entries, according to current format // Output types -1, -l, -C, or stream -static void listfiles(struct dirtree *indir) +static void listfiles(int dirfd, struct dirtree *indir) { struct dirtree *dt, **sort = 0; unsigned long dtlen = 0, ul = 0; unsigned width, flags = toys.optflags, totals[6], len[6]; - // There are two "top of tree" variants: - // ls arg1 arg2 arg3 - // detect: !indir->parent - // behavior: don't display dirs, never show dirname/total, option -H - // ls onedir (or just "ls" which implies "." as first arg). - // detect: indir == TT.files - // behavior: only show dirname/total with -R - - // Show current directory name if showing one directory with -d or - // not top of tree and -R - if (!(indir == TT.files || (flags & FLAG_d)) - || (indir->parent && (flags & FLAG_R))) - { - char *path = dirtree_path(indir, 0); - - if (TT.again++) xputc('\n'); - xprintf("%s:\n", path); - free(path); + + // Silently descend into single directory listed by itself on command line. + // In this case only show dirname/total header when given -R. + if (!indir->parent) { + if (!(dt = indir->child)) return; + if (S_ISDIR(dt->st.st_mode) && !dt->next && !(toys.optflags&FLAG_d)) { + dt->extra = 1; + listfiles(open(dt->name, 0), dt); + return; + } + } else { + // Read directory contents. We dup() the fd because this will close it. + indir->data = dup(dirfd); + dirtree_recurse(indir, filter); } // Copy linked list to array and sort it. Directories go in array because @@ -203,6 +199,16 @@ } else if (*len > *totals) *totals = *len; } + // Label directory if not top of tree, or if -R + if (indir->parent && (!indir->extra || (flags&FLAG_R))) + { + char *path = dirtree_path(indir, 0); + + if (TT.nl_title++) xputc('\n'); + xprintf("%s:\n", path); + free(path); + } + // This is wrong, should be blocks used not file count. if (indir->parent && (flags & FLAG_l)) xprintf("total %lu\n", dtlen); @@ -216,6 +222,7 @@ // Skip directories at the top of the tree when -d isn't set if (S_ISDIR(mode) && !indir->parent && !(flags & FLAG_d)) continue; + TT.nl_title=1; // Do we need to wrap at right edge of screen? entrylen(sort[ul], len); @@ -285,17 +292,11 @@ || dirtree_isdotdot(sort[ul])) continue; // Recurse into dirs if at top of the tree or given -R - if (!indir->parent || (flags & FLAG_R)) { - int fd = openat(indir->data, sort[ul]->name, 0); - - sort[ul]->data = dup(fd); - dirtree_recurse(sort[ul], filter); - sort[ul]->data = fd; - listfiles(sort[ul]); - } + if (!indir->parent || (flags & FLAG_R)) + listfiles(openat(dirfd, sort[ul]->name, 0), sort[ul]); } free(sort); - if (indir->data != AT_FDCWD) close(indir->data); + if (dirfd != AT_FDCWD) close(indir->data); } void ls_main(void) @@ -330,27 +331,11 @@ (struct double_list *)dt); } - if (!TT.files->child) return; - // Turn double_list into dirtree dlist_to_dirtree(TT.files); - // Special case a single directory argument: silently descend into it. - dt = TT.files->child; + // Display the files we collected + listfiles(AT_FDCWD, TT.files); - if (S_ISDIR(dt->st.st_mode) && !dt->next && !(toys.optflags&FLAG_d)) { - int fd = open(dt->name, 0); - TT.files = dt; - dt->data = dup(fd); - dirtree_recurse(dt, filter); - dt->data = fd; - } else TT.files->data = AT_FDCWD; - - // Display the files we collected - listfiles(TT.files); - - if (CFG_TOYBOX_FREE) { - free(TT.files->parent); - free(TT.files); - } + if (CFG_TOYBOX_FREE) free(TT.files); }