(print_long_format): First patch from Paul Eggert.
[platform/upstream/coreutils.git] / src / ls.c
1 /* `dir', `vdir' and `ls' directory listing programs for GNU.
2    Copyright (C) 85, 88, 90, 91, 95, 1996 Free Software Foundation, Inc.
3
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)
7    any later version.
8
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.
13
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 Foundation,
16    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 /* If ls_mode is LS_MULTI_COL,
19    the multi-column format is the default regardless
20    of the type of output device.
21    This is for the `dir' program.
22
23    If ls_mode is LS_LONG_FORMAT,
24    the long format is the default regardless of the
25    type of output device.
26    This is for the `vdir' program.
27
28    If ls_mode is LS_LS,
29    the output format depends on whether the output
30    device is a terminal.
31    This is for the `ls' program. */
32
33 /* Written by Richard Stallman and David MacKenzie.  */
34
35 /* Color support by Peter Anvin <Peter.Anvin@linux.org> and Dennis
36    Flaherty <dennisf@denix.elk.miles.com> based on original patches by
37    Greg Lee <lee@uhunix.uhcc.hawaii.edu>.  */
38
39 #ifdef _AIX
40  #pragma alloca
41 #endif
42
43 #include <config.h>
44 #include <sys/types.h>
45
46 #include <termios.h>
47 #ifdef GWINSZ_IN_SYS_IOCTL
48 # include <sys/ioctl.h>
49 #endif
50
51 #include <stdio.h>
52 #include <grp.h>
53 #include <pwd.h>
54 #include <getopt.h>
55
56 #if HAVE_LIMITS_H
57 /* limits.h must come before system.h because limits.h on some systems
58    undefs PATH_MAX, whereas system.h includes pathmax.h which sets
59    PATH_MAX.  */
60 # include <limits.h>
61 #endif
62
63 #include "system.h"
64 #include <fnmatch.h>
65
66 #include "obstack.h"
67 #include "ls.h"
68 #include "error.h"
69 #include "argmatch.h"
70 #include "xstrtol.h"
71
72 #define obstack_chunk_alloc xmalloc
73 #define obstack_chunk_free free
74
75 #ifndef INT_MAX
76 # define INT_MAX 2147483647
77 #endif
78
79 /* Return an int indicating the result of comparing two longs. */
80 #if (INT_MAX <= 65535)
81 # define longdiff(a, b) ((a) < (b) ? -1 : (a) > (b) ? 1 : 0)
82 #else
83 # define longdiff(a, b) ((a) - (b))
84 #endif
85
86 /* The maximum number of digits required to print an inode number
87    in an unsigned format.  */
88 #ifndef INODE_DIGITS
89 # define INODE_DIGITS 7
90 #endif
91
92 enum filetype
93   {
94     symbolic_link,
95     directory,
96     arg_directory,              /* Directory given as command line arg. */
97     normal                      /* All others. */
98   };
99
100 struct fileinfo
101   {
102     /* The file name. */
103     char *name;
104
105     struct stat stat;
106
107     /* For symbolic link, name of the file linked to, otherwise zero. */
108     char *linkname;
109
110     /* For symbolic link and long listing, st_mode of file linked to, otherwise
111        zero. */
112     unsigned int linkmode;
113
114     /* For symbolic link and color printing, 1 if linked-to file
115        exists, otherwise 0.  */
116     int linkok;
117
118     enum filetype filetype;
119   };
120
121 #define LEN_STR_PAIR(s) sizeof (s) - 1, s
122
123 /* Null is a valid character in a color indicator (think about Epson
124    printers, for example) so we have to use a length/buffer string
125    type.  */
126
127 struct bin_str
128   {
129     unsigned int len;           /* Number of bytes */
130     char *string;               /* Pointer to the same */
131   };
132
133 #ifndef STDC_HEADERS
134 time_t time ();
135 void free ();
136 #endif
137
138 void mode_string ();
139
140 char *stpcpy ();
141 char *xstrdup ();
142 char *getgroup ();
143 char *getuser ();
144 char *xmalloc ();
145 char *xrealloc ();
146 void invalid_arg ();
147
148 static char *make_link_path __P ((const char *path, const char *linkname));
149 static int compare_atime __P ((const struct fileinfo *file1,
150                                const struct fileinfo *file2));
151 static int rev_cmp_atime __P ((const struct fileinfo *file2,
152                                const struct fileinfo *file1));
153 static int compare_ctime __P ((const struct fileinfo *file1,
154                                const struct fileinfo *file2));
155 static int rev_cmp_ctime __P ((const struct fileinfo *file2,
156                                const struct fileinfo *file1));
157 static int compare_mtime __P ((const struct fileinfo *file1,
158                                const struct fileinfo *file2));
159 static int rev_cmp_mtime __P ((const struct fileinfo *file2,
160                                const struct fileinfo *file1));
161 static int compare_size __P ((const struct fileinfo *file1,
162                               const struct fileinfo *file2));
163 static int rev_cmp_size __P ((const struct fileinfo *file2,
164                               const struct fileinfo *file1));
165 static int compare_name __P ((const struct fileinfo *file1,
166                               const struct fileinfo *file2));
167 static int rev_cmp_name __P ((const struct fileinfo *file2,
168                               const struct fileinfo *file1));
169 static int compare_extension __P ((const struct fileinfo *file1,
170                                    const struct fileinfo *file2));
171 static int rev_cmp_extension __P ((const struct fileinfo *file2,
172                                    const struct fileinfo *file1));
173 static int decode_switches __P ((int argc, char **argv));
174 static int file_interesting __P ((const struct dirent *next));
175 static int gobble_file __P ((const char *name, int explicit_arg,
176                              const char *dirname));
177 static int is_not_dot_or_dotdot __P ((const char *name));
178 static void print_color_indicator __P ((const char *name, unsigned int mode,
179                                         int linkok));
180 static void put_indicator __P ((const struct bin_str *ind));
181 static int length_of_file_name_and_frills __P ((const struct fileinfo *f));
182 static void add_ignore_pattern __P ((const char *pattern));
183 static void attach __P ((char *dest, const char *dirname, const char *name));
184 static void clear_files __P ((void));
185 static void extract_dirs_from_files __P ((const char *dirname, int recursive));
186 static void get_link_name __P ((const char *filename, struct fileinfo *f));
187 static void indent __P ((int from, int to));
188 static void print_current_files __P ((void));
189 static void print_dir __P ((const char *name, const char *realname));
190 static void print_file_name_and_frills __P ((const struct fileinfo *f));
191 static void print_horizontal __P ((void));
192 static void print_long_format __P ((const struct fileinfo *f));
193 static void print_many_per_line __P ((void));
194 static void print_name_with_quoting __P ((const char *p, unsigned int mode,
195                                           int linkok));
196 static void prep_non_filename_text __P ((void));
197 static void print_type_indicator __P ((unsigned int mode));
198 static void print_with_commas __P ((void));
199 static void queue_directory __P ((const char *name, const char *realname));
200 static void sort_files __P ((void));
201 static void parse_ls_color __P ((void));
202 static void usage __P ((int status));
203
204 /* The name the program was run with, stripped of any leading path. */
205 char *program_name;
206
207 /* The table of files in the current directory:
208
209    `files' points to a vector of `struct fileinfo', one per file.
210    `nfiles' is the number of elements space has been allocated for.
211    `files_index' is the number actually in use.  */
212
213 /* Address of block containing the files that are described.  */
214
215 static struct fileinfo *files;
216
217 /* Length of block that `files' points to, measured in files.  */
218
219 static int nfiles;
220
221 /* Index of first unused in `files'.  */
222
223 static int files_index;
224
225 /* Record of one pending directory waiting to be listed.  */
226
227 struct pending
228   {
229     char *name;
230     /* If the directory is actually the file pointed to by a symbolic link we
231        were told to list, `realname' will contain the name of the symbolic
232        link, otherwise zero. */
233     char *realname;
234     struct pending *next;
235   };
236
237 static struct pending *pending_dirs;
238
239 /* Current time (seconds since 1970).  When we are printing a file's time,
240    include the year if it is more than 6 months before this time.  */
241
242 static time_t current_time;
243
244 /* The number of digits to use for block sizes.
245    4, or more if needed for bigger numbers.  */
246
247 static int block_size_size;
248
249 /* Option flags */
250
251 /* long_format for lots of info, one per line.
252    one_per_line for just names, one per line.
253    many_per_line for just names, many per line, sorted vertically.
254    horizontal for just names, many per line, sorted horizontally.
255    with_commas for just names, many per line, separated by commas.
256
257    -l, -1, -C, -x and -m control this parameter.  */
258
259 enum format
260   {
261     long_format,                /* -l */
262     one_per_line,               /* -1 */
263     many_per_line,              /* -C */
264     horizontal,                 /* -x */
265     with_commas                 /* -m */
266   };
267
268 static enum format format;
269
270 /* Type of time to print or sort by.  Controlled by -c and -u.  */
271
272 enum time_type
273   {
274     time_mtime,                 /* default */
275     time_ctime,                 /* -c */
276     time_atime                  /* -u */
277   };
278
279 static enum time_type time_type;
280
281 /* print the full time, otherwise the standard unix heuristics. */
282
283 int full_time;
284
285 /* The file characteristic to sort by.  Controlled by -t, -S, -U, -X. */
286
287 enum sort_type
288   {
289     sort_none,                  /* -U */
290     sort_name,                  /* default */
291     sort_extension,             /* -X */
292     sort_time,                  /* -t */
293     sort_size                   /* -S */
294   };
295
296 static enum sort_type sort_type;
297
298 /* Direction of sort.
299    0 means highest first if numeric,
300    lowest first if alphabetic;
301    these are the defaults.
302    1 means the opposite order in each case.  -r  */
303
304 static int sort_reverse;
305
306 /* Nonzero means to NOT display group information.  -G  */
307
308 int inhibit_group;
309
310 /* Nonzero means print the user and group id's as numbers rather
311    than as names.  -n  */
312
313 static int numeric_users;
314
315 /* Nonzero means mention the size in 512 byte blocks of each file.  -s  */
316
317 static int print_block_size;
318
319 /* Nonzero means show file sizes in kilobytes instead of blocks
320    (the size of which is system-dependent).  -k */
321
322 static int kilobyte_blocks;
323
324 /* Precede each line of long output (per file) with a string like `m,n:'
325    where M is the number of characters after the `:' and before the
326    filename and N is the length of the filename.  Using this format,
327    Emacs' dired mode starts up twice as fast, and can handle all
328    strange characters in file names.  */
329 static int dired;
330
331 /* `none' means don't mention the type of files.
332    `all' means mention the types of all files.
333    `not_programs' means do so except for executables.
334
335    Controlled by -F and -p.  */
336
337 enum indicator_style
338   {
339     none,                      /* default */
340     all,                       /* -F */
341     not_programs               /* -p */
342   };
343
344 static enum indicator_style indicator_style;
345
346 /* Nonzero means use colors to mark types.  Also define the different
347    colors as well as the stuff for the LS_COLORS environment variable.
348    The LS_COLORS variable is now in a termcap-like format.  */
349
350 static int print_with_color;
351
352 enum color_type
353   {
354     color_never,                /* 0: default or --color=never */
355     color_always,               /* 1: --color=always */
356     color_if_tty                /* 2: --color=tty */
357   };
358
359 enum indicator_no
360   {
361     C_LEFT, C_RIGHT, C_END, C_NORM, C_FILE, C_DIR, C_LINK, C_FIFO, C_SOCK,
362     C_BLK, C_CHR, C_MISSING, C_ORPHAN, C_EXEC
363   };
364
365 static const char *const indicator_name[]=
366   {
367     "lc", "rc", "ec", "no", "fi", "di", "ln", "pi", "so",
368     "bd", "cd", "mi", "or", "ex", NULL
369   };
370
371 struct col_ext_type
372   {
373     struct bin_str ext;         /* The extension we're looking for */
374     struct bin_str seq;         /* The sequence to output when we do */
375     struct col_ext_type *next;  /* Next in list */
376   };
377
378 static struct bin_str color_indicator[] =
379   {
380     { LEN_STR_PAIR ("\033[") },         /* lc: Left of color sequence */
381     { LEN_STR_PAIR ("m") },             /* rc: Right of color sequence */
382     { 0, NULL },                        /* ec: End color (replaces lc+no+rc) */
383     { LEN_STR_PAIR ("0") },             /* no: Normal */
384     { LEN_STR_PAIR ("0") },             /* fi: File: default */
385     { LEN_STR_PAIR ("01;34") },         /* di: Directory: bright blue */
386     { LEN_STR_PAIR ("01;36") },         /* ln: Symlink: bright cyan */
387     { LEN_STR_PAIR ("33") },            /* pi: Pipe: yellow/brown */
388     { LEN_STR_PAIR ("01;35") },         /* so: Socket: bright magenta */
389     { LEN_STR_PAIR ("01;33") },         /* bd: Block device: bright yellow */
390     { LEN_STR_PAIR ("01;33") },         /* cd: Char device: bright yellow */
391     { 0, NULL },                        /* mi: Missing file: undefined */
392     { 0, NULL },                        /* or: Orphanned symlink: undefined */
393     { LEN_STR_PAIR ("01;32") }          /* ex: Executable: bright green */
394   };
395
396 /* FIXME: comment  */
397 struct col_ext_type *col_ext_list = NULL;
398
399 /* Buffer for color sequences */
400 static char *color_buf;
401
402 /* Nonzero means mention the inode number of each file.  -i  */
403
404 static int print_inode;
405
406 /* Nonzero means when a symbolic link is found, display info on
407    the file linked to.  -L  */
408
409 static int trace_links;
410
411 /* Nonzero means when a directory is found, display info on its
412    contents.  -R  */
413
414 static int trace_dirs;
415
416 /* Nonzero means when an argument is a directory name, display info
417    on it itself.  -d  */
418
419 static int immediate_dirs;
420
421 /* Nonzero means don't omit files whose names start with `.'.  -A */
422
423 static int all_files;
424
425 /* Nonzero means don't omit files `.' and `..'
426    This flag implies `all_files'.  -a  */
427
428 static int really_all_files;
429
430 /* A linked list of shell-style globbing patterns.  If a non-argument
431    file name matches any of these patterns, it is omitted.
432    Controlled by -I.  Multiple -I options accumulate.
433    The -B option adds `*~' and `.*~' to this list.  */
434
435 struct ignore_pattern
436   {
437     const char *pattern;
438     struct ignore_pattern *next;
439   };
440
441 static struct ignore_pattern *ignore_patterns;
442
443 /* Nonzero means quote nongraphic chars in file names.  -b  */
444
445 static int quote_funny_chars;
446
447 /* Nonzero means output nongraphic chars in file names as `?'.  -q  */
448
449 static int qmark_funny_chars;
450
451 /* Nonzero means output each file name using C syntax for a string.
452    Always accompanied by `quote_funny_chars'.
453    This mode, together with -x or -C or -m,
454    and without such frills as -F or -s,
455    is guaranteed to make it possible for a program receiving
456    the output to tell exactly what file names are present.  -Q  */
457
458 static int quote_as_string;
459
460 /* The number of chars per hardware tab stop.  Setting this to zero
461    inhibits the use of TAB characters for separating columns.  -T */
462 static int tabsize;
463
464 /* Nonzero means we are listing the working directory because no
465    non-option arguments were given. */
466
467 static int dir_defaulted;
468
469 /* Nonzero means print each directory name before listing it. */
470
471 static int print_dir_name;
472
473 /* The line length to use for breaking lines in many-per-line format.
474    Can be set with -w.  */
475
476 static int line_length;
477
478 /* If nonzero, the file listing format requires that stat be called on
479    each file. */
480
481 static int format_needs_stat;
482
483 /* The exit status to use if we don't get any fatal errors. */
484
485 static int exit_status;
486
487 /* If nonzero, display usage information and exit.  */
488 static int show_help;
489
490 /* If nonzero, print the version on standard output and exit.  */
491 static int show_version;
492
493 static struct option const long_options[] =
494 {
495   {"all", no_argument, 0, 'a'},
496   {"escape", no_argument, 0, 'b'},
497   {"directory", no_argument, 0, 'd'},
498   {"dired", no_argument, 0, 'D'},
499   {"full-time", no_argument, &full_time, 1},
500   {"inode", no_argument, 0, 'i'},
501   {"kilobytes", no_argument, 0, 'k'},
502   {"numeric-uid-gid", no_argument, 0, 'n'},
503   {"no-group", no_argument, 0, 'G'},
504   {"hide-control-chars", no_argument, 0, 'q'},
505   {"reverse", no_argument, 0, 'r'},
506   {"size", no_argument, 0, 's'},
507   {"width", required_argument, 0, 'w'},
508   {"almost-all", no_argument, 0, 'A'},
509   {"ignore-backups", no_argument, 0, 'B'},
510   {"classify", no_argument, 0, 'F'},
511   {"file-type", no_argument, 0, 'F'},
512   {"ignore", required_argument, 0, 'I'},
513   {"dereference", no_argument, 0, 'L'},
514   {"literal", no_argument, 0, 'N'},
515   {"quote-name", no_argument, 0, 'Q'},
516   {"recursive", no_argument, 0, 'R'},
517   {"format", required_argument, 0, 12},
518   {"sort", required_argument, 0, 10},
519   {"tabsize", required_argument, 0, 'T'},
520   {"time", required_argument, 0, 11},
521   {"help", no_argument, &show_help, 1},
522   {"version", no_argument, &show_version, 1},
523   {"color", optional_argument, 0, 13},
524   {NULL, 0, NULL, 0}
525 };
526
527 static char const *const format_args[] =
528 {
529   "verbose", "long", "commas", "horizontal", "across",
530   "vertical", "single-column", 0
531 };
532
533 static enum format const formats[] =
534 {
535   long_format, long_format, with_commas, horizontal, horizontal,
536   many_per_line, one_per_line
537 };
538
539 static char const *const sort_args[] =
540 {
541   "none", "time", "size", "extension", 0
542 };
543
544 static enum sort_type const sort_types[] =
545 {
546   sort_none, sort_time, sort_size, sort_extension
547 };
548
549 static char const *const time_args[] =
550 {
551   "atime", "access", "use", "ctime", "status", 0
552 };
553
554 /* This zero-based index is used solely with the --dired option.
555    When that option is in effect, this counter is incremented for each
556    character of output generated by this program so that the beginning
557    and ending indices (in that output) of every file name can be recorded
558    and later output themselves.  */
559 static size_t dired_pos;
560
561 #define PUTCHAR(c) do {putchar ((c)); ++dired_pos;} while (0)
562
563 /* Write S to STREAM and increment DIRED_POS by S_LEN.  */
564 #define FPUTS(s, stream, s_len) \
565     do {fputs ((s), (stream)); dired_pos += s_len;} while (0)
566
567 /* Like FPUTS, but for use when S is a literal string.  */
568 #define FPUTS_LITERAL(s, stream) \
569     do {fputs ((s), (stream)); dired_pos += sizeof((s)) - 1;} while (0)
570
571 #define DIRED_INDENT()                                                  \
572     do                                                                  \
573       {                                                                 \
574         /* FIXME: remove the `&& format == long_format' clause.  */     \
575         if (dired && format == long_format)                             \
576           FPUTS_LITERAL ("  ", stdout);                                 \
577       }                                                                 \
578     while (0)
579
580 /* With --dired, store pairs of beginning and ending indices of filenames.  */
581 static struct obstack dired_obstack;
582
583 /* With --dired, store pairs of beginning and ending indices of any
584    directory names that appear as headers (just before `total' line)
585    for lists of directory entries.  Such directory names are seen when
586    listing hierarchies using -R and when a directory is listed with at
587    least one other command line argument.  */
588 static struct obstack subdired_obstack;
589
590 /* Save the current index on the specified obstack, OBS.  */
591 #define PUSH_CURRENT_DIRED_POS(obs)                                     \
592   do                                                                    \
593     {                                                                   \
594       /* FIXME: remove the `&& format == long_format' clause.  */       \
595       if (dired && format == long_format)                               \
596         obstack_grow ((obs), &dired_pos, sizeof (dired_pos));           \
597     }                                                                   \
598   while (0)
599
600 static enum time_type const time_types[] =
601 {
602   time_atime, time_atime, time_atime, time_ctime, time_ctime
603 };
604
605 static char const *const color_args[] =
606   {
607     /* Note: "no" is a prefix of "none" so we don't include it.  */
608     /* force and none are for compatibility with another color-ls version */
609     "always", "yes", "force",
610     "never", "none",
611     "auto", "tty", "if-tty", 0
612   };
613
614 static enum color_type const color_types[] =
615   {
616     color_always, color_always, color_always,
617     color_never, color_never,
618     color_if_tty, color_if_tty, color_if_tty
619   };
620
621
622 /* Write to standard output the string PREFIX followed by a space-separated
623    list of the integers stored in OS all on one line.  */
624
625 static void
626 dired_dump_obstack (const char *prefix, struct obstack *os)
627 {
628   int n_pos;
629
630   n_pos = obstack_object_size (os) / sizeof (size_t);
631   if (n_pos > 0)
632     {
633       int i;
634       size_t *pos;
635
636       pos = (size_t *) obstack_finish (os);
637       fputs (prefix, stdout);
638       for (i = 0; i < n_pos; i++)
639         printf (" %d", (int) pos[i]);
640       fputs ("\n", stdout);
641     }
642 }
643
644 int
645 main (int argc, char **argv)
646 {
647   register int i;
648   register struct pending *thispend;
649
650   program_name = argv[0];
651   setlocale (LC_ALL, "");
652   bindtextdomain (PACKAGE, LOCALEDIR);
653   textdomain (PACKAGE);
654
655   exit_status = 0;
656   dir_defaulted = 1;
657   print_dir_name = 1;
658   pending_dirs = 0;
659   current_time = time ((time_t *) 0);
660
661   i = decode_switches (argc, argv);
662
663   if (show_version)
664     {
665       printf ("%s (%s) %s\n",
666               (ls_mode == LS_LS ? "ls"
667                : (ls_mode == LS_MULTI_COL ? "dir" : "vdir")),
668               GNU_PACKAGE, VERSION);
669       exit (EXIT_SUCCESS);
670     }
671
672   if (show_help)
673     usage (EXIT_SUCCESS);
674
675   if (print_with_color)
676     {
677       parse_ls_color ();
678       prep_non_filename_text ();
679     }
680
681   format_needs_stat = sort_type == sort_time || sort_type == sort_size
682     || format == long_format
683     || trace_links || trace_dirs || indicator_style != none
684     || print_block_size || print_inode || print_with_color;
685
686   if (dired && format == long_format)
687     {
688       obstack_init (&dired_obstack);
689       obstack_init (&subdired_obstack);
690     }
691
692   nfiles = 100;
693   files = (struct fileinfo *) xmalloc (sizeof (struct fileinfo) * nfiles);
694   files_index = 0;
695
696   clear_files ();
697
698   if (i < argc)
699     dir_defaulted = 0;
700   for (; i < argc; i++)
701     gobble_file (argv[i], 1, "");
702
703   if (dir_defaulted)
704     {
705       if (immediate_dirs)
706         gobble_file (".", 1, "");
707       else
708         queue_directory (".", 0);
709     }
710
711   if (files_index)
712     {
713       sort_files ();
714       if (!immediate_dirs)
715         extract_dirs_from_files ("", 0);
716       /* `files_index' might be zero now.  */
717     }
718   if (files_index)
719     {
720       print_current_files ();
721       if (pending_dirs)
722         PUTCHAR ('\n');
723     }
724   else if (pending_dirs && pending_dirs->next == 0)
725     print_dir_name = 0;
726
727   while (pending_dirs)
728     {
729       thispend = pending_dirs;
730       pending_dirs = pending_dirs->next;
731       print_dir (thispend->name, thispend->realname);
732       free (thispend->name);
733       if (thispend->realname)
734         free (thispend->realname);
735       free (thispend);
736       print_dir_name = 1;
737     }
738
739   if (dired && format == long_format)
740     {
741       /* No need to free these since we're about to exit.  */
742       dired_dump_obstack ("//DIRED//", &dired_obstack);
743       dired_dump_obstack ("//SUBDIRED//", &subdired_obstack);
744     }
745
746   if (fclose (stdout) == EOF)
747     error (EXIT_FAILURE, errno, _("write error"));
748
749   /* Restore default color before exiting */
750   if (print_with_color)
751     {
752       put_indicator (&color_indicator[C_LEFT]);
753       put_indicator (&color_indicator[C_RIGHT]);
754     }
755
756   exit (exit_status);
757 }
758
759 /* Set all the option flags according to the switches specified.
760    Return the index of the first non-option argument.  */
761
762 static int
763 decode_switches (int argc, char **argv)
764 {
765   register char *p;
766   int c;
767   int i;
768   long int tmp_long;
769
770   qmark_funny_chars = 0;
771   quote_funny_chars = 0;
772
773   /* initialize all switches to default settings */
774
775   switch (ls_mode)
776     {
777     case LS_MULTI_COL:
778       /* This is for the `dir' program.  */
779       format = many_per_line;
780       quote_funny_chars = 1;
781       break;
782
783     case LS_LONG_FORMAT:
784       /* This is for the `vdir' program.  */
785       format = long_format;
786       quote_funny_chars = 1;
787       break;
788
789     case LS_LS:
790       /* This is for the `ls' program.  */
791       if (isatty (1))
792         {
793           format = many_per_line;
794           qmark_funny_chars = 1;
795         }
796       else
797         {
798           format = one_per_line;
799           qmark_funny_chars = 0;
800         }
801       break;
802
803     default:
804       abort ();
805     }
806
807   time_type = time_mtime;
808   full_time = 0;
809   sort_type = sort_name;
810   sort_reverse = 0;
811   numeric_users = 0;
812   print_block_size = 0;
813   kilobyte_blocks = getenv ("POSIXLY_CORRECT") == 0;
814   indicator_style = none;
815   print_inode = 0;
816   trace_links = 0;
817   trace_dirs = 0;
818   immediate_dirs = 0;
819   all_files = 0;
820   really_all_files = 0;
821   ignore_patterns = 0;
822   quote_as_string = 0;
823
824   line_length = 80;
825   if ((p = getenv ("COLUMNS")))
826     {
827       if (xstrtol (p, NULL, 0, &tmp_long, NULL) == LONGINT_OK
828           && 0 < tmp_long && tmp_long <= INT_MAX)
829         {
830           line_length = (int) tmp_long;
831         }
832       else
833         {
834           error (0, 0,
835                _("ignoring invalid width in environment variable COLUMNS: %s"),
836                  p);
837         }
838     }
839
840 #ifdef TIOCGWINSZ
841   {
842     struct winsize ws;
843
844     if (ioctl (1, TIOCGWINSZ, &ws) != -1 && ws.ws_col != 0)
845       line_length = ws.ws_col;
846   }
847 #endif
848
849   /* Using the TABSIZE environment variable is not POSIX-approved.
850      Ignore it when POSIXLY_CORRECT is set.  */
851   tabsize = 8;
852   if (!getenv ("POSIXLY_CORRECT") && (p = getenv ("TABSIZE")))
853     {
854       if (xstrtol (p, NULL, 0, &tmp_long, NULL) == LONGINT_OK
855           && 0 <= tmp_long && tmp_long <= INT_MAX)
856         {
857           tabsize = (int) tmp_long;
858         }
859       else
860         {
861           error (0, 0,
862            _("ignoring invalid tab size in environment variable TABSIZE: %s"),
863                  p);
864         }
865     }
866
867   while ((c = getopt_long (argc, argv,
868                            "abcdfgiklmnopqrstuw:xABCDFGI:LNQRST:UX1",
869                            long_options, (int *) 0)) != EOF)
870     {
871       switch (c)
872         {
873         case 0:
874           break;
875
876         case 'a':
877           all_files = 1;
878           really_all_files = 1;
879           break;
880
881         case 'b':
882           quote_funny_chars = 1;
883           qmark_funny_chars = 0;
884           break;
885
886         case 'c':
887           time_type = time_ctime;
888           sort_type = sort_time;
889           break;
890
891         case 'd':
892           immediate_dirs = 1;
893           break;
894
895         case 'f':
896           /* Same as enabling -a -U and disabling -l -s.  */
897           all_files = 1;
898           really_all_files = 1;
899           sort_type = sort_none;
900           /* disable -l */
901           if (format == long_format)
902             format = (isatty (1) ? many_per_line : one_per_line);
903           print_block_size = 0; /* disable -s */
904           print_with_color = 0; /* disable --color */
905           break;
906
907         case 'g':
908           /* No effect.  For BSD compatibility. */
909           break;
910
911         case 'i':
912           print_inode = 1;
913           break;
914
915         case 'k':
916           kilobyte_blocks = 1;
917           break;
918
919         case 'l':
920           format = long_format;
921           break;
922
923         case 'm':
924           format = with_commas;
925           break;
926
927         case 'n':
928           numeric_users = 1;
929           break;
930
931         case 'o':  /* Just like -l, but don't display group info.  */
932           format = long_format;
933           inhibit_group = 1;
934           break;
935
936         case 'p':
937           indicator_style = not_programs;
938           break;
939
940         case 'q':
941           qmark_funny_chars = 1;
942           quote_funny_chars = 0;
943           break;
944
945         case 'r':
946           sort_reverse = 1;
947           break;
948
949         case 's':
950           print_block_size = 1;
951           break;
952
953         case 't':
954           sort_type = sort_time;
955           break;
956
957         case 'u':
958           time_type = time_atime;
959           break;
960
961         case 'w':
962           if (xstrtol (optarg, NULL, 0, &tmp_long, NULL) != LONGINT_OK
963               || tmp_long <= 0 || tmp_long > INT_MAX)
964             error (EXIT_FAILURE, 0, _("invalid line width: %s"), optarg);
965           line_length = (int) tmp_long;
966           break;
967
968         case 'x':
969           format = horizontal;
970           break;
971
972         case 'A':
973           really_all_files = 0;
974           all_files = 1;
975           break;
976
977         case 'B':
978           add_ignore_pattern ("*~");
979           add_ignore_pattern (".*~");
980           break;
981
982         case 'C':
983           format = many_per_line;
984           break;
985
986         case 'D':
987           dired = 1;
988           break;
989
990         case 'F':
991           indicator_style = all;
992           break;
993
994         case 'G':               /* inhibit display of group info */
995           inhibit_group = 1;
996           break;
997
998         case 'I':
999           add_ignore_pattern (optarg);
1000           break;
1001
1002         case 'L':
1003           trace_links = 1;
1004           break;
1005
1006         case 'N':
1007           quote_funny_chars = 0;
1008           qmark_funny_chars = 0;
1009           break;
1010
1011         case 'Q':
1012           quote_as_string = 1;
1013           quote_funny_chars = 1;
1014           qmark_funny_chars = 0;
1015           break;
1016
1017         case 'R':
1018           trace_dirs = 1;
1019           break;
1020
1021         case 'S':
1022           sort_type = sort_size;
1023           break;
1024
1025         case 'T':
1026           if (xstrtol (optarg, NULL, 0, &tmp_long, NULL) != LONGINT_OK
1027               || tmp_long < 0 || tmp_long > INT_MAX)
1028             error (EXIT_FAILURE, 0, _("invalid tab size: %s"), optarg);
1029           tabsize = (int) tmp_long;
1030           break;
1031
1032         case 'U':
1033           sort_type = sort_none;
1034           break;
1035
1036         case 'X':
1037           sort_type = sort_extension;
1038           break;
1039
1040         case '1':
1041           format = one_per_line;
1042           break;
1043
1044         case 10:                /* --sort */
1045           i = argmatch (optarg, sort_args);
1046           if (i < 0)
1047             {
1048               invalid_arg (_("sort type"), optarg, i);
1049               usage (EXIT_FAILURE);
1050             }
1051           sort_type = sort_types[i];
1052           break;
1053
1054         case 11:                /* --time */
1055           i = argmatch (optarg, time_args);
1056           if (i < 0)
1057             {
1058               invalid_arg (_("time type"), optarg, i);
1059               usage (EXIT_FAILURE);
1060             }
1061           time_type = time_types[i];
1062           break;
1063
1064         case 12:                /* --format */
1065           i = argmatch (optarg, format_args);
1066           if (i < 0)
1067             {
1068               invalid_arg (_("format type"), optarg, i);
1069               usage (EXIT_FAILURE);
1070             }
1071           format = formats[i];
1072           break;
1073
1074         case 13:                /* --color */
1075           if (optarg)
1076             {
1077               i = argmatch (optarg, color_args);
1078               if (i < 0)
1079                 {
1080                   invalid_arg (_("colorization criterion"), optarg, i);
1081                   usage (EXIT_FAILURE);
1082                 }
1083               i = color_types[i];
1084             }
1085           else
1086             {
1087               /* Using --color with no argument is equivalent to using
1088                  --color=always.  */
1089               i = color_always;
1090             }
1091
1092           print_with_color = (i == color_always
1093                               || (i == color_if_tty
1094                                   && isatty (STDOUT_FILENO)));
1095
1096           if (print_with_color)
1097             {
1098               /* Don't use TAB characters in output.  Some terminal
1099                  emulators can't handle the combination of tabs and
1100                  color codes on the same line.  */
1101               tabsize = 0;
1102             }
1103           break;
1104
1105         default:
1106           usage (EXIT_FAILURE);
1107         }
1108     }
1109
1110   return optind;
1111 }
1112
1113 /* Parse a string as part of the LS_COLORS variable; this may involve
1114    decoding all kinds of escape characters.  If equals_end is set an
1115    unescaped equal sign ends the string, otherwise only a : or \0
1116    does.  Returns the number of characters output, or -1 on failure.
1117
1118    The resulting string is *not* null-terminated, but may contain
1119    embedded nulls.
1120
1121    Note that both dest and src are char **; on return they point to
1122    the first free byte after the array and the character that ended
1123    the input string, respectively.  */
1124
1125 static int
1126 get_funky_string (char **dest, const char **src, int equals_end)
1127 {
1128   int num;                      /* For numerical codes */
1129   int count;                    /* Something to count with */
1130   enum {
1131     ST_GND, ST_BACKSLASH, ST_OCTAL, ST_HEX, ST_CARET, ST_END, ST_ERROR
1132   } state;
1133   const char *p;
1134   char *q;
1135
1136   p = *src;                     /* We don't want to double-indirect */
1137   q = *dest;                    /* the whole darn time.  */
1138
1139   count = 0;                    /* No characters counted in yet.  */
1140   num = 0;
1141
1142   state = ST_GND;               /* Start in ground state.  */
1143   while (state < ST_END)
1144     {
1145       switch (state)
1146         {
1147         case ST_GND:            /* Ground state (no escapes) */
1148           switch (*p)
1149             {
1150             case ':':
1151             case '\0':
1152               state = ST_END;   /* End of string */
1153               break;
1154             case '\\':
1155               state = ST_BACKSLASH; /* Backslash scape sequence */
1156               ++p;
1157               break;
1158             case '^':
1159               state = ST_CARET; /* Caret escape */
1160               ++p;
1161               break;
1162             case '=':
1163               if (equals_end)
1164                 {
1165                   state = ST_END; /* End */
1166                   break;
1167                 }
1168               /* else fall through */
1169             default:
1170               *(q++) = *(p++);
1171               ++count;
1172               break;
1173             }
1174           break;
1175
1176         case ST_BACKSLASH:      /* Backslash escaped character */
1177           switch (*p)
1178             {
1179             case '0':
1180             case '1':
1181             case '2':
1182             case '3':
1183             case '4':
1184             case '5':
1185             case '6':
1186             case '7':
1187               state = ST_OCTAL; /* Octal sequence */
1188               num = *p - '0';
1189               break;
1190             case 'x':
1191             case 'X':
1192               state = ST_HEX;   /* Hex sequence */
1193               num = 0;
1194               break;
1195             case 'a':           /* Bell */
1196               num = 7;          /* Not all C compilers know what \a means */
1197               break;
1198             case 'b':           /* Backspace */
1199               num = '\b';
1200               break;
1201             case 'e':           /* Escape */
1202               num = 27;
1203               break;
1204             case 'f':           /* Form feed */
1205               num = '\f';
1206               break;
1207             case 'n':           /* Newline */
1208               num = '\n';
1209               break;
1210             case 'r':           /* Carriage return */
1211               num = '\r';
1212               break;
1213             case 't':           /* Tab */
1214               num = '\t';
1215               break;
1216             case 'v':           /* Vtab */
1217               num = '\v';
1218               break;
1219             case '?':           /* Delete */
1220               num = 127;
1221               break;
1222             case '_':           /* Space */
1223               num = ' ';
1224               break;
1225             case '\0':          /* End of string */
1226               state = ST_ERROR; /* Error! */
1227               break;
1228             default:            /* Escaped character like \ ^ : = */
1229               num = *p;
1230               break;
1231             }
1232           if (state == ST_BACKSLASH)
1233             {
1234               *(q++) = num;
1235               ++count;
1236               state = ST_GND;
1237             }
1238           ++p;
1239           break;
1240
1241         case ST_OCTAL:          /* Octal sequence */
1242           if (*p < '0' || *p > '7')
1243             {
1244               *(q++) = num;
1245               ++count;
1246               state = ST_GND;
1247             }
1248           else
1249             num = (num << 3) + (*(p++) - '0');
1250           break;
1251
1252         case ST_HEX:            /* Hex sequence */
1253           switch (*p)
1254             {
1255             case '0':
1256             case '1':
1257             case '2':
1258             case '3':
1259             case '4':
1260             case '5':
1261             case '6':
1262             case '7':
1263             case '8':
1264             case '9':
1265               num = (num << 4) + (*(p++) - '0');
1266               break;
1267             case 'a':
1268             case 'b':
1269             case 'c':
1270             case 'd':
1271             case 'e':
1272             case 'f':
1273               num = (num << 4) + (*(p++) - 'a') + 10;
1274               break;
1275             case 'A':
1276             case 'B':
1277             case 'C':
1278             case 'D':
1279             case 'E':
1280             case 'F':
1281               num = (num << 4) + (*(p++) - 'A') + 10;
1282               break;
1283             default:
1284               *(q++) = num;
1285               ++count;
1286               state = ST_GND;
1287               break;
1288             }
1289           break;
1290
1291         case ST_CARET:          /* Caret escape */
1292           state = ST_GND;       /* Should be the next state... */
1293           if (*p >= '@' && *p <= '~')
1294             {
1295               *(q++) = *(p++) & 037;
1296               ++count;
1297             }
1298           else if ( *p == '?')
1299             {
1300               *(q++) = 127;
1301               ++count;
1302             }
1303           else
1304             state = ST_ERROR;
1305           break;
1306
1307         default:
1308           abort();
1309         }
1310     }
1311
1312   *dest = q;
1313   *src = p;
1314
1315   return state == ST_ERROR ? -1 : count;
1316 }
1317
1318 static void
1319 parse_ls_color (void)
1320 {
1321   const char *p;                /* Pointer to character being parsed */
1322   char *buf;                    /* color_buf buffer pointer */
1323   int state;                    /* State of parser */
1324   int ind_no;                   /* Indicator number */
1325   char label[3];                /* Indicator label */
1326   struct col_ext_type *ext;     /* Extension we are working on */
1327   struct col_ext_type *ext2;    /* Extra pointer */
1328
1329   if ((p = getenv ("LS_COLORS")) == NULL || *p == '\0')
1330     return;
1331
1332   ext = NULL;
1333   strcpy (label, "??");
1334
1335   /* This is an overly conservative estimate, but any possible
1336      LS_COLORS string will *not* generate a color_buf longer than
1337      itself, so it is a safe way of allocating a buffer in
1338      advance.  */
1339   buf = color_buf = xstrdup (p);
1340
1341   state = 1;
1342   while (state > 0)
1343     {
1344       switch (state)
1345         {
1346         case 1:         /* First label character */
1347           switch (*p)
1348             {
1349             case ':':
1350               ++p;
1351               break;
1352
1353             case '*':
1354               /* Allocate new extension block and add to head of
1355                  linked list (this way a later definition will
1356                  override an earlier one, which can be useful for
1357                  having terminal-specific defs override global).  */
1358
1359               ext = (struct col_ext_type *)
1360                 xmalloc (sizeof (struct col_ext_type));
1361               ext->next = col_ext_list;
1362               col_ext_list = ext;
1363
1364               ++p;
1365               ext->ext.string = buf;
1366
1367               state = (ext->ext.len =
1368                        get_funky_string (&buf, &p, 1)) < 0 ? -1 : 4;
1369               break;
1370
1371             case '\0':
1372               state = 0;        /* Done! */
1373               break;
1374
1375             default:    /* Assume it is file type label */
1376               label[0] = *(p++);
1377               state = 2;
1378               break;
1379             }
1380           break;
1381
1382         case 2:         /* Second label character */
1383           if (*p)
1384             {
1385               label[1] = *(p++);
1386               state = 3;
1387             }
1388           else
1389             state = -1; /* Error */
1390           break;
1391
1392         case 3:         /* Equal sign after indicator label */
1393           state = -1;   /* Assume failure... */
1394           if (*(p++) == '=')/* It *should* be... */
1395             {
1396               for (ind_no = 0; indicator_name[ind_no] != NULL; ++ind_no)
1397                 {
1398                   if (STREQ (label, indicator_name[ind_no]))
1399                     {
1400                       color_indicator[ind_no].string = buf;
1401                       state = ((color_indicator[ind_no].len =
1402                                 get_funky_string (&buf, &p, 0)) < 0 ? -1 : 1);
1403                       break;
1404                     }
1405                 }
1406               if (state == -1)
1407                 error (0, 0, _("unrecognized prefix: %s"), label);
1408             }
1409          break;
1410
1411         case 4:         /* Equal sign after *.ext */
1412           if (*(p++) == '=')
1413             {
1414               ext->seq.string = buf;
1415               state = (ext->seq.len =
1416                        get_funky_string (&buf, &p, 0)) < 0 ? -1 : 1;
1417             }
1418           else
1419             state = -1;
1420           break;
1421         }
1422     }
1423
1424   if (state < 0)
1425     {
1426       struct col_ext_type *e;
1427
1428       error (0, 0,
1429              _("unparsable value for LS_COLORS environment variable"));
1430       free (color_buf);
1431       for (e = col_ext_list; e != NULL ; /* empty */)
1432         {
1433           ext2 = e;
1434           e = e->next;
1435           free (ext2);
1436         }
1437       print_with_color = 0;
1438     }
1439 }
1440
1441 /* Request that the directory named `name' have its contents listed later.
1442    If `realname' is nonzero, it will be used instead of `name' when the
1443    directory name is printed.  This allows symbolic links to directories
1444    to be treated as regular directories but still be listed under their
1445    real names. */
1446
1447 static void
1448 queue_directory (const char *name, const char *realname)
1449 {
1450   struct pending *new;
1451
1452   new = (struct pending *) xmalloc (sizeof (struct pending));
1453   new->next = pending_dirs;
1454   pending_dirs = new;
1455   new->name = xstrdup (name);
1456   if (realname)
1457     new->realname = xstrdup (realname);
1458   else
1459     new->realname = 0;
1460 }
1461
1462 /* Read directory `name', and list the files in it.
1463    If `realname' is nonzero, print its name instead of `name';
1464    this is used for symbolic links to directories. */
1465
1466 static void
1467 print_dir (const char *name, const char *realname)
1468 {
1469   register DIR *reading;
1470   register struct dirent *next;
1471   register int total_blocks = 0;
1472
1473   errno = 0;
1474   reading = opendir (name);
1475   if (!reading)
1476     {
1477       error (0, errno, "%s", name);
1478       exit_status = 1;
1479       return;
1480     }
1481
1482   /* Read the directory entries, and insert the subfiles into the `files'
1483      table.  */
1484
1485   clear_files ();
1486
1487   while ((next = readdir (reading)) != NULL)
1488     if (file_interesting (next))
1489       total_blocks += gobble_file (next->d_name, 0, name);
1490
1491   if (CLOSEDIR (reading))
1492     {
1493       error (0, errno, "%s", name);
1494       exit_status = 1;
1495       /* Don't return; print whatever we got. */
1496     }
1497
1498   /* Sort the directory contents.  */
1499   sort_files ();
1500
1501   /* If any member files are subdirectories, perhaps they should have their
1502      contents listed rather than being mentioned here as files.  */
1503
1504   if (trace_dirs)
1505     extract_dirs_from_files (name, 1);
1506
1507   if (print_dir_name)
1508     {
1509       const char *dir;
1510
1511       DIRED_INDENT ();
1512       dir = (realname ? realname : name);
1513       PUSH_CURRENT_DIRED_POS (&subdired_obstack);
1514       FPUTS (dir, stdout, strlen (dir));
1515       PUSH_CURRENT_DIRED_POS (&subdired_obstack);
1516       FPUTS_LITERAL (":\n", stdout);
1517     }
1518
1519   if (format == long_format || print_block_size)
1520     {
1521       char buf[6 + 20 + 1 + 1];
1522
1523       DIRED_INDENT ();
1524       sprintf (buf, "total %u\n", total_blocks);
1525       FPUTS (buf, stdout, strlen (buf));
1526     }
1527
1528   if (files_index)
1529     print_current_files ();
1530
1531   if (pending_dirs)
1532     PUTCHAR ('\n');
1533 }
1534
1535 /* Add `pattern' to the list of patterns for which files that match are
1536    not listed.  */
1537
1538 static void
1539 add_ignore_pattern (const char *pattern)
1540 {
1541   register struct ignore_pattern *ignore;
1542
1543   ignore = (struct ignore_pattern *) xmalloc (sizeof (struct ignore_pattern));
1544   ignore->pattern = pattern;
1545   /* Add it to the head of the linked list. */
1546   ignore->next = ignore_patterns;
1547   ignore_patterns = ignore;
1548 }
1549
1550 /* Return nonzero if the file in `next' should be listed. */
1551
1552 static int
1553 file_interesting (const struct dirent *next)
1554 {
1555   register struct ignore_pattern *ignore;
1556
1557   for (ignore = ignore_patterns; ignore; ignore = ignore->next)
1558     if (fnmatch (ignore->pattern, next->d_name, FNM_PERIOD) == 0)
1559       return 0;
1560
1561   if (really_all_files
1562       || next->d_name[0] != '.'
1563       || (all_files
1564           && next->d_name[1] != '\0'
1565           && (next->d_name[1] != '.' || next->d_name[2] != '\0')))
1566     return 1;
1567
1568   return 0;
1569 }
1570
1571 /* Enter and remove entries in the table `files'.  */
1572
1573 /* Empty the table of files. */
1574
1575 static void
1576 clear_files (void)
1577 {
1578   register int i;
1579
1580   for (i = 0; i < files_index; i++)
1581     {
1582       free (files[i].name);
1583       if (files[i].linkname)
1584         free (files[i].linkname);
1585     }
1586
1587   files_index = 0;
1588   block_size_size = 4;
1589 }
1590
1591 /* Add a file to the current table of files.
1592    Verify that the file exists, and print an error message if it does not.
1593    Return the number of blocks that the file occupies.  */
1594
1595 static int
1596 gobble_file (const char *name, int explicit_arg, const char *dirname)
1597 {
1598   register int blocks;
1599   register int val;
1600   register char *path;
1601
1602   if (files_index == nfiles)
1603     {
1604       nfiles *= 2;
1605       files = (struct fileinfo *) xrealloc (files, sizeof (*files) * nfiles);
1606     }
1607
1608   files[files_index].linkname = 0;
1609   files[files_index].linkmode = 0;
1610   files[files_index].linkok = 0;
1611
1612   if (explicit_arg || format_needs_stat)
1613     {
1614       /* `path' is the absolute pathname of this file. */
1615
1616       if (name[0] == '/' || dirname[0] == 0)
1617         path = (char *) name;
1618       else
1619         {
1620           path = (char *) alloca (strlen (name) + strlen (dirname) + 2);
1621           attach (path, dirname, name);
1622         }
1623
1624       if (trace_links)
1625         {
1626           val = stat (path, &files[files_index].stat);
1627           if (val < 0)
1628             /* Perhaps a symbolically-linked to file doesn't exist; stat
1629                the link instead. */
1630             val = lstat (path, &files[files_index].stat);
1631         }
1632       else
1633         val = lstat (path, &files[files_index].stat);
1634       if (val < 0)
1635         {
1636           error (0, errno, "%s", path);
1637           exit_status = 1;
1638           return 0;
1639         }
1640
1641 #ifdef S_ISLNK
1642       if (S_ISLNK (files[files_index].stat.st_mode)
1643           && (explicit_arg || format == long_format || print_with_color))
1644         {
1645           char *linkpath;
1646           struct stat linkstats;
1647
1648           get_link_name (path, &files[files_index]);
1649           linkpath = make_link_path (path, files[files_index].linkname);
1650
1651           /* Avoid following symbolic links when possible, ie, when
1652              they won't be traced and when no indicator is needed. */
1653           if (linkpath
1654               && ((explicit_arg && format != long_format)
1655                   || indicator_style != none
1656                   || print_with_color)
1657               && stat (linkpath, &linkstats) == 0)
1658             {
1659               files[files_index].linkok = 1;
1660
1661               /* Symbolic links to directories that are mentioned on the
1662                  command line are automatically traced if not being
1663                  listed as files.  */
1664               if (explicit_arg && format != long_format
1665                   && S_ISDIR (linkstats.st_mode))
1666                 {
1667                   /* Substitute the linked-to directory's name, but
1668                      save the real name in `linkname' for printing.  */
1669                   if (!immediate_dirs)
1670                     {
1671                       const char *tempname = name;
1672                       name = linkpath;
1673                       linkpath = files[files_index].linkname;
1674                       files[files_index].linkname = (char *) tempname;
1675                     }
1676                   files[files_index].stat = linkstats;
1677                 }
1678               else
1679                 {
1680                   /* Get the linked-to file's mode for the filetype indicator
1681                      in long listings.  */
1682                   files[files_index].linkmode = linkstats.st_mode;
1683                   files[files_index].linkok = 1;
1684                 }
1685             }
1686           if (linkpath)
1687             free (linkpath);
1688         }
1689 #endif
1690
1691 #ifdef S_ISLNK
1692       if (S_ISLNK (files[files_index].stat.st_mode))
1693         files[files_index].filetype = symbolic_link;
1694       else
1695 #endif
1696       if (S_ISDIR (files[files_index].stat.st_mode))
1697         {
1698           if (explicit_arg && !immediate_dirs)
1699             files[files_index].filetype = arg_directory;
1700           else
1701             files[files_index].filetype = directory;
1702         }
1703       else
1704         files[files_index].filetype = normal;
1705
1706       blocks = convert_blocks (ST_NBLOCKS (files[files_index].stat),
1707                                kilobyte_blocks);
1708       if (blocks >= 10000 && block_size_size < 5)
1709         block_size_size = 5;
1710       if (blocks >= 100000 && block_size_size < 6)
1711         block_size_size = 6;
1712       if (blocks >= 1000000 && block_size_size < 7)
1713         block_size_size = 7;
1714     }
1715   else
1716     blocks = 0;
1717
1718   files[files_index].name = xstrdup (name);
1719   files_index++;
1720
1721   return blocks;
1722 }
1723
1724 #ifdef S_ISLNK
1725
1726 /* Put the name of the file that `filename' is a symbolic link to
1727    into the `linkname' field of `f'. */
1728
1729 static void
1730 get_link_name (const char *filename, struct fileinfo *f)
1731 {
1732   char *linkbuf;
1733   register int linksize;
1734
1735   linkbuf = (char *) alloca (PATH_MAX + 2);
1736   /* Some automounters give incorrect st_size for mount points.
1737      I can't think of a good workaround for it, though.  */
1738   linksize = readlink (filename, linkbuf, PATH_MAX + 1);
1739   if (linksize < 0)
1740     {
1741       error (0, errno, "%s", filename);
1742       exit_status = 1;
1743     }
1744   else
1745     {
1746       linkbuf[linksize] = '\0';
1747       f->linkname = xstrdup (linkbuf);
1748     }
1749 }
1750
1751 /* If `linkname' is a relative path and `path' contains one or more
1752    leading directories, return `linkname' with those directories
1753    prepended; otherwise, return a copy of `linkname'.
1754    If `linkname' is zero, return zero. */
1755
1756 static char *
1757 make_link_path (const char *path, const char *linkname)
1758 {
1759   char *linkbuf;
1760   int bufsiz;
1761
1762   if (linkname == 0)
1763     return 0;
1764
1765   if (*linkname == '/')
1766     return xstrdup (linkname);
1767
1768   /* The link is to a relative path.  Prepend any leading path
1769      in `path' to the link name. */
1770   linkbuf = strrchr (path, '/');
1771   if (linkbuf == 0)
1772     return xstrdup (linkname);
1773
1774   bufsiz = linkbuf - path + 1;
1775   linkbuf = xmalloc (bufsiz + strlen (linkname) + 1);
1776   strncpy (linkbuf, path, bufsiz);
1777   strcpy (linkbuf + bufsiz, linkname);
1778   return linkbuf;
1779 }
1780 #endif
1781
1782 /* Remove any entries from `files' that are for directories,
1783    and queue them to be listed as directories instead.
1784    `dirname' is the prefix to prepend to each dirname
1785    to make it correct relative to ls's working dir.
1786    `recursive' is nonzero if we should not treat `.' and `..' as dirs.
1787    This is desirable when processing directories recursively.  */
1788
1789 static void
1790 extract_dirs_from_files (const char *dirname, int recursive)
1791 {
1792   register int i, j;
1793   register char *path;
1794   int dirlen;
1795
1796   dirlen = strlen (dirname) + 2;
1797   /* Queue the directories last one first, because queueing reverses the
1798      order.  */
1799   for (i = files_index - 1; i >= 0; i--)
1800     if ((files[i].filetype == directory || files[i].filetype == arg_directory)
1801         && (!recursive || is_not_dot_or_dotdot (files[i].name)))
1802       {
1803         if (files[i].name[0] == '/' || dirname[0] == 0)
1804           {
1805             queue_directory (files[i].name, files[i].linkname);
1806           }
1807         else
1808           {
1809             path = (char *) xmalloc (strlen (files[i].name) + dirlen);
1810             attach (path, dirname, files[i].name);
1811             queue_directory (path, files[i].linkname);
1812             free (path);
1813           }
1814         if (files[i].filetype == arg_directory)
1815           free (files[i].name);
1816       }
1817
1818   /* Now delete the directories from the table, compacting all the remaining
1819      entries.  */
1820
1821   for (i = 0, j = 0; i < files_index; i++)
1822     if (files[i].filetype != arg_directory)
1823       files[j++] = files[i];
1824   files_index = j;
1825 }
1826
1827 /* Return nonzero if `name' doesn't end in `.' or `..'
1828    This is so we don't try to recurse on `././././. ...' */
1829
1830 static int
1831 is_not_dot_or_dotdot (const char *name)
1832 {
1833   char *t;
1834
1835   t = strrchr (name, '/');
1836   if (t)
1837     name = t + 1;
1838
1839   if (name[0] == '.'
1840       && (name[1] == '\0'
1841           || (name[1] == '.' && name[2] == '\0')))
1842     return 0;
1843
1844   return 1;
1845 }
1846
1847 /* Sort the files now in the table.  */
1848
1849 static void
1850 sort_files (void)
1851 {
1852   int (*func) ();
1853
1854   switch (sort_type)
1855     {
1856     case sort_none:
1857       return;
1858     case sort_time:
1859       switch (time_type)
1860         {
1861         case time_ctime:
1862           func = sort_reverse ? rev_cmp_ctime : compare_ctime;
1863           break;
1864         case time_mtime:
1865           func = sort_reverse ? rev_cmp_mtime : compare_mtime;
1866           break;
1867         case time_atime:
1868           func = sort_reverse ? rev_cmp_atime : compare_atime;
1869           break;
1870         default:
1871           abort ();
1872         }
1873       break;
1874     case sort_name:
1875       func = sort_reverse ? rev_cmp_name : compare_name;
1876       break;
1877     case sort_extension:
1878       func = sort_reverse ? rev_cmp_extension : compare_extension;
1879       break;
1880     case sort_size:
1881       func = sort_reverse ? rev_cmp_size : compare_size;
1882       break;
1883     default:
1884       abort ();
1885     }
1886
1887   qsort (files, files_index, sizeof (struct fileinfo), func);
1888 }
1889
1890 /* Comparison routines for sorting the files. */
1891
1892 static int
1893 compare_ctime (const struct fileinfo *file1, const struct fileinfo *file2)
1894 {
1895   return longdiff (file2->stat.st_ctime, file1->stat.st_ctime);
1896 }
1897
1898 static int
1899 rev_cmp_ctime (const struct fileinfo *file2, const struct fileinfo *file1)
1900 {
1901   return longdiff (file2->stat.st_ctime, file1->stat.st_ctime);
1902 }
1903
1904 static int
1905 compare_mtime (const struct fileinfo *file1, const struct fileinfo *file2)
1906 {
1907   return longdiff (file2->stat.st_mtime, file1->stat.st_mtime);
1908 }
1909
1910 static int
1911 rev_cmp_mtime (const struct fileinfo *file2, const struct fileinfo *file1)
1912 {
1913   return longdiff (file2->stat.st_mtime, file1->stat.st_mtime);
1914 }
1915
1916 static int
1917 compare_atime (const struct fileinfo *file1, const struct fileinfo *file2)
1918 {
1919   return longdiff (file2->stat.st_atime, file1->stat.st_atime);
1920 }
1921
1922 static int
1923 rev_cmp_atime (const struct fileinfo *file2, const struct fileinfo *file1)
1924 {
1925   return longdiff (file2->stat.st_atime, file1->stat.st_atime);
1926 }
1927
1928 static int
1929 compare_size (const struct fileinfo *file1, const struct fileinfo *file2)
1930 {
1931   return longdiff (file2->stat.st_size, file1->stat.st_size);
1932 }
1933
1934 static int
1935 rev_cmp_size (const struct fileinfo *file2, const struct fileinfo *file1)
1936 {
1937   return longdiff (file2->stat.st_size, file1->stat.st_size);
1938 }
1939
1940 static int
1941 compare_name (const struct fileinfo *file1, const struct fileinfo *file2)
1942 {
1943   return strcmp (file1->name, file2->name);
1944 }
1945
1946 static int
1947 rev_cmp_name (const struct fileinfo *file2, const struct fileinfo *file1)
1948 {
1949   return strcmp (file1->name, file2->name);
1950 }
1951
1952 /* Compare file extensions.  Files with no extension are `smallest'.
1953    If extensions are the same, compare by filenames instead. */
1954
1955 static int
1956 compare_extension (const struct fileinfo *file1, const struct fileinfo *file2)
1957 {
1958   register char *base1, *base2;
1959   register int cmp;
1960
1961   base1 = strrchr (file1->name, '.');
1962   base2 = strrchr (file2->name, '.');
1963   if (base1 == 0 && base2 == 0)
1964     return strcmp (file1->name, file2->name);
1965   if (base1 == 0)
1966     return -1;
1967   if (base2 == 0)
1968     return 1;
1969   cmp = strcmp (base1, base2);
1970   if (cmp == 0)
1971     return strcmp (file1->name, file2->name);
1972   return cmp;
1973 }
1974
1975 static int
1976 rev_cmp_extension (const struct fileinfo *file2, const struct fileinfo *file1)
1977 {
1978   register char *base1, *base2;
1979   register int cmp;
1980
1981   base1 = strrchr (file1->name, '.');
1982   base2 = strrchr (file2->name, '.');
1983   if (base1 == 0 && base2 == 0)
1984     return strcmp (file1->name, file2->name);
1985   if (base1 == 0)
1986     return -1;
1987   if (base2 == 0)
1988     return 1;
1989   cmp = strcmp (base1, base2);
1990   if (cmp == 0)
1991     return strcmp (file1->name, file2->name);
1992   return cmp;
1993 }
1994
1995 /* List all the files now in the table.  */
1996
1997 static void
1998 print_current_files (void)
1999 {
2000   register int i;
2001
2002   switch (format)
2003     {
2004     case one_per_line:
2005       for (i = 0; i < files_index; i++)
2006         {
2007           print_file_name_and_frills (files + i);
2008           putchar ('\n');
2009         }
2010       break;
2011
2012     case many_per_line:
2013       print_many_per_line ();
2014       break;
2015
2016     case horizontal:
2017       print_horizontal ();
2018       break;
2019
2020     case with_commas:
2021       print_with_commas ();
2022       break;
2023
2024     case long_format:
2025       for (i = 0; i < files_index; i++)
2026         {
2027           print_long_format (files + i);
2028           PUTCHAR ('\n');
2029         }
2030       break;
2031     }
2032 }
2033
2034 static void
2035 print_long_format (const struct fileinfo *f)
2036 {
2037   char modebuf[20];
2038 /* This is more than enough for all known LC_TIME locales.  */
2039 #define TIMEBUF_SIZE 100
2040
2041   /* 7 fields that may (worst case: 64-bit integral values) require 20 bytes,
2042      1 10-character mode string,
2043      1 TIMEBUF_SIZE-character time string,
2044      9 spaces, one following each of these fields,
2045      and 1 trailing NUL byte.  */
2046   char bigbuf[7 * 20 + 10 + TIMEBUF_SIZE + 9 + 1];
2047   char *p;
2048   time_t when;
2049   const char *fmt;
2050
2051 #ifdef HAVE_ST_DM_MODE
2052   mode_string (f->stat.st_dm_mode, modebuf);
2053 #else
2054   mode_string (f->stat.st_mode, modebuf);
2055 #endif
2056
2057   modebuf[10] = '\0';
2058
2059   switch (time_type)
2060     {
2061     case time_ctime:
2062       when = f->stat.st_ctime;
2063       break;
2064     case time_mtime:
2065       when = f->stat.st_mtime;
2066       break;
2067     case time_atime:
2068       when = f->stat.st_atime;
2069       break;
2070     }
2071
2072   if (full_time)
2073     {
2074       fmt = "%a %b %d %H:%M:%S %Y";
2075     }
2076   else
2077     {
2078       if (current_time > when + 6L * 30L * 24L * 60L * 60L      /* Old. */
2079           || current_time < when - 60L * 60L)   /* In the future. */
2080         {
2081           /* The file is fairly old or in the future.
2082              POSIX says the cutoff is 6 months old;
2083              approximate this by 6*30 days.
2084              Allow a 1 hour slop factor for what is considered "the future",
2085              to allow for NFS server/client clock disagreement.
2086              Show the year instead of the time of day.  */
2087           fmt = "%b %e  %Y";
2088         }
2089       else
2090         {
2091           fmt = "%b %e %H:%M";
2092         }
2093     }
2094
2095   p = bigbuf;
2096
2097   if (print_inode)
2098     {
2099       sprintf (p, "%*lu ", INODE_DIGITS, (unsigned long) f->stat.st_ino);
2100       p += strlen (p);
2101     }
2102
2103   if (print_block_size)
2104     {
2105       sprintf (p, "%*u ", block_size_size,
2106                (unsigned) convert_blocks (ST_NBLOCKS (f->stat),
2107                                           kilobyte_blocks));
2108       p += strlen (p);
2109     }
2110
2111   /* The space between the mode and the number of links is the POSIX
2112      "optional alternate access method flag". */
2113   sprintf (p, "%s %3u ", modebuf, (unsigned int) f->stat.st_nlink);
2114   p += strlen (p);
2115
2116   if (numeric_users)
2117     sprintf (p, "%-8u ", (unsigned int) f->stat.st_uid);
2118   else
2119     sprintf (p, "%-8.8s ", getuser (f->stat.st_uid));
2120   p += strlen (p);
2121
2122   if (!inhibit_group)
2123     {
2124       if (numeric_users)
2125         sprintf (p, "%-8u ", (unsigned int) f->stat.st_gid);
2126       else
2127         sprintf (p, "%-8.8s ", getgroup (f->stat.st_gid));
2128       p += strlen (p);
2129     }
2130
2131   if (S_ISCHR (f->stat.st_mode) || S_ISBLK (f->stat.st_mode))
2132     sprintf (p, "%3u, %3u ", (unsigned) major (f->stat.st_rdev),
2133              (unsigned) minor (f->stat.st_rdev));
2134   else
2135     sprintf (p, "%8lu ", (unsigned long) f->stat.st_size);
2136   p += strlen (p);
2137
2138   /* Use strftime rather than ctime, because the former can produce
2139      locale-dependent names for the weekday (%a) and month (%b).  */
2140   p += strftime (p, TIMEBUF_SIZE, fmt, localtime (&when));
2141   *p++ = ' ';
2142
2143   DIRED_INDENT ();
2144   FPUTS (bigbuf, stdout, p - bigbuf);
2145   PUSH_CURRENT_DIRED_POS (&dired_obstack);
2146   print_name_with_quoting (f->name, f->stat.st_mode, f->linkok);
2147   PUSH_CURRENT_DIRED_POS (&dired_obstack);
2148
2149   if (f->filetype == symbolic_link)
2150     {
2151       if (f->linkname)
2152         {
2153           FPUTS_LITERAL (" -> ", stdout);
2154           print_name_with_quoting (f->linkname, f->linkmode, f->linkok - 1);
2155           if (indicator_style != none)
2156             print_type_indicator (f->linkmode);
2157         }
2158     }
2159   else if (indicator_style != none)
2160     print_type_indicator (f->stat.st_mode);
2161 }
2162
2163 /* Set QUOTED_LENGTH to strlen(P) and return NULL if P == quoted(P).
2164    Otherwise, return xmalloc'd storage containing the quoted version
2165    of P and set QUOTED_LENGTH to the length of the quoted P.  */
2166
2167 static char *
2168 quote_filename (register const char *p, size_t *quoted_length)
2169 {
2170   register unsigned char c;
2171   const char *p0 = p;
2172   char *quoted, *q;
2173   int found_quotable;
2174
2175   if (!quote_as_string && !quote_funny_chars && !qmark_funny_chars)
2176     {
2177       *quoted_length = strlen (p);
2178       return NULL;
2179     }
2180
2181   found_quotable = 0;
2182   for (c = *p; c; c = *++p)
2183     {
2184       if (quote_funny_chars)
2185         {
2186           switch (c)
2187             {
2188             case '\\':
2189             case '\n':
2190             case '\b':
2191             case '\r':
2192             case '\t':
2193             case '\f':
2194             case ' ':
2195             case '"':
2196               found_quotable = 1;
2197               break;
2198
2199             default:
2200               if (!ISGRAPH (c))
2201                 found_quotable = 1;
2202               break;
2203             }
2204         }
2205       else
2206         {
2207           if (!ISPRINT (c) && qmark_funny_chars)
2208             found_quotable = 1;
2209         }
2210       if (found_quotable)
2211         break;
2212     }
2213
2214   if (!found_quotable && !quote_as_string)
2215     {
2216       *quoted_length = p - p0;
2217       return NULL;
2218     }
2219
2220   p = p0;
2221   quoted = xmalloc (4 * strlen (p) + 1);
2222   q = quoted;
2223
2224 #define SAVECHAR(c) *q++ = (c)
2225 #define SAVE_2_CHARS(c12) \
2226     do { *q++ = ((c12)[0]); \
2227          *q++ = ((c12)[1]); } while (0)
2228
2229   if (quote_as_string)
2230     SAVECHAR ('"');
2231
2232   while ((c = *p++))
2233     {
2234       if (quote_funny_chars)
2235         {
2236           switch (c)
2237             {
2238             case '\\':
2239               SAVE_2_CHARS ("\\\\");
2240               break;
2241
2242             case '\n':
2243               SAVE_2_CHARS ("\\n");
2244               break;
2245
2246             case '\b':
2247               SAVE_2_CHARS ("\\b");
2248               break;
2249
2250             case '\r':
2251               SAVE_2_CHARS ("\\r");
2252               break;
2253
2254             case '\t':
2255               SAVE_2_CHARS ("\\t");
2256               break;
2257
2258             case '\f':
2259               SAVE_2_CHARS ("\\f");
2260               break;
2261
2262             case ' ':
2263               SAVE_2_CHARS ("\\ ");
2264               break;
2265
2266             case '"':
2267               SAVE_2_CHARS ("\\\"");
2268               break;
2269
2270             default:
2271               if (ISGRAPH (c))
2272                 SAVECHAR (c);
2273               else
2274                 {
2275                   char buf[5];
2276                   sprintf (buf, "\\%03o", (unsigned int) c);
2277                   q = stpcpy (q, buf);
2278                 }
2279             }
2280         }
2281       else
2282         {
2283           if (ISPRINT (c))
2284             SAVECHAR (c);
2285           else if (!qmark_funny_chars)
2286             SAVECHAR (c);
2287           else
2288             SAVECHAR ('?');
2289         }
2290     }
2291
2292   if (quote_as_string)
2293     SAVECHAR ('"');
2294
2295   *quoted_length = q - quoted;
2296
2297   SAVECHAR ('\0');
2298
2299   return quoted;
2300 }
2301
2302 static void
2303 print_name_with_quoting (const char *p, unsigned int mode, int linkok)
2304 {
2305   char *quoted;
2306   size_t quoted_length;
2307
2308   if (print_with_color)
2309     print_color_indicator (p, mode, linkok);
2310
2311   quoted = quote_filename (p, &quoted_length);
2312   FPUTS (quoted != NULL ? quoted : p, stdout, quoted_length);
2313   if (quoted)
2314     free (quoted);
2315
2316   if (print_with_color)
2317     prep_non_filename_text ();
2318 }
2319
2320 static void
2321 prep_non_filename_text (void)
2322 {
2323   if (color_indicator[C_END].string != NULL)
2324     put_indicator (&color_indicator[C_END]);
2325   else
2326     {
2327       put_indicator (&color_indicator[C_LEFT]);
2328       put_indicator (&color_indicator[C_NORM]);
2329       put_indicator (&color_indicator[C_RIGHT]);
2330     }
2331 }
2332
2333 /* Print the file name of `f' with appropriate quoting.
2334    Also print file size, inode number, and filetype indicator character,
2335    as requested by switches.  */
2336
2337 static void
2338 print_file_name_and_frills (const struct fileinfo *f)
2339 {
2340   if (print_inode)
2341     printf ("%*lu ", INODE_DIGITS, (unsigned long) f->stat.st_ino);
2342
2343   if (print_block_size)
2344     printf ("%*u ", block_size_size,
2345             (unsigned) convert_blocks (ST_NBLOCKS (f->stat),
2346                                        kilobyte_blocks));
2347
2348   print_name_with_quoting (f->name, f->stat.st_mode, f->linkok);
2349
2350   if (indicator_style != none)
2351     print_type_indicator (f->stat.st_mode);
2352 }
2353
2354 static void
2355 print_type_indicator (unsigned int mode)
2356 {
2357   if (S_ISDIR (mode))
2358     PUTCHAR ('/');
2359
2360 #ifdef S_ISLNK
2361   if (S_ISLNK (mode))
2362     PUTCHAR ('@');
2363 #endif
2364
2365 #ifdef S_ISFIFO
2366   if (S_ISFIFO (mode))
2367     PUTCHAR ('|');
2368 #endif
2369
2370 #ifdef S_ISSOCK
2371   if (S_ISSOCK (mode))
2372     PUTCHAR ('=');
2373 #endif
2374
2375   if (S_ISREG (mode) && indicator_style == all
2376       && (mode & S_IXUGO))
2377     PUTCHAR ('*');
2378 }
2379
2380 static void
2381 print_color_indicator (const char *name, unsigned int mode, int linkok)
2382 {
2383   int type = C_FILE;
2384   struct col_ext_type *ext;     /* Color extension */
2385   size_t len;                   /* Length of name */
2386
2387   /* Is this a nonexistent file?  If so, linkok == -1.  */
2388
2389   if (linkok == -1 && color_indicator[C_MISSING].string != NULL)
2390     {
2391       ext = NULL;
2392       type = C_MISSING;
2393     }
2394   else
2395     {
2396       if (S_ISDIR (mode))
2397         type = C_DIR;
2398
2399 #ifdef S_ISLNK
2400       else if (S_ISLNK (mode))
2401         type = ((!linkok && color_indicator[C_ORPHAN].string)
2402                 ? C_ORPHAN : C_LINK);
2403 #endif
2404
2405 #ifdef S_ISFIFO
2406       else if (S_ISFIFO (mode))
2407         type = C_FIFO;
2408 #endif
2409
2410 #ifdef S_ISSOCK
2411       else if (S_ISSOCK (mode))
2412         type = C_SOCK;
2413 #endif
2414
2415 #ifdef S_ISBLK
2416       else if (S_ISBLK (mode))
2417         type = C_BLK;
2418 #endif
2419
2420 #ifdef S_ISCHR
2421       else if (S_ISCHR (mode))
2422         type = C_CHR;
2423 #endif
2424
2425       if (type == C_FILE && (mode & S_IXUGO) != 0)
2426         type = C_EXEC;
2427
2428       /* Check the file's suffix only if still classified as C_FILE.  */
2429       ext = NULL;
2430       if (type == C_FILE)
2431         {
2432           /* Test if NAME has a recognized suffix.  */
2433
2434           len = strlen (name);
2435           name += len;          /* Pointer to final \0.  */
2436           for (ext = col_ext_list; ext != NULL; ext = ext->next)
2437             {
2438               if (ext->ext.len <= len
2439                   && strncmp (name - ext->ext.len, ext->ext.string,
2440                               ext->ext.len) == 0)
2441                 break;
2442             }
2443         }
2444     }
2445
2446   put_indicator (&color_indicator[C_LEFT]);
2447   put_indicator (ext ? &(ext->seq) : &color_indicator[type]);
2448   put_indicator (&color_indicator[C_RIGHT]);
2449 }
2450
2451 /* Output a color indicator (which may contain nulls).  */
2452 static void
2453 put_indicator (const struct bin_str *ind)
2454 {
2455   register int i;
2456   register char *p;
2457
2458   p = ind->string;
2459
2460   for (i = ind->len; i > 0; --i)
2461     putchar (*(p++));
2462 }
2463
2464 static int
2465 length_of_file_name_and_frills (const struct fileinfo *f)
2466 {
2467   register char *p = f->name;
2468   register unsigned char c;
2469   register int len = 0;
2470
2471   if (print_inode)
2472     len += INODE_DIGITS + 1;
2473
2474   if (print_block_size)
2475     len += 1 + block_size_size;
2476
2477   if (quote_as_string)
2478     len += 2;
2479
2480   while ((c = *p++))
2481     {
2482       if (quote_funny_chars)
2483         {
2484           switch (c)
2485             {
2486             case '\\':
2487             case '\n':
2488             case '\b':
2489             case '\r':
2490             case '\t':
2491             case '\f':
2492             case ' ':
2493               len += 2;
2494               break;
2495
2496             case '"':
2497               if (quote_as_string)
2498                 len += 2;
2499               else
2500                 len += 1;
2501               break;
2502
2503             default:
2504               if (ISPRINT (c))
2505                 len += 1;
2506               else
2507                 len += 4;
2508             }
2509         }
2510       else
2511         len += 1;
2512     }
2513
2514   if (indicator_style != none)
2515     {
2516       unsigned filetype = f->stat.st_mode;
2517
2518       if (S_ISREG (filetype))
2519         {
2520           if (indicator_style == all
2521               && (f->stat.st_mode & S_IXUGO))
2522             len += 1;
2523         }
2524       else if (S_ISDIR (filetype)
2525 #ifdef S_ISLNK
2526                || S_ISLNK (filetype)
2527 #endif
2528 #ifdef S_ISFIFO
2529                || S_ISFIFO (filetype)
2530 #endif
2531 #ifdef S_ISSOCK
2532                || S_ISSOCK (filetype)
2533 #endif
2534         )
2535         len += 1;
2536     }
2537
2538   return len;
2539 }
2540
2541 static void
2542 print_many_per_line (void)
2543 {
2544   int filesno;                  /* Index into files. */
2545   int row;                      /* Current row. */
2546   int max_name_length;          /* Length of longest file name + frills. */
2547   int name_length;              /* Length of each file name + frills. */
2548   int pos;                      /* Current character column. */
2549   int cols;                     /* Number of files across. */
2550   int rows;                     /* Maximum number of files down. */
2551
2552   /* Compute the maximum file name length.  */
2553   max_name_length = 0;
2554   for (filesno = 0; filesno < files_index; filesno++)
2555     {
2556       name_length = length_of_file_name_and_frills (files + filesno);
2557       if (name_length > max_name_length)
2558         max_name_length = name_length;
2559     }
2560
2561   /* Allow at least two spaces between names.  */
2562   max_name_length += 2;
2563
2564   /* Calculate the maximum number of columns that will fit. */
2565   cols = line_length / max_name_length;
2566   if (cols == 0)
2567     cols = 1;
2568   /* Calculate the number of rows that will be in each column except possibly
2569      for a short column on the right. */
2570   rows = files_index / cols + (files_index % cols != 0);
2571   /* Recalculate columns based on rows. */
2572   cols = files_index / rows + (files_index % rows != 0);
2573
2574   for (row = 0; row < rows; row++)
2575     {
2576       filesno = row;
2577       pos = 0;
2578       /* Print the next row.  */
2579       while (1)
2580         {
2581           print_file_name_and_frills (files + filesno);
2582           name_length = length_of_file_name_and_frills (files + filesno);
2583
2584           filesno += rows;
2585           if (filesno >= files_index)
2586             break;
2587
2588           indent (pos + name_length, pos + max_name_length);
2589           pos += max_name_length;
2590         }
2591       putchar ('\n');
2592     }
2593 }
2594
2595 static void
2596 print_horizontal (void)
2597 {
2598   int filesno;
2599   int max_name_length;
2600   int name_length;
2601   int cols;
2602   int pos;
2603
2604   /* Compute the maximum file name length.  */
2605   max_name_length = 0;
2606   for (filesno = 0; filesno < files_index; filesno++)
2607     {
2608       name_length = length_of_file_name_and_frills (files + filesno);
2609       if (name_length > max_name_length)
2610         max_name_length = name_length;
2611     }
2612
2613   /* Allow two spaces between names.  */
2614   max_name_length += 2;
2615
2616   cols = line_length / max_name_length;
2617   if (cols == 0)
2618     cols = 1;
2619
2620   pos = 0;
2621   name_length = 0;
2622
2623   for (filesno = 0; filesno < files_index; filesno++)
2624     {
2625       if (filesno != 0)
2626         {
2627           if (filesno % cols == 0)
2628             {
2629               putchar ('\n');
2630               pos = 0;
2631             }
2632           else
2633             {
2634               indent (pos + name_length, pos + max_name_length);
2635               pos += max_name_length;
2636             }
2637         }
2638
2639       print_file_name_and_frills (files + filesno);
2640
2641       name_length = length_of_file_name_and_frills (files + filesno);
2642     }
2643   putchar ('\n');
2644 }
2645
2646 static void
2647 print_with_commas (void)
2648 {
2649   int filesno;
2650   int pos, old_pos;
2651
2652   pos = 0;
2653
2654   for (filesno = 0; filesno < files_index; filesno++)
2655     {
2656       old_pos = pos;
2657
2658       pos += length_of_file_name_and_frills (files + filesno);
2659       if (filesno + 1 < files_index)
2660         pos += 2;               /* For the comma and space */
2661
2662       if (old_pos != 0 && pos >= line_length)
2663         {
2664           putchar ('\n');
2665           pos -= old_pos;
2666         }
2667
2668       print_file_name_and_frills (files + filesno);
2669       if (filesno + 1 < files_index)
2670         {
2671           putchar (',');
2672           putchar (' ');
2673         }
2674     }
2675   putchar ('\n');
2676 }
2677
2678 /* Assuming cursor is at position FROM, indent up to position TO.
2679    Use a TAB character instead of two or more spaces whenever possible.  */
2680
2681 static void
2682 indent (int from, int to)
2683 {
2684   while (from < to)
2685     {
2686       if (tabsize > 0 && to / tabsize > (from + 1) / tabsize)
2687         {
2688           putchar ('\t');
2689           from += tabsize - from % tabsize;
2690         }
2691       else
2692         {
2693           putchar (' ');
2694           from++;
2695         }
2696     }
2697 }
2698
2699 /* Put DIRNAME/NAME into DEST, handling `.' and `/' properly. */
2700
2701 static void
2702 attach (char *dest, const char *dirname, const char *name)
2703 {
2704   const char *dirnamep = dirname;
2705
2706   /* Copy dirname if it is not ".". */
2707   if (dirname[0] != '.' || dirname[1] != 0)
2708     {
2709       while (*dirnamep)
2710         *dest++ = *dirnamep++;
2711       /* Add '/' if `dirname' doesn't already end with it. */
2712       if (dirnamep > dirname && dirnamep[-1] != '/')
2713         *dest++ = '/';
2714     }
2715   while (*name)
2716     *dest++ = *name++;
2717   *dest = 0;
2718 }
2719
2720 static void
2721 usage (int status)
2722 {
2723   if (status != 0)
2724     fprintf (stderr, _("Try `%s --help' for more information.\n"),
2725              program_name);
2726   else
2727     {
2728       printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name);
2729       printf (_("\
2730 List information about the FILEs (the current directory by default).\n\
2731 Sort entries alphabetically if none of -cftuSUX nor --sort.\n\
2732 \n\
2733   -a, --all                  do not hide entries starting with .\n\
2734   -A, --almost-all           do not list implied . and ..\n\
2735   -b, --escape               print octal escapes for nongraphic characters\n\
2736   -B, --ignore-backups       do not list implied entries ending with ~\n\
2737   -c                         sort by change time; with -l: show ctime\n\
2738   -C                         list entries by columns\n\
2739       --color[=WHEN]         control whether color is used to distinguish file\n\
2740                                types.  WHEN may be `never', `always', or `auto'\n\
2741   -d, --directory            list directory entries instead of contents\n\
2742   -D, --dired                generate output designed for Emacs' dired mode\n\
2743   -f                         do not sort, enable -aU, disable -lst\n\
2744   -F, --classify             append a character for typing each entry\n\
2745       --format=WORD          across -x, commas -m, horizontal -x, long -l,\n\
2746                                single-column -1, verbose -l, vertical -C\n\
2747       --full-time            list both full date and full time\n"));
2748
2749       printf (_("\
2750   -g                         (ignored)\n\
2751   -G, --no-group             inhibit display of group information\n\
2752   -i, --inode                print index number of each file\n\
2753   -I, --ignore=PATTERN       do not list implied entries matching shell PATTERN\n\
2754   -k, --kilobytes            use 1024 blocks, not 512 despite POSIXLY_CORRECT\n\
2755   -l                         use a long listing format\n\
2756   -L, --dereference          list entries pointed to by symbolic links\n\
2757   -m                         fill width with a comma separated list of entries\n\
2758   -n, --numeric-uid-gid      list numeric UIDs and GIDs instead of names\n\
2759   -N, --literal              print raw entry names (don't treat e.g. control\n\
2760                                characters specially)\n\
2761   -o                         use long listing format without group info\n\
2762   -p                         append a character for typing each entry\n\
2763   -q, --hide-control-chars   print ? instead of non graphic characters\n\
2764   -Q, --quote-name           enclose entry names in double quotes\n\
2765   -r, --reverse              reverse order while sorting\n\
2766   -R, --recursive            list subdirectories recursively\n\
2767   -s, --size                 print size of each file, in blocks\n"));
2768
2769       printf (_("\
2770   -S                         sort by file size\n\
2771       --sort=WORD            ctime -c, extension -X, none -U, size -S,\n\
2772                              status -c, time -t, atime -u, access -u, use -u\n\
2773       --time=WORD            show time as WORD instead of modification time:\n\
2774                              atime, access, use, ctime or status\n\
2775   -t                         sort by modification time; with -l: show mtime\n\
2776   -T, --tabsize=COLS         assume tab stops at each COLS instead of 8\n\
2777   -u                         sort by last access time; with -l: show atime\n\
2778   -U                         do not sort; list entries in directory order\n\
2779   -w, --width=COLS           assume screen width instead of current value\n\
2780   -x                         list entries by lines instead of by columns\n\
2781   -X                         sort alphabetically by entry extension\n\
2782   -1                         list one file per line\n\
2783       --help                 display this help and exit\n\
2784       --version              output version information and exit\n\
2785 \n\
2786 By default, color is not used to distinguish types of files.  That is\n\
2787 equivalent to using --color=none.  Using the --color option without the\n\
2788 optional WHEN argument is equivalent to using --color=always.  With\n\
2789 --color=auto, color codes are output only if standard output is connected\n\
2790 to a terminal (tty).\n\
2791 "));
2792       puts (_("\nReport bugs to fileutils-bugs@gnu.ai.mit.edu"));
2793     }
2794   exit (status);
2795 }