1 /* `dir', `vdir' and `ls' directory listing programs for GNU.
2 Copyright (C) 85, 88, 90, 91, 95, 96, 97, 1998 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
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.
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.
29 the output format depends on whether the output
31 This is for the `ls' program. */
33 /* Written by Richard Stallman and David MacKenzie. */
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>. */
44 #include <sys/types.h>
47 # include <inttypes.h>
54 #ifdef GWINSZ_IN_SYS_IOCTL
55 # include <sys/ioctl.h>
73 #include "strverscmp.h"
75 #define obstack_chunk_alloc malloc
76 #define obstack_chunk_free free
78 /* Return an int indicating the result of comparing two integers.
79 Subtracting doesn't always work, due to overflow. */
80 #define longdiff(a, b) ((a) < (b) ? -1 : (a) > (b))
82 /* The field width for inode numbers. On some hosts inode numbers are
83 64 bits, so columns won't line up exactly when a huge inode number
84 is encountered, but in practice 7 digits is usually enough. */
86 # define INODE_DIGITS 7
93 arg_directory
, /* Directory given as command line arg. */
94 normal
/* All others. */
104 /* For symbolic link, name of the file linked to, otherwise zero. */
107 /* For symbolic link and long listing, st_mode of file linked to, otherwise
109 unsigned int linkmode
;
111 /* For symbolic link and color printing, 1 if linked-to file
112 exists, otherwise 0. */
115 enum filetype filetype
;
118 #define LEN_STR_PAIR(s) sizeof (s) - 1, s
120 /* Null is a valid character in a color indicator (think about Epson
121 printers, for example) so we have to use a length/buffer string
126 int len
; /* Number of bytes */
127 char *string
; /* Pointer to the same */
138 void strip_trailing_slashes ();
142 static size_t quote_filename
PARAMS ((FILE *out
, const char *filename
));
143 static char *make_link_path
PARAMS ((const char *path
, const char *linkname
));
144 static int compare_atime
PARAMS ((const struct fileinfo
*file1
,
145 const struct fileinfo
*file2
));
146 static int rev_cmp_atime
PARAMS ((const struct fileinfo
*file2
,
147 const struct fileinfo
*file1
));
148 static int compare_ctime
PARAMS ((const struct fileinfo
*file1
,
149 const struct fileinfo
*file2
));
150 static int rev_cmp_ctime
PARAMS ((const struct fileinfo
*file2
,
151 const struct fileinfo
*file1
));
152 static int compare_mtime
PARAMS ((const struct fileinfo
*file1
,
153 const struct fileinfo
*file2
));
154 static int rev_cmp_mtime
PARAMS ((const struct fileinfo
*file2
,
155 const struct fileinfo
*file1
));
156 static int compare_size
PARAMS ((const struct fileinfo
*file1
,
157 const struct fileinfo
*file2
));
158 static int rev_cmp_size
PARAMS ((const struct fileinfo
*file2
,
159 const struct fileinfo
*file1
));
160 static int compare_name
PARAMS ((const struct fileinfo
*file1
,
161 const struct fileinfo
*file2
));
162 static int rev_cmp_name
PARAMS ((const struct fileinfo
*file2
,
163 const struct fileinfo
*file1
));
164 static int compare_extension
PARAMS ((const struct fileinfo
*file1
,
165 const struct fileinfo
*file2
));
166 static int rev_cmp_extension
PARAMS ((const struct fileinfo
*file2
,
167 const struct fileinfo
*file1
));
168 static int compare_version
PARAMS ((const struct fileinfo
*file1
,
169 const struct fileinfo
*file2
));
170 static int rev_cmp_version
PARAMS ((const struct fileinfo
*file2
,
171 const struct fileinfo
*file1
));
172 static int decode_switches
PARAMS ((int argc
, char **argv
));
173 static int file_interesting
PARAMS ((const struct dirent
*next
));
174 static uintmax_t gobble_file
PARAMS ((const char *name
, int explicit_arg
,
175 const char *dirname
));
176 static int is_not_dot_or_dotdot
PARAMS ((const char *name
));
177 static void print_color_indicator
PARAMS ((const char *name
, unsigned int mode
,
179 static void put_indicator
PARAMS ((const struct bin_str
*ind
));
180 static int length_of_file_name_and_frills
PARAMS ((const struct fileinfo
*f
));
181 static void add_ignore_pattern
PARAMS ((const char *pattern
));
182 static void attach
PARAMS ((char *dest
, const char *dirname
, const char *name
));
183 static void clear_files
PARAMS ((void));
184 static void extract_dirs_from_files
PARAMS ((const char *dirname
,
186 static void get_link_name
PARAMS ((const char *filename
, struct fileinfo
*f
));
187 static void indent
PARAMS ((int from
, int to
));
188 static void init_col_info
PARAMS ((void));
189 static void print_current_files
PARAMS ((void));
190 static void print_dir
PARAMS ((const char *name
, const char *realname
));
191 static void print_file_name_and_frills
PARAMS ((const struct fileinfo
*f
));
192 static void print_horizontal
PARAMS ((void));
193 static void print_long_format
PARAMS ((const struct fileinfo
*f
));
194 static void print_many_per_line
PARAMS ((void));
195 static void print_name_with_quoting
PARAMS ((const char *p
, unsigned int mode
,
197 struct obstack
*stack
));
198 static void prep_non_filename_text
PARAMS ((void));
199 static void print_type_indicator
PARAMS ((unsigned int mode
));
200 static void print_with_commas
PARAMS ((void));
201 static void queue_directory
PARAMS ((const char *name
, const char *realname
));
202 static void sort_files
PARAMS ((void));
203 static void parse_ls_color
PARAMS ((void));
204 static void usage
PARAMS ((int status
));
206 /* The name the program was run with, stripped of any leading path. */
209 /* The table of files in the current directory:
211 `files' points to a vector of `struct fileinfo', one per file.
212 `nfiles' is the number of elements space has been allocated for.
213 `files_index' is the number actually in use. */
215 /* Address of block containing the files that are described. */
217 static struct fileinfo
*files
;
219 /* Length of block that `files' points to, measured in files. */
223 /* Index of first unused in `files'. */
225 static int files_index
;
227 /* Record of one pending directory waiting to be listed. */
232 /* If the directory is actually the file pointed to by a symbolic link we
233 were told to list, `realname' will contain the name of the symbolic
234 link, otherwise zero. */
236 struct pending
*next
;
239 static struct pending
*pending_dirs
;
241 /* Current time (seconds since 1970). When we are printing a file's time,
242 include the year if it is more than 6 months before this time. */
244 static time_t current_time
;
246 /* The number of digits to use for block sizes.
247 4, or more if needed for bigger numbers. */
249 static int block_size_size
;
253 /* long_format for lots of info, one per line.
254 one_per_line for just names, one per line.
255 many_per_line for just names, many per line, sorted vertically.
256 horizontal for just names, many per line, sorted horizontally.
257 with_commas for just names, many per line, separated by commas.
259 -l, -1, -C, -x and -m control this parameter. */
263 long_format
, /* -l */
264 one_per_line
, /* -1 */
265 many_per_line
, /* -C */
270 static enum format format
;
272 /* Type of time to print or sort by. Controlled by -c and -u. */
276 time_mtime
, /* default */
281 static enum time_type time_type
;
283 /* print the full time, otherwise the standard unix heuristics. */
287 /* The file characteristic to sort by. Controlled by -t, -S, -U, -X, -v. */
292 sort_name
, /* default */
293 sort_extension
, /* -X */
296 sort_version
/* -v */
299 static enum sort_type sort_type
;
301 /* Direction of sort.
302 0 means highest first if numeric,
303 lowest first if alphabetic;
304 these are the defaults.
305 1 means the opposite order in each case. -r */
307 static int sort_reverse
;
309 /* Nonzero means to NOT display group information. -G */
313 /* Nonzero means print the user and group id's as numbers rather
316 static int numeric_ids
;
318 /* Nonzero means mention the size in 512 byte blocks of each file. -s */
320 static int print_block_size
;
322 /* The units to count blocks in. */
324 static int output_units
;
326 /* Precede each line of long output (per file) with a string like `m,n:'
327 where M is the number of characters after the `:' and before the
328 filename and N is the length of the filename. Using this format,
329 Emacs' dired mode starts up twice as fast, and can handle all
330 strange characters in file names. */
333 /* `none' means don't mention the type of files.
334 `all' means mention the types of all files.
335 `not_programs' means do so except for executables.
337 Controlled by -F and -p. */
343 not_programs
/* -p */
346 static enum indicator_style indicator_style
;
348 /* Nonzero means use colors to mark types. Also define the different
349 colors as well as the stuff for the LS_COLORS environment variable.
350 The LS_COLORS variable is now in a termcap-like format. */
352 static int print_with_color
;
356 color_never
, /* 0: default or --color=never */
357 color_always
, /* 1: --color=always */
358 color_if_tty
/* 2: --color=tty */
363 C_LEFT
, C_RIGHT
, C_END
, C_NORM
, C_FILE
, C_DIR
, C_LINK
, C_FIFO
, C_SOCK
,
364 C_BLK
, C_CHR
, C_MISSING
, C_ORPHAN
, C_EXEC
367 static const char *const indicator_name
[]=
369 "lc", "rc", "ec", "no", "fi", "di", "ln", "pi", "so",
370 "bd", "cd", "mi", "or", "ex", NULL
375 struct bin_str ext
; /* The extension we're looking for */
376 struct bin_str seq
; /* The sequence to output when we do */
377 struct col_ext_type
*next
; /* Next in list */
380 static struct bin_str color_indicator
[] =
382 { LEN_STR_PAIR ("\033[") }, /* lc: Left of color sequence */
383 { LEN_STR_PAIR ("m") }, /* rc: Right of color sequence */
384 { 0, NULL
}, /* ec: End color (replaces lc+no+rc) */
385 { LEN_STR_PAIR ("0") }, /* no: Normal */
386 { LEN_STR_PAIR ("0") }, /* fi: File: default */
387 { LEN_STR_PAIR ("01;34") }, /* di: Directory: bright blue */
388 { LEN_STR_PAIR ("01;36") }, /* ln: Symlink: bright cyan */
389 { LEN_STR_PAIR ("33") }, /* pi: Pipe: yellow/brown */
390 { LEN_STR_PAIR ("01;35") }, /* so: Socket: bright magenta */
391 { LEN_STR_PAIR ("01;33") }, /* bd: Block device: bright yellow */
392 { LEN_STR_PAIR ("01;33") }, /* cd: Char device: bright yellow */
393 { 0, NULL
}, /* mi: Missing file: undefined */
394 { 0, NULL
}, /* or: Orphanned symlink: undefined */
395 { LEN_STR_PAIR ("01;32") } /* ex: Executable: bright green */
399 struct col_ext_type
*col_ext_list
= NULL
;
401 /* Buffer for color sequences */
402 static char *color_buf
;
404 /* base used for human style output */
406 static int human_readable_base
;
408 /* Nonzero means mention the inode number of each file. -i */
410 static int print_inode
;
412 /* Nonzero means when a symbolic link is found, display info on
413 the file linked to. -L */
415 static int trace_links
;
417 /* Nonzero means when a directory is found, display info on its
420 static int trace_dirs
;
422 /* Nonzero means when an argument is a directory name, display info
425 static int immediate_dirs
;
427 /* Nonzero means don't omit files whose names start with `.'. -A */
429 static int all_files
;
431 /* Nonzero means don't omit files `.' and `..'
432 This flag implies `all_files'. -a */
434 static int really_all_files
;
436 /* A linked list of shell-style globbing patterns. If a non-argument
437 file name matches any of these patterns, it is omitted.
438 Controlled by -I. Multiple -I options accumulate.
439 The -B option adds `*~' and `.*~' to this list. */
441 struct ignore_pattern
444 struct ignore_pattern
*next
;
447 static struct ignore_pattern
*ignore_patterns
;
449 /* Nonzero means quote nongraphic chars in file names. -b */
451 static int quote_funny_chars
;
453 /* Nonzero means output nongraphic chars in file names as `?'. -q */
455 static int qmark_funny_chars
;
457 /* Nonzero means output each file name using C syntax for a string.
458 Always accompanied by `quote_funny_chars'.
459 This mode, together with -x or -C or -m,
460 and without such frills as -F or -s,
461 is guaranteed to make it possible for a program receiving
462 the output to tell exactly what file names are present. -Q */
464 static int quote_as_string
;
466 /* Nonzero means use shell style quoting; it is also unambiguous. -e */
468 static int quote_shell
;
470 /* The number of chars per hardware tab stop. Setting this to zero
471 inhibits the use of TAB characters for separating columns. -T */
474 /* Nonzero means we are listing the working directory because no
475 non-option arguments were given. */
477 static int dir_defaulted
;
479 /* Nonzero means print each directory name before listing it. */
481 static int print_dir_name
;
483 /* The line length to use for breaking lines in many-per-line format.
484 Can be set with -w. */
486 static int line_length
;
488 /* If nonzero, the file listing format requires that stat be called on
491 static int format_needs_stat
;
493 /* The exit status to use if we don't get any fatal errors. */
495 static int exit_status
;
497 /* If nonzero, display usage information and exit. */
498 static int show_help
;
500 /* If nonzero, print the version on standard output and exit. */
501 static int show_version
;
503 static struct option
const long_options
[] =
505 {"all", no_argument
, 0, 'a'},
506 {"escape", no_argument
, 0, 'b'},
507 {"directory", no_argument
, 0, 'd'},
508 {"dired", no_argument
, 0, 'D'},
509 {"full-time", no_argument
, &full_time
, 1},
510 {"human-readable", no_argument
, 0, 'h'},
511 {"inode", no_argument
, 0, 'i'},
512 {"kilobytes", no_argument
, 0, 'k'},
513 {"numeric-uid-gid", no_argument
, 0, 'n'},
514 {"no-group", no_argument
, 0, 'G'},
515 {"hide-control-chars", no_argument
, 0, 'q'},
516 {"reverse", no_argument
, 0, 'r'},
517 {"size", no_argument
, 0, 's'},
518 {"width", required_argument
, 0, 'w'},
519 {"almost-all", no_argument
, 0, 'A'},
520 {"ignore-backups", no_argument
, 0, 'B'},
521 {"classify", no_argument
, 0, 'F'},
522 {"file-type", no_argument
, 0, 'F'},
523 {"si", no_argument
, 0, 'H'},
524 {"ignore", required_argument
, 0, 'I'},
525 {"dereference", no_argument
, 0, 'L'},
526 {"literal", no_argument
, 0, 'N'},
527 {"quote-name", no_argument
, 0, 'Q'},
528 {"quote-shell", no_argument
, 0, 'e'},
529 {"recursive", no_argument
, 0, 'R'},
530 {"format", required_argument
, 0, 12},
531 {"sort", required_argument
, 0, 10},
532 {"tabsize", required_argument
, 0, 'T'},
533 {"time", required_argument
, 0, 11},
534 {"help", no_argument
, &show_help
, 1},
535 {"version", no_argument
, &show_version
, 1},
536 {"color", optional_argument
, 0, 13},
540 static char const *const format_args
[] =
542 "verbose", "long", "commas", "horizontal", "across",
543 "vertical", "single-column", 0
546 static enum format
const formats
[] =
548 long_format
, long_format
, with_commas
, horizontal
, horizontal
,
549 many_per_line
, one_per_line
552 static char const *const sort_args
[] =
554 "none", "time", "size", "extension", "version", 0
557 static enum sort_type
const sort_types
[] =
559 sort_none
, sort_time
, sort_size
, sort_extension
, sort_version
562 static char const *const time_args
[] =
564 "atime", "access", "use", "ctime", "status", 0
567 /* This zero-based index is used solely with the --dired option.
568 When that option is in effect, this counter is incremented for each
569 character of output generated by this program so that the beginning
570 and ending indices (in that output) of every file name can be recorded
571 and later output themselves. */
572 static size_t dired_pos
;
574 #define PUTCHAR(c) do {putchar ((c)); ++dired_pos;} while (0)
576 /* Write S to STREAM and increment DIRED_POS by S_LEN. */
577 #define FPUTS(s, stream, s_len) \
578 do {fputs ((s), (stream)); dired_pos += s_len;} while (0)
580 /* Like FPUTS, but for use when S is a literal string. */
581 #define FPUTS_LITERAL(s, stream) \
582 do {fputs ((s), (stream)); dired_pos += sizeof((s)) - 1;} while (0)
584 #define DIRED_INDENT() \
587 /* FIXME: remove the `&& format == long_format' clause. */ \
588 if (dired && format == long_format) \
589 FPUTS_LITERAL (" ", stdout); \
593 /* With --dired, store pairs of beginning and ending indices of filenames. */
594 static struct obstack dired_obstack
;
596 /* With --dired, store pairs of beginning and ending indices of any
597 directory names that appear as headers (just before `total' line)
598 for lists of directory entries. Such directory names are seen when
599 listing hierarchies using -R and when a directory is listed with at
600 least one other command line argument. */
601 static struct obstack subdired_obstack
;
603 /* Save the current index on the specified obstack, OBS. */
604 #define PUSH_CURRENT_DIRED_POS(obs) \
607 /* FIXME: remove the `&& format == long_format' clause. */ \
608 if (dired && format == long_format) \
609 obstack_grow ((obs), &dired_pos, sizeof (dired_pos)); \
613 static enum time_type
const time_types
[] =
615 time_atime
, time_atime
, time_atime
, time_ctime
, time_ctime
618 static char const *const color_args
[] =
620 /* Note: "no" is a prefix of "none" so we don't include it. */
621 /* force and none are for compatibility with another color-ls version */
622 "always", "yes", "force",
624 "auto", "tty", "if-tty", 0
627 static enum color_type
const color_types
[] =
629 color_always
, color_always
, color_always
,
630 color_never
, color_never
,
631 color_if_tty
, color_if_tty
, color_if_tty
635 /* Information about filling a column. */
643 /* Array with information about column filledness. */
644 static struct col_info
*col_info
;
646 /* Maximum number of columns ever possible for this display. */
649 /* The minimum width of a colum is 3: 1 character for the name and 2
650 for the separating white space. */
651 #define MIN_COLUMN_WIDTH 3
654 /* Write to standard output the strings PREFIX and STYLE, followed by
655 a space-separated list of the integers stored in OS all on one line. */
658 dired_dump_obstack (const char *prefix
, const char *style
, struct obstack
*os
)
662 n_pos
= obstack_object_size (os
) / sizeof (size_t);
668 pos
= (size_t *) obstack_finish (os
);
669 fputs (prefix
, stdout
);
670 fputs (style
, stdout
);
671 for (i
= 0; i
< n_pos
; i
++)
672 printf (" %d", (int) pos
[i
]);
673 fputs ("\n", stdout
);
678 main (int argc
, char **argv
)
681 register struct pending
*thispend
;
683 program_name
= argv
[0];
684 setlocale (LC_ALL
, "");
685 bindtextdomain (PACKAGE
, LOCALEDIR
);
686 textdomain (PACKAGE
);
692 current_time
= time ((time_t *) 0);
694 i
= decode_switches (argc
, argv
);
698 printf ("%s (%s) %s\n",
699 (ls_mode
== LS_LS
? "ls"
700 : (ls_mode
== LS_MULTI_COL
? "dir" : "vdir")),
701 GNU_PACKAGE
, VERSION
);
707 usage (EXIT_SUCCESS
);
709 if (print_with_color
)
712 prep_non_filename_text ();
715 format_needs_stat
= sort_type
== sort_time
|| sort_type
== sort_size
716 || format
== long_format
717 || trace_links
|| trace_dirs
|| indicator_style
!= none
718 || print_block_size
|| print_inode
|| print_with_color
;
720 if (dired
&& format
== long_format
)
722 obstack_init (&dired_obstack
);
723 obstack_init (&subdired_obstack
);
727 files
= (struct fileinfo
*) xmalloc (sizeof (struct fileinfo
) * nfiles
);
734 for (; i
< argc
; i
++)
736 strip_trailing_slashes (argv
[i
]);
737 gobble_file (argv
[i
], 1, "");
743 gobble_file (".", 1, "");
745 queue_directory (".", 0);
752 extract_dirs_from_files ("", 0);
753 /* `files_index' might be zero now. */
757 print_current_files ();
761 else if (pending_dirs
&& pending_dirs
->next
== 0)
766 thispend
= pending_dirs
;
767 pending_dirs
= pending_dirs
->next
;
768 print_dir (thispend
->name
, thispend
->realname
);
769 free (thispend
->name
);
770 if (thispend
->realname
)
771 free (thispend
->realname
);
776 if (dired
&& format
== long_format
)
778 const char *quoting_style
= (quote_shell
? " -e"
779 : quote_as_string
? " -Q"
780 : quote_funny_chars
? " -b"
782 /* No need to free these since we're about to exit. */
783 dired_dump_obstack ("//DIRED//", quoting_style
, &dired_obstack
);
784 dired_dump_obstack ("//SUBDIRED//", quoting_style
, &subdired_obstack
);
787 /* Restore default color before exiting */
788 if (print_with_color
)
790 put_indicator (&color_indicator
[C_LEFT
]);
791 put_indicator (&color_indicator
[C_RIGHT
]);
798 /* Set all the option flags according to the switches specified.
799 Return the index of the first non-option argument. */
802 decode_switches (int argc
, char **argv
)
809 qmark_funny_chars
= 0;
810 quote_funny_chars
= 0;
812 /* initialize all switches to default settings */
817 /* This is for the `dir' program. */
818 format
= many_per_line
;
819 quote_funny_chars
= 1;
823 /* This is for the `vdir' program. */
824 format
= long_format
;
825 quote_funny_chars
= 1;
829 /* This is for the `ls' program. */
832 format
= many_per_line
;
833 qmark_funny_chars
= 1;
837 format
= one_per_line
;
838 qmark_funny_chars
= 0;
846 time_type
= time_mtime
;
848 sort_type
= sort_name
;
851 print_block_size
= 0;
852 output_units
= getenv ("POSIXLY_CORRECT") ? 512 : 1024;
853 indicator_style
= none
;
859 really_all_files
= 0;
864 if ((p
= getenv ("BLOCKSIZE"))
865 && strncmp (p
, "HUMAN", sizeof ("HUMAN") - 1) == 0)
866 human_readable_base
= 1024;
867 else if (p
&& strcmp (p
, "SI") == 0)
868 human_readable_base
= 1000;
871 if ((p
= getenv ("COLUMNS")) && *p
)
873 if (xstrtol (p
, NULL
, 0, &tmp_long
, NULL
) == LONGINT_OK
874 && 0 < tmp_long
&& tmp_long
<= INT_MAX
)
876 line_length
= (int) tmp_long
;
881 _("ignoring invalid width in environment variable COLUMNS: %s"),
890 if (ioctl (1, TIOCGWINSZ
, &ws
) != -1 && ws
.ws_col
!= 0)
891 line_length
= ws
.ws_col
;
895 /* Using the TABSIZE environment variable is not POSIX-approved.
896 Ignore it when POSIXLY_CORRECT is set. */
898 if (!getenv ("POSIXLY_CORRECT") && (p
= getenv ("TABSIZE")))
900 if (xstrtol (p
, NULL
, 0, &tmp_long
, NULL
) == LONGINT_OK
901 && 0 <= tmp_long
&& tmp_long
<= INT_MAX
)
903 tabsize
= (int) tmp_long
;
908 _("ignoring invalid tab size in environment variable TABSIZE: %s"),
913 while ((c
= getopt_long (argc
, argv
,
914 "abcdefghiklmnopqrstuvw:xABCDFGHI:LNQRST:UX1",
915 long_options
, NULL
)) != -1)
924 really_all_files
= 1;
928 quote_funny_chars
= 1;
931 qmark_funny_chars
= 0;
935 time_type
= time_ctime
;
936 sort_type
= sort_time
;
946 quote_funny_chars
= 0;
947 qmark_funny_chars
= 0;
951 /* Same as enabling -a -U and disabling -l -s. */
953 really_all_files
= 1;
954 sort_type
= sort_none
;
956 if (format
== long_format
)
957 format
= (isatty (1) ? many_per_line
: one_per_line
);
958 print_block_size
= 0; /* disable -s */
959 print_with_color
= 0; /* disable --color */
963 /* No effect. For BSD compatibility. */
967 human_readable_base
= 1024;
971 human_readable_base
= 1000;
983 format
= long_format
;
987 format
= with_commas
;
994 case 'o': /* Just like -l, but don't display group info. */
995 format
= long_format
;
1000 indicator_style
= not_programs
;
1004 qmark_funny_chars
= 1;
1005 quote_as_string
= 0;
1006 quote_funny_chars
= 0;
1015 print_block_size
= 1;
1019 sort_type
= sort_time
;
1023 sort_type
= sort_time
;
1024 time_type
= time_atime
;
1028 sort_type
= sort_version
;
1032 if (xstrtol (optarg
, NULL
, 0, &tmp_long
, NULL
) != LONGINT_OK
1033 || tmp_long
<= 0 || tmp_long
> INT_MAX
)
1034 error (EXIT_FAILURE
, 0, _("invalid line width: %s"), optarg
);
1035 line_length
= (int) tmp_long
;
1039 format
= horizontal
;
1043 really_all_files
= 0;
1048 add_ignore_pattern ("*~");
1049 add_ignore_pattern (".*~");
1053 format
= many_per_line
;
1061 indicator_style
= all
;
1064 case 'G': /* inhibit display of group info */
1069 add_ignore_pattern (optarg
);
1077 quote_as_string
= 0;
1078 quote_funny_chars
= 0;
1080 qmark_funny_chars
= 0;
1084 quote_as_string
= 1;
1085 quote_funny_chars
= 1;
1087 qmark_funny_chars
= 0;
1095 sort_type
= sort_size
;
1099 if (xstrtol (optarg
, NULL
, 0, &tmp_long
, NULL
) != LONGINT_OK
1100 || tmp_long
< 0 || tmp_long
> INT_MAX
)
1101 error (EXIT_FAILURE
, 0, _("invalid tab size: %s"), optarg
);
1102 tabsize
= (int) tmp_long
;
1106 sort_type
= sort_none
;
1110 sort_type
= sort_extension
;
1114 format
= one_per_line
;
1117 case 10: /* --sort */
1118 i
= argmatch (optarg
, sort_args
);
1121 invalid_arg (_("sort type"), optarg
, i
);
1122 usage (EXIT_FAILURE
);
1124 sort_type
= sort_types
[i
];
1127 case 11: /* --time */
1128 i
= argmatch (optarg
, time_args
);
1131 invalid_arg (_("time type"), optarg
, i
);
1132 usage (EXIT_FAILURE
);
1134 time_type
= time_types
[i
];
1137 case 12: /* --format */
1138 i
= argmatch (optarg
, format_args
);
1141 invalid_arg (_("format type"), optarg
, i
);
1142 usage (EXIT_FAILURE
);
1144 format
= formats
[i
];
1147 case 13: /* --color */
1150 i
= argmatch (optarg
, color_args
);
1153 invalid_arg (_("colorization criterion"), optarg
, i
);
1154 usage (EXIT_FAILURE
);
1160 /* Using --color with no argument is equivalent to using
1165 print_with_color
= (i
== color_always
1166 || (i
== color_if_tty
1167 && isatty (STDOUT_FILENO
)));
1169 if (print_with_color
)
1171 /* Don't use TAB characters in output. Some terminal
1172 emulators can't handle the combination of tabs and
1173 color codes on the same line. */
1179 usage (EXIT_FAILURE
);
1183 if (human_readable_base
)
1189 /* Parse a string as part of the LS_COLORS variable; this may involve
1190 decoding all kinds of escape characters. If equals_end is set an
1191 unescaped equal sign ends the string, otherwise only a : or \0
1192 does. Returns the number of characters output, or -1 on failure.
1194 The resulting string is *not* null-terminated, but may contain
1197 Note that both dest and src are char **; on return they point to
1198 the first free byte after the array and the character that ended
1199 the input string, respectively. */
1202 get_funky_string (char **dest
, const char **src
, int equals_end
)
1204 int num
; /* For numerical codes */
1205 int count
; /* Something to count with */
1207 ST_GND
, ST_BACKSLASH
, ST_OCTAL
, ST_HEX
, ST_CARET
, ST_END
, ST_ERROR
1212 p
= *src
; /* We don't want to double-indirect */
1213 q
= *dest
; /* the whole darn time. */
1215 count
= 0; /* No characters counted in yet. */
1218 state
= ST_GND
; /* Start in ground state. */
1219 while (state
< ST_END
)
1223 case ST_GND
: /* Ground state (no escapes) */
1228 state
= ST_END
; /* End of string */
1231 state
= ST_BACKSLASH
; /* Backslash scape sequence */
1235 state
= ST_CARET
; /* Caret escape */
1241 state
= ST_END
; /* End */
1244 /* else fall through */
1252 case ST_BACKSLASH
: /* Backslash escaped character */
1263 state
= ST_OCTAL
; /* Octal sequence */
1268 state
= ST_HEX
; /* Hex sequence */
1271 case 'a': /* Bell */
1272 num
= 7; /* Not all C compilers know what \a means */
1274 case 'b': /* Backspace */
1277 case 'e': /* Escape */
1280 case 'f': /* Form feed */
1283 case 'n': /* Newline */
1286 case 'r': /* Carriage return */
1292 case 'v': /* Vtab */
1295 case '?': /* Delete */
1298 case '_': /* Space */
1301 case '\0': /* End of string */
1302 state
= ST_ERROR
; /* Error! */
1304 default: /* Escaped character like \ ^ : = */
1308 if (state
== ST_BACKSLASH
)
1317 case ST_OCTAL
: /* Octal sequence */
1318 if (*p
< '0' || *p
> '7')
1325 num
= (num
<< 3) + (*(p
++) - '0');
1328 case ST_HEX
: /* Hex sequence */
1341 num
= (num
<< 4) + (*(p
++) - '0');
1349 num
= (num
<< 4) + (*(p
++) - 'a') + 10;
1357 num
= (num
<< 4) + (*(p
++) - 'A') + 10;
1367 case ST_CARET
: /* Caret escape */
1368 state
= ST_GND
; /* Should be the next state... */
1369 if (*p
>= '@' && *p
<= '~')
1371 *(q
++) = *(p
++) & 037;
1374 else if ( *p
== '?')
1391 return state
== ST_ERROR
? -1 : count
;
1395 parse_ls_color (void)
1397 const char *p
; /* Pointer to character being parsed */
1398 char *buf
; /* color_buf buffer pointer */
1399 int state
; /* State of parser */
1400 int ind_no
; /* Indicator number */
1401 char label
[3]; /* Indicator label */
1402 struct col_ext_type
*ext
; /* Extension we are working on */
1403 struct col_ext_type
*ext2
; /* Extra pointer */
1405 if ((p
= getenv ("LS_COLORS")) == NULL
|| *p
== '\0')
1409 strcpy (label
, "??");
1411 /* This is an overly conservative estimate, but any possible
1412 LS_COLORS string will *not* generate a color_buf longer than
1413 itself, so it is a safe way of allocating a buffer in
1415 buf
= color_buf
= xstrdup (p
);
1422 case 1: /* First label character */
1430 /* Allocate new extension block and add to head of
1431 linked list (this way a later definition will
1432 override an earlier one, which can be useful for
1433 having terminal-specific defs override global). */
1435 ext
= (struct col_ext_type
*)
1436 xmalloc (sizeof (struct col_ext_type
));
1437 ext
->next
= col_ext_list
;
1441 ext
->ext
.string
= buf
;
1443 state
= (ext
->ext
.len
=
1444 get_funky_string (&buf
, &p
, 1)) < 0 ? -1 : 4;
1448 state
= 0; /* Done! */
1451 default: /* Assume it is file type label */
1458 case 2: /* Second label character */
1465 state
= -1; /* Error */
1468 case 3: /* Equal sign after indicator label */
1469 state
= -1; /* Assume failure... */
1470 if (*(p
++) == '=')/* It *should* be... */
1472 for (ind_no
= 0; indicator_name
[ind_no
] != NULL
; ++ind_no
)
1474 if (STREQ (label
, indicator_name
[ind_no
]))
1476 color_indicator
[ind_no
].string
= buf
;
1477 state
= ((color_indicator
[ind_no
].len
=
1478 get_funky_string (&buf
, &p
, 0)) < 0 ? -1 : 1);
1483 error (0, 0, _("unrecognized prefix: %s"), label
);
1487 case 4: /* Equal sign after *.ext */
1490 ext
->seq
.string
= buf
;
1491 state
= (ext
->seq
.len
=
1492 get_funky_string (&buf
, &p
, 0)) < 0 ? -1 : 1;
1502 struct col_ext_type
*e
;
1505 _("unparsable value for LS_COLORS environment variable"));
1507 for (e
= col_ext_list
; e
!= NULL
; /* empty */)
1513 print_with_color
= 0;
1517 /* Request that the directory named `name' have its contents listed later.
1518 If `realname' is nonzero, it will be used instead of `name' when the
1519 directory name is printed. This allows symbolic links to directories
1520 to be treated as regular directories but still be listed under their
1524 queue_directory (const char *name
, const char *realname
)
1526 struct pending
*new;
1528 new = (struct pending
*) xmalloc (sizeof (struct pending
));
1529 new->next
= pending_dirs
;
1531 new->name
= xstrdup (name
);
1533 new->realname
= xstrdup (realname
);
1538 /* Read directory `name', and list the files in it.
1539 If `realname' is nonzero, print its name instead of `name';
1540 this is used for symbolic links to directories. */
1543 print_dir (const char *name
, const char *realname
)
1545 register DIR *reading
;
1546 register struct dirent
*next
;
1547 register uintmax_t total_blocks
= 0;
1550 reading
= opendir (name
);
1553 error (0, errno
, "%s", name
);
1558 /* Read the directory entries, and insert the subfiles into the `files'
1563 while ((next
= readdir (reading
)) != NULL
)
1564 if (file_interesting (next
))
1565 total_blocks
+= gobble_file (next
->d_name
, 0, name
);
1567 if (CLOSEDIR (reading
))
1569 error (0, errno
, "%s", name
);
1571 /* Don't return; print whatever we got. */
1574 /* Sort the directory contents. */
1577 /* If any member files are subdirectories, perhaps they should have their
1578 contents listed rather than being mentioned here as files. */
1581 extract_dirs_from_files (name
, 1);
1586 PUSH_CURRENT_DIRED_POS (&subdired_obstack
);
1587 dired_pos
+= quote_filename (stdout
, realname
? realname
: name
);
1588 PUSH_CURRENT_DIRED_POS (&subdired_obstack
);
1589 FPUTS_LITERAL (":\n", stdout
);
1592 if (format
== long_format
|| print_block_size
)
1595 char buf
[LONGEST_HUMAN_READABLE
+ 1];
1599 FPUTS (p
, stdout
, strlen (p
));
1601 p
= human_readable (total_blocks
, buf
, ST_NBLOCKSIZE
, output_units
,
1602 human_readable_base
);
1603 FPUTS (p
, stdout
, strlen (p
));
1608 print_current_files ();
1614 /* Add `pattern' to the list of patterns for which files that match are
1618 add_ignore_pattern (const char *pattern
)
1620 register struct ignore_pattern
*ignore
;
1622 ignore
= (struct ignore_pattern
*) xmalloc (sizeof (struct ignore_pattern
));
1623 ignore
->pattern
= pattern
;
1624 /* Add it to the head of the linked list. */
1625 ignore
->next
= ignore_patterns
;
1626 ignore_patterns
= ignore
;
1629 /* Return nonzero if the file in `next' should be listed. */
1632 file_interesting (const struct dirent
*next
)
1634 register struct ignore_pattern
*ignore
;
1636 for (ignore
= ignore_patterns
; ignore
; ignore
= ignore
->next
)
1637 if (fnmatch (ignore
->pattern
, next
->d_name
, FNM_PERIOD
) == 0)
1640 if (really_all_files
1641 || next
->d_name
[0] != '.'
1643 && next
->d_name
[1] != '\0'
1644 && (next
->d_name
[1] != '.' || next
->d_name
[2] != '\0')))
1650 /* Enter and remove entries in the table `files'. */
1652 /* Empty the table of files. */
1659 for (i
= 0; i
< files_index
; i
++)
1661 free (files
[i
].name
);
1662 if (files
[i
].linkname
)
1663 free (files
[i
].linkname
);
1667 block_size_size
= 4;
1670 /* Add a file to the current table of files.
1671 Verify that the file exists, and print an error message if it does not.
1672 Return the number of blocks that the file occupies. */
1675 gobble_file (const char *name
, int explicit_arg
, const char *dirname
)
1677 register uintmax_t blocks
;
1679 register char *path
;
1681 if (files_index
== nfiles
)
1684 files
= (struct fileinfo
*) xrealloc ((char *) files
,
1685 sizeof (*files
) * nfiles
);
1688 files
[files_index
].linkname
= 0;
1689 files
[files_index
].linkmode
= 0;
1690 files
[files_index
].linkok
= 0;
1692 if (explicit_arg
|| format_needs_stat
)
1694 /* `path' is the absolute pathname of this file. */
1696 if (name
[0] == '/' || dirname
[0] == 0)
1697 path
= (char *) name
;
1700 path
= (char *) alloca (strlen (name
) + strlen (dirname
) + 2);
1701 attach (path
, dirname
, name
);
1706 val
= stat (path
, &files
[files_index
].stat
);
1708 /* Perhaps a symbolically-linked to file doesn't exist; stat
1709 the link instead. */
1710 val
= lstat (path
, &files
[files_index
].stat
);
1713 val
= lstat (path
, &files
[files_index
].stat
);
1716 error (0, errno
, "%s", path
);
1722 if (S_ISLNK (files
[files_index
].stat
.st_mode
)
1723 && (explicit_arg
|| format
== long_format
|| print_with_color
))
1726 struct stat linkstats
;
1728 get_link_name (path
, &files
[files_index
]);
1729 linkpath
= make_link_path (path
, files
[files_index
].linkname
);
1731 /* Avoid following symbolic links when possible, ie, when
1732 they won't be traced and when no indicator is needed. */
1734 && ((explicit_arg
&& format
!= long_format
)
1735 || indicator_style
!= none
1736 || print_with_color
)
1737 && stat (linkpath
, &linkstats
) == 0)
1739 files
[files_index
].linkok
= 1;
1741 /* Symbolic links to directories that are mentioned on the
1742 command line are automatically traced if not being
1744 if (explicit_arg
&& format
!= long_format
1745 && S_ISDIR (linkstats
.st_mode
))
1747 /* Substitute the linked-to directory's name, but
1748 save the real name in `linkname' for printing. */
1749 if (!immediate_dirs
)
1751 const char *tempname
= name
;
1753 linkpath
= files
[files_index
].linkname
;
1754 files
[files_index
].linkname
= (char *) tempname
;
1756 files
[files_index
].stat
= linkstats
;
1760 /* Get the linked-to file's mode for the filetype indicator
1761 in long listings. */
1762 files
[files_index
].linkmode
= linkstats
.st_mode
;
1763 files
[files_index
].linkok
= 1;
1772 if (S_ISLNK (files
[files_index
].stat
.st_mode
))
1773 files
[files_index
].filetype
= symbolic_link
;
1776 if (S_ISDIR (files
[files_index
].stat
.st_mode
))
1778 if (explicit_arg
&& !immediate_dirs
)
1779 files
[files_index
].filetype
= arg_directory
;
1781 files
[files_index
].filetype
= directory
;
1784 files
[files_index
].filetype
= normal
;
1786 blocks
= ST_NBLOCKS (files
[files_index
].stat
);
1788 char buf
[LONGEST_HUMAN_READABLE
+ 1];
1789 int len
= strlen (human_readable (blocks
, buf
, ST_NBLOCKSIZE
,
1790 output_units
, human_readable_base
));
1791 if (block_size_size
< len
)
1792 block_size_size
= len
< 7 ? len
: 7;
1798 files
[files_index
].name
= xstrdup (name
);
1806 /* Put the name of the file that `filename' is a symbolic link to
1807 into the `linkname' field of `f'. */
1810 get_link_name (const char *filename
, struct fileinfo
*f
)
1813 register int linksize
;
1815 linkbuf
= (char *) alloca (PATH_MAX
+ 2);
1816 /* Some automounters give incorrect st_size for mount points.
1817 I can't think of a good workaround for it, though. */
1818 linksize
= readlink (filename
, linkbuf
, PATH_MAX
+ 1);
1821 error (0, errno
, "%s", filename
);
1826 linkbuf
[linksize
] = '\0';
1827 f
->linkname
= xstrdup (linkbuf
);
1831 /* If `linkname' is a relative path and `path' contains one or more
1832 leading directories, return `linkname' with those directories
1833 prepended; otherwise, return a copy of `linkname'.
1834 If `linkname' is zero, return zero. */
1837 make_link_path (const char *path
, const char *linkname
)
1845 if (*linkname
== '/')
1846 return xstrdup (linkname
);
1848 /* The link is to a relative path. Prepend any leading path
1849 in `path' to the link name. */
1850 linkbuf
= strrchr (path
, '/');
1852 return xstrdup (linkname
);
1854 bufsiz
= linkbuf
- path
+ 1;
1855 linkbuf
= xmalloc (bufsiz
+ strlen (linkname
) + 1);
1856 strncpy (linkbuf
, path
, bufsiz
);
1857 strcpy (linkbuf
+ bufsiz
, linkname
);
1862 /* Remove any entries from `files' that are for directories,
1863 and queue them to be listed as directories instead.
1864 `dirname' is the prefix to prepend to each dirname
1865 to make it correct relative to ls's working dir.
1866 `recursive' is nonzero if we should not treat `.' and `..' as dirs.
1867 This is desirable when processing directories recursively. */
1870 extract_dirs_from_files (const char *dirname
, int recursive
)
1873 register char *path
;
1876 dirlen
= strlen (dirname
) + 2;
1877 /* Queue the directories last one first, because queueing reverses the
1879 for (i
= files_index
- 1; i
>= 0; i
--)
1880 if ((files
[i
].filetype
== directory
|| files
[i
].filetype
== arg_directory
)
1881 && (!recursive
|| is_not_dot_or_dotdot (files
[i
].name
)))
1883 if (files
[i
].name
[0] == '/' || dirname
[0] == 0)
1885 queue_directory (files
[i
].name
, files
[i
].linkname
);
1889 path
= (char *) xmalloc (strlen (files
[i
].name
) + dirlen
);
1890 attach (path
, dirname
, files
[i
].name
);
1891 queue_directory (path
, files
[i
].linkname
);
1894 if (files
[i
].filetype
== arg_directory
)
1895 free (files
[i
].name
);
1898 /* Now delete the directories from the table, compacting all the remaining
1901 for (i
= 0, j
= 0; i
< files_index
; i
++)
1902 if (files
[i
].filetype
!= arg_directory
)
1903 files
[j
++] = files
[i
];
1907 /* Return nonzero if `name' doesn't end in `.' or `..'
1908 This is so we don't try to recurse on `././././. ...' */
1911 is_not_dot_or_dotdot (const char *name
)
1915 t
= strrchr (name
, '/');
1921 || (name
[1] == '.' && name
[2] == '\0')))
1927 /* Sort the files now in the table. */
1942 func
= sort_reverse
? rev_cmp_ctime
: compare_ctime
;
1945 func
= sort_reverse
? rev_cmp_mtime
: compare_mtime
;
1948 func
= sort_reverse
? rev_cmp_atime
: compare_atime
;
1955 func
= sort_reverse
? rev_cmp_name
: compare_name
;
1957 case sort_extension
:
1958 func
= sort_reverse
? rev_cmp_extension
: compare_extension
;
1961 func
= sort_reverse
? rev_cmp_size
: compare_size
;
1964 func
= sort_reverse
? rev_cmp_version
: compare_version
;
1970 qsort (files
, files_index
, sizeof (struct fileinfo
), func
);
1973 /* Comparison routines for sorting the files. */
1976 compare_ctime (const struct fileinfo
*file1
, const struct fileinfo
*file2
)
1978 return longdiff (file2
->stat
.st_ctime
, file1
->stat
.st_ctime
);
1982 rev_cmp_ctime (const struct fileinfo
*file2
, const struct fileinfo
*file1
)
1984 return longdiff (file2
->stat
.st_ctime
, file1
->stat
.st_ctime
);
1988 compare_mtime (const struct fileinfo
*file1
, const struct fileinfo
*file2
)
1990 return longdiff (file2
->stat
.st_mtime
, file1
->stat
.st_mtime
);
1994 rev_cmp_mtime (const struct fileinfo
*file2
, const struct fileinfo
*file1
)
1996 return longdiff (file2
->stat
.st_mtime
, file1
->stat
.st_mtime
);
2000 compare_atime (const struct fileinfo
*file1
, const struct fileinfo
*file2
)
2002 return longdiff (file2
->stat
.st_atime
, file1
->stat
.st_atime
);
2006 rev_cmp_atime (const struct fileinfo
*file2
, const struct fileinfo
*file1
)
2008 return longdiff (file2
->stat
.st_atime
, file1
->stat
.st_atime
);
2012 compare_size (const struct fileinfo
*file1
, const struct fileinfo
*file2
)
2014 return longdiff (file2
->stat
.st_size
, file1
->stat
.st_size
);
2018 rev_cmp_size (const struct fileinfo
*file2
, const struct fileinfo
*file1
)
2020 return longdiff (file2
->stat
.st_size
, file1
->stat
.st_size
);
2024 compare_version (const struct fileinfo
*file1
, const struct fileinfo
*file2
)
2026 return strverscmp (file1
->name
, file2
->name
);
2030 rev_cmp_version (const struct fileinfo
*file2
, const struct fileinfo
*file1
)
2032 return strverscmp (file1
->name
, file2
->name
);
2036 compare_name (const struct fileinfo
*file1
, const struct fileinfo
*file2
)
2038 return strcmp (file1
->name
, file2
->name
);
2042 rev_cmp_name (const struct fileinfo
*file2
, const struct fileinfo
*file1
)
2044 return strcmp (file1
->name
, file2
->name
);
2047 /* Compare file extensions. Files with no extension are `smallest'.
2048 If extensions are the same, compare by filenames instead. */
2051 compare_extension (const struct fileinfo
*file1
, const struct fileinfo
*file2
)
2053 register char *base1
, *base2
;
2056 base1
= strrchr (file1
->name
, '.');
2057 base2
= strrchr (file2
->name
, '.');
2058 if (base1
== 0 && base2
== 0)
2059 return strcmp (file1
->name
, file2
->name
);
2064 cmp
= strcmp (base1
, base2
);
2066 return strcmp (file1
->name
, file2
->name
);
2071 rev_cmp_extension (const struct fileinfo
*file2
, const struct fileinfo
*file1
)
2073 register char *base1
, *base2
;
2076 base1
= strrchr (file1
->name
, '.');
2077 base2
= strrchr (file2
->name
, '.');
2078 if (base1
== 0 && base2
== 0)
2079 return strcmp (file1
->name
, file2
->name
);
2084 cmp
= strcmp (base1
, base2
);
2086 return strcmp (file1
->name
, file2
->name
);
2090 /* List all the files now in the table. */
2093 print_current_files (void)
2100 for (i
= 0; i
< files_index
; i
++)
2102 print_file_name_and_frills (files
+ i
);
2109 print_many_per_line ();
2114 print_horizontal ();
2118 print_with_commas ();
2122 for (i
= 0; i
< files_index
; i
++)
2124 print_long_format (files
+ i
);
2132 print_long_format (const struct fileinfo
*f
)
2136 /* 7 fields that may require LONGEST_HUMAN_READABLE bytes,
2137 1 10-byte mode string,
2138 1 24-byte time string (may be longer in some locales -- see below)
2139 or LONGEST_HUMAN_READABLE integer,
2140 9 spaces, one following each of these fields, and
2141 1 trailing NUL byte. */
2142 char init_bigbuf
[7 * LONGEST_HUMAN_READABLE
+ 10
2143 + (LONGEST_HUMAN_READABLE
< 24 ? 24 : LONGEST_HUMAN_READABLE
)
2145 char *buf
= init_bigbuf
;
2146 size_t bufsize
= sizeof (init_bigbuf
);
2150 struct tm
*when_local
;
2154 #ifdef HAVE_ST_DM_MODE
2155 mode_string (f
->stat
.st_dm_mode
, modebuf
);
2157 mode_string (f
->stat
.st_mode
, modebuf
);
2165 when
= f
->stat
.st_ctime
;
2168 when
= f
->stat
.st_mtime
;
2171 when
= f
->stat
.st_atime
;
2177 fmt
= "%a %b %d %H:%M:%S %Y";
2181 if (current_time
> when
+ 6L * 30L * 24L * 60L * 60L /* Old. */
2182 || current_time
< when
- 60L * 60L) /* In the future. */
2184 /* The file is fairly old or in the future.
2185 POSIX says the cutoff is 6 months old;
2186 approximate this by 6*30 days.
2187 Allow a 1 hour slop factor for what is considered "the future",
2188 to allow for NFS server/client clock disagreement.
2189 Show the year instead of the time of day. */
2194 fmt
= "%b %e %H:%M";
2202 char hbuf
[LONGEST_HUMAN_READABLE
+ 1];
2203 sprintf (p
, "%*s ", INODE_DIGITS
,
2204 human_readable ((uintmax_t) f
->stat
.st_ino
, hbuf
, 1, 1, 0));
2208 if (print_block_size
)
2210 char hbuf
[LONGEST_HUMAN_READABLE
+ 1];
2211 sprintf (p
, "%*s ", block_size_size
,
2212 human_readable ((uintmax_t) ST_NBLOCKS (f
->stat
), hbuf
,
2213 ST_NBLOCKSIZE
, output_units
,
2214 human_readable_base
));
2218 /* The space between the mode and the number of links is the POSIX
2219 "optional alternate access method flag". */
2220 sprintf (p
, "%s %3u ", modebuf
, (unsigned int) f
->stat
.st_nlink
);
2223 user_name
= (numeric_ids
? NULL
: getuser (f
->stat
.st_uid
));
2225 sprintf (p
, "%-8.8s ", user_name
);
2227 sprintf (p
, "%-8u ", (unsigned int) f
->stat
.st_uid
);
2232 char *group_name
= (numeric_ids
? NULL
: getgroup (f
->stat
.st_gid
));
2234 sprintf (p
, "%-8.8s ", group_name
);
2236 sprintf (p
, "%-8u ", (unsigned int) f
->stat
.st_gid
);
2240 if (S_ISCHR (f
->stat
.st_mode
) || S_ISBLK (f
->stat
.st_mode
))
2241 sprintf (p
, "%3u, %3u ", (unsigned) major (f
->stat
.st_rdev
),
2242 (unsigned) minor (f
->stat
.st_rdev
));
2245 char hbuf
[LONGEST_HUMAN_READABLE
+ 1];
2247 human_readable ((uintmax_t) f
->stat
.st_size
,
2248 hbuf
, 1, 1, human_readable_base
));
2253 /* Use strftime rather than ctime, because the former can produce
2254 locale-dependent names for the weekday (%a) and month (%b). */
2256 if ((when_local
= localtime (&when
)))
2258 while (! (s
= strftime (p
, buf
+ bufsize
- p
- 1, fmt
, when_local
)))
2260 char *newbuf
= (char *) alloca (bufsize
*= 2);
2261 memcpy (newbuf
, buf
, p
- buf
);
2262 p
= newbuf
+ (p
- buf
);
2269 /* NUL-terminate the string -- fputs (via FPUTS) requires it. */
2274 /* The time cannot be represented as a local time;
2275 print it as a huge integer number of seconds. */
2276 char hbuf
[LONGEST_HUMAN_READABLE
+ 1];
2277 int width
= full_time
? 24 : 12;
2281 const char *num
= human_readable (- (uintmax_t) when
, hbuf
, 1, 1, 0);
2282 int sign_width
= width
- strlen (num
);
2283 sprintf (p
, "%*s%s ", sign_width
< 0 ? 0 : sign_width
, "-", num
);
2286 sprintf (p
, "%*s ", width
,
2287 human_readable ((uintmax_t) when
, hbuf
, 1, 1, 0));
2293 FPUTS (buf
, stdout
, p
- buf
);
2294 print_name_with_quoting (f
->name
, f
->stat
.st_mode
, f
->linkok
,
2297 if (f
->filetype
== symbolic_link
)
2301 FPUTS_LITERAL (" -> ", stdout
);
2302 print_name_with_quoting (f
->linkname
, f
->linkmode
, f
->linkok
- 1,
2304 if (indicator_style
!= none
)
2305 print_type_indicator (f
->linkmode
);
2308 else if (indicator_style
!= none
)
2309 print_type_indicator (f
->stat
.st_mode
);
2312 /* If OUT is not null, output a quoted representation of the file name P.
2313 Return the number of characters in P's quoted representation. */
2316 quote_filename (register FILE *out
, register const char *p
)
2318 register unsigned char c
;
2319 register size_t len
;
2320 #define OUTCHAR(c) do { len++; if (out) putc (c, out); } while (0)
2328 case '\0': case '#': case '~':
2339 case '\t': case '\n': case ' ':
2340 case '!': /* special in csh */
2341 case '"': case '$': case '&': case '\'':
2342 case '(': case ')': case '*': case ';':
2343 case '<': case '>': case '?': case '[': case '\\':
2344 case '^': /* synonym for | in old /bin/sh, e.g. SunOS 4.1.4 */
2352 /* These require quoting if at the end of the file name,
2353 to avoid ambiguity with the output of -F or -p. */
2359 fwrite (p0
, 1, len
, out
);
2370 /* Shell quoting is needed. */
2394 if (quote_as_string
)
2399 if (quote_funny_chars
)
2403 case '\\': OUTCHAR ('\\'); break;
2404 case '\n': OUTCHAR ('\\'); c
= 'n'; break;
2405 case '\b': OUTCHAR ('\\'); c
= 'b'; break;
2406 case '\r': OUTCHAR ('\\'); c
= 'r'; break;
2407 case '\t': OUTCHAR ('\\'); c
= 't'; break;
2408 case '\f': OUTCHAR ('\\'); c
= 'f'; break;
2411 if (!quote_as_string
)
2416 if (quote_as_string
)
2424 OUTCHAR ('0' + (c
>> 6));
2425 OUTCHAR ('0' + ((c
>> 3) & 3));
2430 else if (qmark_funny_chars
&& !ISPRINT (c
))
2436 if (quote_as_string
)
2444 print_name_with_quoting (const char *p
, unsigned int mode
, int linkok
,
2445 struct obstack
*stack
)
2447 if (print_with_color
)
2448 print_color_indicator (p
, mode
, linkok
);
2451 PUSH_CURRENT_DIRED_POS (stack
);
2453 dired_pos
+= quote_filename (stdout
, p
);
2456 PUSH_CURRENT_DIRED_POS (stack
);
2458 if (print_with_color
)
2459 prep_non_filename_text ();
2463 prep_non_filename_text (void)
2465 if (color_indicator
[C_END
].string
!= NULL
)
2466 put_indicator (&color_indicator
[C_END
]);
2469 put_indicator (&color_indicator
[C_LEFT
]);
2470 put_indicator (&color_indicator
[C_NORM
]);
2471 put_indicator (&color_indicator
[C_RIGHT
]);
2475 /* Print the file name of `f' with appropriate quoting.
2476 Also print file size, inode number, and filetype indicator character,
2477 as requested by switches. */
2480 print_file_name_and_frills (const struct fileinfo
*f
)
2482 char buf
[LONGEST_HUMAN_READABLE
+ 1];
2485 printf ("%*s ", INODE_DIGITS
,
2486 human_readable ((uintmax_t) f
->stat
.st_ino
, buf
, 1, 1, 0));
2488 if (print_block_size
)
2489 printf ("%*s ", block_size_size
,
2490 human_readable ((uintmax_t) ST_NBLOCKS (f
->stat
), buf
,
2491 ST_NBLOCKSIZE
, output_units
, human_readable_base
));
2493 print_name_with_quoting (f
->name
, f
->stat
.st_mode
, f
->linkok
, NULL
);
2495 if (indicator_style
!= none
)
2496 print_type_indicator (f
->stat
.st_mode
);
2500 print_type_indicator (unsigned int mode
)
2511 if (S_ISFIFO (mode
))
2516 if (S_ISSOCK (mode
))
2520 if (S_ISREG (mode
) && indicator_style
== all
2521 && (mode
& S_IXUGO
))
2526 print_color_indicator (const char *name
, unsigned int mode
, int linkok
)
2529 struct col_ext_type
*ext
; /* Color extension */
2530 size_t len
; /* Length of name */
2532 /* Is this a nonexistent file? If so, linkok == -1. */
2534 if (linkok
== -1 && color_indicator
[C_MISSING
].string
!= NULL
)
2545 else if (S_ISLNK (mode
))
2546 type
= ((!linkok
&& color_indicator
[C_ORPHAN
].string
)
2547 ? C_ORPHAN
: C_LINK
);
2551 else if (S_ISFIFO (mode
))
2556 else if (S_ISSOCK (mode
))
2561 else if (S_ISBLK (mode
))
2566 else if (S_ISCHR (mode
))
2570 if (type
== C_FILE
&& (mode
& S_IXUGO
) != 0)
2573 /* Check the file's suffix only if still classified as C_FILE. */
2577 /* Test if NAME has a recognized suffix. */
2579 len
= strlen (name
);
2580 name
+= len
; /* Pointer to final \0. */
2581 for (ext
= col_ext_list
; ext
!= NULL
; ext
= ext
->next
)
2583 if ((size_t) ext
->ext
.len
<= len
2584 && strncmp (name
- ext
->ext
.len
, ext
->ext
.string
,
2591 put_indicator (&color_indicator
[C_LEFT
]);
2592 put_indicator (ext
? &(ext
->seq
) : &color_indicator
[type
]);
2593 put_indicator (&color_indicator
[C_RIGHT
]);
2596 /* Output a color indicator (which may contain nulls). */
2598 put_indicator (const struct bin_str
*ind
)
2605 for (i
= ind
->len
; i
> 0; --i
)
2610 length_of_file_name_and_frills (const struct fileinfo
*f
)
2612 register int len
= 0;
2615 len
+= INODE_DIGITS
+ 1;
2617 if (print_block_size
)
2618 len
+= 1 + block_size_size
;
2620 len
+= quote_filename (0, f
->name
);
2622 if (indicator_style
!= none
)
2624 unsigned filetype
= f
->stat
.st_mode
;
2626 if (S_ISREG (filetype
))
2628 if (indicator_style
== all
2629 && (f
->stat
.st_mode
& S_IXUGO
))
2632 else if (S_ISDIR (filetype
)
2634 || S_ISLNK (filetype
)
2637 || S_ISFIFO (filetype
)
2640 || S_ISSOCK (filetype
)
2650 print_many_per_line (void)
2652 struct col_info
*line_fmt
;
2653 int filesno
; /* Index into files. */
2654 int row
; /* Current row. */
2655 int max_name_length
; /* Length of longest file name + frills. */
2656 int name_length
; /* Length of each file name + frills. */
2657 int pos
; /* Current character column. */
2658 int cols
; /* Number of files across. */
2659 int rows
; /* Maximum number of files down. */
2662 /* Normally the maximum number of columns is determined by the
2663 screen width. But if few files are available this might limit it
2665 max_cols
= max_idx
> files_index
? files_index
: max_idx
;
2667 /* Compute the maximum number of possible columns. */
2668 for (filesno
= 0; filesno
< files_index
; ++filesno
)
2672 name_length
= length_of_file_name_and_frills (files
+ filesno
);
2674 for (i
= 0; i
< max_cols
; ++i
)
2676 if (col_info
[i
].valid_len
)
2678 int idx
= filesno
/ ((files_index
+ i
) / (i
+ 1));
2679 int real_length
= name_length
+ (idx
== i
? 0 : 2);
2681 if (real_length
> col_info
[i
].col_arr
[idx
])
2683 col_info
[i
].line_len
+= (real_length
2684 - col_info
[i
].col_arr
[idx
]);
2685 col_info
[i
].col_arr
[idx
] = real_length
;
2686 col_info
[i
].valid_len
= col_info
[i
].line_len
< line_length
;
2692 /* Find maximum allowed columns. */
2693 for (cols
= max_cols
; cols
> 1; --cols
)
2695 if (col_info
[cols
- 1].valid_len
)
2699 line_fmt
= &col_info
[cols
- 1];
2701 /* Calculate the number of rows that will be in each column except possibly
2702 for a short column on the right. */
2703 rows
= files_index
/ cols
+ (files_index
% cols
!= 0);
2705 for (row
= 0; row
< rows
; row
++)
2710 /* Print the next row. */
2713 print_file_name_and_frills (files
+ filesno
);
2714 name_length
= length_of_file_name_and_frills (files
+ filesno
);
2715 max_name_length
= line_fmt
->col_arr
[col
++];
2718 if (filesno
>= files_index
)
2721 indent (pos
+ name_length
, pos
+ max_name_length
);
2722 pos
+= max_name_length
;
2729 print_horizontal (void)
2731 struct col_info
*line_fmt
;
2733 int max_name_length
;
2739 /* Normally the maximum number of columns is determined by the
2740 screen width. But if few files are available this might limit it
2742 max_cols
= max_idx
> files_index
? files_index
: max_idx
;
2744 /* Compute the maximum file name length. */
2745 max_name_length
= 0;
2746 for (filesno
= 0; filesno
< files_index
; ++filesno
)
2750 name_length
= length_of_file_name_and_frills (files
+ filesno
);
2752 for (i
= 0; i
< max_cols
; ++i
)
2754 if (col_info
[i
].valid_len
)
2756 int idx
= filesno
% (i
+ 1);
2757 int real_length
= name_length
+ (idx
== i
? 0 : 2);
2759 if (real_length
> col_info
[i
].col_arr
[idx
])
2761 col_info
[i
].line_len
+= (real_length
2762 - col_info
[i
].col_arr
[idx
]);
2763 col_info
[i
].col_arr
[idx
] = real_length
;
2764 col_info
[i
].valid_len
= col_info
[i
].line_len
< line_length
;
2770 /* Find maximum allowed columns. */
2771 for (cols
= max_cols
; cols
> 1; --cols
)
2773 if (col_info
[cols
- 1].valid_len
)
2777 line_fmt
= &col_info
[cols
- 1];
2781 /* Print first entry. */
2782 print_file_name_and_frills (files
);
2783 name_length
= length_of_file_name_and_frills (files
);
2784 max_name_length
= line_fmt
->col_arr
[0];
2787 for (filesno
= 1; filesno
< files_index
; ++filesno
)
2789 int col
= filesno
% cols
;
2798 indent (pos
+ name_length
, pos
+ max_name_length
);
2799 pos
+= max_name_length
;
2802 print_file_name_and_frills (files
+ filesno
);
2804 name_length
= length_of_file_name_and_frills (files
+ filesno
);
2805 max_name_length
= line_fmt
->col_arr
[col
];
2811 print_with_commas (void)
2818 for (filesno
= 0; filesno
< files_index
; filesno
++)
2822 pos
+= length_of_file_name_and_frills (files
+ filesno
);
2823 if (filesno
+ 1 < files_index
)
2824 pos
+= 2; /* For the comma and space */
2826 if (old_pos
!= 0 && pos
>= line_length
)
2832 print_file_name_and_frills (files
+ filesno
);
2833 if (filesno
+ 1 < files_index
)
2842 /* Assuming cursor is at position FROM, indent up to position TO.
2843 Use a TAB character instead of two or more spaces whenever possible. */
2846 indent (int from
, int to
)
2850 if (tabsize
> 0 && to
/ tabsize
> (from
+ 1) / tabsize
)
2853 from
+= tabsize
- from
% tabsize
;
2863 /* Put DIRNAME/NAME into DEST, handling `.' and `/' properly. */
2866 attach (char *dest
, const char *dirname
, const char *name
)
2868 const char *dirnamep
= dirname
;
2870 /* Copy dirname if it is not ".". */
2871 if (dirname
[0] != '.' || dirname
[1] != 0)
2874 *dest
++ = *dirnamep
++;
2875 /* Add '/' if `dirname' doesn't already end with it. */
2876 if (dirnamep
> dirname
&& dirnamep
[-1] != '/')
2885 init_col_info (void)
2890 max_idx
= line_length
/ MIN_COLUMN_WIDTH
;
2894 if (col_info
== NULL
)
2896 col_info
= (struct col_info
*) xmalloc (max_idx
2897 * sizeof (struct col_info
));
2901 for (i
= 0; i
< max_idx
; ++i
)
2905 col_info
[i
].valid_len
= 1;
2906 col_info
[i
].line_len
= (i
+ 1) * MIN_COLUMN_WIDTH
;
2909 col_info
[i
].col_arr
= (int *) xmalloc ((i
+ 1) * sizeof (int));
2911 for (j
= 0; j
<= i
; ++j
)
2912 col_info
[i
].col_arr
[j
] = MIN_COLUMN_WIDTH
;
2920 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
2924 printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name
);
2926 List information about the FILEs (the current directory by default).\n\
2927 Sort entries alphabetically if none of -cftuSUX nor --sort.\n\
2929 -a, --all do not hide entries starting with .\n\
2930 -A, --almost-all do not list implied . and ..\n\
2931 -b, --escape print octal escapes for nongraphic characters\n\
2932 -B, --ignore-backups do not list implied entries ending with ~\n\
2933 -c sort by change time; with -l: show ctime\n\
2934 -C list entries by columns\n\
2935 --color[=WHEN] control whether color is used to distinguish file\n\
2936 types. WHEN may be `never', `always', or `auto'\n\
2937 -d, --directory list directory entries instead of contents\n\
2938 -D, --dired generate output designed for Emacs' dired mode\n\
2939 -e, --quote-shell quote entry names for shell (default)\n\
2940 -f do not sort, enable -aU, disable -lst\n\
2941 -F, --classify append a character for typing each entry\n\
2942 --format=WORD across -x, commas -m, horizontal -x, long -l,\n\
2943 single-column -1, verbose -l, vertical -C\n\
2944 --full-time list both full date and full time\n"));
2948 -G, --no-group inhibit display of group information\n\
2949 -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\n\
2950 -H, --si likewise, but use powers of 1000 not 1024\n\
2951 -i, --inode print index number of each file\n\
2952 -I, --ignore=PATTERN do not list implied entries matching shell PATTERN\n\
2953 -k, --kilobytes use 1024 blocks, not 512 despite POSIXLY_CORRECT\n\
2954 -l use a long listing format\n\
2955 -L, --dereference list entries pointed to by symbolic links\n\
2956 -m fill width with a comma separated list of entries\n\
2957 -n, --numeric-uid-gid list numeric UIDs and GIDs instead of names\n\
2958 -N, --literal print raw entry names (don't treat e.g. control\n\
2959 characters specially)\n\
2960 -o use long listing format without group info\n\
2961 -p append a character for typing each entry\n\
2962 -q, --hide-control-chars print ? instead of non graphic characters\n\
2963 -Q, --quote-name enclose entry names in double quotes\n\
2964 -r, --reverse reverse order while sorting\n\
2965 -R, --recursive list subdirectories recursively\n\
2966 -s, --size print size of each file, in blocks\n"));
2969 -S sort by file size\n\
2970 --sort=WORD extension -X, none -U, size -S, time -t,\n\
2972 status -c, time -t, atime -u, access -u, use -u\n\
2973 --time=WORD show time as WORD instead of modification time:\n\
2974 atime, access, use, ctime or status; use\n\
2975 specified time as sort key if --sort=time\n\
2976 -t sort by modification time\n\
2977 -T, --tabsize=COLS assume tab stops at each COLS instead of 8\n\
2978 -u sort by last access time; with -l: show atime\n\
2979 -U do not sort; list entries in directory order\n\
2980 -v sort by version\n\
2981 -w, --width=COLS assume screen width instead of current value\n\
2982 -x list entries by lines instead of by columns\n\
2983 -X sort alphabetically by entry extension\n\
2984 -1 list one file per line\n\
2985 --help display this help and exit\n\
2986 --version output version information and exit\n\
2988 By default, color is not used to distinguish types of files. That is\n\
2989 equivalent to using --color=none. Using the --color option without the\n\
2990 optional WHEN argument is equivalent to using --color=always. With\n\
2991 --color=auto, color codes are output only if standard output is connected\n\
2992 to a terminal (tty).\n\
2994 puts (_("\nReport bugs to <fileutils-bugs@gnu.org>."));