bin/116425: [patch]ls options for pre-sort of directories first or last, & listing of directories or non-directories explicitly

Victor Vaile bsdls at vaile.info
Mon Sep 17 15:10:02 PDT 2007


>Number:         116425
>Category:       bin
>Synopsis:       [patch]ls options for pre-sort of directories first or last, & listing of directories or non-directories explicitly
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Mon Sep 17 22:10:01 GMT 2007
>Closed-Date:
>Last-Modified:
>Originator:     Victor Vaile
>Release:        6.2-STABLE-200708
>Organization:
>Environment:
FreeBSD engineering08.efilm.com 6.2-STABLE-200708 FreeBSD 6.2-STABLE-200708 #0: Tue Sep 11 12:26:16 UTC 2007     Rvev at engineering08.vaile.info:/usr/obj/usr/src/sys/ENGINEERINGSMP  i386
>Description:
I seem to recall seeing a PR asking about one of these options quite some time ago, however I didn't see any response posted back then, and my search today did not yeild any results. (If this is a duplicate request, my apologies are hereby included.)
The previous request had asked for a way to cause ls to return directories first or last in the listing, with the various sorting options applied to the directory, and non-directory groups individually.  In addition, I was looking for a way to get ls to output only directories, or only non-directories.  I don't recall when I started to use this initally, but I updated the patch that I used when I upgraded a machine to 6.2-RELEASE.  I've just installed a machine with 6.2-STABLE-200708 last week, and used the same updated patch today which still seems to work fine.
This is non-critical of course, and although I've not had the inclusion of the options added effect anything adversly on any of the systems I've installed it, I suspect there might be some discussion needed as to whether such options should be included in the regular distribution.  I have found the options to be quite handy.
As there aren't many free single character command line options left, my choices of options (D,V,N  for sorting directories first,last,no sort[normal], and v,z,e for listing only directories, only non-directories, everything [normal]) may not be all that intuitive, and could be changed if desired.

>How-To-Repeat:

>Fix:
I've included a patch that adds the features mentioned above to ls that works as of 6.2-STABLE-200708.  This also updates the manpage with the options added.

Patch attached with submission follows:

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);


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list