1 /* `dir', `vdir' and `ls' directory listing programs for GNU.
2 Copyright (C) 1985, 1988, 1990, 1991 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
18 /* If the macro MULTI_COL is defined,
19 the multi-column format is the default regardless
20 of the type of output device.
21 This is for the `dir' program.
23 If the macro LONG_FORMAT is defined,
24 the long format is the default regardless of the
25 type of output device.
26 This is for the `vdir' program.
28 If neither is defined,
29 the output format depends on whether the output
31 This is for the `ls' program. */
33 /* Written by Richard Stallman and David MacKenzie. */
40 #include <sys/types.h>
41 #if !defined(_POSIX_SOURCE) || defined(_AIX)
42 #include <sys/ioctl.h>
58 #include "safe-stat.h"
59 #include "safe-lstat.h"
61 #define obstack_chunk_alloc xmalloc
62 #define obstack_chunk_free free
65 #define INT_MAX 2147483647
68 /* Return an int indicating the result of comparing two longs. */
69 #if (INT_MAX <= 65535)
70 #define longdiff(a, b) ((a) < (b) ? -1 : (a) > (b) ? 1 : 0)
72 #define longdiff(a, b) ((a) - (b))
75 /* The maximum number of digits required to print an inode number
76 in an unsigned format. */
78 #define INODE_DIGITS 7
99 static char *make_link_path ();
100 static int compare_atime ();
101 static int rev_cmp_atime ();
102 static int compare_ctime ();
103 static int rev_cmp_ctime ();
104 static int compare_mtime ();
105 static int rev_cmp_mtime ();
106 static int compare_size ();
107 static int rev_cmp_size ();
108 static int compare_name ();
109 static int rev_cmp_name ();
110 static int compare_extension ();
111 static int rev_cmp_extension ();
112 static int decode_switches ();
113 static int file_interesting ();
114 static int gobble_file ();
115 static int is_not_dot_or_dotdot ();
116 static int length_of_file_name_and_frills ();
117 static void add_ignore_pattern ();
118 static void attach ();
119 static void clear_files ();
120 static void extract_dirs_from_files ();
121 static void get_link_name ();
122 static void indent ();
123 static void print_current_files ();
124 static void print_dir ();
125 static void print_file_name_and_frills ();
126 static void print_horizontal ();
127 static void print_long_format ();
128 static void print_many_per_line ();
129 static void print_name_with_quoting ();
130 static void print_type_indicator ();
131 static void print_with_commas ();
132 static void queue_directory ();
133 static void sort_files ();
134 static void usage ();
137 /* The name the program was run with, stripped of any leading path. */
144 arg_directory, /* Directory given as command line arg. */
145 normal /* All others. */
155 /* For symbolic link, name of the file linked to, otherwise zero. */
158 /* For symbolic link and long listing, st_mode of file linked to, otherwise
160 unsigned int linkmode;
162 enum filetype filetype;
165 /* The table of files in the current directory:
167 `files' points to a vector of `struct fileinfo', one per file.
168 `nfiles' is the number of elements space has been allocated for.
169 `files_index' is the number actually in use. */
171 /* Address of block containing the files that are described. */
173 static struct fileinfo *files;
175 /* Length of block that `files' points to, measured in files. */
179 /* Index of first unused in `files'. */
181 static int files_index;
183 /* Record of one pending directory waiting to be listed. */
188 /* If the directory is actually the file pointed to by a symbolic link we
189 were told to list, `realname' will contain the name of the symbolic
190 link, otherwise zero. */
192 struct pending *next;
195 static struct pending *pending_dirs;
197 /* Current time (seconds since 1970). When we are printing a file's time,
198 include the year if it is more than 6 months before this time. */
200 static time_t current_time;
202 /* The number of digits to use for block sizes.
203 4, or more if needed for bigger numbers. */
205 static int block_size_size;
209 /* long_format for lots of info, one per line.
210 one_per_line for just names, one per line.
211 many_per_line for just names, many per line, sorted vertically.
212 horizontal for just names, many per line, sorted horizontally.
213 with_commas for just names, many per line, separated by commas.
215 -l, -1, -C, -x and -m control this parameter. */
219 long_format, /* -l */
220 one_per_line, /* -1 */
221 many_per_line, /* -C */
226 static enum format format;
228 /* Type of time to print or sort by. Controlled by -c and -u. */
232 time_mtime, /* default */
237 static enum time_type time_type;
239 /* print the full time, otherwise the standard unix heuristics. */
243 /* The file characteristic to sort by. Controlled by -t, -S, -U, -X. */
248 sort_name, /* default */
249 sort_extension, /* -X */
254 static enum sort_type sort_type;
256 /* Direction of sort.
257 0 means highest first if numeric,
258 lowest first if alphabetic;
259 these are the defaults.
260 1 means the opposite order in each case. -r */
262 static int sort_reverse;
264 /* Nonzero means to NOT display group information. -G */
268 /* Nonzero means print the user and group id's as numbers rather
271 static int numeric_users;
273 /* Nonzero means mention the size in 512 byte blocks of each file. -s */
275 static int print_block_size;
277 /* Nonzero means show file sizes in kilobytes instead of blocks
278 (the size of which is system-dependent). -k */
280 static int kilobyte_blocks;
282 /* Precede each line of long output (per file) with a string like `m,n:'
283 where M is the number of characters after the `:' and before the
284 filename and N is the length of the filename. Using this format,
285 Emacs' dired mode starts up twice as fast, and can handle all
286 strange characters in file names. */
289 /* none means don't mention the type of files.
290 all means mention the types of all files.
291 not_programs means do so except for executables.
293 Controlled by -F and -p. */
299 not_programs /* -p */
302 static enum indicator_style indicator_style;
304 /* Nonzero means mention the inode number of each file. -i */
306 static int print_inode;
308 /* Nonzero means when a symbolic link is found, display info on
309 the file linked to. -L */
311 static int trace_links;
313 /* Nonzero means when a directory is found, display info on its
316 static int trace_dirs;
318 /* Nonzero means when an argument is a directory name, display info
321 static int immediate_dirs;
323 /* Nonzero means don't omit files whose names start with `.'. -A */
325 static int all_files;
327 /* Nonzero means don't omit files `.' and `..'
328 This flag implies `all_files'. -a */
330 static int really_all_files;
332 /* A linked list of shell-style globbing patterns. If a non-argument
333 file name matches any of these patterns, it is omitted.
334 Controlled by -I. Multiple -I options accumulate.
335 The -B option adds `*~' and `.*~' to this list. */
337 struct ignore_pattern
340 struct ignore_pattern *next;
343 static struct ignore_pattern *ignore_patterns;
345 /* Nonzero means quote nongraphic chars in file names. -b */
347 static int quote_funny_chars;
349 /* Nonzero means output nongraphic chars in file names as `?'. -q */
351 static int qmark_funny_chars;
353 /* Nonzero means output each file name using C syntax for a string.
354 Always accompanied by `quote_funny_chars'.
355 This mode, together with -x or -C or -m,
356 and without such frills as -F or -s,
357 is guaranteed to make it possible for a program receiving
358 the output to tell exactly what file names are present. -Q */
360 static int quote_as_string;
362 /* The number of chars per hardware tab stop. -T */
365 /* Nonzero means we are listing the working directory because no
366 non-option arguments were given. */
368 static int dir_defaulted;
370 /* Nonzero means print each directory name before listing it. */
372 static int print_dir_name;
374 /* The line length to use for breaking lines in many-per-line format.
375 Can be set with -w. */
377 static int line_length;
379 /* If nonzero, the file listing format requires that stat be called on
382 static int format_needs_stat;
384 /* The exit status to use if we don't get any fatal errors. */
386 static int exit_status;
388 /* If non-zero, display usage information and exit. */
389 static int show_help;
391 /* If non-zero, print the version on standard output and exit. */
392 static int show_version;
394 static struct option const long_options[] =
396 {"all", no_argument, 0, 'a'},
397 {"escape", no_argument, 0, 'b'},
398 {"directory", no_argument, 0, 'd'},
399 {"dired", no_argument, 0, 'D'},
400 {"full-time", no_argument, &full_time, 1},
401 {"inode", no_argument, 0, 'i'},
402 {"kilobytes", no_argument, 0, 'k'},
403 {"numeric-uid-gid", no_argument, 0, 'n'},
404 {"no-group", no_argument, 0, 'G'},
405 {"hide-control-chars", no_argument, 0, 'q'},
406 {"reverse", no_argument, 0, 'r'},
407 {"size", no_argument, 0, 's'},
408 {"width", required_argument, 0, 'w'},
409 {"almost-all", no_argument, 0, 'A'},
410 {"ignore-backups", no_argument, 0, 'B'},
411 {"classify", no_argument, 0, 'F'},
412 {"file-type", no_argument, 0, 'F'},
413 {"ignore", required_argument, 0, 'I'},
414 {"dereference", no_argument, 0, 'L'},
415 {"literal", no_argument, 0, 'N'},
416 {"quote-name", no_argument, 0, 'Q'},
417 {"recursive", no_argument, 0, 'R'},
418 {"format", required_argument, 0, 12},
419 {"sort", required_argument, 0, 10},
420 {"tabsize", required_argument, 0, 'T'},
421 {"time", required_argument, 0, 11},
422 {"help", no_argument, &show_help, 1},
423 {"version", no_argument, &show_version, 1},
427 static char const* const format_args[] =
429 "verbose", "long", "commas", "horizontal", "across",
430 "vertical", "single-column", 0
433 static enum format const formats[] =
435 long_format, long_format, with_commas, horizontal, horizontal,
436 many_per_line, one_per_line
439 static char const* const sort_args[] =
441 "none", "time", "size", "extension", 0
444 static enum sort_type const sort_types[] =
446 sort_none, sort_time, sort_size, sort_extension
449 static char const* const time_args[] =
451 "atime", "access", "use", "ctime", "status", 0
454 /* This zero-based index is used solely with the --dired option.
455 When that option is in effect, this counter is incremented for each
456 character of output generated by this program so that the beginning
457 and ending indices (in that output) of every file name can be recorded
458 and later output themselves. */
459 static size_t dired_pos;
461 #define PUTCHAR(c) do {putchar ((c)); ++dired_pos;} while (0)
463 /* Write S to STREAM and increment DIRED_POS by S_LEN. */
464 #define FPUTS(s, stream, s_len) \
465 do {fputs ((s), (stream)); dired_pos += s_len;} while (0)
467 /* Like FPUTS, but for use when S is a literal string. */
468 #define FPUTS_LITERAL(s, stream) \
469 do {fputs ((s), (stream)); dired_pos += sizeof((s)) - 1;} while (0)
471 #define DIRED_INDENT() \
474 /* FIXME: remove the `&& format == long_format' clause. */ \
475 if (dired && format == long_format) \
476 FPUTS_LITERAL (" ", stdout); \
480 /* With --dired, store pairs of beginning and ending indices of filenames. */
481 static struct obstack dired_obstack;
483 /* With --dired and --recursive, store pairs of beginning and ending
484 indices of directory names. */
485 static struct obstack subdired_obstack;
487 /* Save the current index on the specified obstack, OBS. */
488 #define PUSH_CURRENT_DIRED_POS(obs) \
491 /* FIXME: remove the `&& format == long_format' clause. */ \
492 if (dired && format == long_format) \
493 obstack_grow ((obs), &dired_pos, sizeof (dired_pos)); \
497 static enum time_type const time_types[] =
499 time_atime, time_atime, time_atime, time_ctime, time_ctime
503 /* Write to standard output the string PREFIX followed by a space-separated
504 list of the integers stored in OS all on one line. */
507 dired_dump_obstack (prefix, os)
514 fputs (prefix, stdout);
515 n_pos = obstack_object_size (os) / sizeof (size_t);
516 pos = (size_t *) obstack_finish (os);
517 for (i = 0; i < n_pos; i++)
518 printf (" %d", (int) pos[i]);
519 fputs ("\n", stdout);
528 register struct pending *thispend;
534 current_time = time ((time_t *) 0);
536 program_name = argv[0];
537 i = decode_switches (argc, argv);
541 printf ("%s\n", version_string);
548 format_needs_stat = sort_type == sort_time || sort_type == sort_size
549 || format == long_format
550 || trace_links || trace_dirs || indicator_style != none
551 || print_block_size || print_inode;
553 if (dired && format == long_format)
555 obstack_init (&dired_obstack);
557 obstack_init (&subdired_obstack);
561 files = (struct fileinfo *) xmalloc (sizeof (struct fileinfo) * nfiles);
568 for (; i < argc; i++)
569 gobble_file (argv[i], 1, "");
574 gobble_file (".", 1, "");
576 queue_directory (".", 0);
583 extract_dirs_from_files ("", 0);
584 /* `files_index' might be zero now. */
588 print_current_files ();
592 else if (pending_dirs && pending_dirs->next == 0)
597 thispend = pending_dirs;
598 pending_dirs = pending_dirs->next;
599 print_dir (thispend->name, thispend->realname);
600 free (thispend->name);
601 if (thispend->realname)
602 free (thispend->realname);
607 if (dired && format == long_format)
609 /* No need to free these since we're about to exit. */
610 dired_dump_obstack ("//DIRED//", &dired_obstack);
612 dired_dump_obstack ("//SUBDIRED//", &subdired_obstack);
618 /* Set all the option flags according to the switches specified.
619 Return the index of the first non-option argument. */
622 decode_switches (argc, argv)
630 qmark_funny_chars = 0;
631 quote_funny_chars = 0;
633 /* initialize all switches to default settings */
638 /* This is for the `dir' program. */
639 format = many_per_line;
640 quote_funny_chars = 1;
644 /* This is for the `vdir' program. */
645 format = long_format;
646 quote_funny_chars = 1;
650 /* This is for the `ls' program. */
653 format = many_per_line;
654 qmark_funny_chars = 1;
658 format = one_per_line;
659 qmark_funny_chars = 0;
667 time_type = time_mtime;
669 sort_type = sort_name;
672 print_block_size = 0;
673 kilobyte_blocks = getenv ("POSIXLY_CORRECT") == 0;
674 indicator_style = none;
680 really_all_files = 0;
684 p = getenv ("COLUMNS");
685 line_length = p ? atoi (p) : 80;
691 if (ioctl (1, TIOCGWINSZ, &ws) != -1 && ws.ws_col != 0)
692 line_length = ws.ws_col;
696 p = getenv ("TABSIZE");
697 tabsize = p ? atoi (p) : 8;
699 while ((c = getopt_long (argc, argv, "abcdfgiklmnpqrstuw:xABCDFGI:LNQRST:UX1",
700 long_options, (int *) 0)) != EOF)
709 really_all_files = 1;
713 quote_funny_chars = 1;
714 qmark_funny_chars = 0;
718 time_type = time_ctime;
726 /* Same as enabling -a -U and disabling -l -s. */
728 really_all_files = 1;
729 sort_type = sort_none;
731 if (format == long_format)
732 format = (isatty (1) ? many_per_line : one_per_line);
733 print_block_size = 0; /* disable -s */
737 /* No effect. For BSD compatibility. */
749 format = long_format;
753 format = with_commas;
761 indicator_style = not_programs;
765 qmark_funny_chars = 1;
766 quote_funny_chars = 0;
774 print_block_size = 1;
778 sort_type = sort_time;
782 time_type = time_atime;
786 line_length = atoi (optarg);
788 error (1, 0, "invalid line width: %s", optarg);
800 add_ignore_pattern ("*~");
801 add_ignore_pattern (".*~");
805 format = many_per_line;
813 indicator_style = all;
816 case 'G': /* inhibit display of group info */
821 add_ignore_pattern (optarg);
829 quote_funny_chars = 0;
830 qmark_funny_chars = 0;
835 quote_funny_chars = 1;
836 qmark_funny_chars = 0;
844 sort_type = sort_size;
848 tabsize = atoi (optarg);
850 error (1, 0, "invalid tab size: %s", optarg);
854 sort_type = sort_none;
858 sort_type = sort_extension;
862 format = one_per_line;
866 i = argmatch (optarg, sort_args);
869 invalid_arg ("sort type", optarg, i);
872 sort_type = sort_types[i];
876 i = argmatch (optarg, time_args);
879 invalid_arg ("time type", optarg, i);
882 time_type = time_types[i];
885 case 12: /* +format */
886 i = argmatch (optarg, format_args);
889 invalid_arg ("format type", optarg, i);
903 /* Request that the directory named `name' have its contents listed later.
904 If `realname' is nonzero, it will be used instead of `name' when the
905 directory name is printed. This allows symbolic links to directories
906 to be treated as regular directories but still be listed under their
910 queue_directory (name, realname)
916 new = (struct pending *) xmalloc (sizeof (struct pending));
917 new->next = pending_dirs;
919 new->name = xstrdup (name);
921 new->realname = xstrdup (realname);
926 /* Read directory `name', and list the files in it.
927 If `realname' is nonzero, print its name instead of `name';
928 this is used for symbolic links to directories. */
931 print_dir (name, realname)
933 const char *realname;
935 register DIR *reading;
936 register struct dirent *next;
937 register int total_blocks = 0;
940 reading = opendir (name);
943 error (0, errno, "%s", name);
948 /* Read the directory entries, and insert the subfiles into the `files'
953 while ((next = readdir (reading)) != NULL)
954 if (file_interesting (next))
955 total_blocks += gobble_file (next->d_name, 0, name);
957 if (CLOSEDIR (reading))
959 error (0, errno, "%s", name);
961 /* Don't return; print whatever we got. */
964 /* Sort the directory contents. */
967 /* If any member files are subdirectories, perhaps they should have their
968 contents listed rather than being mentioned here as files. */
971 extract_dirs_from_files (name, 1);
978 dir = (realname ? realname : name);
979 PUSH_CURRENT_DIRED_POS (&subdired_obstack);
980 FPUTS (dir, stdout, strlen (dir));
981 PUSH_CURRENT_DIRED_POS (&subdired_obstack);
982 FPUTS_LITERAL (":\n", stdout);
985 if (format == long_format || print_block_size)
987 char buf[6 + 20 + 1 + 1];
990 sprintf (buf, "total %u\n", total_blocks);
991 FPUTS (buf, stdout, strlen (buf));
995 print_current_files ();
1001 /* Add `pattern' to the list of patterns for which files that match are
1005 add_ignore_pattern (pattern)
1008 register struct ignore_pattern *ignore;
1010 ignore = (struct ignore_pattern *) xmalloc (sizeof (struct ignore_pattern));
1011 ignore->pattern = pattern;
1012 /* Add it to the head of the linked list. */
1013 ignore->next = ignore_patterns;
1014 ignore_patterns = ignore;
1017 /* Return nonzero if the file in `next' should be listed. */
1020 file_interesting (next)
1021 register struct dirent *next;
1023 register struct ignore_pattern *ignore;
1025 for (ignore = ignore_patterns; ignore; ignore = ignore->next)
1026 if (fnmatch (ignore->pattern, next->d_name, FNM_PERIOD) == 0)
1029 if (really_all_files
1030 || next->d_name[0] != '.'
1032 && next->d_name[1] != '\0'
1033 && (next->d_name[1] != '.' || next->d_name[2] != '\0')))
1039 /* Enter and remove entries in the table `files'. */
1041 /* Empty the table of files. */
1048 for (i = 0; i < files_index; i++)
1050 free (files[i].name);
1051 if (files[i].linkname)
1052 free (files[i].linkname);
1056 block_size_size = 4;
1059 /* Add a file to the current table of files.
1060 Verify that the file exists, and print an error message if it does not.
1061 Return the number of blocks that the file occupies. */
1064 gobble_file (name, explicit_arg, dirname)
1069 register int blocks;
1071 register char *path;
1073 if (files_index == nfiles)
1076 files = (struct fileinfo *) xrealloc (files, sizeof (*files) * nfiles);
1079 files[files_index].linkname = 0;
1080 files[files_index].linkmode = 0;
1082 if (explicit_arg || format_needs_stat)
1084 /* `path' is the absolute pathname of this file. */
1086 if (name[0] == '/' || dirname[0] == 0)
1090 path = (char *) alloca (strlen (name) + strlen (dirname) + 2);
1091 attach (path, dirname, name);
1096 val = SAFE_STAT (path, &files[files_index].stat);
1098 /* Perhaps a symbolically-linked to file doesn't exist; stat
1099 the link instead. */
1100 val = SAFE_LSTAT (path, &files[files_index].stat);
1103 val = SAFE_LSTAT (path, &files[files_index].stat);
1106 error (0, errno, "%s", path);
1112 if (S_ISLNK (files[files_index].stat.st_mode)
1113 && (explicit_arg || format == long_format))
1116 struct stat linkstats;
1118 get_link_name (path, &files[files_index]);
1119 linkpath = make_link_path (path, files[files_index].linkname);
1121 /* Avoid following symbolic links when possible, ie, when
1122 they won't be traced and when no indicator is needed. */
1124 && ((explicit_arg && format != long_format)
1125 || indicator_style != none)
1126 && SAFE_STAT (linkpath, &linkstats) == 0)
1128 /* Symbolic links to directories that are mentioned on the
1129 command line are automatically traced if not being
1131 if (explicit_arg && format != long_format
1132 && S_ISDIR (linkstats.st_mode))
1134 /* Substitute the linked-to directory's name, but
1135 save the real name in `linkname' for printing. */
1136 if (!immediate_dirs)
1138 char *tempname = name;
1140 linkpath = files[files_index].linkname;
1141 files[files_index].linkname = tempname;
1143 files[files_index].stat = linkstats;
1146 /* Get the linked-to file's mode for the filetype indicator
1147 in long listings. */
1148 files[files_index].linkmode = linkstats.st_mode;
1156 if (S_ISLNK (files[files_index].stat.st_mode))
1157 files[files_index].filetype = symbolic_link;
1160 if (S_ISDIR (files[files_index].stat.st_mode))
1162 if (explicit_arg && !immediate_dirs)
1163 files[files_index].filetype = arg_directory;
1165 files[files_index].filetype = directory;
1168 files[files_index].filetype = normal;
1170 blocks = convert_blocks (ST_NBLOCKS (files[files_index].stat),
1172 if (blocks >= 10000 && block_size_size < 5)
1173 block_size_size = 5;
1174 if (blocks >= 100000 && block_size_size < 6)
1175 block_size_size = 6;
1176 if (blocks >= 1000000 && block_size_size < 7)
1177 block_size_size = 7;
1182 files[files_index].name = xstrdup (name);
1190 /* Put the name of the file that `filename' is a symbolic link to
1191 into the `linkname' field of `f'. */
1194 get_link_name (filename, f)
1199 register int linksize;
1201 linkbuf = (char *) alloca (PATH_MAX + 2);
1202 /* Some automounters give incorrect st_size for mount points.
1203 I can't think of a good workaround for it, though. */
1204 linksize = readlink (filename, linkbuf, PATH_MAX + 1);
1207 error (0, errno, "%s", filename);
1212 linkbuf[linksize] = '\0';
1213 f->linkname = xstrdup (linkbuf);
1217 /* If `linkname' is a relative path and `path' contains one or more
1218 leading directories, return `linkname' with those directories
1219 prepended; otherwise, return a copy of `linkname'.
1220 If `linkname' is zero, return zero. */
1223 make_link_path (path, linkname)
1233 if (*linkname == '/')
1234 return xstrdup (linkname);
1236 /* The link is to a relative path. Prepend any leading path
1237 in `path' to the link name. */
1238 linkbuf = rindex (path, '/');
1240 return xstrdup (linkname);
1242 bufsiz = linkbuf - path + 1;
1243 linkbuf = xmalloc (bufsiz + strlen (linkname) + 1);
1244 strncpy (linkbuf, path, bufsiz);
1245 strcpy (linkbuf + bufsiz, linkname);
1250 /* Remove any entries from `files' that are for directories,
1251 and queue them to be listed as directories instead.
1252 `dirname' is the prefix to prepend to each dirname
1253 to make it correct relative to ls's working dir.
1254 `recursive' is nonzero if we should not treat `.' and `..' as dirs.
1255 This is desirable when processing directories recursively. */
1258 extract_dirs_from_files (dirname, recursive)
1263 register char *path;
1266 dirlen = strlen (dirname) + 2;
1267 /* Queue the directories last one first, because queueing reverses the
1269 for (i = files_index - 1; i >= 0; i--)
1270 if ((files[i].filetype == directory || files[i].filetype == arg_directory)
1271 && (!recursive || is_not_dot_or_dotdot (files[i].name)))
1273 if (files[i].name[0] == '/' || dirname[0] == 0)
1275 queue_directory (files[i].name, files[i].linkname);
1279 path = (char *) xmalloc (strlen (files[i].name) + dirlen);
1280 attach (path, dirname, files[i].name);
1281 queue_directory (path, files[i].linkname);
1284 if (files[i].filetype == arg_directory)
1285 free (files[i].name);
1288 /* Now delete the directories from the table, compacting all the remaining
1291 for (i = 0, j = 0; i < files_index; i++)
1292 if (files[i].filetype != arg_directory)
1293 files[j++] = files[i];
1297 /* Return non-zero if `name' doesn't end in `.' or `..'
1298 This is so we don't try to recurse on `././././. ...' */
1301 is_not_dot_or_dotdot (name)
1306 t = rindex (name, '/');
1312 || (name[1] == '.' && name[2] == '\0')))
1318 /* Sort the files now in the table. */
1333 func = sort_reverse ? rev_cmp_ctime : compare_ctime;
1336 func = sort_reverse ? rev_cmp_mtime : compare_mtime;
1339 func = sort_reverse ? rev_cmp_atime : compare_atime;
1346 func = sort_reverse ? rev_cmp_name : compare_name;
1348 case sort_extension:
1349 func = sort_reverse ? rev_cmp_extension : compare_extension;
1352 func = sort_reverse ? rev_cmp_size : compare_size;
1358 qsort (files, files_index, sizeof (struct fileinfo), func);
1361 /* Comparison routines for sorting the files. */
1364 compare_ctime (file1, file2)
1365 struct fileinfo *file1, *file2;
1367 return longdiff (file2->stat.st_ctime, file1->stat.st_ctime);
1371 rev_cmp_ctime (file2, file1)
1372 struct fileinfo *file1, *file2;
1374 return longdiff (file2->stat.st_ctime, file1->stat.st_ctime);
1378 compare_mtime (file1, file2)
1379 struct fileinfo *file1, *file2;
1381 return longdiff (file2->stat.st_mtime, file1->stat.st_mtime);
1385 rev_cmp_mtime (file2, file1)
1386 struct fileinfo *file1, *file2;
1388 return longdiff (file2->stat.st_mtime, file1->stat.st_mtime);
1392 compare_atime (file1, file2)
1393 struct fileinfo *file1, *file2;
1395 return longdiff (file2->stat.st_atime, file1->stat.st_atime);
1399 rev_cmp_atime (file2, file1)
1400 struct fileinfo *file1, *file2;
1402 return longdiff (file2->stat.st_atime, file1->stat.st_atime);
1406 compare_size (file1, file2)
1407 struct fileinfo *file1, *file2;
1409 return longdiff (file2->stat.st_size, file1->stat.st_size);
1413 rev_cmp_size (file2, file1)
1414 struct fileinfo *file1, *file2;
1416 return longdiff (file2->stat.st_size, file1->stat.st_size);
1420 compare_name (file1, file2)
1421 struct fileinfo *file1, *file2;
1423 return strcmp (file1->name, file2->name);
1427 rev_cmp_name (file2, file1)
1428 struct fileinfo *file1, *file2;
1430 return strcmp (file1->name, file2->name);
1433 /* Compare file extensions. Files with no extension are `smallest'.
1434 If extensions are the same, compare by filenames instead. */
1437 compare_extension (file1, file2)
1438 struct fileinfo *file1, *file2;
1440 register char *base1, *base2;
1443 base1 = rindex (file1->name, '.');
1444 base2 = rindex (file2->name, '.');
1445 if (base1 == 0 && base2 == 0)
1446 return strcmp (file1->name, file2->name);
1451 cmp = strcmp (base1, base2);
1453 return strcmp (file1->name, file2->name);
1458 rev_cmp_extension (file2, file1)
1459 struct fileinfo *file1, *file2;
1461 register char *base1, *base2;
1464 base1 = rindex (file1->name, '.');
1465 base2 = rindex (file2->name, '.');
1466 if (base1 == 0 && base2 == 0)
1467 return strcmp (file1->name, file2->name);
1472 cmp = strcmp (base1, base2);
1474 return strcmp (file1->name, file2->name);
1478 /* List all the files now in the table. */
1481 print_current_files ()
1488 for (i = 0; i < files_index; i++)
1490 print_file_name_and_frills (files + i);
1496 print_many_per_line ();
1500 print_horizontal ();
1504 print_with_commas ();
1508 for (i = 0; i < files_index; i++)
1510 print_long_format (files + i);
1518 print_long_format (f)
1524 /* 7 fields that may (worst case be 64-bit integral values) require 20 bytes,
1525 10 character mode field,
1526 24 characters for the time,
1527 9 spaces following each of these fields,
1528 and 1 trailing NUL byte. */
1529 char bigbuf[7 * 20 + 10 + 24 + 9 + 1];
1533 mode_string (f->stat.st_mode, modebuf);
1539 when = f->stat.st_ctime;
1542 when = f->stat.st_mtime;
1545 when = f->stat.st_atime;
1549 strcpy (timebuf, ctime (&when));
1555 if (current_time > when + 6L * 30L * 24L * 60L * 60L /* Old. */
1556 || current_time < when - 60L * 60L) /* In the future. */
1558 /* The file is fairly old or in the future.
1559 POSIX says the cutoff is 6 months old;
1560 approximate this by 6*30 days.
1561 Allow a 1 hour slop factor for what is considered "the future",
1562 to allow for NFS server/client clock disagreement.
1563 Show the year instead of the time of day. */
1564 strcpy (timebuf + 11, timebuf + 19);
1573 sprintf (p, "%*lu ", INODE_DIGITS, (unsigned long) f->stat.st_ino);
1577 if (print_block_size)
1579 sprintf (p, "%*u ", block_size_size,
1580 (unsigned) convert_blocks (ST_NBLOCKS (f->stat),
1585 /* The space between the mode and the number of links is the POSIX
1586 "optional alternate access method flag". */
1587 sprintf (p, "%s %3u ", modebuf, (unsigned int) f->stat.st_nlink);
1591 sprintf (p, "%-8u ", (unsigned int) f->stat.st_uid);
1593 sprintf (p, "%-8.8s ", getuser (f->stat.st_uid));
1599 sprintf (p, "%-8u ", (unsigned int) f->stat.st_gid);
1601 sprintf (p, "%-8.8s ", getgroup (f->stat.st_gid));
1605 if (S_ISCHR (f->stat.st_mode) || S_ISBLK (f->stat.st_mode))
1606 sprintf (p, "%3u, %3u ", (unsigned) major (f->stat.st_rdev),
1607 (unsigned) minor (f->stat.st_rdev));
1609 sprintf (p, "%8lu ", (unsigned long) f->stat.st_size);
1612 sprintf (p, "%s ", full_time ? timebuf : timebuf + 4);
1616 FPUTS (bigbuf, stdout, p - bigbuf);
1617 PUSH_CURRENT_DIRED_POS (&dired_obstack);
1618 print_name_with_quoting (f->name);
1619 PUSH_CURRENT_DIRED_POS (&dired_obstack);
1621 if (f->filetype == symbolic_link)
1625 FPUTS_LITERAL (" -> ", stdout);
1626 print_name_with_quoting (f->linkname);
1627 if (indicator_style != none)
1628 print_type_indicator (f->linkmode);
1631 else if (indicator_style != none)
1632 print_type_indicator (f->stat.st_mode);
1636 /* Set QUOTED_LENGTH to strlen(P) and return NULL if P == quoted(P).
1637 Otherwise, return xmalloc'd storage containing the quoted version
1638 of P and set QUOTED_LENGTH to the length of the quoted P. */
1641 quote_filename (p, quoted_length)
1642 register const char *p;
1643 size_t *quoted_length;
1645 register unsigned char c;
1650 if (!quote_as_string && !quote_funny_chars && !qmark_funny_chars)
1652 *quoted_length = strlen (p);
1657 for (c = *p; c; c = *++p)
1659 if (quote_funny_chars)
1675 /* FIXME: why not just use the ISPRINT macro here? */
1676 if (!(c > 040 && c < 0177))
1683 if (!(c >= 040 && c < 0177) && qmark_funny_chars)
1690 if (!found_quotable)
1692 *quoted_length = p - p0;
1697 quoted = xmalloc (4 * strlen (p) + 1);
1700 #define SAVECHAR(c) *q++ = (c)
1701 #define SAVE_2_CHARS(c12) \
1702 do { *q++ = ((c12)[0]); \
1703 *q++ = ((c12)[1]); } while (0)
1705 if (quote_as_string)
1710 if (quote_funny_chars)
1715 SAVE_2_CHARS ("\\\\");
1719 SAVE_2_CHARS ("\\n");
1723 SAVE_2_CHARS ("\\b");
1727 SAVE_2_CHARS ("\\r");
1731 SAVE_2_CHARS ("\\t");
1735 SAVE_2_CHARS ("\\f");
1739 SAVE_2_CHARS ("\\ ");
1743 SAVE_2_CHARS ("\\\"");
1747 if (c > 040 && c < 0177)
1752 sprintf (buf, "\\%03o", (unsigned int) c);
1753 q = stpcpy (q, buf);
1759 if (c >= 040 && c < 0177)
1761 else if (!qmark_funny_chars)
1768 if (quote_as_string)
1771 *quoted_length = q - quoted;
1779 print_name_with_quoting (p)
1783 size_t quoted_length;
1785 quoted = quote_filename (p, "ed_length);
1786 FPUTS (quoted != NULL ? quoted : p, stdout, quoted_length);
1791 /* Print the file name of `f' with appropriate quoting.
1792 Also print file size, inode number, and filetype indicator character,
1793 as requested by switches. */
1796 print_file_name_and_frills (f)
1800 printf ("%*lu ", INODE_DIGITS, (unsigned long) f->stat.st_ino);
1802 if (print_block_size)
1803 printf ("%*u ", block_size_size,
1804 (unsigned) convert_blocks (ST_NBLOCKS (f->stat),
1807 print_name_with_quoting (f->name);
1809 if (indicator_style != none)
1810 print_type_indicator (f->stat.st_mode);
1814 print_type_indicator (mode)
1826 if (S_ISFIFO (mode))
1831 if (S_ISSOCK (mode))
1835 if (S_ISREG (mode) && indicator_style == all
1836 && (mode & (S_IEXEC | S_IXGRP | S_IXOTH)))
1841 length_of_file_name_and_frills (f)
1844 register char *p = f->name;
1846 register int len = 0;
1849 len += INODE_DIGITS + 1;
1851 if (print_block_size)
1852 len += 1 + block_size_size;
1854 if (quote_as_string)
1859 if (quote_funny_chars)
1874 if (quote_as_string)
1881 if (c >= 040 && c < 0177)
1891 if (indicator_style != none)
1893 unsigned filetype = f->stat.st_mode;
1895 if (S_ISREG (filetype))
1897 if (indicator_style == all
1898 && (f->stat.st_mode & (S_IEXEC | S_IEXEC >> 3 | S_IEXEC >> 6)))
1901 else if (S_ISDIR (filetype)
1903 || S_ISLNK (filetype)
1906 || S_ISFIFO (filetype)
1909 || S_ISSOCK (filetype)
1919 print_many_per_line ()
1921 int filesno; /* Index into files. */
1922 int row; /* Current row. */
1923 int max_name_length; /* Length of longest file name + frills. */
1924 int name_length; /* Length of each file name + frills. */
1925 int pos; /* Current character column. */
1926 int cols; /* Number of files across. */
1927 int rows; /* Maximum number of files down. */
1929 /* Compute the maximum file name length. */
1930 max_name_length = 0;
1931 for (filesno = 0; filesno < files_index; filesno++)
1933 name_length = length_of_file_name_and_frills (files + filesno);
1934 if (name_length > max_name_length)
1935 max_name_length = name_length;
1938 /* Allow at least two spaces between names. */
1939 max_name_length += 2;
1941 /* Calculate the maximum number of columns that will fit. */
1942 cols = line_length / max_name_length;
1945 /* Calculate the number of rows that will be in each column except possibly
1946 for a short column on the right. */
1947 rows = files_index / cols + (files_index % cols != 0);
1948 /* Recalculate columns based on rows. */
1949 cols = files_index / rows + (files_index % rows != 0);
1951 for (row = 0; row < rows; row++)
1955 /* Print the next row. */
1958 print_file_name_and_frills (files + filesno);
1959 name_length = length_of_file_name_and_frills (files + filesno);
1962 if (filesno >= files_index)
1965 indent (pos + name_length, pos + max_name_length);
1966 pos += max_name_length;
1976 int max_name_length;
1981 /* Compute the maximum file name length. */
1982 max_name_length = 0;
1983 for (filesno = 0; filesno < files_index; filesno++)
1985 name_length = length_of_file_name_and_frills (files + filesno);
1986 if (name_length > max_name_length)
1987 max_name_length = name_length;
1990 /* Allow two spaces between names. */
1991 max_name_length += 2;
1993 cols = line_length / max_name_length;
2000 for (filesno = 0; filesno < files_index; filesno++)
2004 if (filesno % cols == 0)
2011 indent (pos + name_length, pos + max_name_length);
2012 pos += max_name_length;
2016 print_file_name_and_frills (files + filesno);
2018 name_length = length_of_file_name_and_frills (files + filesno);
2024 print_with_commas ()
2031 for (filesno = 0; filesno < files_index; filesno++)
2035 pos += length_of_file_name_and_frills (files + filesno);
2036 if (filesno + 1 < files_index)
2037 pos += 2; /* For the comma and space */
2039 if (old_pos != 0 && pos >= line_length)
2045 print_file_name_and_frills (files + filesno);
2046 if (filesno + 1 < files_index)
2055 /* Assuming cursor is at position FROM, indent up to position TO. */
2063 if (to / tabsize > from / tabsize)
2066 from += tabsize - from % tabsize;
2076 /* Put DIRNAME/NAME into DEST, handling `.' and `/' properly. */
2079 attach (dest, dirname, name)
2080 char *dest, *dirname, *name;
2082 char *dirnamep = dirname;
2084 /* Copy dirname if it is not ".". */
2085 if (dirname[0] != '.' || dirname[1] != 0)
2088 *dest++ = *dirnamep++;
2089 /* Add '/' if `dirname' doesn't already end with it. */
2090 if (dirnamep > dirname && dirnamep[-1] != '/')
2103 fprintf (stderr, "Try `%s --help' for more information.\n",
2107 printf ("Usage: %s [OPTION]... [PATH]...\n", program_name);
2110 -A, --almost-all do not list implied . and ..\n\
2111 -a, --all do not hide entries starting with .\n\
2112 -B, --ignore-backups do not list implied entries ending with ~\n\
2113 -b, --escape print octal escapes for nongraphic characters\n\
2114 -C list entries by columns\n\
2115 -c sort by change time; with -l: show ctime\n\
2116 -D, --dired generate output well suited to Emacs' dired mode\n\
2117 -d, --directory list directory entries instead of contents\n\
2118 -F, --classify append a character for typing each entry\n\
2119 -f do not sort, enable -aU, disable -lst\n\
2120 --format=WORD across -x, commas -m, horizontal -x, long -l,\n\
2121 single-column -1, verbose -l, vertical -C\n\
2122 --full-time list both full date and full time\n");
2125 -G, --no-group inhibit display of group information\n\
2127 -I, --ignore=PATTERN do not list implied entries matching shell PATTERN\n\
2128 -i, --inode print index number of each file\n\
2129 -k, --kilobytes use 1024 blocks, not 512 despite POSIXLY_CORRECT\n\
2130 -L, --dereference list entries pointed to by symbolic links\n\
2131 -l use a long listing format\n\
2132 -m fill width with a comma separated list of entries\n\
2133 -N, --literal do not quote entry names\n\
2134 -n, --numeric-uid-gid list numeric UIDs and GIDs instead of names\n\
2135 -p append a character for typing each entry\n\
2136 -Q, --quote-name enclose entry names in double quotes\n\
2137 -q, --hide-control-chars print ? instead of non graphic characters\n\
2138 -R, --recursive list subdirectories recursively\n\
2139 -r, --reverse reverse order while sorting\n\
2140 -S sort by file size\n");
2143 -s, --size print block size of each file\n\
2144 --sort=WORD ctime -c, extension -X, none -U, size -S,\n\
2145 status -c, time -t\n\
2146 --time=WORD atime -u, access -u, use -u\n\
2147 -T, --tabsize=COLS assume tab stops at each COLS instead of 8\n\
2148 -t sort by modification time; with -l: show mtime\n\
2149 -U do not sort; list entries in directory order\n\
2150 -u sort by last access time; with -l: show atime\n\
2151 -w, --width=COLS assume screen width instead of current value\n\
2152 -x list entries by lines instead of by columns\n\
2153 -X sort alphabetically by entry extension\n\
2154 -1 list one file per line\n\
2155 --help display this help and exit\n\
2156 --version output version information and exit\n\
2158 Sort entries alphabetically if none of -cftuSUX nor --sort.\n");