bracket bug address with <> and append a period
[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, NULL)) != -1)
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[11];
2038
2039   /* 7 fields that may (worst case: 64-bit integral values) require 20 bytes,
2040      1 10-byte mode string,
2041      1 24-byte time string (may be longer in some locales -- see below),
2042      9 spaces, one following each of these fields, and
2043      1 trailing NUL byte.  */
2044   char init_bigbuf[7 * 20 + 10 + 24 + 9 + 1];
2045   char *buf = init_bigbuf;
2046   size_t bufsize = sizeof (init_bigbuf);
2047   size_t s;
2048   char *p;
2049   time_t when;
2050   const char *fmt;
2051
2052 #ifdef HAVE_ST_DM_MODE
2053   mode_string (f->stat.st_dm_mode, modebuf);
2054 #else
2055   mode_string (f->stat.st_mode, modebuf);
2056 #endif
2057
2058   modebuf[10] = '\0';
2059
2060   switch (time_type)
2061     {
2062     case time_ctime:
2063       when = f->stat.st_ctime;
2064       break;
2065     case time_mtime:
2066       when = f->stat.st_mtime;
2067       break;
2068     case time_atime:
2069       when = f->stat.st_atime;
2070       break;
2071     }
2072
2073   if (full_time)
2074     {
2075       fmt = "%a %b %d %H:%M:%S %Y";
2076     }
2077   else
2078     {
2079       if (current_time > when + 6L * 30L * 24L * 60L * 60L      /* Old. */
2080           || current_time < when - 60L * 60L)   /* In the future. */
2081         {
2082           /* The file is fairly old or in the future.
2083              POSIX says the cutoff is 6 months old;
2084              approximate this by 6*30 days.
2085              Allow a 1 hour slop factor for what is considered "the future",
2086              to allow for NFS server/client clock disagreement.
2087              Show the year instead of the time of day.  */
2088           fmt = "%b %e  %Y";
2089         }
2090       else
2091         {
2092           fmt = "%b %e %H:%M";
2093         }
2094     }
2095
2096   p = buf;
2097
2098   if (print_inode)
2099     {
2100       sprintf (p, "%*lu ", INODE_DIGITS, (unsigned long) f->stat.st_ino);
2101       p += strlen (p);
2102     }
2103
2104   if (print_block_size)
2105     {
2106       sprintf (p, "%*u ", block_size_size,
2107                (unsigned) convert_blocks (ST_NBLOCKS (f->stat),
2108                                           kilobyte_blocks));
2109       p += strlen (p);
2110     }
2111
2112   /* The space between the mode and the number of links is the POSIX
2113      "optional alternate access method flag". */
2114   sprintf (p, "%s %3u ", modebuf, (unsigned int) f->stat.st_nlink);
2115   p += strlen (p);
2116
2117   if (numeric_users)
2118     sprintf (p, "%-8u ", (unsigned int) f->stat.st_uid);
2119   else
2120     sprintf (p, "%-8.8s ", getuser (f->stat.st_uid));
2121   p += strlen (p);
2122
2123   if (!inhibit_group)
2124     {
2125       if (numeric_users)
2126         sprintf (p, "%-8u ", (unsigned int) f->stat.st_gid);
2127       else
2128         sprintf (p, "%-8.8s ", getgroup (f->stat.st_gid));
2129       p += strlen (p);
2130     }
2131
2132   if (S_ISCHR (f->stat.st_mode) || S_ISBLK (f->stat.st_mode))
2133     sprintf (p, "%3u, %3u ", (unsigned) major (f->stat.st_rdev),
2134              (unsigned) minor (f->stat.st_rdev));
2135   else
2136     sprintf (p, "%8lu ", (unsigned long) f->stat.st_size);
2137   p += strlen (p);
2138
2139   /* Use strftime rather than ctime, because the former can produce
2140      locale-dependent names for the weekday (%a) and month (%b).  */
2141
2142   while (! (s = strftime (p, buf + bufsize - p - 1, fmt, localtime (&when))))
2143     {
2144       char *newbuf = (char *) alloca (bufsize *= 2);
2145       memcpy (newbuf, buf, p - buf);
2146       p = newbuf + (p - buf);
2147       buf = newbuf;
2148     }
2149
2150   p += s;
2151   *p++ = ' ';
2152
2153   /* NUL-terminate the string -- fputs (via FPUTS) requires it.  */
2154   *p = '\0';
2155
2156   DIRED_INDENT ();
2157   FPUTS (buf, stdout, p - buf);
2158   PUSH_CURRENT_DIRED_POS (&dired_obstack);
2159   print_name_with_quoting (f->name, f->stat.st_mode, f->linkok);
2160   PUSH_CURRENT_DIRED_POS (&dired_obstack);
2161
2162   if (f->filetype == symbolic_link)
2163     {
2164       if (f->linkname)
2165         {
2166           FPUTS_LITERAL (" -> ", stdout);
2167           print_name_with_quoting (f->linkname, f->linkmode, f->linkok - 1);
2168           if (indicator_style != none)
2169             print_type_indicator (f->linkmode);
2170         }
2171     }
2172   else if (indicator_style != none)
2173     print_type_indicator (f->stat.st_mode);
2174 }
2175
2176 /* Set QUOTED_LENGTH to strlen(P) and return NULL if P == quoted(P).
2177    Otherwise, return xmalloc'd storage containing the quoted version
2178    of P and set QUOTED_LENGTH to the length of the quoted P.  */
2179
2180 static char *
2181 quote_filename (register const char *p, size_t *quoted_length)
2182 {
2183   register unsigned char c;
2184   const char *p0 = p;
2185   char *quoted, *q;
2186   int found_quotable;
2187
2188   if (!quote_as_string && !quote_funny_chars && !qmark_funny_chars)
2189     {
2190       *quoted_length = strlen (p);
2191       return NULL;
2192     }
2193
2194   found_quotable = 0;
2195   for (c = *p; c; c = *++p)
2196     {
2197       if (quote_funny_chars)
2198         {
2199           switch (c)
2200             {
2201             case '\\':
2202             case '\n':
2203             case '\b':
2204             case '\r':
2205             case '\t':
2206             case '\f':
2207             case ' ':
2208             case '"':
2209               found_quotable = 1;
2210               break;
2211
2212             default:
2213               if (!ISGRAPH (c))
2214                 found_quotable = 1;
2215               break;
2216             }
2217         }
2218       else
2219         {
2220           if (!ISPRINT (c) && qmark_funny_chars)
2221             found_quotable = 1;
2222         }
2223       if (found_quotable)
2224         break;
2225     }
2226
2227   if (!found_quotable && !quote_as_string)
2228     {
2229       *quoted_length = p - p0;
2230       return NULL;
2231     }
2232
2233   p = p0;
2234   quoted = xmalloc (4 * strlen (p) + 1);
2235   q = quoted;
2236
2237 #define SAVECHAR(c) *q++ = (c)
2238 #define SAVE_2_CHARS(c12) \
2239     do { *q++ = ((c12)[0]); \
2240          *q++ = ((c12)[1]); } while (0)
2241
2242   if (quote_as_string)
2243     SAVECHAR ('"');
2244
2245   while ((c = *p++))
2246     {
2247       if (quote_funny_chars)
2248         {
2249           switch (c)
2250             {
2251             case '\\':
2252               SAVE_2_CHARS ("\\\\");
2253               break;
2254
2255             case '\n':
2256               SAVE_2_CHARS ("\\n");
2257               break;
2258
2259             case '\b':
2260               SAVE_2_CHARS ("\\b");
2261               break;
2262
2263             case '\r':
2264               SAVE_2_CHARS ("\\r");
2265               break;
2266
2267             case '\t':
2268               SAVE_2_CHARS ("\\t");
2269               break;
2270
2271             case '\f':
2272               SAVE_2_CHARS ("\\f");
2273               break;
2274
2275             case ' ':
2276               SAVE_2_CHARS ("\\ ");
2277               break;
2278
2279             case '"':
2280               SAVE_2_CHARS ("\\\"");
2281               break;
2282
2283             default:
2284               if (ISGRAPH (c))
2285                 SAVECHAR (c);
2286               else
2287                 {
2288                   char buf[5];
2289                   sprintf (buf, "\\%03o", (unsigned int) c);
2290                   q = stpcpy (q, buf);
2291                 }
2292             }
2293         }
2294       else
2295         {
2296           if (ISPRINT (c))
2297             SAVECHAR (c);
2298           else if (!qmark_funny_chars)
2299             SAVECHAR (c);
2300           else
2301             SAVECHAR ('?');
2302         }
2303     }
2304
2305   if (quote_as_string)
2306     SAVECHAR ('"');
2307
2308   *quoted_length = q - quoted;
2309
2310   SAVECHAR ('\0');
2311
2312   return quoted;
2313 }
2314
2315 static void
2316 print_name_with_quoting (const char *p, unsigned int mode, int linkok)
2317 {
2318   char *quoted;
2319   size_t quoted_length;
2320
2321   if (print_with_color)
2322     print_color_indicator (p, mode, linkok);
2323
2324   quoted = quote_filename (p, &quoted_length);
2325   FPUTS (quoted != NULL ? quoted : p, stdout, quoted_length);
2326   if (quoted)
2327     free (quoted);
2328
2329   if (print_with_color)
2330     prep_non_filename_text ();
2331 }
2332
2333 static void
2334 prep_non_filename_text (void)
2335 {
2336   if (color_indicator[C_END].string != NULL)
2337     put_indicator (&color_indicator[C_END]);
2338   else
2339     {
2340       put_indicator (&color_indicator[C_LEFT]);
2341       put_indicator (&color_indicator[C_NORM]);
2342       put_indicator (&color_indicator[C_RIGHT]);
2343     }
2344 }
2345
2346 /* Print the file name of `f' with appropriate quoting.
2347    Also print file size, inode number, and filetype indicator character,
2348    as requested by switches.  */
2349
2350 static void
2351 print_file_name_and_frills (const struct fileinfo *f)
2352 {
2353   if (print_inode)
2354     printf ("%*lu ", INODE_DIGITS, (unsigned long) f->stat.st_ino);
2355
2356   if (print_block_size)
2357     printf ("%*u ", block_size_size,
2358             (unsigned) convert_blocks (ST_NBLOCKS (f->stat),
2359                                        kilobyte_blocks));
2360
2361   print_name_with_quoting (f->name, f->stat.st_mode, f->linkok);
2362
2363   if (indicator_style != none)
2364     print_type_indicator (f->stat.st_mode);
2365 }
2366
2367 static void
2368 print_type_indicator (unsigned int mode)
2369 {
2370   if (S_ISDIR (mode))
2371     PUTCHAR ('/');
2372
2373 #ifdef S_ISLNK
2374   if (S_ISLNK (mode))
2375     PUTCHAR ('@');
2376 #endif
2377
2378 #ifdef S_ISFIFO
2379   if (S_ISFIFO (mode))
2380     PUTCHAR ('|');
2381 #endif
2382
2383 #ifdef S_ISSOCK
2384   if (S_ISSOCK (mode))
2385     PUTCHAR ('=');
2386 #endif
2387
2388   if (S_ISREG (mode) && indicator_style == all
2389       && (mode & S_IXUGO))
2390     PUTCHAR ('*');
2391 }
2392
2393 static void
2394 print_color_indicator (const char *name, unsigned int mode, int linkok)
2395 {
2396   int type = C_FILE;
2397   struct col_ext_type *ext;     /* Color extension */
2398   size_t len;                   /* Length of name */
2399
2400   /* Is this a nonexistent file?  If so, linkok == -1.  */
2401
2402   if (linkok == -1 && color_indicator[C_MISSING].string != NULL)
2403     {
2404       ext = NULL;
2405       type = C_MISSING;
2406     }
2407   else
2408     {
2409       if (S_ISDIR (mode))
2410         type = C_DIR;
2411
2412 #ifdef S_ISLNK
2413       else if (S_ISLNK (mode))
2414         type = ((!linkok && color_indicator[C_ORPHAN].string)
2415                 ? C_ORPHAN : C_LINK);
2416 #endif
2417
2418 #ifdef S_ISFIFO
2419       else if (S_ISFIFO (mode))
2420         type = C_FIFO;
2421 #endif
2422
2423 #ifdef S_ISSOCK
2424       else if (S_ISSOCK (mode))
2425         type = C_SOCK;
2426 #endif
2427
2428 #ifdef S_ISBLK
2429       else if (S_ISBLK (mode))
2430         type = C_BLK;
2431 #endif
2432
2433 #ifdef S_ISCHR
2434       else if (S_ISCHR (mode))
2435         type = C_CHR;
2436 #endif
2437
2438       if (type == C_FILE && (mode & S_IXUGO) != 0)
2439         type = C_EXEC;
2440
2441       /* Check the file's suffix only if still classified as C_FILE.  */
2442       ext = NULL;
2443       if (type == C_FILE)
2444         {
2445           /* Test if NAME has a recognized suffix.  */
2446
2447           len = strlen (name);
2448           name += len;          /* Pointer to final \0.  */
2449           for (ext = col_ext_list; ext != NULL; ext = ext->next)
2450             {
2451               if (ext->ext.len <= len
2452                   && strncmp (name - ext->ext.len, ext->ext.string,
2453                               ext->ext.len) == 0)
2454                 break;
2455             }
2456         }
2457     }
2458
2459   put_indicator (&color_indicator[C_LEFT]);
2460   put_indicator (ext ? &(ext->seq) : &color_indicator[type]);
2461   put_indicator (&color_indicator[C_RIGHT]);
2462 }
2463
2464 /* Output a color indicator (which may contain nulls).  */
2465 static void
2466 put_indicator (const struct bin_str *ind)
2467 {
2468   register int i;
2469   register char *p;
2470
2471   p = ind->string;
2472
2473   for (i = ind->len; i > 0; --i)
2474     putchar (*(p++));
2475 }
2476
2477 static int
2478 length_of_file_name_and_frills (const struct fileinfo *f)
2479 {
2480   register char *p = f->name;
2481   register unsigned char c;
2482   register int len = 0;
2483
2484   if (print_inode)
2485     len += INODE_DIGITS + 1;
2486
2487   if (print_block_size)
2488     len += 1 + block_size_size;
2489
2490   if (quote_as_string)
2491     len += 2;
2492
2493   while ((c = *p++))
2494     {
2495       if (quote_funny_chars)
2496         {
2497           switch (c)
2498             {
2499             case '\\':
2500             case '\n':
2501             case '\b':
2502             case '\r':
2503             case '\t':
2504             case '\f':
2505             case ' ':
2506               len += 2;
2507               break;
2508
2509             case '"':
2510               if (quote_as_string)
2511                 len += 2;
2512               else
2513                 len += 1;
2514               break;
2515
2516             default:
2517               if (ISPRINT (c))
2518                 len += 1;
2519               else
2520                 len += 4;
2521             }
2522         }
2523       else
2524         len += 1;
2525     }
2526
2527   if (indicator_style != none)
2528     {
2529       unsigned filetype = f->stat.st_mode;
2530
2531       if (S_ISREG (filetype))
2532         {
2533           if (indicator_style == all
2534               && (f->stat.st_mode & S_IXUGO))
2535             len += 1;
2536         }
2537       else if (S_ISDIR (filetype)
2538 #ifdef S_ISLNK
2539                || S_ISLNK (filetype)
2540 #endif
2541 #ifdef S_ISFIFO
2542                || S_ISFIFO (filetype)
2543 #endif
2544 #ifdef S_ISSOCK
2545                || S_ISSOCK (filetype)
2546 #endif
2547         )
2548         len += 1;
2549     }
2550
2551   return len;
2552 }
2553
2554 static void
2555 print_many_per_line (void)
2556 {
2557   int filesno;                  /* Index into files. */
2558   int row;                      /* Current row. */
2559   int max_name_length;          /* Length of longest file name + frills. */
2560   int name_length;              /* Length of each file name + frills. */
2561   int pos;                      /* Current character column. */
2562   int cols;                     /* Number of files across. */
2563   int rows;                     /* Maximum number of files down. */
2564
2565   /* Compute the maximum file name length.  */
2566   max_name_length = 0;
2567   for (filesno = 0; filesno < files_index; filesno++)
2568     {
2569       name_length = length_of_file_name_and_frills (files + filesno);
2570       if (name_length > max_name_length)
2571         max_name_length = name_length;
2572     }
2573
2574   /* Allow at least two spaces between names.  */
2575   max_name_length += 2;
2576
2577   /* Calculate the maximum number of columns that will fit. */
2578   cols = line_length / max_name_length;
2579   if (cols == 0)
2580     cols = 1;
2581   /* Calculate the number of rows that will be in each column except possibly
2582      for a short column on the right. */
2583   rows = files_index / cols + (files_index % cols != 0);
2584   /* Recalculate columns based on rows. */
2585   cols = files_index / rows + (files_index % rows != 0);
2586
2587   for (row = 0; row < rows; row++)
2588     {
2589       filesno = row;
2590       pos = 0;
2591       /* Print the next row.  */
2592       while (1)
2593         {
2594           print_file_name_and_frills (files + filesno);
2595           name_length = length_of_file_name_and_frills (files + filesno);
2596
2597           filesno += rows;
2598           if (filesno >= files_index)
2599             break;
2600
2601           indent (pos + name_length, pos + max_name_length);
2602           pos += max_name_length;
2603         }
2604       putchar ('\n');
2605     }
2606 }
2607
2608 static void
2609 print_horizontal (void)
2610 {
2611   int filesno;
2612   int max_name_length;
2613   int name_length;
2614   int cols;
2615   int pos;
2616
2617   /* Compute the maximum file name length.  */
2618   max_name_length = 0;
2619   for (filesno = 0; filesno < files_index; filesno++)
2620     {
2621       name_length = length_of_file_name_and_frills (files + filesno);
2622       if (name_length > max_name_length)
2623         max_name_length = name_length;
2624     }
2625
2626   /* Allow two spaces between names.  */
2627   max_name_length += 2;
2628
2629   cols = line_length / max_name_length;
2630   if (cols == 0)
2631     cols = 1;
2632
2633   pos = 0;
2634   name_length = 0;
2635
2636   for (filesno = 0; filesno < files_index; filesno++)
2637     {
2638       if (filesno != 0)
2639         {
2640           if (filesno % cols == 0)
2641             {
2642               putchar ('\n');
2643               pos = 0;
2644             }
2645           else
2646             {
2647               indent (pos + name_length, pos + max_name_length);
2648               pos += max_name_length;
2649             }
2650         }
2651
2652       print_file_name_and_frills (files + filesno);
2653
2654       name_length = length_of_file_name_and_frills (files + filesno);
2655     }
2656   putchar ('\n');
2657 }
2658
2659 static void
2660 print_with_commas (void)
2661 {
2662   int filesno;
2663   int pos, old_pos;
2664
2665   pos = 0;
2666
2667   for (filesno = 0; filesno < files_index; filesno++)
2668     {
2669       old_pos = pos;
2670
2671       pos += length_of_file_name_and_frills (files + filesno);
2672       if (filesno + 1 < files_index)
2673         pos += 2;               /* For the comma and space */
2674
2675       if (old_pos != 0 && pos >= line_length)
2676         {
2677           putchar ('\n');
2678           pos -= old_pos;
2679         }
2680
2681       print_file_name_and_frills (files + filesno);
2682       if (filesno + 1 < files_index)
2683         {
2684           putchar (',');
2685           putchar (' ');
2686         }
2687     }
2688   putchar ('\n');
2689 }
2690
2691 /* Assuming cursor is at position FROM, indent up to position TO.
2692    Use a TAB character instead of two or more spaces whenever possible.  */
2693
2694 static void
2695 indent (int from, int to)
2696 {
2697   while (from < to)
2698     {
2699       if (tabsize > 0 && to / tabsize > (from + 1) / tabsize)
2700         {
2701           putchar ('\t');
2702           from += tabsize - from % tabsize;
2703         }
2704       else
2705         {
2706           putchar (' ');
2707           from++;
2708         }
2709     }
2710 }
2711
2712 /* Put DIRNAME/NAME into DEST, handling `.' and `/' properly. */
2713
2714 static void
2715 attach (char *dest, const char *dirname, const char *name)
2716 {
2717   const char *dirnamep = dirname;
2718
2719   /* Copy dirname if it is not ".". */
2720   if (dirname[0] != '.' || dirname[1] != 0)
2721     {
2722       while (*dirnamep)
2723         *dest++ = *dirnamep++;
2724       /* Add '/' if `dirname' doesn't already end with it. */
2725       if (dirnamep > dirname && dirnamep[-1] != '/')
2726         *dest++ = '/';
2727     }
2728   while (*name)
2729     *dest++ = *name++;
2730   *dest = 0;
2731 }
2732
2733 static void
2734 usage (int status)
2735 {
2736   if (status != 0)
2737     fprintf (stderr, _("Try `%s --help' for more information.\n"),
2738              program_name);
2739   else
2740     {
2741       printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name);
2742       printf (_("\
2743 List information about the FILEs (the current directory by default).\n\
2744 Sort entries alphabetically if none of -cftuSUX nor --sort.\n\
2745 \n\
2746   -a, --all                  do not hide entries starting with .\n\
2747   -A, --almost-all           do not list implied . and ..\n\
2748   -b, --escape               print octal escapes for nongraphic characters\n\
2749   -B, --ignore-backups       do not list implied entries ending with ~\n\
2750   -c                         sort by change time; with -l: show ctime\n\
2751   -C                         list entries by columns\n\
2752       --color[=WHEN]         control whether color is used to distinguish file\n\
2753                                types.  WHEN may be `never', `always', or `auto'\n\
2754   -d, --directory            list directory entries instead of contents\n\
2755   -D, --dired                generate output designed for Emacs' dired mode\n\
2756   -f                         do not sort, enable -aU, disable -lst\n\
2757   -F, --classify             append a character for typing each entry\n\
2758       --format=WORD          across -x, commas -m, horizontal -x, long -l,\n\
2759                                single-column -1, verbose -l, vertical -C\n\
2760       --full-time            list both full date and full time\n"));
2761
2762       printf (_("\
2763   -g                         (ignored)\n\
2764   -G, --no-group             inhibit display of group information\n\
2765   -i, --inode                print index number of each file\n\
2766   -I, --ignore=PATTERN       do not list implied entries matching shell PATTERN\n\
2767   -k, --kilobytes            use 1024 blocks, not 512 despite POSIXLY_CORRECT\n\
2768   -l                         use a long listing format\n\
2769   -L, --dereference          list entries pointed to by symbolic links\n\
2770   -m                         fill width with a comma separated list of entries\n\
2771   -n, --numeric-uid-gid      list numeric UIDs and GIDs instead of names\n\
2772   -N, --literal              print raw entry names (don't treat e.g. control\n\
2773                                characters specially)\n\
2774   -o                         use long listing format without group info\n\
2775   -p                         append a character for typing each entry\n\
2776   -q, --hide-control-chars   print ? instead of non graphic characters\n\
2777   -Q, --quote-name           enclose entry names in double quotes\n\
2778   -r, --reverse              reverse order while sorting\n\
2779   -R, --recursive            list subdirectories recursively\n\
2780   -s, --size                 print size of each file, in blocks\n"));
2781
2782       printf (_("\
2783   -S                         sort by file size\n\
2784       --sort=WORD            ctime -c, extension -X, none -U, size -S,\n\
2785                              status -c, time -t, atime -u, access -u, use -u\n\
2786       --time=WORD            show time as WORD instead of modification time:\n\
2787                              atime, access, use, ctime or status\n\
2788   -t                         sort by modification time; with -l: show mtime\n\
2789   -T, --tabsize=COLS         assume tab stops at each COLS instead of 8\n\
2790   -u                         sort by last access time; with -l: show atime\n\
2791   -U                         do not sort; list entries in directory order\n\
2792   -w, --width=COLS           assume screen width instead of current value\n\
2793   -x                         list entries by lines instead of by columns\n\
2794   -X                         sort alphabetically by entry extension\n\
2795   -1                         list one file per line\n\
2796       --help                 display this help and exit\n\
2797       --version              output version information and exit\n\
2798 \n\
2799 By default, color is not used to distinguish types of files.  That is\n\
2800 equivalent to using --color=none.  Using the --color option without the\n\
2801 optional WHEN argument is equivalent to using --color=always.  With\n\
2802 --color=auto, color codes are output only if standard output is connected\n\
2803 to a terminal (tty).\n\
2804 "));
2805       puts (_("\nReport bugs to <fileutils-bugs@gnu.ai.mit.edu>."));
2806     }
2807   exit (status);
2808 }