diff -u ls/cmp.c ls.new/cmp.c --- ls/cmp.c Thu May 18 15:02:20 2006 +++ ls.new/cmp.c Thu May 17 04:14:52 2007 @@ -183,3 +183,35 @@ return (sizecmp(b, a)); } + +#define IS_FTS_DIR(x) ((x)->fts_info == FTS_D \ + || (x)->fts_info == FTS_DOT \ + || (x)->fts_info == FTS_DC \ + || (x)->fts_info == FTS_DNR \ + || (x)->fts_info == FTS_DP) + +int +dirfcmp(const FTSENT *a, const FTSENT *b) +{ + + if ((IS_FTS_DIR(a) && IS_FTS_DIR(b)) || (!IS_FTS_DIR(a) && !IS_FTS_DIR(b))) + return (real_sortfcn(a, b)); + return (IS_FTS_DIR(a) ? -1 : 1); +} + +int +revdirfcmp(const FTSENT *a, const FTSENT *b) +{ + + if ((IS_FTS_DIR(a) && IS_FTS_DIR(b)) || (!IS_FTS_DIR(a) && !IS_FTS_DIR(b))) + return (real_sortfcn(a, b)); + return (IS_FTS_DIR(b) ? -1 : 1); +} +int +checkisdir(const FTSENT *a) +{ + if (IS_FTS_DIR(a)) + return (0); + else + return (1); +} diff -u ls/extern.h ls.new/extern.h --- ls/extern.h Thu May 18 15:02:20 2006 +++ ls.new/extern.h Thu May 17 04:14:52 2007 @@ -42,6 +42,12 @@ int revstatcmp(const FTSENT *, const FTSENT *); int sizecmp(const FTSENT *, const FTSENT *); int revsizecmp(const FTSENT *, const FTSENT *); +int dirfcmp(const FTSENT *, const FTSENT *); +int revdirfcmp(const FTSENT *, const FTSENT *); +int checkisdir(const FTSENT *); + +/* save the real sortfcn when sorting directories first */ +int (*real_sortfcn)(const FTSENT *, const FTSENT *); void printcol(const DISPLAY *); void printlong(const DISPLAY *); diff -u ls/ls.1 ls.new/ls.1 --- ls/ls.1 Mon Oct 16 04:54:36 2006 +++ ls.new/ls.1 Fri May 18 02:05:57 2007 @@ -40,7 +40,7 @@ .Nd list directory contents .Sh SYNOPSIS .Nm -.Op Fl ABCFGHILPRSTUWZabcdfghiklmnopqrstuwx1 +.Op Fl ABCDFGHILNPRSTUVWZabcdefghiklmnopqrstuvwxz1 .Op Ar .Sh DESCRIPTION For each operand that names a @@ -88,6 +88,10 @@ is the numeric value of the character in octal. .It Fl C Force multi-column output; this is the default when output is to a terminal. +.It Fl D +Sorts directories first. This is independent of the +.Fl r +option. .It Fl F Display a slash .Pq Ql / @@ -132,6 +136,12 @@ This option cancels the .Fl P option. +.It Fl N +Negates sorting directories first or last (the +.Fl D +and +.Fl V +options). .It Fl P If argument is a symbolic link, list the link itself rather than the object the link references. @@ -154,6 +164,10 @@ month, day, hour, minute, second, and year. .It Fl U Use time when file was created for sorting or printing. +.It Fl V +Sorts directories last. This is independent of the +.Fl r +option. .It Fl W Display whiteouts when scanning directories. .It Fl Z @@ -173,6 +187,12 @@ Use time when file status was last changed for sorting or printing. .It Fl d Directories are listed as plain files (not searched recursively). +.It Fl e +List everything (not strictly, but negates the +.Fl v +and +.Fl z +options). .It Fl f Output is not sorted. .It Fl g @@ -242,6 +262,8 @@ .Pq Fl t or printing .Pq Fl l . +.It Fl v +Lists only directories. .It Fl w Force raw printing of non-printable characters. This is the default @@ -251,6 +273,8 @@ .Fl C , except that the multi-column output is produced with entries sorted across, rather than down, the columns. +.It Fl z +Lists only non-directories. .It Fl 1 (The numeric digit .Dq one . ) diff -u ls/ls.c ls.new/ls.c --- ls/ls.c Thu May 18 15:02:20 2006 +++ ls.new/ls.c Thu May 17 04:21:40 2007 @@ -105,6 +105,10 @@ /* flags */ int f_accesstime; /* use time of last access */ int f_birthtime; /* use time of birth */ +static int f_dirfirstsort; /* put directories first */ +static int f_dirlastsort; /* put directories last */ +static int f_dirlistonly; /* list directories only */ +static int f_dirlistnone; /* list non-directories only */ int f_flags; /* show flags associated with a file */ int f_humanval; /* show human-readable file sizes */ int f_inode; /* print inode */ @@ -179,11 +183,12 @@ fts_options = FTS_PHYSICAL; while ((ch = getopt(argc, argv, - "1ABCFGHILPRSTUWZabcdfghiklmnopqrstuwx")) != -1) { + "1ABCDFGHILNPRSTUVWZabcdefghiklmnopqrstuvwxz")) != -1) { switch (ch) { /* - * The -1, -C, -x and -l options all override each other so - * shell aliasing works right. + * The -1, -C, -x and -l options all override each other, + * as do also the -D and -Z options, and the -v and -z + * options so shell aliasing works right. */ case '1': f_singlecol = 1; @@ -198,6 +203,30 @@ case 'C': f_sortacross = f_longform = f_singlecol = 0; break; + case 'D': + f_dirfirstsort = 1; + f_dirlastsort = 0; + break; + case 'V': + f_dirfirstsort = 0; + f_dirlastsort = 1; + break; + case 'N': + f_dirfirstsort = 0; + f_dirlastsort = 0; + break; + case 'v': + f_dirlistonly = 1; + f_dirlistnone = 0; + break; + case 'z': + f_dirlistonly = 0; + f_dirlistnone = 1; + break; + case 'e': + f_dirlistonly = 0; + f_dirlistnone = 0; + break; case 'l': f_longform = 1; f_singlecol = 0; @@ -376,12 +405,13 @@ #endif /* - * If not -F, -i, -l, -s, -S or -t options, don't require stat - * information, unless in color mode in which case we do - * need this to determine which colors to display. + * If not -D, -V, -v, -z, -F, -i, -l, -s, -S or -t options, don't + * require stat information, unless in color mode in which case + * we do need this to determine which colors to display. */ if (!f_inode && !f_longform && !f_size && !f_timesort && - !f_sizesort && !f_type + !f_sizesort && !f_type && !f_dirfirstsort && !f_dirlastsort && + !f_dirlistonly && !f_dirlistnone #ifdef COLORLS && !f_color #endif @@ -426,6 +456,14 @@ sortfcn = revsizecmp; else /* Use modification time. */ sortfcn = revmodcmp; + if (f_dirfirstsort) { + real_sortfcn = sortfcn; + sortfcn = dirfcmp; + } else if (f_dirlastsort) { + real_sortfcn = sortfcn; + sortfcn = revdirfcmp; + } + } else { if (!f_timesort && !f_sizesort) sortfcn = namecmp; @@ -439,6 +477,14 @@ sortfcn = sizecmp; else /* Use modification time. */ sortfcn = modcmp; + if (f_dirfirstsort) { + real_sortfcn = sortfcn; + sortfcn = dirfcmp; + } else if (f_dirlastsort) { + real_sortfcn = sortfcn; + sortfcn = revdirfcmp; + } + } /* Select a print function. */ @@ -653,6 +699,20 @@ cur->fts_number = NO_PRINT; rval = 1; continue; + } + /* + * Tell to print (only dirs|no dirs) if set + */ + if (f_dirlistonly) { + if (checkisdir(cur)) { + cur->fts_number = NO_PRINT; + continue; + } + } else if (f_dirlistnone) { + if (! checkisdir(cur)) { + cur->fts_number = NO_PRINT; + continue; + } } /* * P is NULL if list is the argv list, to which different rules diff -u ls/util.c ls.new/util.c --- ls/util.c Thu May 18 15:02:20 2006 +++ ls.new/util.c Thu May 17 04:23:21 2007 @@ -222,9 +222,9 @@ { (void)fprintf(stderr, #ifdef COLORLS - "usage: ls [-ABCFGHILPRSTUWZabcdfghiklmnopqrstuwx1]" + "usage: ls [-ABCDFGHILNPRSTUVWZabcdefghiklmnopqrstuvwxz1]" #else - "usage: ls [-ABCFHILPRSTUWZabcdfghiklmnopqrstuwx1]" + "usage: ls [-ABCDFHILNPRSTUVWZabcdefghiklmnopqrstuvwxz1]" #endif " [file ...]\n"); exit(1);