diff --git a/bin/ls/ls.1 b/bin/ls/ls.1 --- a/bin/ls/ls.1 +++ b/bin/ls/ls.1 @@ -41,6 +41,8 @@ .Nm .Op Fl ABCFGHILPRSTUWZabcdfghiklmnopqrstuvwxy1\&, .Op Fl -color Ns = Ns Ar when +.Op Fl -group-directories Ns = Ns Ar order +.Op Fl -group-directories-first .Op Fl D Ar format .Op Ar .Sh DESCRIPTION @@ -305,6 +307,16 @@ Display the long .Pq Fl l format output without the file owner's name or number. +.It Fl -group-directories Ns = Ns Ar order +Within results for each operand, +group directories together and print them either +.Cm first +or +.Cm last. +.It Fl -group-directories-first +Equivalent to +.Fl -group-directories Ns = Ns Ar first . +Implemented for compatibility with GNU coreutils. .It Fl h When used with the .Fl l @@ -915,8 +927,13 @@ .St -p1003.1-2008 . The options .Fl B , D , G , I , T , U , W , Z , b , h , v , w , y -and +, .Fl , +.Fl -color +and +.Fl -group-directories Ns = +(including +.Fl -group-directories-first ) are non-standard extensions. .Pp The ACL support is compatible with diff --git a/bin/ls/ls.c b/bin/ls/ls.c --- a/bin/ls/ls.c +++ b/bin/ls/ls.c @@ -99,12 +99,24 @@ static int mastercmp(const FTSENT * const *, const FTSENT * const *); static void traverse(int, char **, int); -#define COLOR_OPT (CHAR_MAX + 1) +enum { + GRP_NONE = 0, + GRP_DIR_FIRST = -1, + GRP_DIR_LAST = 1 +}; + +enum { + BIN_OPT = CHAR_MAX, + COLOR_OPT, + GROUP_OPT +}; static const struct option long_opts[] = { - {"color", optional_argument, NULL, COLOR_OPT}, - {NULL, no_argument, NULL, 0} + {"color", optional_argument, NULL, COLOR_OPT}, + {"group-directories", optional_argument, NULL, GROUP_OPT}, + {"group-directories-first", no_argument, NULL, GROUP_OPT}, + {NULL, no_argument, NULL, 0} }; static void (*printfcn)(const DISPLAY *); @@ -117,6 +129,7 @@ int f_accesstime; /* use time of last access */ int f_birthtime; /* use time of birth */ int f_flags; /* show flags associated with a file */ +static int f_groupdir = GRP_NONE;/* group directories first/last */ int f_humanval; /* show human-readable file sizes */ int f_inode; /* print inode */ static int f_kblocks; /* print size in kilobytes */ @@ -461,6 +474,15 @@ case 'y': f_samesort = 1; break; + case GROUP_OPT: + if (optarg == NULL || strcmp(optarg, "first") == 0) + f_groupdir = GRP_DIR_FIRST; + else if (strcmp(optarg, "last") == 0) + f_groupdir = GRP_DIR_LAST; + else + errx(2, "unsupported --group-directories value '%s' (must be first or last)", + optarg); + break; case COLOR_OPT: #ifdef COLORLS if (optarg == NULL || do_color_always(optarg)) @@ -1013,7 +1035,7 @@ static int mastercmp(const FTSENT * const *a, const FTSENT * const *b) { - int a_info, b_info; + int a_info, b_info, dir; a_info = (*a)->fts_info; if (a_info == FTS_ERR) @@ -1032,5 +1054,10 @@ if (b_info == FTS_D) return (-1); } + + if (f_groupdir != GRP_NONE) + if ((dir = (a_info == FTS_D) - (b_info == FTS_D)) != 0) + return (f_groupdir * dir); + return (sortfcn(*a, *b)); } diff --git a/bin/ls/util.c b/bin/ls/util.c --- a/bin/ls/util.c +++ b/bin/ls/util.c @@ -225,9 +225,9 @@ { (void)fprintf(stderr, #ifdef COLORLS - "usage: ls [-ABCFGHILPRSTUWZabcdfghiklmnopqrstuvwxy1,] [--color=when] [-D format]" + "usage: ls [-ABCFGHILPRSTUWZabcdfghiklmnopqrstuvwxy1,] [--color=when] [-D format] [--group-directories=]" #else - "usage: ls [-ABCFHILPRSTUWZabcdfghiklmnopqrstuvwxy1,] [-D format]" + "usage: ls [-ABCFHILPRSTUWZabcdfghiklmnopqrstuvwxy1,] [-D format] [--group-directories=]" #endif " [file ...]\n"); exit(1);