From owner-freebsd-bugs@FreeBSD.ORG Mon Sep 17 22:10:02 2007 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 5197A16A417 for ; Mon, 17 Sep 2007 22:10:02 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 3050F13C465 for ; Mon, 17 Sep 2007 22:10:02 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.14.1/8.14.1) with ESMTP id l8HMA2aL095554 for ; Mon, 17 Sep 2007 22:10:02 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.1/8.14.1/Submit) id l8HMA1rS095553; Mon, 17 Sep 2007 22:10:01 GMT (envelope-from gnats) Resent-Date: Mon, 17 Sep 2007 22:10:01 GMT Resent-Message-Id: <200709172210.l8HMA1rS095553@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Victor Vaile Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id E5E0B16A420 for ; Mon, 17 Sep 2007 22:00:41 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21]) by mx1.freebsd.org (Postfix) with ESMTP id EB0EF13C474 for ; Mon, 17 Sep 2007 22:00:41 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from www.freebsd.org (localhost [127.0.0.1]) by www.freebsd.org (8.14.1/8.14.1) with ESMTP id l8HM0f37004374 for ; Mon, 17 Sep 2007 22:00:41 GMT (envelope-from nobody@www.freebsd.org) Received: (from nobody@localhost) by www.freebsd.org (8.14.1/8.14.1/Submit) id l8HM0fYh004373; Mon, 17 Sep 2007 22:00:41 GMT (envelope-from nobody) Message-Id: <200709172200.l8HM0fYh004373@www.freebsd.org> Date: Mon, 17 Sep 2007 22:00:41 GMT From: Victor Vaile To: freebsd-gnats-submit@FreeBSD.org X-Send-Pr-Version: www-3.1 Cc: Subject: bin/116425: [patch]ls options for pre-sort of directories first or last, & listing of directories or non-directories explicitly X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 17 Sep 2007 22:10:02 -0000 >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@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: