Hi, I've written an enhancement for 'ls' that lists directories first and then all other filetypes. We found that this is immensely useful, especially when using colors, and I'd like to contribute it. I'd be happy to see it in future versions of the GNU fileutils. I have attached a diff based on fileutils v3.16. Florian.
--- ls.c.orig Mon Jan 3 16:28:37 2000 +++ ls.c Wed Jan 5 10:38:36 2000 @@ -166,6 +166,10 @@ const struct fileinfo *file2)); static int rev_cmp_name __P ((const struct fileinfo *file2, const struct fileinfo *file1)); +static int compare_dirfirst __P ((const struct fileinfo *file1, + const struct fileinfo *file2)); +static int rev_cmp_dirfirst __P ((const struct fileinfo *file2, + const struct fileinfo *file1)); static int compare_extension __P ((const struct fileinfo *file1, const struct fileinfo *file2)); static int rev_cmp_extension __P ((const struct fileinfo *file2, @@ -282,12 +286,13 @@ int full_time; -/* The file characteristic to sort by. Controlled by -t, -S, -U, -X. */ +/* The file characteristic to sort by. Controlled by -e, -t, -S, -U, -X. */ enum sort_type { sort_none, /* -U */ sort_name, /* default */ + sort_dirfirst, /* -e */ sort_extension, /* -X */ sort_time, /* -t */ sort_size /* -S */ @@ -538,12 +543,12 @@ static char const *const sort_args[] = { - "none", "time", "size", "extension", 0 + "none", "dirfirst", "time", "size", "extension", 0 }; static enum sort_type const sort_types[] = { - sort_none, sort_time, sort_size, sort_extension + sort_none, sort_dirfirst, sort_time, sort_size, sort_extension }; static char const *const time_args[] = @@ -678,10 +683,11 @@ prep_non_filename_text (); } - format_needs_stat = sort_type == sort_time || sort_type == sort_size - || format == long_format + format_needs_stat = format == long_format + || sort_type == sort_time || sort_type == sort_size + || sort_type == sort_dirfirst || trace_links || trace_dirs || indicator_style != none - || print_block_size || print_inode || print_with_color; + || print_block_size || print_inode || print_with_color; if (dired && format == long_format) { @@ -865,7 +871,7 @@ } while ((c = getopt_long (argc, argv, - "abcdfgiklmnopqrstuw:xABCDFGI:LNQRST:UX1", + "abcdefgiklmnopqrstuw:xABCDFGI:LNQRST:UX1", long_options, (int *) 0)) != EOF) { switch (c) @@ -892,6 +898,10 @@ immediate_dirs = 1; break; + case 'e': + sort_type = sort_dirfirst; + break; + case 'f': /* Same as enabling -a -U and disabling -l -s. */ all_files = 1; @@ -1874,6 +1884,9 @@ case sort_name: func = sort_reverse ? rev_cmp_name : compare_name; break; + case sort_dirfirst: + func = sort_reverse ? rev_cmp_dirfirst : compare_dirfirst; + break; case sort_extension: func = sort_reverse ? rev_cmp_extension : compare_extension; break; @@ -1949,6 +1962,24 @@ return strcmp (file1->name, file2->name); } +static int +compare_dirfirst (const struct fileinfo *file1, + const struct fileinfo *file2) +{ + if (S_ISDIR(file1->stat.st_mode) == S_ISDIR(file2->stat.st_mode)) + return compare_name (file1, file2); + return S_ISDIR(file1->stat.st_mode) ? -1 : 1; +} + +static int +rev_cmp_dirfirst (const struct fileinfo *file2, + const struct fileinfo *file1) +{ + if (S_ISDIR(file1->stat.st_mode) == S_ISDIR(file2->stat.st_mode)) + return compare_name (file1, file2); + return S_ISDIR(file1->stat.st_mode) ? -1 : 1; +} + /* Compare file extensions. Files with no extension are `smallest'. If extensions are the same, compare by filenames instead. */ @@ -2753,6 +2784,7 @@ types. WHEN may be `never', `always', or `auto'\n\ -d, --directory list directory entries instead of contents\n\ -D, --dired generate output designed for Emacs' dired mode\n\ + -e sort by name and list directories first\n\ -f do not sort, enable -aU, disable -lst\n\ -F, --classify append a character for typing each entry\n\ --format=WORD across -x, commas -m, horizontal -x, long -l,\n\ @@ -2781,8 +2813,9 @@ printf (_("\ -S sort by file size\n\ - --sort=WORD ctime -c, extension -X, none -U, size -S,\n\ - status -c, time -t, atime -u, access -u, use -u\n\ + --sort=WORD ctime -c, extension -X, dirfirst -e, none -U,\n\ + size -S, status -c, time -t, atime -u, access -u,\n\ + use -u\n\ --time=WORD show time as WORD instead of modification time:\n\ atime, access, use, ctime or status\n\ -t sort by modification time; with -l: show mtime\n\