Advertisement
Guest User

source code of ls in coreutils

a guest
Nov 20th, 2013
215
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 101.61 KB | None | 0 0
  1. /* `dir', `vdir' and `ls' directory listing programs for GNU.
  2.    Copyright (C) 85, 88, 90, 91, 1995-2002 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. #if HAVE_INTTYPES_H
  47. # include <inttypes.h>
  48. #endif
  49.  
  50. #if HAVE_TERMIOS_H
  51. # include <termios.h>
  52. #endif
  53.  
  54. #ifdef GWINSZ_IN_SYS_IOCTL
  55. # include <sys/ioctl.h>
  56. #endif
  57.  
  58. #ifdef WINSIZE_IN_PTEM
  59. # include <sys/stream.h>
  60. # include <sys/ptem.h>
  61. #endif
  62.  
  63. #include <stdio.h>
  64. #include <assert.h>
  65. #include <setjmp.h>
  66. #include <grp.h>
  67. #include <pwd.h>
  68. #include <getopt.h>
  69.  
  70. /* Get MB_CUR_MAX.  */
  71. #if HAVE_STDLIB_H
  72. # include <stdlib.h>
  73. #endif
  74.  
  75. /* Get mbstate_t, mbrtowc(), mbsinit(), wcwidth().  */
  76. #if HAVE_WCHAR_H
  77. # include <wchar.h>
  78. #endif
  79.  
  80. /* Get iswprint().  */
  81. #if HAVE_WCTYPE_H
  82. # include <wctype.h>
  83. #endif
  84. #if !defined iswprint && !HAVE_ISWPRINT
  85. # define iswprint(wc) 1
  86. #endif
  87.  
  88. #ifndef HAVE_DECL_WCWIDTH
  89. "this configure-time declaration test was not run"
  90. #endif
  91. #if !HAVE_DECL_WCWIDTH
  92. int wcwidth ();
  93. #endif
  94.  
  95. /* If wcwidth() doesn't exist, assume all printable characters have
  96.    width 1.  */
  97. #ifndef wcwidth
  98. # if !HAVE_WCWIDTH
  99. #  define wcwidth(wc) ((wc) == 0 ? 0 : iswprint (wc) ? 1 : -1)
  100. # endif
  101. #endif
  102.  
  103. #include "system.h"
  104. #include <fnmatch.h>
  105.  
  106. #include "acl.h"
  107. #include "argmatch.h"
  108. #include "dirname.h"
  109. #include "dirfd.h"
  110. #include "error.h"
  111. #include "hard-locale.h"
  112. #include "hash.h"
  113. #include "human.h"
  114. #include "filemode.h"
  115. #include "ls.h"
  116. #include "mbswidth.h"
  117. #include "obstack.h"
  118. #include "path-concat.h"
  119. #include "quote.h"
  120. #include "quotearg.h"
  121. #include "same.h"
  122. #include "strverscmp.h"
  123. #include "xstrtol.h"
  124. #include "xreadlink.h"
  125.  
  126. #define PROGRAM_NAME (ls_mode == LS_LS ? "ls" \
  127.               : (ls_mode == LS_MULTI_COL \
  128.              ? "dir" : "vdir"))
  129.  
  130. #define AUTHORS N_ ("Richard Stallman and David MacKenzie")
  131.  
  132. #define obstack_chunk_alloc malloc
  133. #define obstack_chunk_free free
  134.  
  135. /* Return an int indicating the result of comparing two integers.
  136.    Subtracting doesn't always work, due to overflow.  */
  137. #define longdiff(a, b) ((a) < (b) ? -1 : (a) > (b))
  138.  
  139. /* The field width for inode numbers.  On some hosts inode numbers are
  140.    64 bits, so columns won't line up exactly when a huge inode number
  141.    is encountered, but in practice 7 digits is usually enough.  */
  142. #ifndef INODE_DIGITS
  143. # define INODE_DIGITS 7
  144. #endif
  145.  
  146. #ifdef S_ISLNK
  147. # define HAVE_SYMLINKS 1
  148. #else
  149. # define HAVE_SYMLINKS 0
  150. #endif
  151.  
  152. /* Arrange to make lstat calls go through the wrapper function
  153.    on systems with an lstat function that does not dereference symlinks
  154.    that are specified with a trailing slash.  */
  155. #if ! LSTAT_FOLLOWS_SLASHED_SYMLINK
  156. int rpl_lstat PARAMS((const char *, struct stat *));
  157. # undef lstat
  158. # define lstat(Name, Stat_buf) rpl_lstat(Name, Stat_buf)
  159. #endif
  160.  
  161. #if HAVE_STRUCT_DIRENT_D_TYPE && defined DTTOIF
  162. # define DT_INIT(Val) = Val
  163. #else
  164. # define DT_INIT(Val) /* empty */
  165. #endif
  166.  
  167. #ifdef ST_MTIM_NSEC
  168. # define TIMESPEC_NS(timespec) ((timespec).ST_MTIM_NSEC)
  169. #else
  170. # define TIMESPEC_NS(timespec) 0
  171. #endif
  172.  
  173. #if ! HAVE_STRUCT_STAT_ST_AUTHOR
  174. # define st_author st_uid
  175. #endif
  176.  
  177. /* Cray/Unicos DMF: use the file's migrated, not real, status */
  178. #if HAVE_ST_DM_MODE
  179. # define ST_DM_MODE(Stat_buf) ((Stat_buf).st_dm_mode)
  180. #else
  181. # define ST_DM_MODE(Stat_buf) ((Stat_buf).st_mode)
  182. #endif
  183.  
  184. #ifndef LOGIN_NAME_MAX
  185. # if _POSIX_LOGIN_NAME_MAX
  186. #  define LOGIN_NAME_MAX _POSIX_LOGIN_NAME_MAX
  187. # else
  188. #  define LOGIN_NAME_MAX 17
  189. # endif
  190. #endif
  191.  
  192. /* The maximum length of a string representation of a user or group ID,
  193.    not counting any terminating NUL byte.  */
  194. #define ID_LENGTH_MAX \
  195.   MAX (LOGIN_NAME_MAX - 1, LONGEST_HUMAN_READABLE)
  196.  
  197. enum filetype
  198.   {
  199.     unknown DT_INIT (DT_UNKNOWN),
  200.     fifo DT_INIT (DT_FIFO),
  201.     chardev DT_INIT (DT_CHR),
  202.     directory DT_INIT (DT_DIR),
  203.     blockdev DT_INIT (DT_BLK),
  204.     normal DT_INIT (DT_REG),
  205.     symbolic_link DT_INIT (DT_LNK),
  206.     sock DT_INIT (DT_SOCK),
  207.     arg_directory DT_INIT (2 * (DT_UNKNOWN | DT_FIFO | DT_CHR | DT_DIR | DT_BLK
  208.                 | DT_REG | DT_LNK | DT_SOCK))
  209.   };
  210.  
  211. struct fileinfo
  212.   {
  213.     /* The file name. */
  214.     char *name;
  215.  
  216.     struct stat stat;
  217.  
  218.     /* For symbolic link, name of the file linked to, otherwise zero. */
  219.     char *linkname;
  220.  
  221.     /* For symbolic link and long listing, st_mode of file linked to, otherwise
  222.        zero. */
  223.     mode_t linkmode;
  224.  
  225.     /* For symbolic link and color printing, 1 if linked-to file
  226.        exists, otherwise 0.  */
  227.     int linkok;
  228.  
  229.     enum filetype filetype;
  230.  
  231. #if HAVE_ACL
  232.     /* For long listings, true if the file has an access control list.  */
  233.     bool have_acl;
  234. #endif
  235.   };
  236.  
  237. #if HAVE_ACL
  238. # define FILE_HAS_ACL(F) ((F)->have_acl)
  239. #else
  240. # define FILE_HAS_ACL(F) 0
  241. #endif
  242.  
  243. #define LEN_STR_PAIR(s) sizeof (s) - 1, s
  244.  
  245. /* Null is a valid character in a color indicator (think about Epson
  246.    printers, for example) so we have to use a length/buffer string
  247.    type.  */
  248.  
  249. struct bin_str
  250.   {
  251.     int len;            /* Number of bytes */
  252.     const char *string;     /* Pointer to the same */
  253.   };
  254.  
  255. #ifndef STDC_HEADERS
  256. time_t time ();
  257. #endif
  258.  
  259. size_t nstrftime PARAMS ((char *, size_t, char const *,
  260.               struct tm const *, int, int));
  261. char *getgroup ();
  262. char *getuser ();
  263.  
  264. static size_t quote_name PARAMS ((FILE *out, const char *name,
  265.                   struct quoting_options const *options));
  266. static char *make_link_path PARAMS ((const char *path, const char *linkname));
  267. static int decode_switches PARAMS ((int argc, char **argv));
  268. static int file_interesting PARAMS ((const struct dirent *next));
  269. static uintmax_t gobble_file PARAMS ((const char *name, enum filetype type,
  270.                       int explicit_arg, const char *dirname));
  271. static void print_color_indicator PARAMS ((const char *name, mode_t mode,
  272.                        int linkok));
  273. static void put_indicator PARAMS ((const struct bin_str *ind));
  274. static int length_of_file_name_and_frills PARAMS ((const struct fileinfo *f));
  275. static void add_ignore_pattern PARAMS ((const char *pattern));
  276. static void attach PARAMS ((char *dest, const char *dirname, const char *name));
  277. static void clear_files PARAMS ((void));
  278. static void extract_dirs_from_files PARAMS ((const char *dirname,
  279.                          int ignore_dot_and_dot_dot));
  280. static void get_link_name PARAMS ((const char *filename, struct fileinfo *f));
  281. static void indent PARAMS ((int from, int to));
  282. static void init_column_info PARAMS ((void));
  283. static void print_current_files PARAMS ((void));
  284. static void print_dir PARAMS ((const char *name, const char *realname));
  285. static void print_file_name_and_frills PARAMS ((const struct fileinfo *f));
  286. static void print_horizontal PARAMS ((void));
  287. static void print_long_format PARAMS ((const struct fileinfo *f));
  288. static void print_many_per_line PARAMS ((void));
  289. static void print_name_with_quoting PARAMS ((const char *p, mode_t mode,
  290.                          int linkok,
  291.                          struct obstack *stack));
  292. static void prep_non_filename_text PARAMS ((void));
  293. static void print_type_indicator PARAMS ((mode_t mode));
  294. static void print_with_commas PARAMS ((void));
  295. static void queue_directory PARAMS ((const char *name, const char *realname));
  296. static void sort_files PARAMS ((void));
  297. static void parse_ls_color PARAMS ((void));
  298. void usage PARAMS ((int status));
  299.  
  300. /* The name the program was run with, stripped of any leading path. */
  301. char *program_name;
  302.  
  303. /* Initial size of hash table.
  304.    Most hierarchies are likely to be shallower than this.  */
  305. #define INITIAL_TABLE_SIZE 30
  306.  
  307. /* The set of `active' directories, from the current command-line argument
  308.    to the level in the hierarchy at which files are being listed.
  309.    A directory is represented by its device and inode numbers.
  310.    A directory is added to this set when ls begins listing it or its
  311.    entries, and it is removed from the set just after ls has finished
  312.    processing it.  This set is used solely to detect loops, e.g., with
  313.    mkdir loop; cd loop; ln -s ../loop sub; ls -RL  */
  314. static Hash_table *active_dir_set;
  315.  
  316. #define LOOP_DETECT (!!active_dir_set)
  317.  
  318. /* An entry in the active_dir_set.  */
  319. struct dev_ino
  320. {
  321.   dev_t st_dev;
  322.   ino_t st_ino;
  323. };
  324.  
  325. /* The table of files in the current directory:
  326.  
  327.    `files' points to a vector of `struct fileinfo', one per file.
  328.    `nfiles' is the number of elements space has been allocated for.
  329.    `files_index' is the number actually in use.  */
  330.  
  331. /* Address of block containing the files that are described.  */
  332. static struct fileinfo *files;  /* FIXME: rename this to e.g. cwd_file */
  333.  
  334. /* Length of block that `files' points to, measured in files.  */
  335. static int nfiles;  /* FIXME: rename this to e.g. cwd_n_alloc */
  336.  
  337. /* Index of first unused in `files'.  */
  338. static int files_index;  /* FIXME: rename this to e.g. cwd_n_used */
  339.  
  340. /* When nonzero, in a color listing, color each symlink name according to the
  341.    type of file it points to.  Otherwise, color them according to the `ln'
  342.    directive in LS_COLORS.  Dangling (orphan) symlinks are treated specially,
  343.    regardless.  This is set when `ln=target' appears in LS_COLORS.  */
  344.  
  345. static int color_symlink_as_referent;
  346.  
  347. /* mode of appropriate file for colorization */
  348. #define FILE_OR_LINK_MODE(File) \
  349.     ((color_symlink_as_referent && (File)->linkok) \
  350.      ? (File)->linkmode : (File)->stat.st_mode)
  351.  
  352.  
  353. /* Record of one pending directory waiting to be listed.  */
  354.  
  355. struct pending
  356.   {
  357.     char *name;
  358.     /* If the directory is actually the file pointed to by a symbolic link we
  359.        were told to list, `realname' will contain the name of the symbolic
  360.        link, otherwise zero. */
  361.     char *realname;
  362.     struct pending *next;
  363.   };
  364.  
  365. static struct pending *pending_dirs;
  366.  
  367. /* Current time in seconds and nanoseconds since 1970, updated as
  368.    needed when deciding whether a file is recent.  */
  369.  
  370. static time_t current_time = TYPE_MINIMUM (time_t);
  371. static int current_time_ns = -1;
  372.  
  373. /* The number of digits to use for block sizes.
  374.    4, or more if needed for bigger numbers.  */
  375.  
  376. static int block_size_size;
  377.  
  378. /* Option flags */
  379.  
  380. /* long_format for lots of info, one per line.
  381.    one_per_line for just names, one per line.
  382.    many_per_line for just names, many per line, sorted vertically.
  383.    horizontal for just names, many per line, sorted horizontally.
  384.    with_commas for just names, many per line, separated by commas.
  385.  
  386.    -l (and other options that imply -l), -1, -C, -x and -m control
  387.    this parameter.  */
  388.  
  389. enum format
  390.   {
  391.     long_format,        /* -l and other options that imply -l */
  392.     one_per_line,       /* -1 */
  393.     many_per_line,      /* -C */
  394.     horizontal,         /* -x */
  395.     with_commas         /* -m */
  396.   };
  397.  
  398. static enum format format;
  399.  
  400. /* `full-iso' uses full ISO-style dates and times.  `long-iso' uses longer
  401.    ISO-style time stamps, though shorter than `full-iso'.  `iso' uses shorter
  402.    ISO-style time stamps.  `locale' uses locale-dependent time stamps.  */
  403. enum time_style
  404.   {
  405.     full_iso_time_style,    /* --time-style=full-iso */
  406.     long_iso_time_style,    /* --time-style=long-iso */
  407.     iso_time_style,     /* --time-style=iso */
  408.     locale_time_style       /* --time-style=locale */
  409.   };
  410.  
  411. static char const *const time_style_args[] =
  412. {
  413.   "full-iso", "long-iso", "iso", "locale", 0
  414. };
  415.  
  416. static enum time_style const time_style_types[] =
  417. {
  418.   full_iso_time_style, long_iso_time_style, iso_time_style,
  419.   locale_time_style, 0
  420. };
  421.  
  422. /* Type of time to print or sort by.  Controlled by -c and -u.  */
  423.  
  424. enum time_type
  425.   {
  426.     time_mtime,         /* default */
  427.     time_ctime,         /* -c */
  428.     time_atime          /* -u */
  429.   };
  430.  
  431. static enum time_type time_type;
  432.  
  433. /* The file characteristic to sort by.  Controlled by -t, -S, -U, -X, -v. */
  434.  
  435. enum sort_type
  436.   {
  437.     sort_none,          /* -U */
  438.     sort_name,          /* default */
  439.     sort_extension,     /* -X */
  440.     sort_time,          /* -t */
  441.     sort_size,          /* -S */
  442.     sort_version        /* -v */
  443.   };
  444.  
  445. static enum sort_type sort_type;
  446.  
  447. /* Direction of sort.
  448.    0 means highest first if numeric,
  449.    lowest first if alphabetic;
  450.    these are the defaults.
  451.    1 means the opposite order in each case.  -r  */
  452.  
  453. static int sort_reverse;
  454.  
  455. /* Nonzero means to display owner information.  -g turns this off.  */
  456.  
  457. static int print_owner = 1;
  458.  
  459. /* Nonzero means to display author information.  */
  460.  
  461. static bool print_author;
  462.  
  463. /* Nonzero means to display group information.  -G and -o turn this off.  */
  464.  
  465. static int print_group = 1;
  466.  
  467. /* Nonzero means print the user and group id's as numbers rather
  468.    than as names.  -n  */
  469.  
  470. static int numeric_ids;
  471.  
  472. /* Nonzero means mention the size in blocks of each file.  -s  */
  473.  
  474. static int print_block_size;
  475.  
  476. /* If positive, the units to use when printing sizes;
  477.    if negative, the human-readable base.  */
  478. static int output_block_size;
  479.  
  480. /* Precede each line of long output (per file) with a string like `m,n:'
  481.    where M is the number of characters after the `:' and before the
  482.    filename and N is the length of the filename.  Using this format,
  483.    Emacs' dired mode starts up twice as fast, and can handle all
  484.    strange characters in file names.  */
  485. static int dired;
  486.  
  487. /* `none' means don't mention the type of files.
  488.    `classify' means mention file types and mark executables.
  489.    `file_type' means mention only file types.
  490.  
  491.    Controlled by -F, -p, and --indicator-style.  */
  492.  
  493. enum indicator_style
  494.   {
  495.     none,   /*     --indicator-style=none */
  496.     classify,   /* -F, --indicator-style=classify */
  497.     file_type   /* -p, --indicator-style=file-type */
  498.   };
  499.  
  500. static enum indicator_style indicator_style;
  501.  
  502. /* Names of indicator styles.  */
  503. static char const *const indicator_style_args[] =
  504. {
  505.   "none", "classify", "file-type", 0
  506. };
  507.  
  508. static enum indicator_style const indicator_style_types[]=
  509. {
  510.   none, classify, file_type
  511. };
  512.  
  513. /* Nonzero means use colors to mark types.  Also define the different
  514.    colors as well as the stuff for the LS_COLORS environment variable.
  515.    The LS_COLORS variable is now in a termcap-like format.  */
  516.  
  517. static int print_with_color;
  518.  
  519. enum color_type
  520.   {
  521.     color_never,        /* 0: default or --color=never */
  522.     color_always,       /* 1: --color=always */
  523.     color_if_tty        /* 2: --color=tty */
  524.   };
  525.  
  526. enum Dereference_symlink
  527.   {
  528.     DEREF_UNDEFINED = 1,
  529.     DEREF_NEVER,
  530.     DEREF_COMMAND_LINE_ARGUMENTS,   /* -H */
  531.     DEREF_ALWAYS            /* -L */
  532.   };
  533.  
  534. enum indicator_no
  535.   {
  536.     C_LEFT, C_RIGHT, C_END, C_NORM, C_FILE, C_DIR, C_LINK, C_FIFO, C_SOCK,
  537.     C_BLK, C_CHR, C_MISSING, C_ORPHAN, C_EXEC, C_DOOR
  538.   };
  539.  
  540. static const char *const indicator_name[]=
  541.   {
  542.     "lc", "rc", "ec", "no", "fi", "di", "ln", "pi", "so",
  543.     "bd", "cd", "mi", "or", "ex", "do", NULL
  544.   };
  545.  
  546. struct color_ext_type
  547.   {
  548.     struct bin_str ext;     /* The extension we're looking for */
  549.     struct bin_str seq;     /* The sequence to output when we do */
  550.     struct color_ext_type *next;    /* Next in list */
  551.   };
  552.  
  553. static struct bin_str color_indicator[] =
  554.   {
  555.     { LEN_STR_PAIR ("\033[") },     /* lc: Left of color sequence */
  556.     { LEN_STR_PAIR ("m") },     /* rc: Right of color sequence */
  557.     { 0, NULL },            /* ec: End color (replaces lc+no+rc) */
  558.     { LEN_STR_PAIR ("0") },     /* no: Normal */
  559.     { LEN_STR_PAIR ("0") },     /* fi: File: default */
  560.     { LEN_STR_PAIR ("01;34") },     /* di: Directory: bright blue */
  561.     { LEN_STR_PAIR ("01;36") },     /* ln: Symlink: bright cyan */
  562.     { LEN_STR_PAIR ("33") },        /* pi: Pipe: yellow/brown */
  563.     { LEN_STR_PAIR ("01;35") },     /* so: Socket: bright magenta */
  564.     { LEN_STR_PAIR ("01;33") },     /* bd: Block device: bright yellow */
  565.     { LEN_STR_PAIR ("01;33") },     /* cd: Char device: bright yellow */
  566.     { 0, NULL },            /* mi: Missing file: undefined */
  567.     { 0, NULL },            /* or: Orphanned symlink: undefined */
  568.     { LEN_STR_PAIR ("01;32") },     /* ex: Executable: bright green */
  569.     { LEN_STR_PAIR ("01;35") }      /* do: Door: bright magenta */
  570.   };
  571.  
  572. /* FIXME: comment  */
  573. static struct color_ext_type *color_ext_list = NULL;
  574.  
  575. /* Buffer for color sequences */
  576. static char *color_buf;
  577.  
  578. /* Nonzero means to check for orphaned symbolic link, for displaying
  579.    colors.  */
  580.  
  581. static int check_symlink_color;
  582.  
  583. /* Nonzero means mention the inode number of each file.  -i  */
  584.  
  585. static int print_inode;
  586.  
  587. /* What to do with symbolic links.  Affected by -d, -F, -H, -l (and
  588.    other options that imply -l), and -L.  */
  589.  
  590. static enum Dereference_symlink dereference;
  591.  
  592. /* Nonzero means when a directory is found, display info on its
  593.    contents.  -R  */
  594.  
  595. static int recursive;
  596.  
  597. /* Nonzero means when an argument is a directory name, display info
  598.    on it itself.  -d  */
  599.  
  600. static int immediate_dirs;
  601.  
  602. /* Nonzero means don't omit files whose names start with `.'.  -A */
  603.  
  604. static int all_files;
  605.  
  606. /* Nonzero means don't omit files `.' and `..'
  607.    This flag implies `all_files'.  -a  */
  608.  
  609. static int really_all_files;
  610.  
  611. /* A linked list of shell-style globbing patterns.  If a non-argument
  612.    file name matches any of these patterns, it is omitted.
  613.    Controlled by -I.  Multiple -I options accumulate.
  614.    The -B option adds `*~' and `.*~' to this list.  */
  615.  
  616. struct ignore_pattern
  617.   {
  618.     const char *pattern;
  619.     struct ignore_pattern *next;
  620.   };
  621.  
  622. static struct ignore_pattern *ignore_patterns;
  623.  
  624. /* Nonzero means output nongraphic chars in file names as `?'.
  625.    (-q, --hide-control-chars)
  626.    qmark_funny_chars and the quoting style (-Q, --quoting-style=WORD) are
  627.    independent.  The algorithm is: first, obey the quoting style to get a
  628.    string representing the file name;  then, if qmark_funny_chars is set,
  629.    replace all nonprintable chars in that string with `?'.  It's necessary
  630.    to replace nonprintable chars even in quoted strings, because we don't
  631.    want to mess up the terminal if control chars get sent to it, and some
  632.    quoting methods pass through control chars as-is.  */
  633. static int qmark_funny_chars;
  634.  
  635. /* Quoting options for file and dir name output.  */
  636.  
  637. static struct quoting_options *filename_quoting_options;
  638. static struct quoting_options *dirname_quoting_options;
  639.  
  640. /* The number of chars per hardware tab stop.  Setting this to zero
  641.    inhibits the use of TAB characters for separating columns.  -T */
  642. static int tabsize;
  643.  
  644. /* Nonzero means we are listing the working directory because no
  645.    non-option arguments were given. */
  646.  
  647. static int dir_defaulted;
  648.  
  649. /* Nonzero means print each directory name before listing it. */
  650.  
  651. static int print_dir_name;
  652.  
  653. /* The line length to use for breaking lines in many-per-line format.
  654.    Can be set with -w.  */
  655.  
  656. static int line_length;
  657.  
  658. /* If nonzero, the file listing format requires that stat be called on
  659.    each file. */
  660.  
  661. static int format_needs_stat;
  662.  
  663. /* Similar to `format_needs_stat', but set if only the file type is
  664.    needed.  */
  665.  
  666. static int format_needs_type;
  667.  
  668. /* strftime formats for non-recent and recent files, respectively, in
  669.    -l output.  */
  670.  
  671. static char const *long_time_format[2] =
  672.   {
  673.     /* strftime format for non-recent files (older than 6 months), in
  674.        -l output when --time-style=locale is specified.  This should
  675.        contain the year, month and day (at least), in an order that is
  676.        understood by people in your locale's territory.
  677.        Please try to keep the number of used screen columns small,
  678.        because many people work in windows with only 80 columns.  But
  679.        make this as wide as the other string below, for recent files.  */
  680.     N_("%b %e  %Y"),
  681.     /* strftime format for recent files (younger than 6 months), in
  682.        -l output when --time-style=locale is specified.  This should
  683.        contain the month, day and time (at least), in an order that is
  684.        understood by people in your locale's territory.
  685.        Please try to keep the number of used screen columns small,
  686.        because many people work in windows with only 80 columns.  But
  687.        make this as wide as the other string above, for non-recent files.  */
  688.     N_("%b %e %H:%M")
  689.   };
  690.  
  691. /* The exit status to use if we don't get any fatal errors. */
  692.  
  693. static int exit_status;
  694.  
  695. /* For long options that have no equivalent short option, use a
  696.    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
  697. enum
  698. {
  699.   AUTHOR_OPTION = CHAR_MAX + 1,
  700.   BLOCK_SIZE_OPTION,
  701.   COLOR_OPTION,
  702.   FORMAT_OPTION,
  703.   FULL_TIME_OPTION,
  704.   INDICATOR_STYLE_OPTION,
  705.   QUOTING_STYLE_OPTION,
  706.   SHOW_CONTROL_CHARS_OPTION,
  707.   SI_OPTION,
  708.   SORT_OPTION,
  709.   TIME_OPTION,
  710.   TIME_STYLE_OPTION
  711. };
  712.  
  713. static struct option const long_options[] =
  714. {
  715.   {"all", no_argument, 0, 'a'},
  716.   {"escape", no_argument, 0, 'b'},
  717.   {"directory", no_argument, 0, 'd'},
  718.   {"dired", no_argument, 0, 'D'},
  719.   {"full-time", no_argument, 0, FULL_TIME_OPTION},
  720.   {"human-readable", no_argument, 0, 'h'},
  721.   {"inode", no_argument, 0, 'i'},
  722.   {"kilobytes", no_argument, 0, 'k'}, /* long form is obsolescent */
  723.   {"numeric-uid-gid", no_argument, 0, 'n'},
  724.   {"no-group", no_argument, 0, 'G'},
  725.   {"hide-control-chars", no_argument, 0, 'q'},
  726.   {"reverse", no_argument, 0, 'r'},
  727.   {"size", no_argument, 0, 's'},
  728.   {"width", required_argument, 0, 'w'},
  729.   {"almost-all", no_argument, 0, 'A'},
  730.   {"ignore-backups", no_argument, 0, 'B'},
  731.   {"classify", no_argument, 0, 'F'},
  732.   {"file-type", no_argument, 0, 'p'},
  733.   {"si", no_argument, 0, SI_OPTION},
  734.   {"dereference-command-line", no_argument, 0, 'H'},
  735.   {"ignore", required_argument, 0, 'I'},
  736.   {"indicator-style", required_argument, 0, INDICATOR_STYLE_OPTION},
  737.   {"dereference", no_argument, 0, 'L'},
  738.   {"literal", no_argument, 0, 'N'},
  739.   {"quote-name", no_argument, 0, 'Q'},
  740.   {"quoting-style", required_argument, 0, QUOTING_STYLE_OPTION},
  741.   {"recursive", no_argument, 0, 'R'},
  742.   {"format", required_argument, 0, FORMAT_OPTION},
  743.   {"show-control-chars", no_argument, 0, SHOW_CONTROL_CHARS_OPTION},
  744.   {"sort", required_argument, 0, SORT_OPTION},
  745.   {"tabsize", required_argument, 0, 'T'},
  746.   {"time", required_argument, 0, TIME_OPTION},
  747.   {"time-style", required_argument, 0, TIME_STYLE_OPTION},
  748.   {"color", optional_argument, 0, COLOR_OPTION},
  749.   {"block-size", required_argument, 0, BLOCK_SIZE_OPTION},
  750.   {"author", no_argument, 0, AUTHOR_OPTION},
  751.   {GETOPT_HELP_OPTION_DECL},
  752.   {GETOPT_VERSION_OPTION_DECL},
  753.   {NULL, 0, NULL, 0}
  754. };
  755.  
  756. static char const *const format_args[] =
  757. {
  758.   "verbose", "long", "commas", "horizontal", "across",
  759.   "vertical", "single-column", 0
  760. };
  761.  
  762. static enum format const format_types[] =
  763. {
  764.   long_format, long_format, with_commas, horizontal, horizontal,
  765.   many_per_line, one_per_line
  766. };
  767.  
  768. static char const *const sort_args[] =
  769. {
  770.   "none", "time", "size", "extension", "version", 0
  771. };
  772.  
  773. static enum sort_type const sort_types[] =
  774. {
  775.   sort_none, sort_time, sort_size, sort_extension, sort_version
  776. };
  777.  
  778. static char const *const time_args[] =
  779. {
  780.   "atime", "access", "use", "ctime", "status", 0
  781. };
  782.  
  783. static enum time_type const time_types[] =
  784. {
  785.   time_atime, time_atime, time_atime, time_ctime, time_ctime
  786. };
  787.  
  788. static char const *const color_args[] =
  789. {
  790.   /* force and none are for compatibility with another color-ls version */
  791.   "always", "yes", "force",
  792.   "never", "no", "none",
  793.   "auto", "tty", "if-tty", 0
  794. };
  795.  
  796. static enum color_type const color_types[] =
  797. {
  798.   color_always, color_always, color_always,
  799.   color_never, color_never, color_never,
  800.   color_if_tty, color_if_tty, color_if_tty
  801. };
  802.  
  803. /* Information about filling a column.  */
  804. struct column_info
  805. {
  806.   int valid_len;
  807.   int line_len;
  808.   int *col_arr;
  809. };
  810.  
  811. /* Array with information about column filledness.  */
  812. static struct column_info *column_info;
  813.  
  814. /* Maximum number of columns ever possible for this display.  */
  815. static int max_idx;
  816.  
  817. /* The minimum width of a colum is 3: 1 character for the name and 2
  818.    for the separating white space.  */
  819. #define MIN_COLUMN_WIDTH    3
  820.  
  821.  
  822. /* This zero-based index is used solely with the --dired option.
  823.    When that option is in effect, this counter is incremented for each
  824.    character of output generated by this program so that the beginning
  825.    and ending indices (in that output) of every file name can be recorded
  826.    and later output themselves.  */
  827. static size_t dired_pos;
  828.  
  829. #define DIRED_PUTCHAR(c) do {putchar ((c)); ++dired_pos;} while (0)
  830.  
  831. /* Write S to STREAM and increment DIRED_POS by S_LEN.  */
  832. #define DIRED_FPUTS(s, stream, s_len) \
  833.     do {fputs ((s), (stream)); dired_pos += s_len;} while (0)
  834.  
  835. /* Like DIRED_FPUTS, but for use when S is a literal string.  */
  836. #define DIRED_FPUTS_LITERAL(s, stream) \
  837.     do {fputs ((s), (stream)); dired_pos += sizeof((s)) - 1;} while (0)
  838.  
  839. #define DIRED_INDENT()                          \
  840.     do                                  \
  841.       {                                 \
  842.     /* FIXME: remove the `&& format == long_format' clause.  */ \
  843.     if (dired && format == long_format)             \
  844.       DIRED_FPUTS_LITERAL ("  ", stdout);               \
  845.       }                                 \
  846.     while (0)
  847.  
  848. /* With --dired, store pairs of beginning and ending indices of filenames.  */
  849. static struct obstack dired_obstack;
  850.  
  851. /* With --dired, store pairs of beginning and ending indices of any
  852.    directory names that appear as headers (just before `total' line)
  853.    for lists of directory entries.  Such directory names are seen when
  854.    listing hierarchies using -R and when a directory is listed with at
  855.    least one other command line argument.  */
  856. static struct obstack subdired_obstack;
  857.  
  858. /* Save the current index on the specified obstack, OBS.  */
  859. #define PUSH_CURRENT_DIRED_POS(obs)                 \
  860.   do                                    \
  861.     {                                   \
  862.       /* FIXME: remove the `&& format == long_format' clause.  */   \
  863.       if (dired && format == long_format)               \
  864.     obstack_grow ((obs), &dired_pos, sizeof (dired_pos));       \
  865.     }                                   \
  866.   while (0)
  867.  
  868. /* With -R, this stack is used to help detect directory cycles.
  869.    The device/inode pairs on this stack mirror the pairs in the
  870.    active_dir_set hash table.  */
  871. static struct obstack dev_ino_obstack;
  872.  
  873. /* Push a pair onto the device/inode stack.  */
  874. #define DEV_INO_PUSH(Dev, Ino)                      \
  875.   do                                    \
  876.     {                                   \
  877.       struct dev_ino *di;                       \
  878.       obstack_blank (&dev_ino_obstack, sizeof (struct dev_ino));    \
  879.       di = -1 + (struct dev_ino *) obstack_next_free (&dev_ino_obstack); \
  880.       di->st_dev = (Dev);                       \
  881.       di->st_ino = (Ino);                       \
  882.     }                                   \
  883.   while (0)
  884.  
  885. /* Pop a dev/ino struct off the global dev_ino_obstack
  886.    and return that struct.  */
  887. static struct dev_ino
  888. dev_ino_pop (void)
  889. {
  890.   assert (sizeof (struct dev_ino) <= obstack_object_size (&dev_ino_obstack));
  891.   obstack_blank (&dev_ino_obstack, -(int) (sizeof (struct dev_ino)));
  892.   return *(struct dev_ino*) obstack_next_free (&dev_ino_obstack);
  893. }
  894.  
  895. #define ASSERT_MATCHING_DEV_INO(Name, Di)   \
  896.   do                        \
  897.     {                       \
  898.       struct stat sb;               \
  899.       assert (Name);                \
  900.       assert (0 <= stat (Name, &sb));       \
  901.       assert (sb.st_dev == Di.st_dev);      \
  902.       assert (sb.st_ino == Di.st_ino);      \
  903.     }                       \
  904.   while (0)
  905.  
  906.  
  907. /* Write to standard output PREFIX, followed by the quoting style and
  908.    a space-separated list of the integers stored in OS all on one line.  */
  909.  
  910. static void
  911. dired_dump_obstack (const char *prefix, struct obstack *os)
  912. {
  913.   int n_pos;
  914.  
  915.   n_pos = obstack_object_size (os) / sizeof (dired_pos);
  916.   if (n_pos > 0)
  917.     {
  918.       int i;
  919.       size_t *pos;
  920.  
  921.       pos = (size_t *) obstack_finish (os);
  922.       fputs (prefix, stdout);
  923.       for (i = 0; i < n_pos; i++)
  924.     printf (" %lu", (unsigned long) pos[i]);
  925.       fputs ("\n", stdout);
  926.     }
  927. }
  928.  
  929. static unsigned int
  930. dev_ino_hash (void const *x, unsigned int table_size)
  931. {
  932.   struct dev_ino const *p = x;
  933.   return (uintmax_t) p->st_ino % table_size;
  934. }
  935.  
  936. static bool
  937. dev_ino_compare (void const *x, void const *y)
  938. {
  939.   struct dev_ino const *a = x;
  940.   struct dev_ino const *b = y;
  941.   return SAME_INODE (*a, *b) ? true : false;
  942. }
  943.  
  944. static void
  945. dev_ino_free (void *x)
  946. {
  947.   free (x);
  948. }
  949.  
  950. /* Add the device/inode pair (P->st_dev/P->st_ino) to the set of
  951.    active directories.  Return nonzero if there is already a matching
  952.    entry in the table.  Otherwise, return zero.  */
  953.  
  954. static int
  955. visit_dir (dev_t dev, ino_t ino)
  956. {
  957.   struct dev_ino *ent;
  958.   struct dev_ino *ent_from_table;
  959.   int found_match;
  960.  
  961.   ent = XMALLOC (struct dev_ino, 1);
  962.   ent->st_ino = ino;
  963.   ent->st_dev = dev;
  964.  
  965.   /* Attempt to insert this entry into the table.  */
  966.   ent_from_table = hash_insert (active_dir_set, ent);
  967.  
  968.   if (ent_from_table == NULL)
  969.     {
  970.       /* Insertion failed due to lack of memory.  */
  971.       xalloc_die ();
  972.     }
  973.  
  974.   found_match = (ent_from_table != ent);
  975.  
  976.   if (found_match)
  977.     {
  978.       /* ent was not inserted, so free it.  */
  979.       free (ent);
  980.     }
  981.  
  982.   return found_match;
  983. }
  984.  
  985. static void
  986. free_pending_ent (struct pending *p)
  987. {
  988.   if (p->name)
  989.     free (p->name);
  990.   if (p->realname)
  991.     free (p->realname);
  992.   free (p);
  993. }
  994.  
  995. int
  996. main (int argc, char **argv)
  997. {
  998.   register int i;
  999.   register struct pending *thispend;
  1000.   unsigned int n_files;
  1001.  
  1002.   program_name = argv[0];
  1003.   setlocale (LC_ALL, "");
  1004.   bindtextdomain (PACKAGE, LOCALEDIR);
  1005.   textdomain (PACKAGE);
  1006.  
  1007.   atexit (close_stdout);
  1008.  
  1009. #define N_ENTRIES(Array) (sizeof Array / sizeof *(Array))
  1010.   assert (N_ENTRIES (color_indicator) + 1 == N_ENTRIES (indicator_name));
  1011.  
  1012.   exit_status = 0;
  1013.   dir_defaulted = 1;
  1014.   print_dir_name = 1;
  1015.   pending_dirs = 0;
  1016.  
  1017.   i = decode_switches (argc, argv);
  1018.  
  1019.   if (print_with_color)
  1020.     parse_ls_color ();
  1021.  
  1022.   /* Test print_with_color again, because the call to parse_ls_color
  1023.      may have just reset it -- e.g., if LS_COLORS is invalid.  */
  1024.   if (print_with_color)
  1025.     {
  1026.       prep_non_filename_text ();
  1027.       /* Avoid following symbolic links when possible.  */
  1028.       if (color_indicator[C_ORPHAN].string != NULL
  1029.       || (color_indicator[C_MISSING].string != NULL
  1030.           && format == long_format))
  1031.     check_symlink_color = 1;
  1032.     }
  1033.  
  1034.   if (dereference == DEREF_UNDEFINED)
  1035.     dereference = ((immediate_dirs
  1036.             || indicator_style == classify
  1037.             || format == long_format)
  1038.            ? DEREF_NEVER
  1039.            : DEREF_COMMAND_LINE_ARGUMENTS);
  1040.  
  1041.   /* When using -R, initialize a data structure we'll use to
  1042.      detect any directory cycles.  */
  1043.   if (recursive)
  1044.     {
  1045.       active_dir_set = hash_initialize (INITIAL_TABLE_SIZE, NULL,
  1046.                     dev_ino_hash,
  1047.                     dev_ino_compare,
  1048.                     dev_ino_free);
  1049.       if (active_dir_set == NULL)
  1050.     xalloc_die ();
  1051.  
  1052.       obstack_init (&dev_ino_obstack);
  1053.     }
  1054.  
  1055.   format_needs_stat = sort_type == sort_time || sort_type == sort_size
  1056.     || format == long_format
  1057.     || dereference == DEREF_ALWAYS
  1058.     || recursive || print_block_size || print_inode;
  1059.   format_needs_type = (format_needs_stat == 0
  1060.                && (print_with_color || indicator_style != none));
  1061.  
  1062.   if (dired && format == long_format)
  1063.     {
  1064.       obstack_init (&dired_obstack);
  1065.       obstack_init (&subdired_obstack);
  1066.     }
  1067.  
  1068.   nfiles = 100;
  1069.   files = XMALLOC (struct fileinfo, nfiles);
  1070.   files_index = 0;
  1071.  
  1072.   clear_files ();
  1073.  
  1074.   n_files = argc - i;
  1075.   if (0 < n_files)
  1076.     dir_defaulted = 0;
  1077.  
  1078.   for (; i < argc; i++)
  1079.     {
  1080.       gobble_file (argv[i], unknown, 1, "");
  1081.     }
  1082.  
  1083.   if (dir_defaulted)
  1084.     {
  1085.       if (immediate_dirs)
  1086.     gobble_file (".", directory, 1, "");
  1087.       else
  1088.     queue_directory (".", 0);
  1089.     }
  1090.  
  1091.   if (files_index)
  1092.     {
  1093.       sort_files ();
  1094.       if (!immediate_dirs)
  1095.     extract_dirs_from_files ("", 0);
  1096.       /* `files_index' might be zero now.  */
  1097.     }
  1098.  
  1099.   /* In the following if/else blocks, it is sufficient to test `pending_dirs'
  1100.      (and not pending_dirs->name) because there may be no markers in the queue
  1101.      at this point.  A marker may be enqueued when extract_dirs_from_files is
  1102.      called with a non-empty string or via print_dir.  */
  1103.   if (files_index)
  1104.     {
  1105.       print_current_files ();
  1106.       if (pending_dirs)
  1107.     DIRED_PUTCHAR ('\n');
  1108.     }
  1109.   else if (n_files <= 1 && pending_dirs && pending_dirs->next == 0)
  1110.     print_dir_name = 0;
  1111.  
  1112.   while (pending_dirs)
  1113.     {
  1114.       thispend = pending_dirs;
  1115.       pending_dirs = pending_dirs->next;
  1116.  
  1117.       if (LOOP_DETECT)
  1118.     {
  1119.       if (thispend->name == NULL)
  1120.         {
  1121.           /* thispend->name == NULL means this is a marker entry
  1122.          indicating we've finished processing the directory.
  1123.          Use its dev/ino numbers to remove the corresponding
  1124.          entry from the active_dir_set hash table.  */
  1125.           struct dev_ino di = dev_ino_pop ();
  1126.           struct dev_ino *found = hash_delete (active_dir_set, &di);
  1127.           /* ASSERT_MATCHING_DEV_INO (thispend->realname, di); */
  1128.           assert (found);
  1129.           dev_ino_free (found);
  1130.           free_pending_ent (thispend);
  1131.           continue;
  1132.         }
  1133.     }
  1134.  
  1135.       print_dir (thispend->name, thispend->realname);
  1136.  
  1137.       free_pending_ent (thispend);
  1138.       print_dir_name = 1;
  1139.     }
  1140.  
  1141.   if (dired && format == long_format)
  1142.     {
  1143.       /* No need to free these since we're about to exit.  */
  1144.       dired_dump_obstack ("//DIRED//", &dired_obstack);
  1145.       dired_dump_obstack ("//SUBDIRED//", &subdired_obstack);
  1146.       printf ("//DIRED-OPTIONS// --quoting-style=%s\n",
  1147.           quoting_style_args[get_quoting_style (filename_quoting_options)]);
  1148.     }
  1149.  
  1150.   /* Restore default color before exiting */
  1151.   if (print_with_color)
  1152.     {
  1153.       put_indicator (&color_indicator[C_LEFT]);
  1154.       put_indicator (&color_indicator[C_RIGHT]);
  1155.     }
  1156.  
  1157.   if (LOOP_DETECT)
  1158.     {
  1159.       assert (hash_get_n_entries (active_dir_set) == 0);
  1160.       hash_free (active_dir_set);
  1161.     }
  1162.  
  1163.   exit (exit_status);
  1164. }
  1165.  
  1166. /* Set all the option flags according to the switches specified.
  1167.    Return the index of the first non-option argument.  */
  1168.  
  1169. static int
  1170. decode_switches (int argc, char **argv)
  1171. {
  1172.   int c;
  1173.   char *time_style_option = 0;
  1174.  
  1175.   /* Record whether there is an option specifying sort type.  */
  1176.   int sort_type_specified = 0;
  1177.  
  1178.   qmark_funny_chars = 0;
  1179.  
  1180.   /* initialize all switches to default settings */
  1181.  
  1182.   switch (ls_mode)
  1183.     {
  1184.     case LS_MULTI_COL:
  1185.       /* This is for the `dir' program.  */
  1186.       format = many_per_line;
  1187.       set_quoting_style (NULL, escape_quoting_style);
  1188.       break;
  1189.  
  1190.     case LS_LONG_FORMAT:
  1191.       /* This is for the `vdir' program.  */
  1192.       format = long_format;
  1193.       set_quoting_style (NULL, escape_quoting_style);
  1194.       break;
  1195.  
  1196.     case LS_LS:
  1197.       /* This is for the `ls' program.  */
  1198.       if (isatty (STDOUT_FILENO))
  1199.     {
  1200.       format = many_per_line;
  1201.       /* See description of qmark_funny_chars, above.  */
  1202.       qmark_funny_chars = 1;
  1203.     }
  1204.       else
  1205.     {
  1206.       format = one_per_line;
  1207.       qmark_funny_chars = 0;
  1208.     }
  1209.       break;
  1210.  
  1211.     default:
  1212.       abort ();
  1213.     }
  1214.  
  1215.   time_type = time_mtime;
  1216.   sort_type = sort_name;
  1217.   sort_reverse = 0;
  1218.   numeric_ids = 0;
  1219.   print_block_size = 0;
  1220.   indicator_style = none;
  1221.   print_inode = 0;
  1222.   dereference = DEREF_UNDEFINED;
  1223.   recursive = 0;
  1224.   immediate_dirs = 0;
  1225.   all_files = 0;
  1226.   really_all_files = 0;
  1227.   ignore_patterns = 0;
  1228.  
  1229.   /* FIXME: put this in a function.  */
  1230.   {
  1231.     char const *q_style = getenv ("QUOTING_STYLE");
  1232.     if (q_style)
  1233.       {
  1234.     int i = ARGCASEMATCH (q_style, quoting_style_args, quoting_style_vals);
  1235.     if (0 <= i)
  1236.       set_quoting_style (NULL, quoting_style_vals[i]);
  1237.     else
  1238.       error (0, 0,
  1239.      _("ignoring invalid value of environment variable QUOTING_STYLE: %s"),
  1240.          quotearg (q_style));
  1241.       }
  1242.   }
  1243.  
  1244.   human_block_size (getenv ("LS_BLOCK_SIZE"), 0, &output_block_size);
  1245.  
  1246.   line_length = 80;
  1247.   {
  1248.     char const *p = getenv ("COLUMNS");
  1249.     if (p && *p)
  1250.       {
  1251.     long int tmp_long;
  1252.     if (xstrtol (p, NULL, 0, &tmp_long, NULL) == LONGINT_OK
  1253.         && 0 < tmp_long && tmp_long <= INT_MAX)
  1254.       {
  1255.         line_length = (int) tmp_long;
  1256.       }
  1257.     else
  1258.       {
  1259.         error (0, 0,
  1260.            _("ignoring invalid width in environment variable COLUMNS: %s"),
  1261.            quotearg (p));
  1262.       }
  1263.       }
  1264.   }
  1265.  
  1266. #ifdef TIOCGWINSZ
  1267.   {
  1268.     struct winsize ws;
  1269.  
  1270.     if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &ws) != -1 && ws.ws_col != 0)
  1271.       line_length = ws.ws_col;
  1272.   }
  1273. #endif
  1274.  
  1275.   /* Using the TABSIZE environment variable is not POSIX-approved.
  1276.      Ignore it when POSIXLY_CORRECT is set.  */
  1277.   {
  1278.     char const *p;
  1279.     tabsize = 8;
  1280.     if (!getenv ("POSIXLY_CORRECT") && (p = getenv ("TABSIZE")))
  1281.       {
  1282.     long int tmp_long;
  1283.     if (xstrtol (p, NULL, 0, &tmp_long, NULL) == LONGINT_OK
  1284.         && 0 <= tmp_long && tmp_long <= INT_MAX)
  1285.       {
  1286.         tabsize = (int) tmp_long;
  1287.       }
  1288.     else
  1289.       {
  1290.         error (0, 0,
  1291.          _("ignoring invalid tab size in environment variable TABSIZE: %s"),
  1292.            quotearg (p));
  1293.       }
  1294.       }
  1295.   }
  1296.  
  1297.   while ((c = getopt_long (argc, argv,
  1298.                "abcdfghiklmnopqrstuvw:xABCDFGHI:LNQRST:UX1",
  1299.                long_options, NULL)) != -1)
  1300.     {
  1301.       switch (c)
  1302.     {
  1303.     case 0:
  1304.       break;
  1305.  
  1306.     case 'a':
  1307.       all_files = 1;
  1308.       really_all_files = 1;
  1309.       break;
  1310.  
  1311.     case 'b':
  1312.       set_quoting_style (NULL, escape_quoting_style);
  1313.       break;
  1314.  
  1315.     case 'c':
  1316.       time_type = time_ctime;
  1317.       break;
  1318.  
  1319.     case 'd':
  1320.       immediate_dirs = 1;
  1321.       break;
  1322.  
  1323.     case 'f':
  1324.       /* Same as enabling -a -U and disabling -l -s.  */
  1325.       all_files = 1;
  1326.       really_all_files = 1;
  1327.       sort_type = sort_none;
  1328.       sort_type_specified = 1;
  1329.       /* disable -l */
  1330.       if (format == long_format)
  1331.         format = (isatty (STDOUT_FILENO) ? many_per_line : one_per_line);
  1332.       print_block_size = 0; /* disable -s */
  1333.       print_with_color = 0; /* disable --color */
  1334.       break;
  1335.  
  1336.     case 'g':
  1337.       format = long_format;
  1338.       print_owner = 0;
  1339.       break;
  1340.  
  1341.     case 'h':
  1342.       output_block_size = -1024;
  1343.       break;
  1344.  
  1345.     case 'i':
  1346.       print_inode = 1;
  1347.       break;
  1348.  
  1349.     case 'k':
  1350.       output_block_size = 1024;
  1351.       break;
  1352.  
  1353.     case 'l':
  1354.       format = long_format;
  1355.       break;
  1356.  
  1357.     case 'm':
  1358.       format = with_commas;
  1359.       break;
  1360.  
  1361.     case 'n':
  1362.       numeric_ids = 1;
  1363.       format = long_format;
  1364.       break;
  1365.  
  1366.     case 'o':  /* Just like -l, but don't display group info.  */
  1367.       format = long_format;
  1368.       print_group = 0;
  1369.       break;
  1370.  
  1371.     case 'p':
  1372.       indicator_style = file_type;
  1373.       break;
  1374.  
  1375.     case 'q':
  1376.       qmark_funny_chars = 1;
  1377.       break;
  1378.  
  1379.     case 'r':
  1380.       sort_reverse = 1;
  1381.       break;
  1382.  
  1383.     case 's':
  1384.       print_block_size = 1;
  1385.       break;
  1386.  
  1387.     case 't':
  1388.       sort_type = sort_time;
  1389.       sort_type_specified = 1;
  1390.       break;
  1391.  
  1392.     case 'u':
  1393.       time_type = time_atime;
  1394.       break;
  1395.  
  1396.     case 'v':
  1397.       sort_type = sort_version;
  1398.       sort_type_specified = 1;
  1399.       break;
  1400.  
  1401.     case 'w':
  1402.       {
  1403.         long int tmp_long;
  1404.         if (xstrtol (optarg, NULL, 0, &tmp_long, NULL) != LONGINT_OK
  1405.         || tmp_long <= 0 || tmp_long > INT_MAX)
  1406.           error (EXIT_FAILURE, 0, _("invalid line width: %s"),
  1407.              quotearg (optarg));
  1408.         line_length = (int) tmp_long;
  1409.         break;
  1410.       }
  1411.  
  1412.     case 'x':
  1413.       format = horizontal;
  1414.       break;
  1415.  
  1416.     case 'A':
  1417.       really_all_files = 0;
  1418.       all_files = 1;
  1419.       break;
  1420.  
  1421.     case 'B':
  1422.       add_ignore_pattern ("*~");
  1423.       add_ignore_pattern (".*~");
  1424.       break;
  1425.  
  1426.     case 'C':
  1427.       format = many_per_line;
  1428.       break;
  1429.  
  1430.     case 'D':
  1431.       dired = 1;
  1432.       break;
  1433.  
  1434.     case 'F':
  1435.       indicator_style = classify;
  1436.       break;
  1437.  
  1438.     case 'G':       /* inhibit display of group info */
  1439.       print_group = 0;
  1440.       break;
  1441.  
  1442.     case 'H':
  1443.       dereference = DEREF_COMMAND_LINE_ARGUMENTS;
  1444.       break;
  1445.  
  1446.     case 'I':
  1447.       add_ignore_pattern (optarg);
  1448.       break;
  1449.  
  1450.     case 'L':
  1451.       dereference = DEREF_ALWAYS;
  1452.       break;
  1453.  
  1454.     case 'N':
  1455.       set_quoting_style (NULL, literal_quoting_style);
  1456.       break;
  1457.  
  1458.     case 'Q':
  1459.       set_quoting_style (NULL, c_quoting_style);
  1460.       break;
  1461.  
  1462.     case 'R':
  1463.       recursive = 1;
  1464.       break;
  1465.  
  1466.     case 'S':
  1467.       sort_type = sort_size;
  1468.       sort_type_specified = 1;
  1469.       break;
  1470.  
  1471.     case 'T':
  1472.       {
  1473.         long int tmp_long;
  1474.         if (xstrtol (optarg, NULL, 0, &tmp_long, NULL) != LONGINT_OK
  1475.         || tmp_long < 0 || tmp_long > INT_MAX)
  1476.           error (EXIT_FAILURE, 0, _("invalid tab size: %s"),
  1477.              quotearg (optarg));
  1478.         tabsize = (int) tmp_long;
  1479.         break;
  1480.       }
  1481.  
  1482.     case 'U':
  1483.       sort_type = sort_none;
  1484.       sort_type_specified = 1;
  1485.       break;
  1486.  
  1487.     case 'X':
  1488.       sort_type = sort_extension;
  1489.       sort_type_specified = 1;
  1490.       break;
  1491.  
  1492.     case '1':
  1493.       /* -1 has no effect after -l.  */
  1494.       if (format != long_format)
  1495.         format = one_per_line;
  1496.       break;
  1497.  
  1498.         case AUTHOR_OPTION:
  1499.           print_author = true;
  1500.           break;
  1501.  
  1502.     case SORT_OPTION:
  1503.       sort_type = XARGMATCH ("--sort", optarg, sort_args, sort_types);
  1504.       sort_type_specified = 1;
  1505.       break;
  1506.  
  1507.     case TIME_OPTION:
  1508.       time_type = XARGMATCH ("--time", optarg, time_args, time_types);
  1509.       break;
  1510.  
  1511.     case FORMAT_OPTION:
  1512.       format = XARGMATCH ("--format", optarg, format_args, format_types);
  1513.       break;
  1514.  
  1515.     case FULL_TIME_OPTION:
  1516.       format = long_format;
  1517.       time_style_option = "full-iso";
  1518.       break;
  1519.  
  1520.     case COLOR_OPTION:
  1521.       {
  1522.         int i;
  1523.         if (optarg)
  1524.           i = XARGMATCH ("--color", optarg, color_args, color_types);
  1525.         else
  1526.           /* Using --color with no argument is equivalent to using
  1527.          --color=always.  */
  1528.           i = color_always;
  1529.  
  1530.         print_with_color = (i == color_always
  1531.                 || (i == color_if_tty
  1532.                     && isatty (STDOUT_FILENO)));
  1533.  
  1534.         if (print_with_color)
  1535.           {
  1536.         /* Don't use TAB characters in output.  Some terminal
  1537.            emulators can't handle the combination of tabs and
  1538.            color codes on the same line.  */
  1539.         tabsize = 0;
  1540.           }
  1541.         break;
  1542.       }
  1543.  
  1544.     case INDICATOR_STYLE_OPTION:
  1545.       indicator_style = XARGMATCH ("--indicator-style", optarg,
  1546.                        indicator_style_args,
  1547.                        indicator_style_types);
  1548.       break;
  1549.  
  1550.     case QUOTING_STYLE_OPTION:
  1551.       set_quoting_style (NULL,
  1552.                  XARGMATCH ("--quoting-style", optarg,
  1553.                     quoting_style_args,
  1554.                     quoting_style_vals));
  1555.       break;
  1556.  
  1557.     case TIME_STYLE_OPTION:
  1558.       time_style_option = optarg;
  1559.       break;
  1560.  
  1561.     case SHOW_CONTROL_CHARS_OPTION:
  1562.       qmark_funny_chars = 0;
  1563.       break;
  1564.  
  1565.     case BLOCK_SIZE_OPTION:
  1566.       human_block_size (optarg, 1, &output_block_size);
  1567.       break;
  1568.  
  1569.     case SI_OPTION:
  1570.       output_block_size = -1000;
  1571.       break;
  1572.  
  1573.     case_GETOPT_HELP_CHAR;
  1574.  
  1575.     case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
  1576.  
  1577.     default:
  1578.       usage (EXIT_FAILURE);
  1579.     }
  1580.     }
  1581.  
  1582.   filename_quoting_options = clone_quoting_options (NULL);
  1583.   if (get_quoting_style (filename_quoting_options) == escape_quoting_style)
  1584.     set_char_quoting (filename_quoting_options, ' ', 1);
  1585.   if (indicator_style != none)
  1586.     {
  1587.       char const *p;
  1588.       for (p = "*=@|" + (int) indicator_style - 1;  *p;  p++)
  1589.     set_char_quoting (filename_quoting_options, *p, 1);
  1590.     }
  1591.  
  1592.   dirname_quoting_options = clone_quoting_options (NULL);
  1593.   set_char_quoting (dirname_quoting_options, ':', 1);
  1594.  
  1595.   /* If -c or -u is specified and not -l (or any other option that implies -l),
  1596.      and no sort-type was specified, then sort by the ctime (-c) or atime (-u).
  1597.      The behavior of ls when using either -c or -u but with neither -l nor -t
  1598.      appears to be unspecified by POSIX.  So, with GNU ls, `-u' alone means
  1599.      sort by atime (this is the one that's not specified by the POSIX spec),
  1600.      -lu means show atime and sort by name, -lut means show atime and sort
  1601.      by atime.  */
  1602.  
  1603.   if ((time_type == time_ctime || time_type == time_atime)
  1604.       && !sort_type_specified && format != long_format)
  1605.     {
  1606.       sort_type = sort_time;
  1607.     }
  1608.  
  1609.   if (format == long_format)
  1610.     {
  1611.       char *style = time_style_option;
  1612.       static char const posix_prefix[] = "posix-";
  1613.  
  1614.       if (! style)
  1615.     if (! (style = getenv ("TIME_STYLE")))
  1616.       style = "posix-long-iso";
  1617.  
  1618.       while (strncmp (style, posix_prefix, sizeof posix_prefix - 1) == 0)
  1619.     {
  1620.       if (! hard_locale (LC_TIME))
  1621.         return optind;
  1622.       style += sizeof posix_prefix - 1;
  1623.     }
  1624.  
  1625.       if (*style == '+')
  1626.     {
  1627.       char *p0 = style + 1;
  1628.       char *p1 = strchr (p0, '\n');
  1629.       if (! p1)
  1630.         p1 = p0;
  1631.       else
  1632.         {
  1633.           if (strchr (p1 + 1, '\n'))
  1634.         error (EXIT_FAILURE, 0, _("invalid time style format %s"),
  1635.                quote (p0));
  1636.           *p1++ = '\0';
  1637.         }
  1638.       long_time_format[0] = p0;
  1639.       long_time_format[1] = p1;
  1640.     }
  1641.       else
  1642.     switch (XARGMATCH ("time style", style,
  1643.                time_style_args,
  1644.                time_style_types))
  1645.       {
  1646.       case full_iso_time_style:
  1647.         long_time_format[0] = long_time_format[1] =
  1648.           "%Y-%m-%d %H:%M:%S.%N %z";
  1649.         break;
  1650.  
  1651.       case long_iso_time_style:
  1652.         long_time_format[0] = long_time_format[1] = "%Y-%m-%d %H:%M";
  1653.         break;
  1654.  
  1655.       case iso_time_style:
  1656.         long_time_format[0] = "%Y-%m-%d ";
  1657.         long_time_format[1] = "%m-%d %H:%M";
  1658.         break;
  1659.  
  1660.       case locale_time_style:
  1661.         if (hard_locale (LC_TIME))
  1662.           {
  1663.         unsigned int i;
  1664.         for (i = 0; i < 2; i++)
  1665.           long_time_format[i] =
  1666.             dcgettext (NULL, long_time_format[i], LC_TIME);
  1667.           }
  1668.       }
  1669.     }
  1670.  
  1671.   return optind;
  1672. }
  1673.  
  1674. /* Parse a string as part of the LS_COLORS variable; this may involve
  1675.    decoding all kinds of escape characters.  If equals_end is set an
  1676.    unescaped equal sign ends the string, otherwise only a : or \0
  1677.    does.  Returns the number of characters output, or -1 on failure.
  1678.  
  1679.    The resulting string is *not* null-terminated, but may contain
  1680.    embedded nulls.
  1681.  
  1682.    Note that both dest and src are char **; on return they point to
  1683.    the first free byte after the array and the character that ended
  1684.    the input string, respectively.  */
  1685.  
  1686. static int
  1687. get_funky_string (char **dest, const char **src, int equals_end)
  1688. {
  1689.   int num;          /* For numerical codes */
  1690.   int count;            /* Something to count with */
  1691.   enum {
  1692.     ST_GND, ST_BACKSLASH, ST_OCTAL, ST_HEX, ST_CARET, ST_END, ST_ERROR
  1693.   } state;
  1694.   const char *p;
  1695.   char *q;
  1696.  
  1697.   p = *src;         /* We don't want to double-indirect */
  1698.   q = *dest;            /* the whole darn time.  */
  1699.  
  1700.   count = 0;            /* No characters counted in yet.  */
  1701.   num = 0;
  1702.  
  1703.   state = ST_GND;       /* Start in ground state.  */
  1704.   while (state < ST_END)
  1705.     {
  1706.       switch (state)
  1707.     {
  1708.     case ST_GND:        /* Ground state (no escapes) */
  1709.       switch (*p)
  1710.         {
  1711.         case ':':
  1712.         case '\0':
  1713.           state = ST_END;   /* End of string */
  1714.           break;
  1715.         case '\\':
  1716.           state = ST_BACKSLASH; /* Backslash scape sequence */
  1717.           ++p;
  1718.           break;
  1719.         case '^':
  1720.           state = ST_CARET; /* Caret escape */
  1721.           ++p;
  1722.           break;
  1723.         case '=':
  1724.           if (equals_end)
  1725.         {
  1726.           state = ST_END; /* End */
  1727.           break;
  1728.         }
  1729.           /* else fall through */
  1730.         default:
  1731.           *(q++) = *(p++);
  1732.           ++count;
  1733.           break;
  1734.         }
  1735.       break;
  1736.  
  1737.     case ST_BACKSLASH:  /* Backslash escaped character */
  1738.       switch (*p)
  1739.         {
  1740.         case '0':
  1741.         case '1':
  1742.         case '2':
  1743.         case '3':
  1744.         case '4':
  1745.         case '5':
  1746.         case '6':
  1747.         case '7':
  1748.           state = ST_OCTAL; /* Octal sequence */
  1749.           num = *p - '0';
  1750.           break;
  1751.         case 'x':
  1752.         case 'X':
  1753.           state = ST_HEX;   /* Hex sequence */
  1754.           num = 0;
  1755.           break;
  1756.         case 'a':       /* Bell */
  1757.           num = 7;      /* Not all C compilers know what \a means */
  1758.           break;
  1759.         case 'b':       /* Backspace */
  1760.           num = '\b';
  1761.           break;
  1762.         case 'e':       /* Escape */
  1763.           num = 27;
  1764.           break;
  1765.         case 'f':       /* Form feed */
  1766.           num = '\f';
  1767.           break;
  1768.         case 'n':       /* Newline */
  1769.           num = '\n';
  1770.           break;
  1771.         case 'r':       /* Carriage return */
  1772.           num = '\r';
  1773.           break;
  1774.         case 't':       /* Tab */
  1775.           num = '\t';
  1776.           break;
  1777.         case 'v':       /* Vtab */
  1778.           num = '\v';
  1779.           break;
  1780.         case '?':       /* Delete */
  1781.               num = 127;
  1782.           break;
  1783.         case '_':       /* Space */
  1784.           num = ' ';
  1785.           break;
  1786.         case '\0':      /* End of string */
  1787.           state = ST_ERROR; /* Error! */
  1788.           break;
  1789.         default:        /* Escaped character like \ ^ : = */
  1790.           num = *p;
  1791.           break;
  1792.         }
  1793.       if (state == ST_BACKSLASH)
  1794.         {
  1795.           *(q++) = num;
  1796.           ++count;
  1797.           state = ST_GND;
  1798.         }
  1799.       ++p;
  1800.       break;
  1801.  
  1802.     case ST_OCTAL:      /* Octal sequence */
  1803.       if (*p < '0' || *p > '7')
  1804.         {
  1805.           *(q++) = num;
  1806.           ++count;
  1807.           state = ST_GND;
  1808.         }
  1809.       else
  1810.         num = (num << 3) + (*(p++) - '0');
  1811.       break;
  1812.  
  1813.     case ST_HEX:        /* Hex sequence */
  1814.       switch (*p)
  1815.         {
  1816.         case '0':
  1817.         case '1':
  1818.         case '2':
  1819.         case '3':
  1820.         case '4':
  1821.         case '5':
  1822.         case '6':
  1823.         case '7':
  1824.         case '8':
  1825.         case '9':
  1826.           num = (num << 4) + (*(p++) - '0');
  1827.           break;
  1828.         case 'a':
  1829.         case 'b':
  1830.         case 'c':
  1831.         case 'd':
  1832.         case 'e':
  1833.         case 'f':
  1834.           num = (num << 4) + (*(p++) - 'a') + 10;
  1835.           break;
  1836.         case 'A':
  1837.         case 'B':
  1838.         case 'C':
  1839.         case 'D':
  1840.         case 'E':
  1841.         case 'F':
  1842.           num = (num << 4) + (*(p++) - 'A') + 10;
  1843.           break;
  1844.         default:
  1845.           *(q++) = num;
  1846.           ++count;
  1847.           state = ST_GND;
  1848.           break;
  1849.         }
  1850.       break;
  1851.  
  1852.     case ST_CARET:      /* Caret escape */
  1853.       state = ST_GND;   /* Should be the next state... */
  1854.       if (*p >= '@' && *p <= '~')
  1855.         {
  1856.           *(q++) = *(p++) & 037;
  1857.           ++count;
  1858.         }
  1859.       else if (*p == '?')
  1860.         {
  1861.           *(q++) = 127;
  1862.           ++count;
  1863.         }
  1864.       else
  1865.         state = ST_ERROR;
  1866.       break;
  1867.  
  1868.     default:
  1869.       abort ();
  1870.     }
  1871.     }
  1872.  
  1873.   *dest = q;
  1874.   *src = p;
  1875.  
  1876.   return state == ST_ERROR ? -1 : count;
  1877. }
  1878.  
  1879. static void
  1880. parse_ls_color (void)
  1881. {
  1882.   const char *p;        /* Pointer to character being parsed */
  1883.   char *buf;            /* color_buf buffer pointer */
  1884.   int state;            /* State of parser */
  1885.   int ind_no;           /* Indicator number */
  1886.   char label[3];        /* Indicator label */
  1887.   struct color_ext_type *ext;   /* Extension we are working on */
  1888.  
  1889.   if ((p = getenv ("LS_COLORS")) == NULL || *p == '\0')
  1890.     return;
  1891.  
  1892.   ext = NULL;
  1893.   strcpy (label, "??");
  1894.  
  1895.   /* This is an overly conservative estimate, but any possible
  1896.      LS_COLORS string will *not* generate a color_buf longer than
  1897.      itself, so it is a safe way of allocating a buffer in
  1898.      advance.  */
  1899.   buf = color_buf = xstrdup (p);
  1900.  
  1901.   state = 1;
  1902.   while (state > 0)
  1903.     {
  1904.       switch (state)
  1905.     {
  1906.     case 1:     /* First label character */
  1907.       switch (*p)
  1908.         {
  1909.         case ':':
  1910.           ++p;
  1911.           break;
  1912.  
  1913.         case '*':
  1914.           /* Allocate new extension block and add to head of
  1915.          linked list (this way a later definition will
  1916.          override an earlier one, which can be useful for
  1917.          having terminal-specific defs override global).  */
  1918.  
  1919.           ext = XMALLOC (struct color_ext_type, 1);
  1920.           ext->next = color_ext_list;
  1921.           color_ext_list = ext;
  1922.  
  1923.           ++p;
  1924.           ext->ext.string = buf;
  1925.  
  1926.           state = (ext->ext.len =
  1927.                get_funky_string (&buf, &p, 1)) < 0 ? -1 : 4;
  1928.           break;
  1929.  
  1930.         case '\0':
  1931.           state = 0;    /* Done! */
  1932.           break;
  1933.  
  1934.         default:    /* Assume it is file type label */
  1935.           label[0] = *(p++);
  1936.           state = 2;
  1937.           break;
  1938.         }
  1939.       break;
  1940.  
  1941.     case 2:     /* Second label character */
  1942.       if (*p)
  1943.         {
  1944.           label[1] = *(p++);
  1945.           state = 3;
  1946.         }
  1947.       else
  1948.         state = -1; /* Error */
  1949.       break;
  1950.  
  1951.     case 3:     /* Equal sign after indicator label */
  1952.       state = -1;   /* Assume failure... */
  1953.       if (*(p++) == '=')/* It *should* be... */
  1954.         {
  1955.           for (ind_no = 0; indicator_name[ind_no] != NULL; ++ind_no)
  1956.         {
  1957.           if (STREQ (label, indicator_name[ind_no]))
  1958.             {
  1959.               color_indicator[ind_no].string = buf;
  1960.               state = ((color_indicator[ind_no].len =
  1961.                 get_funky_string (&buf, &p, 0)) < 0 ? -1 : 1);
  1962.               break;
  1963.             }
  1964.         }
  1965.           if (state == -1)
  1966.         error (0, 0, _("unrecognized prefix: %s"), quotearg (label));
  1967.         }
  1968.      break;
  1969.  
  1970.     case 4:     /* Equal sign after *.ext */
  1971.       if (*(p++) == '=')
  1972.         {
  1973.           ext->seq.string = buf;
  1974.           state = (ext->seq.len =
  1975.                get_funky_string (&buf, &p, 0)) < 0 ? -1 : 1;
  1976.         }
  1977.       else
  1978.         state = -1;
  1979.       break;
  1980.     }
  1981.     }
  1982.  
  1983.   if (state < 0)
  1984.     {
  1985.       struct color_ext_type *e;
  1986.       struct color_ext_type *e2;
  1987.  
  1988.       error (0, 0,
  1989.          _("unparsable value for LS_COLORS environment variable"));
  1990.       free (color_buf);
  1991.       for (e = color_ext_list; e != NULL; /* empty */)
  1992.     {
  1993.       e2 = e;
  1994.       e = e->next;
  1995.       free (e2);
  1996.     }
  1997.       print_with_color = 0;
  1998.     }
  1999.  
  2000.   if (color_indicator[C_LINK].len == 6
  2001.       && !strncmp (color_indicator[C_LINK].string, "target", 6))
  2002.     color_symlink_as_referent = 1;
  2003. }
  2004.  
  2005. /* Request that the directory named NAME have its contents listed later.
  2006.    If REALNAME is nonzero, it will be used instead of NAME when the
  2007.    directory name is printed.  This allows symbolic links to directories
  2008.    to be treated as regular directories but still be listed under their
  2009.    real names.  NAME == NULL is used to insert a marker entry for the
  2010.    directory named in REALNAME.
  2011.    If F is non-NULL, we use its dev/ino information to save
  2012.    a call to stat -- when doing a recursive (-R) traversal.  */
  2013.  
  2014. static void
  2015. queue_directory (const char *name, const char *realname)
  2016. {
  2017.   struct pending *new;
  2018.  
  2019.   new = XMALLOC (struct pending, 1);
  2020.   new->realname = realname ? xstrdup (realname) : NULL;
  2021.   new->name = name ? xstrdup (name) : NULL;
  2022.   new->next = pending_dirs;
  2023.   pending_dirs = new;
  2024. }
  2025.  
  2026. /* Read directory `name', and list the files in it.
  2027.    If `realname' is nonzero, print its name instead of `name';
  2028.    this is used for symbolic links to directories. */
  2029.  
  2030. static void
  2031. print_dir (const char *name, const char *realname)
  2032. {
  2033.   register DIR *dirp;
  2034.   register struct dirent *next;
  2035.   register uintmax_t total_blocks = 0;
  2036.   static int first = 1;
  2037.  
  2038.   errno = 0;
  2039.   dirp = opendir (name);
  2040.   if (!dirp)
  2041.     {
  2042.       error (0, errno, "%s", quotearg_colon (name));
  2043.       exit_status = 1;
  2044.       return;
  2045.     }
  2046.  
  2047.   if (LOOP_DETECT)
  2048.     {
  2049.       struct stat dir_stat;
  2050.       int fd = dirfd (dirp);
  2051.  
  2052.       /* If dirfd failed, endure the overhead of using stat.  */
  2053.       if ((0 <= fd
  2054.        ? fstat (fd, &dir_stat)
  2055.        : stat (name, &dir_stat)) < 0)
  2056.     {
  2057.       error (0, errno, _("cannot determine device and inode of %s"),
  2058.          quotearg_colon (name));
  2059.       exit_status = 1;
  2060.       return;
  2061.     }
  2062.  
  2063.       /* If we've already visited this dev/inode pair, warn that
  2064.      we've found a loop, and do not process this directory.  */
  2065.       if (visit_dir (dir_stat.st_dev, dir_stat.st_ino))
  2066.     {
  2067.       error (0, 0, _("not listing already-listed directory: %s"),
  2068.          quotearg_colon (name));
  2069.       return;
  2070.     }
  2071.  
  2072.       DEV_INO_PUSH (dir_stat.st_dev, dir_stat.st_ino);
  2073.     }
  2074.  
  2075.   /* Read the directory entries, and insert the subfiles into the `files'
  2076.      table.  */
  2077.  
  2078.   clear_files ();
  2079.  
  2080.   while (1)
  2081.     {
  2082.       /* Set errno to zero so we can distinguish between a readdir failure
  2083.      and when readdir simply finds that there are no more entries.  */
  2084.       errno = 0;
  2085.       if ((next = readdir (dirp)) == NULL)
  2086.     {
  2087.       if (errno)
  2088.         {
  2089.           /* Save/restore errno across closedir call.  */
  2090.           int e = errno;
  2091.           closedir (dirp);
  2092.           errno = e;
  2093.  
  2094.           /* Arrange to give a diagnostic after exiting this loop.  */
  2095.           dirp = NULL;
  2096.         }
  2097.       break;
  2098.     }
  2099.  
  2100.       if (file_interesting (next))
  2101.     {
  2102.       enum filetype type = unknown;
  2103.  
  2104. #if HAVE_STRUCT_DIRENT_D_TYPE
  2105.       if (next->d_type == DT_DIR || next->d_type == DT_CHR
  2106.           || next->d_type == DT_BLK || next->d_type == DT_SOCK
  2107.           || next->d_type == DT_FIFO)
  2108.         type = next->d_type;
  2109. #endif
  2110.       total_blocks += gobble_file (next->d_name, type, 0, name);
  2111.     }
  2112.     }
  2113.  
  2114.   if (dirp == NULL || CLOSEDIR (dirp))
  2115.     {
  2116.       error (0, errno, _("reading directory %s"), quotearg_colon (name));
  2117.       exit_status = 1;
  2118.       /* Don't return; print whatever we got. */
  2119.     }
  2120.  
  2121.   /* Sort the directory contents.  */
  2122.   sort_files ();
  2123.  
  2124.   /* If any member files are subdirectories, perhaps they should have their
  2125.      contents listed rather than being mentioned here as files.  */
  2126.  
  2127.   if (recursive)
  2128.     extract_dirs_from_files (name, 1);
  2129.  
  2130.   if (recursive || print_dir_name)
  2131.     {
  2132.       if (!first)
  2133.     DIRED_PUTCHAR ('\n');
  2134.       first = 0;
  2135.       DIRED_INDENT ();
  2136.       PUSH_CURRENT_DIRED_POS (&subdired_obstack);
  2137.       dired_pos += quote_name (stdout, realname ? realname : name,
  2138.                    dirname_quoting_options);
  2139.       PUSH_CURRENT_DIRED_POS (&subdired_obstack);
  2140.       DIRED_FPUTS_LITERAL (":\n", stdout);
  2141.     }
  2142.  
  2143.   if (format == long_format || print_block_size)
  2144.     {
  2145.       const char *p;
  2146.       char buf[LONGEST_HUMAN_READABLE + 1];
  2147.  
  2148.       DIRED_INDENT ();
  2149.       p = _("total");
  2150.       DIRED_FPUTS (p, stdout, strlen (p));
  2151.       DIRED_PUTCHAR (' ');
  2152.       p = human_readable_inexact (total_blocks, buf, ST_NBLOCKSIZE,
  2153.                   output_block_size, human_ceiling);
  2154.       DIRED_FPUTS (p, stdout, strlen (p));
  2155.       DIRED_PUTCHAR ('\n');
  2156.     }
  2157.  
  2158.   if (files_index)
  2159.     print_current_files ();
  2160. }
  2161.  
  2162. /* Add `pattern' to the list of patterns for which files that match are
  2163.    not listed.  */
  2164.  
  2165. static void
  2166. add_ignore_pattern (const char *pattern)
  2167. {
  2168.   register struct ignore_pattern *ignore;
  2169.  
  2170.   ignore = XMALLOC (struct ignore_pattern, 1);
  2171.   ignore->pattern = pattern;
  2172.   /* Add it to the head of the linked list. */
  2173.   ignore->next = ignore_patterns;
  2174.   ignore_patterns = ignore;
  2175. }
  2176.  
  2177. /* Return nonzero if the file in `next' should be listed. */
  2178.  
  2179. static int
  2180. file_interesting (const struct dirent *next)
  2181. {
  2182.   register struct ignore_pattern *ignore;
  2183.  
  2184.   for (ignore = ignore_patterns; ignore; ignore = ignore->next)
  2185.     if (fnmatch (ignore->pattern, next->d_name, FNM_PERIOD) == 0)
  2186.       return 0;
  2187.  
  2188.   if (really_all_files
  2189.       || next->d_name[0] != '.'
  2190.       || (all_files
  2191.       && next->d_name[1] != '\0'
  2192.       && (next->d_name[1] != '.' || next->d_name[2] != '\0')))
  2193.     return 1;
  2194.  
  2195.   return 0;
  2196. }
  2197.  
  2198. /* Enter and remove entries in the table `files'.  */
  2199.  
  2200. /* Empty the table of files. */
  2201.  
  2202. static void
  2203. clear_files (void)
  2204. {
  2205.   register int i;
  2206.  
  2207.   for (i = 0; i < files_index; i++)
  2208.     {
  2209.       free (files[i].name);
  2210.       if (files[i].linkname)
  2211.     free (files[i].linkname);
  2212.     }
  2213.  
  2214.   files_index = 0;
  2215.   block_size_size = 4;
  2216. }
  2217.  
  2218. /* Add a file to the current table of files.
  2219.    Verify that the file exists, and print an error message if it does not.
  2220.    Return the number of blocks that the file occupies.  */
  2221.  
  2222. static uintmax_t
  2223. gobble_file (const char *name, enum filetype type, int explicit_arg,
  2224.          const char *dirname)
  2225. {
  2226.   register uintmax_t blocks;
  2227.   register char *path;
  2228.  
  2229.   if (files_index == nfiles)
  2230.     {
  2231.       nfiles *= 2;
  2232.       files = XREALLOC (files, struct fileinfo, nfiles);
  2233.     }
  2234.  
  2235.   files[files_index].linkname = 0;
  2236.   files[files_index].linkmode = 0;
  2237.   files[files_index].linkok = 0;
  2238.  
  2239.   /* FIXME: this use of ls: `mkdir a; touch a/{b,c,d}; ls -R a'
  2240.      shouldn't require that ls stat b, c, and d -- at least
  2241.      not on systems with usable d_type.  The problem is that
  2242.      format_needs_stat is set, because of the -R.  */
  2243.   if (explicit_arg || format_needs_stat
  2244.       || (format_needs_type && type == unknown))
  2245.     {
  2246.       /* `path' is the absolute pathname of this file. */
  2247.       int val;
  2248.  
  2249.       if (name[0] == '/' || dirname[0] == 0)
  2250.     path = (char *) name;
  2251.       else
  2252.     {
  2253.       path = (char *) alloca (strlen (name) + strlen (dirname) + 2);
  2254.       attach (path, dirname, name);
  2255.     }
  2256.  
  2257.       val = (DEREF_ALWAYS <= dereference + explicit_arg
  2258.          ? stat (path, &files[files_index].stat)
  2259.          : lstat (path, &files[files_index].stat));
  2260.  
  2261.       if (val < 0)
  2262.     {
  2263.       error (0, errno, "%s", quotearg_colon (path));
  2264.       exit_status = 1;
  2265.       return 0;
  2266.     }
  2267.  
  2268. #if HAVE_ACL
  2269.       if (format == long_format)
  2270.     {
  2271.       int n = file_has_acl (path, &files[files_index].stat);
  2272.       files[files_index].have_acl = (0 < n);
  2273.       if (n < 0)
  2274.         error (0, errno, "%s", quotearg_colon (path));
  2275.     }
  2276. #endif
  2277.  
  2278.       if (S_ISLNK (files[files_index].stat.st_mode)
  2279.       && (format == long_format || check_symlink_color))
  2280.     {
  2281.       char *linkpath;
  2282.       struct stat linkstats;
  2283.  
  2284.       get_link_name (path, &files[files_index]);
  2285.       linkpath = make_link_path (path, files[files_index].linkname);
  2286.  
  2287.       /* Avoid following symbolic links when possible, ie, when
  2288.          they won't be traced and when no indicator is needed. */
  2289.       if (linkpath
  2290.           && (indicator_style != none || check_symlink_color)
  2291.           && stat (linkpath, &linkstats) == 0)
  2292.         {
  2293.           files[files_index].linkok = 1;
  2294.  
  2295.           /* Symbolic links to directories that are mentioned on the
  2296.              command line are automatically traced if not being
  2297.              listed as files.  */
  2298.           if (explicit_arg && format != long_format
  2299.           && S_ISDIR (linkstats.st_mode))
  2300.         {
  2301.           /* Substitute the linked-to directory's name, but
  2302.              save the real name in `linkname' for printing.  */
  2303.           if (!immediate_dirs)
  2304.             {
  2305.               const char *tempname = name;
  2306.               name = linkpath;
  2307.               linkpath = files[files_index].linkname;
  2308.               files[files_index].linkname = (char *) tempname;
  2309.             }
  2310.           files[files_index].stat = linkstats;
  2311.         }
  2312.           else
  2313.         {
  2314.           /* Get the linked-to file's mode for the filetype indicator
  2315.              in long listings.  */
  2316.           files[files_index].linkmode = linkstats.st_mode;
  2317.           files[files_index].linkok = 1;
  2318.         }
  2319.         }
  2320.       if (linkpath)
  2321.         free (linkpath);
  2322.     }
  2323.  
  2324.       if (S_ISLNK (files[files_index].stat.st_mode))
  2325.     files[files_index].filetype = symbolic_link;
  2326.       else if (S_ISDIR (files[files_index].stat.st_mode))
  2327.     {
  2328.       if (explicit_arg && !immediate_dirs)
  2329.         files[files_index].filetype = arg_directory;
  2330.       else
  2331.         files[files_index].filetype = directory;
  2332.     }
  2333.       else
  2334.     files[files_index].filetype = normal;
  2335.  
  2336.       blocks = ST_NBLOCKS (files[files_index].stat);
  2337.       {
  2338.     char buf[LONGEST_HUMAN_READABLE + 1];
  2339.     int len = strlen (human_readable_inexact (blocks, buf, ST_NBLOCKSIZE,
  2340.                           output_block_size,
  2341.                           human_ceiling));
  2342.     if (block_size_size < len)
  2343.       block_size_size = len < 7 ? len : 7;
  2344.       }
  2345.     }
  2346.   else
  2347.     {
  2348.       files[files_index].filetype = type;
  2349. #if HAVE_STRUCT_DIRENT_D_TYPE
  2350.       files[files_index].stat.st_mode = DTTOIF (type);
  2351. #endif
  2352.       blocks = 0;
  2353.     }
  2354.  
  2355.   files[files_index].name = xstrdup (name);
  2356.   files_index++;
  2357.  
  2358.   return blocks;
  2359. }
  2360.  
  2361. #if HAVE_SYMLINKS
  2362.  
  2363. /* Put the name of the file that `filename' is a symbolic link to
  2364.    into the `linkname' field of `f'. */
  2365.  
  2366. static void
  2367. get_link_name (const char *filename, struct fileinfo *f)
  2368. {
  2369.   f->linkname = xreadlink (filename);
  2370.   if (f->linkname == NULL)
  2371.     {
  2372.       error (0, errno, _("cannot read symbolic link %s"),
  2373.          quotearg_colon (filename));
  2374.       exit_status = 1;
  2375.     }
  2376. }
  2377.  
  2378. /* If `linkname' is a relative path and `path' contains one or more
  2379.    leading directories, return `linkname' with those directories
  2380.    prepended; otherwise, return a copy of `linkname'.
  2381.    If `linkname' is zero, return zero. */
  2382.  
  2383. static char *
  2384. make_link_path (const char *path, const char *linkname)
  2385. {
  2386.   char *linkbuf;
  2387.   size_t bufsiz;
  2388.  
  2389.   if (linkname == 0)
  2390.     return 0;
  2391.  
  2392.   if (*linkname == '/')
  2393.     return xstrdup (linkname);
  2394.  
  2395.   /* The link is to a relative path.  Prepend any leading path
  2396.      in `path' to the link name. */
  2397.   linkbuf = strrchr (path, '/');
  2398.   if (linkbuf == 0)
  2399.     return xstrdup (linkname);
  2400.  
  2401.   bufsiz = linkbuf - path + 1;
  2402.   linkbuf = xmalloc (bufsiz + strlen (linkname) + 1);
  2403.   strncpy (linkbuf, path, bufsiz);
  2404.   strcpy (linkbuf + bufsiz, linkname);
  2405.   return linkbuf;
  2406. }
  2407. #endif
  2408.  
  2409. /* Return nonzero if base_name (NAME) ends in `.' or `..'
  2410.    This is so we don't try to recurse on `././././. ...' */
  2411.  
  2412. static int
  2413. basename_is_dot_or_dotdot (const char *name)
  2414. {
  2415.   char const *base = base_name (name);
  2416.   return DOT_OR_DOTDOT (base);
  2417. }
  2418.  
  2419. /* Remove any entries from `files' that are for directories,
  2420.    and queue them to be listed as directories instead.
  2421.    `dirname' is the prefix to prepend to each dirname
  2422.    to make it correct relative to ls's working dir.
  2423.    If IGNORE_DOT_AND_DOT_DOT is nonzero don't treat `.' and `..' as dirs.
  2424.    This is desirable when processing directories recursively.  */
  2425.  
  2426. static void
  2427. extract_dirs_from_files (const char *dirname, int ignore_dot_and_dot_dot)
  2428. {
  2429.   register int i, j;
  2430.  
  2431.   if (*dirname && LOOP_DETECT)
  2432.     {
  2433.       /* Insert a marker entry first.  When we dequeue this marker entry,
  2434.      we'll know that DIRNAME has been processed and may be removed
  2435.      from the set of active directories.  */
  2436.       queue_directory (NULL, dirname);
  2437.     }
  2438.  
  2439.   /* Queue the directories last one first, because queueing reverses the
  2440.      order.  */
  2441.   for (i = files_index - 1; i >= 0; i--)
  2442.     if ((files[i].filetype == directory || files[i].filetype == arg_directory)
  2443.     && (!ignore_dot_and_dot_dot
  2444.         || !basename_is_dot_or_dotdot (files[i].name)))
  2445.       {
  2446.     if (files[i].name[0] == '/' || dirname[0] == 0)
  2447.       {
  2448.         queue_directory (files[i].name, files[i].linkname);
  2449.       }
  2450.     else
  2451.       {
  2452.         char *path = path_concat (dirname, files[i].name, NULL);
  2453.         queue_directory (path, files[i].linkname);
  2454.         free (path);
  2455.       }
  2456.     if (files[i].filetype == arg_directory)
  2457.       free (files[i].name);
  2458.       }
  2459.  
  2460.   /* Now delete the directories from the table, compacting all the remaining
  2461.      entries.  */
  2462.  
  2463.   for (i = 0, j = 0; i < files_index; i++)
  2464.     if (files[i].filetype != arg_directory)
  2465.       files[j++] = files[i];
  2466.   files_index = j;
  2467. }
  2468.  
  2469. /* Use strcoll to compare strings in this locale.  If an error occurs,
  2470.    report an error and longjmp to failed_strcoll.  */
  2471.  
  2472. static jmp_buf failed_strcoll;
  2473.  
  2474. static int
  2475. xstrcoll (char const *a, char const *b)
  2476. {
  2477.   int diff;
  2478.   errno = 0;
  2479.   diff = strcoll (a, b);
  2480.   if (errno)
  2481.     {
  2482.       error (0, errno, _("cannot compare file names %s and %s"),
  2483.          quote_n (0, a), quote_n (1, b));
  2484.       exit_status = 1;
  2485.       longjmp (failed_strcoll, 1);
  2486.     }
  2487.   return diff;
  2488. }
  2489.  
  2490. /* Comparison routines for sorting the files. */
  2491.  
  2492. typedef void const *V;
  2493.  
  2494. static inline int
  2495. cmp_ctime (struct fileinfo const *a, struct fileinfo const *b,
  2496.        int (*cmp) PARAMS ((char const *, char const *)))
  2497. {
  2498.   int diff = CTIME_CMP (b->stat, a->stat);
  2499.   return diff ? diff : cmp (a->name, b->name);
  2500. }
  2501. static int compare_ctime (V a, V b) { return cmp_ctime (a, b, xstrcoll); }
  2502. static int compstr_ctime (V a, V b) { return cmp_ctime (a, b, strcmp); }
  2503. static int rev_cmp_ctime (V a, V b) { return compare_ctime (b, a); }
  2504. static int rev_str_ctime (V a, V b) { return compstr_ctime (b, a); }
  2505.  
  2506. static inline int
  2507. cmp_mtime (struct fileinfo const *a, struct fileinfo const *b,
  2508.        int (*cmp) PARAMS((char const *, char const *)))
  2509. {
  2510.   int diff = MTIME_CMP (b->stat, a->stat);
  2511.   return diff ? diff : cmp (a->name, b->name);
  2512. }
  2513. static int compare_mtime (V a, V b) { return cmp_mtime (a, b, xstrcoll); }
  2514. static int compstr_mtime (V a, V b) { return cmp_mtime (a, b, strcmp); }
  2515. static int rev_cmp_mtime (V a, V b) { return compare_mtime (b, a); }
  2516. static int rev_str_mtime (V a, V b) { return compstr_mtime (b, a); }
  2517.  
  2518. static inline int
  2519. cmp_atime (struct fileinfo const *a, struct fileinfo const *b,
  2520.        int (*cmp) PARAMS ((char const *, char const *)))
  2521. {
  2522.   int diff = ATIME_CMP (b->stat, a->stat);
  2523.   return diff ? diff : cmp (a->name, b->name);
  2524. }
  2525. static int compare_atime (V a, V b) { return cmp_atime (a, b, xstrcoll); }
  2526. static int compstr_atime (V a, V b) { return cmp_atime (a, b, strcmp); }
  2527. static int rev_cmp_atime (V a, V b) { return compare_atime (b, a); }
  2528. static int rev_str_atime (V a, V b) { return compstr_atime (b, a); }
  2529.  
  2530. static inline int
  2531. cmp_size (struct fileinfo const *a, struct fileinfo const *b,
  2532.       int (*cmp) PARAMS ((char const *, char const *)))
  2533. {
  2534.   int diff = longdiff (b->stat.st_size, a->stat.st_size);
  2535.   return diff ? diff : cmp (a->name, b->name);
  2536. }
  2537. static int compare_size (V a, V b) { return cmp_size (a, b, xstrcoll); }
  2538. static int compstr_size (V a, V b) { return cmp_size (a, b, strcmp); }
  2539. static int rev_cmp_size (V a, V b) { return compare_size (b, a); }
  2540. static int rev_str_size (V a, V b) { return compstr_size (b, a); }
  2541.  
  2542. static inline int
  2543. cmp_version (struct fileinfo const *a, struct fileinfo const *b)
  2544. {
  2545.   return strverscmp (a->name, b->name);
  2546. }
  2547. static int compare_version (V a, V b) { return cmp_version (a, b); }
  2548. static int rev_cmp_version (V a, V b) { return compare_version (b, a); }
  2549.  
  2550. static inline int
  2551. cmp_name (struct fileinfo const *a, struct fileinfo const *b,
  2552.       int (*cmp) PARAMS ((char const *, char const *)))
  2553. {
  2554.   return cmp (a->name, b->name);
  2555. }
  2556. static int compare_name (V a, V b) { return cmp_name (a, b, xstrcoll); }
  2557. static int compstr_name (V a, V b) { return cmp_name (a, b, strcmp); }
  2558. static int rev_cmp_name (V a, V b) { return compare_name (b, a); }
  2559. static int rev_str_name (V a, V b) { return compstr_name (b, a); }
  2560.  
  2561. /* Compare file extensions.  Files with no extension are `smallest'.
  2562.    If extensions are the same, compare by filenames instead. */
  2563.  
  2564. static inline int
  2565. cmp_extension (struct fileinfo const *a, struct fileinfo const *b,
  2566.            int (*cmp) PARAMS ((char const *, char const *)))
  2567. {
  2568.   char const *base1 = strrchr (a->name, '.');
  2569.   char const *base2 = strrchr (b->name, '.');
  2570.   int diff = cmp (base1 ? base1 : "", base2 ? base2 : "");
  2571.   return diff ? diff : cmp (a->name, b->name);
  2572. }
  2573. static int compare_extension (V a, V b) { return cmp_extension (a, b, xstrcoll); }
  2574. static int compstr_extension (V a, V b) { return cmp_extension (a, b, strcmp); }
  2575. static int rev_cmp_extension (V a, V b) { return compare_extension (b, a); }
  2576. static int rev_str_extension (V a, V b) { return compstr_extension (b, a); }
  2577.  
  2578. /* Sort the files now in the table.  */
  2579.  
  2580. static void
  2581. sort_files (void)
  2582. {
  2583.   int (*func) PARAMS ((V, V));
  2584.  
  2585.   switch (sort_type)
  2586.     {
  2587.     case sort_none:
  2588.       return;
  2589.     case sort_time:
  2590.       switch (time_type)
  2591.     {
  2592.     case time_ctime:
  2593.       func = sort_reverse ? rev_cmp_ctime : compare_ctime;
  2594.       break;
  2595.     case time_mtime:
  2596.       func = sort_reverse ? rev_cmp_mtime : compare_mtime;
  2597.       break;
  2598.     case time_atime:
  2599.       func = sort_reverse ? rev_cmp_atime : compare_atime;
  2600.       break;
  2601.     default:
  2602.       abort ();
  2603.     }
  2604.       break;
  2605.     case sort_name:
  2606.       func = sort_reverse ? rev_cmp_name : compare_name;
  2607.       break;
  2608.     case sort_extension:
  2609.       func = sort_reverse ? rev_cmp_extension : compare_extension;
  2610.       break;
  2611.     case sort_size:
  2612.       func = sort_reverse ? rev_cmp_size : compare_size;
  2613.       break;
  2614.     case sort_version:
  2615.       func = sort_reverse ? rev_cmp_version : compare_version;
  2616.       break;
  2617.     default:
  2618.       abort ();
  2619.     }
  2620.  
  2621.   /* Try strcoll.  If it fails, fall back on strcmp.  We can't safely
  2622.      ignore strcoll failures, as a failing strcoll might be a
  2623.      comparison function that is not a total order, and if we ignored
  2624.      the failure this might cause qsort to dump core.  */
  2625.  
  2626.   if (setjmp (failed_strcoll))
  2627.     {
  2628.       switch (sort_type)
  2629.     {
  2630.     case sort_time:
  2631.       switch (time_type)
  2632.         {
  2633.         case time_ctime:
  2634.           func = sort_reverse ? rev_str_ctime : compstr_ctime;
  2635.           break;
  2636.         case time_mtime:
  2637.           func = sort_reverse ? rev_str_mtime : compstr_mtime;
  2638.           break;
  2639.         case time_atime:
  2640.           func = sort_reverse ? rev_str_atime : compstr_atime;
  2641.           break;
  2642.         default:
  2643.           abort ();
  2644.         }
  2645.       break;
  2646.     case sort_name:
  2647.       func = sort_reverse ? rev_str_name : compstr_name;
  2648.       break;
  2649.     case sort_extension:
  2650.       func = sort_reverse ? rev_str_extension : compstr_extension;
  2651.       break;
  2652.     case sort_size:
  2653.       func = sort_reverse ? rev_str_size : compstr_size;
  2654.       break;
  2655.     default:
  2656.       abort ();
  2657.     }
  2658.     }
  2659.  
  2660.   qsort (files, files_index, sizeof (struct fileinfo), func);
  2661. }
  2662.  
  2663. /* List all the files now in the table.  */
  2664.  
  2665. static void
  2666. print_current_files (void)
  2667. {
  2668.   register int i;
  2669.  
  2670.   switch (format)
  2671.     {
  2672.     case one_per_line:
  2673.       for (i = 0; i < files_index; i++)
  2674.     {
  2675.       print_file_name_and_frills (files + i);
  2676.       putchar ('\n');
  2677.     }
  2678.       break;
  2679.  
  2680.     case many_per_line:
  2681.       init_column_info ();
  2682.       print_many_per_line ();
  2683.       break;
  2684.  
  2685.     case horizontal:
  2686.       init_column_info ();
  2687.       print_horizontal ();
  2688.       break;
  2689.  
  2690.     case with_commas:
  2691.       print_with_commas ();
  2692.       break;
  2693.  
  2694.     case long_format:
  2695.       for (i = 0; i < files_index; i++)
  2696.     {
  2697.       print_long_format (files + i);
  2698.       DIRED_PUTCHAR ('\n');
  2699.     }
  2700.       break;
  2701.     }
  2702. }
  2703.  
  2704. /* Return the expected number of columns in a long-format time stamp,
  2705.    or zero if it cannot be calculated.  */
  2706.  
  2707. static int
  2708. long_time_expected_width (void)
  2709. {
  2710.   static int width = -1;
  2711.  
  2712.   if (width < 0)
  2713.     {
  2714.       time_t epoch = 0;
  2715.       struct tm const *tm = localtime (&epoch);
  2716.       char const *fmt = long_time_format[0];
  2717.       char initbuf[100];
  2718.       char *buf = initbuf;
  2719.       size_t bufsize = sizeof initbuf;
  2720.       size_t len;
  2721.  
  2722.       for (;;)
  2723.     {
  2724.       *buf = '\1';
  2725.       len = nstrftime (buf, bufsize, fmt, tm, 0, 0);
  2726.       if (len || ! *buf)
  2727.         break;
  2728.       buf = alloca (bufsize *= 2);
  2729.     }
  2730.  
  2731.       width = mbsnwidth (buf, len, 0);
  2732.       if (width < 0)
  2733.     width = 0;
  2734.     }
  2735.  
  2736.   return width;
  2737. }
  2738.  
  2739. /* Get the current time.  */
  2740.  
  2741. static void
  2742. get_current_time (void)
  2743. {
  2744. #if HAVE_CLOCK_GETTIME && defined CLOCK_REALTIME
  2745.   {
  2746.     struct timespec timespec;
  2747.     if (clock_gettime (CLOCK_REALTIME, &timespec) == 0)
  2748.       {
  2749.     current_time = timespec.tv_sec;
  2750.     current_time_ns = timespec.tv_nsec;
  2751.     return;
  2752.       }
  2753.   }
  2754. #endif
  2755.  
  2756.   /* The clock does not have nanosecond resolution, so get the maximum
  2757.      possible value for the current time that is consistent with the
  2758.      reported clock.  That way, files are not considered to be in the
  2759.      future merely because their time stamps have higher resolution
  2760.      than the clock resolution.  */
  2761.  
  2762. #if HAVE_GETTIMEOFDAY
  2763.   {
  2764.     struct timeval timeval;
  2765.     if (gettimeofday (&timeval, NULL) == 0)
  2766.       {
  2767.     current_time = timeval.tv_sec;
  2768.     current_time_ns = timeval.tv_usec * 1000 + 999;
  2769.     return;
  2770.       }
  2771.   }
  2772. #endif
  2773.  
  2774.   current_time = time (NULL);
  2775.   current_time_ns = 999999999;
  2776. }
  2777.  
  2778. /* Format into BUFFER the name or id of the user with id U.  Return
  2779.    the length of the formatted buffer, not counting the terminating
  2780.    null.  */
  2781.  
  2782. static size_t
  2783. format_user (char *buffer, uid_t u)
  2784. {
  2785.   char const *name = (numeric_ids ? NULL : getuser (u));
  2786.   if (name)
  2787.     sprintf (buffer, "%-8s ", name);
  2788.   else
  2789.     sprintf (buffer, "%-8lu ", (unsigned long) u);
  2790.   return strlen (buffer);
  2791. }
  2792.  
  2793. /* Print information about F in long format.  */
  2794.  
  2795. static void
  2796. print_long_format (const struct fileinfo *f)
  2797. {
  2798.   char modebuf[12];
  2799.   char init_bigbuf
  2800.     [LONGEST_HUMAN_READABLE + 1     /* inode */
  2801.      + LONGEST_HUMAN_READABLE + 1   /* size in blocks */
  2802.      + sizeof (modebuf) - 1 + 1     /* mode string */
  2803.      + LONGEST_HUMAN_READABLE + 1   /* st_nlink */
  2804.      + ID_LENGTH_MAX + 1        /* owner name */
  2805.      + ID_LENGTH_MAX + 1        /* group name */
  2806.      + ID_LENGTH_MAX + 1        /* author name */
  2807.      + LONGEST_HUMAN_READABLE + 1   /* major device number */
  2808.      + LONGEST_HUMAN_READABLE + 1   /* minor device number */
  2809.      + 35 + 1   /* usual length of time/date -- may be longer; see below */
  2810.      ];
  2811.   char *buf = init_bigbuf;
  2812.   size_t bufsize = sizeof (init_bigbuf);
  2813.   size_t s;
  2814.   char *p;
  2815.   time_t when;
  2816.   int when_ns IF_LINT (= 0);
  2817.   struct tm *when_local;
  2818.  
  2819.   /* Compute mode string.  On most systems, it's based on st_mode.
  2820.      On systems with migration (via the stat.st_dm_mode field), use
  2821.      the file's migrated status.  */
  2822.   mode_string (ST_DM_MODE (f->stat), modebuf);
  2823.  
  2824.   modebuf[10] = (FILE_HAS_ACL (f) ? '+' : ' ');
  2825.   modebuf[11] = '\0';
  2826.  
  2827.   switch (time_type)
  2828.     {
  2829.     case time_ctime:
  2830.       when = f->stat.st_ctime;
  2831.       when_ns = TIMESPEC_NS (f->stat.st_ctim);
  2832.       break;
  2833.     case time_mtime:
  2834.       when = f->stat.st_mtime;
  2835.       when_ns = TIMESPEC_NS (f->stat.st_mtim);
  2836.       break;
  2837.     case time_atime:
  2838.       when = f->stat.st_atime;
  2839.       when_ns = TIMESPEC_NS (f->stat.st_atim);
  2840.       break;
  2841.     }
  2842.  
  2843.   p = buf;
  2844.  
  2845.   if (print_inode)
  2846.     {
  2847.       char hbuf[LONGEST_HUMAN_READABLE + 1];
  2848.       sprintf (p, "%*s ", INODE_DIGITS,
  2849.            human_readable ((uintmax_t) f->stat.st_ino, hbuf, 1, 1));
  2850.       p += strlen (p);
  2851.     }
  2852.  
  2853.   if (print_block_size)
  2854.     {
  2855.       char hbuf[LONGEST_HUMAN_READABLE + 1];
  2856.       sprintf (p, "%*s ", block_size_size,
  2857.            human_readable_inexact ((uintmax_t) ST_NBLOCKS (f->stat), hbuf,
  2858.                        ST_NBLOCKSIZE, output_block_size,
  2859.                        human_ceiling));
  2860.       p += strlen (p);
  2861.     }
  2862.  
  2863.   /* The last byte of the mode string is the POSIX
  2864.      "optional alternate access method flag".  */
  2865.   sprintf (p, "%s %3lu ", modebuf, (unsigned long) f->stat.st_nlink);
  2866.   p += strlen (p);
  2867.  
  2868.   if (print_owner)
  2869.     p += format_user (p, f->stat.st_uid);
  2870.  
  2871.   if (print_group)
  2872.     {
  2873.       char const *group_name = (numeric_ids ? NULL : getgroup (f->stat.st_gid));
  2874.       if (group_name)
  2875.     sprintf (p, "%-8s ", group_name);
  2876.       else
  2877.     sprintf (p, "%-8lu ", (unsigned long) f->stat.st_gid);
  2878.       p += strlen (p);
  2879.     }
  2880.  
  2881.   if (print_author)
  2882.     p += format_user (p, f->stat.st_author);
  2883.  
  2884.   if (S_ISCHR (f->stat.st_mode) || S_ISBLK (f->stat.st_mode))
  2885.     sprintf (p, "%3lu, %3lu ",
  2886.          (unsigned long) major (f->stat.st_rdev),
  2887.          (unsigned long) minor (f->stat.st_rdev));
  2888.   else
  2889.     {
  2890.       char hbuf[LONGEST_HUMAN_READABLE + 1];
  2891.       uintmax_t size = f->stat.st_size;
  2892.  
  2893.       /* POSIX requires that the size be printed without a sign, even
  2894.      when negative.  Assume the typical case where negative sizes
  2895.      are actually positive values that have wrapped around.  */
  2896.       size += (f->stat.st_size < 0) * ((uintmax_t) OFF_T_MAX - OFF_T_MIN + 1);
  2897.  
  2898.       sprintf (p, "%8s ",
  2899.            human_readable (size, hbuf, 1,
  2900.                    output_block_size < 0 ? output_block_size : 1));
  2901.     }
  2902.  
  2903.   p += strlen (p);
  2904.  
  2905.   if ((when_local = localtime (&when)))
  2906.     {
  2907.       time_t six_months_ago;
  2908.       int recent;
  2909.       char const *fmt;
  2910.  
  2911.       /* If the file appears to be in the future, update the current
  2912.      time, in case the file happens to have been modified since
  2913.      the last time we checked the clock.  */
  2914.       if (current_time < when
  2915.       || (current_time == when && current_time_ns < when_ns))
  2916.     {
  2917.       /* Note that get_current_time calls gettimeofday which, on some non-
  2918.          compliant systems, clobbers the buffer used for localtime's result.
  2919.          But it's ok here, because we use a gettimeofday wrapper that
  2920.          saves and restores the buffer around the gettimeofday call.  */
  2921.       get_current_time ();
  2922.     }
  2923.  
  2924.       /* Consider a time to be recent if it is within the past six
  2925.      months.  A Gregorian year has 365.2425 * 24 * 60 * 60 ==
  2926.      31556952 seconds on the average.  Write this value as an
  2927.      integer constant to avoid floating point hassles.  */
  2928.       six_months_ago = current_time - 31556952 / 2;
  2929.       recent = (six_months_ago <= when
  2930.         && (when < current_time
  2931.             || (when == current_time && when_ns <= current_time_ns)));
  2932.       fmt = long_time_format[recent];
  2933.  
  2934.       for (;;)
  2935.     {
  2936.       char *newbuf;
  2937.       *p = '\1';
  2938.       s = nstrftime (p, buf + bufsize - p - 1, fmt,
  2939.              when_local, 0, when_ns);
  2940.       if (s || ! *p)
  2941.         break;
  2942.       newbuf = alloca (bufsize *= 2);
  2943.       memcpy (newbuf, buf, p - buf);
  2944.       p = newbuf + (p - buf);
  2945.       buf = newbuf;
  2946.     }
  2947.  
  2948.       p += s;
  2949.       *p++ = ' ';
  2950.  
  2951.       /* NUL-terminate the string -- fputs (via DIRED_FPUTS) requires it.  */
  2952.       *p = '\0';
  2953.     }
  2954.   else
  2955.     {
  2956.       /* The time cannot be represented as a local time;
  2957.      print it as a huge integer number of seconds.  */
  2958.       char hbuf[LONGEST_HUMAN_READABLE + 1];
  2959.       int width = long_time_expected_width ();
  2960.  
  2961.       if (when < 0)
  2962.     {
  2963.       const char *num = human_readable (- (uintmax_t) when, hbuf, 1, 1);
  2964.       int sign_width = width - strlen (num);
  2965.       sprintf (p, "%*s%s ", sign_width < 0 ? 0 : sign_width, "-", num);
  2966.     }
  2967.       else
  2968.     sprintf (p, "%*s ", width,
  2969.          human_readable ((uintmax_t) when, hbuf, 1, 1));
  2970.  
  2971.       p += strlen (p);
  2972.     }
  2973.  
  2974.   DIRED_INDENT ();
  2975.   DIRED_FPUTS (buf, stdout, p - buf);
  2976.   print_name_with_quoting (f->name, FILE_OR_LINK_MODE (f), f->linkok,
  2977.                &dired_obstack);
  2978.  
  2979.   if (f->filetype == symbolic_link)
  2980.     {
  2981.       if (f->linkname)
  2982.     {
  2983.       DIRED_FPUTS_LITERAL (" -> ", stdout);
  2984.       print_name_with_quoting (f->linkname, f->linkmode, f->linkok - 1,
  2985.                    NULL);
  2986.       if (indicator_style != none)
  2987.         print_type_indicator (f->linkmode);
  2988.     }
  2989.     }
  2990.   else if (indicator_style != none)
  2991.     print_type_indicator (f->stat.st_mode);
  2992. }
  2993.  
  2994. /* Output to OUT a quoted representation of the file name NAME,
  2995.    using OPTIONS to control quoting.  Produce no output if OUT is NULL.
  2996.    Return the number of screen columns occupied by NAME's quoted
  2997.    representation.  */
  2998.  
  2999. static size_t
  3000. quote_name (FILE *out, const char *name, struct quoting_options const *options)
  3001. {
  3002.   char smallbuf[BUFSIZ];
  3003.   size_t len = quotearg_buffer (smallbuf, sizeof smallbuf, name, -1, options);
  3004.   char *buf;
  3005.   int displayed_width;
  3006.  
  3007.   if (len < sizeof smallbuf)
  3008.     buf = smallbuf;
  3009.   else
  3010.     {
  3011.       buf = (char *) alloca (len + 1);
  3012.       quotearg_buffer (buf, len + 1, name, -1, options);
  3013.     }
  3014.  
  3015.   if (qmark_funny_chars)
  3016.     {
  3017. #if HAVE_MBRTOWC
  3018.       if (MB_CUR_MAX > 1)
  3019.     {
  3020.       char const *p = buf;
  3021.       char const *plimit = buf + len;
  3022.       char *q = buf;
  3023.       displayed_width = 0;
  3024.  
  3025.       while (p < plimit)
  3026.         switch (*p)
  3027.           {
  3028.         case ' ': case '!': case '"': case '#': case '%':
  3029.         case '&': case '\'': case '(': case ')': case '*':
  3030.         case '+': case ',': case '-': case '.': case '/':
  3031.         case '0': case '1': case '2': case '3': case '4':
  3032.         case '5': case '6': case '7': case '8': case '9':
  3033.         case ':': case ';': case '<': case '=': case '>':
  3034.         case '?':
  3035.         case 'A': case 'B': case 'C': case 'D': case 'E':
  3036.         case 'F': case 'G': case 'H': case 'I': case 'J':
  3037.         case 'K': case 'L': case 'M': case 'N': case 'O':
  3038.         case 'P': case 'Q': case 'R': case 'S': case 'T':
  3039.         case 'U': case 'V': case 'W': case 'X': case 'Y':
  3040.         case 'Z':
  3041.         case '[': case '\\': case ']': case '^': case '_':
  3042.         case 'a': case 'b': case 'c': case 'd': case 'e':
  3043.         case 'f': case 'g': case 'h': case 'i': case 'j':
  3044.         case 'k': case 'l': case 'm': case 'n': case 'o':
  3045.         case 'p': case 'q': case 'r': case 's': case 't':
  3046.         case 'u': case 'v': case 'w': case 'x': case 'y':
  3047.         case 'z': case '{': case '|': case '}': case '~':
  3048.           /* These characters are printable ASCII characters.  */
  3049.           *q++ = *p++;
  3050.           displayed_width += 1;
  3051.           break;
  3052.         default:
  3053.           /* If we have a multibyte sequence, copy it until we
  3054.              reach its end, replacing each non-printable multibyte
  3055.              character with a single question mark.  */
  3056.           {
  3057.             mbstate_t mbstate;
  3058.             memset (&mbstate, 0, sizeof mbstate);
  3059.             do
  3060.               {
  3061.             wchar_t wc;
  3062.             size_t bytes;
  3063.             int w;
  3064.  
  3065.             bytes = mbrtowc (&wc, p, plimit - p, &mbstate);
  3066.  
  3067.             if (bytes == (size_t) -1)
  3068.               {
  3069.                 /* An invalid multibyte sequence was
  3070.                    encountered.  Skip one input byte, and
  3071.                    put a question mark.  */
  3072.                 p++;
  3073.                 *q++ = '?';
  3074.                 displayed_width += 1;
  3075.                 break;
  3076.               }
  3077.  
  3078.             if (bytes == (size_t) -2)
  3079.               {
  3080.                 /* An incomplete multibyte character
  3081.                    at the end.  Replace it entirely with
  3082.                    a question mark.  */
  3083.                 p = plimit;
  3084.                 *q++ = '?';
  3085.                 displayed_width += 1;
  3086.                 break;
  3087.               }
  3088.  
  3089.             if (bytes == 0)
  3090.               /* A null wide character was encountered.  */
  3091.               bytes = 1;
  3092.  
  3093.             w = wcwidth (wc);
  3094.             if (w >= 0)
  3095.               {
  3096.                 /* A printable multibyte character.
  3097.                    Keep it.  */
  3098.                 for (; bytes > 0; --bytes)
  3099.                   *q++ = *p++;
  3100.                 displayed_width += w;
  3101.               }
  3102.             else
  3103.               {
  3104.                 /* An unprintable multibyte character.
  3105.                    Replace it entirely with a question
  3106.                    mark.  */
  3107.                 p += bytes;
  3108.                 *q++ = '?';
  3109.                 displayed_width += 1;
  3110.               }
  3111.               }
  3112.             while (! mbsinit (&mbstate));
  3113.           }
  3114.           break;
  3115.           }
  3116.  
  3117.       /* The buffer may have shrunk.  */
  3118.       len = q - buf;
  3119.     }
  3120.       else
  3121. #endif
  3122.     {
  3123.       char *p = buf;
  3124.       char const *plimit = buf + len;
  3125.  
  3126.       while (p < plimit)
  3127.         {
  3128.           if (! ISPRINT ((unsigned char) *p))
  3129.         *p = '?';
  3130.           p++;
  3131.         }
  3132.       displayed_width = len;
  3133.     }
  3134.     }
  3135.   else
  3136.     {
  3137.       /* Assume unprintable characters have a displayed_width of 1.  */
  3138. #if HAVE_MBRTOWC
  3139.       if (MB_CUR_MAX > 1)
  3140.     displayed_width = mbsnwidth (buf, len, 0);
  3141.       else
  3142. #endif
  3143.     displayed_width = len;
  3144.     }
  3145.  
  3146.   if (out != NULL)
  3147.     fwrite (buf, 1, len, out);
  3148.   return displayed_width;
  3149. }
  3150.  
  3151. static void
  3152. print_name_with_quoting (const char *p, mode_t mode, int linkok,
  3153.              struct obstack *stack)
  3154. {
  3155.   if (print_with_color)
  3156.     print_color_indicator (p, mode, linkok);
  3157.  
  3158.   if (stack)
  3159.     PUSH_CURRENT_DIRED_POS (stack);
  3160.  
  3161.   dired_pos += quote_name (stdout, p, filename_quoting_options);
  3162.  
  3163.   if (stack)
  3164.     PUSH_CURRENT_DIRED_POS (stack);
  3165.  
  3166.   if (print_with_color)
  3167.     prep_non_filename_text ();
  3168. }
  3169.  
  3170. static void
  3171. prep_non_filename_text (void)
  3172. {
  3173.   if (color_indicator[C_END].string != NULL)
  3174.     put_indicator (&color_indicator[C_END]);
  3175.   else
  3176.     {
  3177.       put_indicator (&color_indicator[C_LEFT]);
  3178.       put_indicator (&color_indicator[C_NORM]);
  3179.       put_indicator (&color_indicator[C_RIGHT]);
  3180.     }
  3181. }
  3182.  
  3183. /* Print the file name of `f' with appropriate quoting.
  3184.    Also print file size, inode number, and filetype indicator character,
  3185.    as requested by switches.  */
  3186.  
  3187. static void
  3188. print_file_name_and_frills (const struct fileinfo *f)
  3189. {
  3190.   char buf[LONGEST_HUMAN_READABLE + 1];
  3191.  
  3192.   if (print_inode)
  3193.     printf ("%*s ", INODE_DIGITS,
  3194.         human_readable ((uintmax_t) f->stat.st_ino, buf, 1, 1));
  3195.  
  3196.   if (print_block_size)
  3197.     printf ("%*s ", block_size_size,
  3198.         human_readable_inexact ((uintmax_t) ST_NBLOCKS (f->stat), buf,
  3199.                     ST_NBLOCKSIZE, output_block_size,
  3200.                     human_ceiling));
  3201.  
  3202.   print_name_with_quoting (f->name, FILE_OR_LINK_MODE (f), f->linkok, NULL);
  3203.  
  3204.   if (indicator_style != none)
  3205.     print_type_indicator (f->stat.st_mode);
  3206. }
  3207.  
  3208. static void
  3209. print_type_indicator (mode_t mode)
  3210. {
  3211.   int c;
  3212.  
  3213.   if (S_ISREG (mode))
  3214.     {
  3215.       if (indicator_style == classify && (mode & S_IXUGO))
  3216.     c ='*';
  3217.       else
  3218.     c = 0;
  3219.     }
  3220.   else
  3221.     {
  3222.       if (S_ISDIR (mode))
  3223.     c = '/';
  3224.       else if (S_ISLNK (mode))
  3225.     c = '@';
  3226.       else if (S_ISFIFO (mode))
  3227.     c = '|';
  3228.       else if (S_ISSOCK (mode))
  3229.     c = '=';
  3230.       else if (S_ISDOOR (mode))
  3231.     c = '>';
  3232.       else
  3233.     c = 0;
  3234.     }
  3235.  
  3236.   if (c)
  3237.     DIRED_PUTCHAR (c);
  3238. }
  3239.  
  3240. static void
  3241. print_color_indicator (const char *name, mode_t mode, int linkok)
  3242. {
  3243.   int type = C_FILE;
  3244.   struct color_ext_type *ext;   /* Color extension */
  3245.   size_t len;           /* Length of name */
  3246.  
  3247.   /* Is this a nonexistent file?  If so, linkok == -1.  */
  3248.  
  3249.   if (linkok == -1 && color_indicator[C_MISSING].string != NULL)
  3250.     {
  3251.       ext = NULL;
  3252.       type = C_MISSING;
  3253.     }
  3254.   else
  3255.     {
  3256.       if (S_ISDIR (mode))
  3257.     type = C_DIR;
  3258.       else if (S_ISLNK (mode))
  3259.     type = ((!linkok && color_indicator[C_ORPHAN].string)
  3260.         ? C_ORPHAN : C_LINK);
  3261.       else if (S_ISFIFO (mode))
  3262.     type = C_FIFO;
  3263.       else if (S_ISSOCK (mode))
  3264.     type = C_SOCK;
  3265.       else if (S_ISBLK (mode))
  3266.     type = C_BLK;
  3267.       else if (S_ISCHR (mode))
  3268.     type = C_CHR;
  3269.       else if (S_ISDOOR (mode))
  3270.     type = C_DOOR;
  3271.  
  3272.       if (type == C_FILE && (mode & S_IXUGO) != 0)
  3273.     type = C_EXEC;
  3274.  
  3275.       /* Check the file's suffix only if still classified as C_FILE.  */
  3276.       ext = NULL;
  3277.       if (type == C_FILE)
  3278.     {
  3279.       /* Test if NAME has a recognized suffix.  */
  3280.  
  3281.       len = strlen (name);
  3282.       name += len;      /* Pointer to final \0.  */
  3283.       for (ext = color_ext_list; ext != NULL; ext = ext->next)
  3284.         {
  3285.           if ((size_t) ext->ext.len <= len
  3286.           && strncmp (name - ext->ext.len, ext->ext.string,
  3287.                   ext->ext.len) == 0)
  3288.         break;
  3289.         }
  3290.     }
  3291.     }
  3292.  
  3293.   put_indicator (&color_indicator[C_LEFT]);
  3294.   put_indicator (ext ? &(ext->seq) : &color_indicator[type]);
  3295.   put_indicator (&color_indicator[C_RIGHT]);
  3296. }
  3297.  
  3298. /* Output a color indicator (which may contain nulls).  */
  3299. static void
  3300. put_indicator (const struct bin_str *ind)
  3301. {
  3302.   register int i;
  3303.   register const char *p;
  3304.  
  3305.   p = ind->string;
  3306.  
  3307.   for (i = ind->len; i > 0; --i)
  3308.     putchar (*(p++));
  3309. }
  3310.  
  3311. static int
  3312. length_of_file_name_and_frills (const struct fileinfo *f)
  3313. {
  3314.   register int len = 0;
  3315.  
  3316.   if (print_inode)
  3317.     len += INODE_DIGITS + 1;
  3318.  
  3319.   if (print_block_size)
  3320.     len += 1 + block_size_size;
  3321.  
  3322.   len += quote_name (NULL, f->name, filename_quoting_options);
  3323.  
  3324.   if (indicator_style != none)
  3325.     {
  3326.       mode_t filetype = f->stat.st_mode;
  3327.  
  3328.       if (S_ISREG (filetype))
  3329.     {
  3330.       if (indicator_style == classify
  3331.           && (f->stat.st_mode & S_IXUGO))
  3332.         len += 1;
  3333.     }
  3334.       else if (S_ISDIR (filetype)
  3335.            || S_ISLNK (filetype)
  3336.            || S_ISFIFO (filetype)
  3337.            || S_ISSOCK (filetype)
  3338.            || S_ISDOOR (filetype)
  3339.            )
  3340.     len += 1;
  3341.     }
  3342.  
  3343.   return len;
  3344. }
  3345.  
  3346. static void
  3347. print_many_per_line (void)
  3348. {
  3349.   struct column_info *line_fmt;
  3350.   int filesno;          /* Index into files. */
  3351.   int row;          /* Current row. */
  3352.   int max_name_length;      /* Length of longest file name + frills. */
  3353.   int name_length;      /* Length of each file name + frills. */
  3354.   int pos;          /* Current character column. */
  3355.   int cols;         /* Number of files across. */
  3356.   int rows;         /* Maximum number of files down. */
  3357.   int max_cols;
  3358.  
  3359.   /* Normally the maximum number of columns is determined by the
  3360.      screen width.  But if few files are available this might limit it
  3361.      as well.  */
  3362.   max_cols = max_idx > files_index ? files_index : max_idx;
  3363.  
  3364.   /* Compute the maximum number of possible columns.  */
  3365.   for (filesno = 0; filesno < files_index; ++filesno)
  3366.     {
  3367.       int i;
  3368.  
  3369.       name_length = length_of_file_name_and_frills (files + filesno);
  3370.  
  3371.       for (i = 0; i < max_cols; ++i)
  3372.     {
  3373.       if (column_info[i].valid_len)
  3374.         {
  3375.           int idx = filesno / ((files_index + i) / (i + 1));
  3376.           int real_length = name_length + (idx == i ? 0 : 2);
  3377.  
  3378.           if (real_length > column_info[i].col_arr[idx])
  3379.         {
  3380.           column_info[i].line_len += (real_length
  3381.                        - column_info[i].col_arr[idx]);
  3382.           column_info[i].col_arr[idx] = real_length;
  3383.           column_info[i].valid_len = column_info[i].line_len < line_length;
  3384.         }
  3385.         }
  3386.     }
  3387.     }
  3388.  
  3389.   /* Find maximum allowed columns.  */
  3390.   for (cols = max_cols; cols > 1; --cols)
  3391.     {
  3392.       if (column_info[cols - 1].valid_len)
  3393.     break;
  3394.     }
  3395.  
  3396.   line_fmt = &column_info[cols - 1];
  3397.  
  3398.   /* Calculate the number of rows that will be in each column except possibly
  3399.      for a short column on the right. */
  3400.   rows = files_index / cols + (files_index % cols != 0);
  3401.  
  3402.   for (row = 0; row < rows; row++)
  3403.     {
  3404.       int col = 0;
  3405.       filesno = row;
  3406.       pos = 0;
  3407.       /* Print the next row.  */
  3408.       while (1)
  3409.     {
  3410.       print_file_name_and_frills (files + filesno);
  3411.       name_length = length_of_file_name_and_frills (files + filesno);
  3412.       max_name_length = line_fmt->col_arr[col++];
  3413.  
  3414.       filesno += rows;
  3415.       if (filesno >= files_index)
  3416.         break;
  3417.  
  3418.       indent (pos + name_length, pos + max_name_length);
  3419.       pos += max_name_length;
  3420.     }
  3421.       putchar ('\n');
  3422.     }
  3423. }
  3424.  
  3425. static void
  3426. print_horizontal (void)
  3427. {
  3428.   struct column_info *line_fmt;
  3429.   int filesno;
  3430.   int max_name_length;
  3431.   int name_length;
  3432.   int cols;
  3433.   int pos;
  3434.   int max_cols;
  3435.  
  3436.   /* Normally the maximum number of columns is determined by the
  3437.      screen width.  But if few files are available this might limit it
  3438.      as well.  */
  3439.   max_cols = max_idx > files_index ? files_index : max_idx;
  3440.  
  3441.   /* Compute the maximum file name length.  */
  3442.   max_name_length = 0;
  3443.   for (filesno = 0; filesno < files_index; ++filesno)
  3444.     {
  3445.       int i;
  3446.  
  3447.       name_length = length_of_file_name_and_frills (files + filesno);
  3448.  
  3449.       for (i = 0; i < max_cols; ++i)
  3450.     {
  3451.       if (column_info[i].valid_len)
  3452.         {
  3453.           int idx = filesno % (i + 1);
  3454.           int real_length = name_length + (idx == i ? 0 : 2);
  3455.  
  3456.           if (real_length > column_info[i].col_arr[idx])
  3457.         {
  3458.           column_info[i].line_len += (real_length
  3459.                        - column_info[i].col_arr[idx]);
  3460.           column_info[i].col_arr[idx] = real_length;
  3461.           column_info[i].valid_len = column_info[i].line_len < line_length;
  3462.         }
  3463.         }
  3464.     }
  3465.     }
  3466.  
  3467.   /* Find maximum allowed columns.  */
  3468.   for (cols = max_cols; cols > 1; --cols)
  3469.     {
  3470.       if (column_info[cols - 1].valid_len)
  3471.     break;
  3472.     }
  3473.  
  3474.   line_fmt = &column_info[cols - 1];
  3475.  
  3476.   pos = 0;
  3477.  
  3478.   /* Print first entry.  */
  3479.   print_file_name_and_frills (files);
  3480.   name_length = length_of_file_name_and_frills (files);
  3481.   max_name_length = line_fmt->col_arr[0];
  3482.  
  3483.   /* Now the rest.  */
  3484.   for (filesno = 1; filesno < files_index; ++filesno)
  3485.     {
  3486.       int col = filesno % cols;
  3487.  
  3488.       if (col == 0)
  3489.     {
  3490.       putchar ('\n');
  3491.       pos = 0;
  3492.     }
  3493.       else
  3494.     {
  3495.       indent (pos + name_length, pos + max_name_length);
  3496.       pos += max_name_length;
  3497.     }
  3498.  
  3499.       print_file_name_and_frills (files + filesno);
  3500.  
  3501.       name_length = length_of_file_name_and_frills (files + filesno);
  3502.       max_name_length = line_fmt->col_arr[col];
  3503.     }
  3504.   putchar ('\n');
  3505. }
  3506.  
  3507. static void
  3508. print_with_commas (void)
  3509. {
  3510.   int filesno;
  3511.   int pos, old_pos;
  3512.  
  3513.   pos = 0;
  3514.  
  3515.   for (filesno = 0; filesno < files_index; filesno++)
  3516.     {
  3517.       old_pos = pos;
  3518.  
  3519.       pos += length_of_file_name_and_frills (files + filesno);
  3520.       if (filesno + 1 < files_index)
  3521.     pos += 2;       /* For the comma and space */
  3522.  
  3523.       if (old_pos != 0 && pos >= line_length)
  3524.     {
  3525.       putchar ('\n');
  3526.       pos -= old_pos;
  3527.     }
  3528.  
  3529.       print_file_name_and_frills (files + filesno);
  3530.       if (filesno + 1 < files_index)
  3531.     {
  3532.       putchar (',');
  3533.       putchar (' ');
  3534.     }
  3535.     }
  3536.   putchar ('\n');
  3537. }
  3538.  
  3539. /* Assuming cursor is at position FROM, indent up to position TO.
  3540.    Use a TAB character instead of two or more spaces whenever possible.  */
  3541.  
  3542. static void
  3543. indent (int from, int to)
  3544. {
  3545.   while (from < to)
  3546.     {
  3547.       if (tabsize > 0 && to / tabsize > (from + 1) / tabsize)
  3548.     {
  3549.       putchar ('\t');
  3550.       from += tabsize - from % tabsize;
  3551.     }
  3552.       else
  3553.     {
  3554.       putchar (' ');
  3555.       from++;
  3556.     }
  3557.     }
  3558. }
  3559.  
  3560. /* Put DIRNAME/NAME into DEST, handling `.' and `/' properly. */
  3561. /* FIXME: maybe remove this function someday.  See about using a
  3562.    non-malloc'ing version of path_concat.  */
  3563.  
  3564. static void
  3565. attach (char *dest, const char *dirname, const char *name)
  3566. {
  3567.   const char *dirnamep = dirname;
  3568.  
  3569.   /* Copy dirname if it is not ".". */
  3570.   if (dirname[0] != '.' || dirname[1] != 0)
  3571.     {
  3572.       while (*dirnamep)
  3573.     *dest++ = *dirnamep++;
  3574.       /* Add '/' if `dirname' doesn't already end with it. */
  3575.       if (dirnamep > dirname && dirnamep[-1] != '/')
  3576.     *dest++ = '/';
  3577.     }
  3578.   while (*name)
  3579.     *dest++ = *name++;
  3580.   *dest = 0;
  3581. }
  3582.  
  3583. static void
  3584. init_column_info (void)
  3585. {
  3586.   int i;
  3587.   int allocate = 0;
  3588.  
  3589.   max_idx = line_length / MIN_COLUMN_WIDTH;
  3590.   if (max_idx == 0)
  3591.     max_idx = 1;
  3592.  
  3593.   if (column_info == NULL)
  3594.     {
  3595.       column_info = XMALLOC (struct column_info, max_idx);
  3596.       allocate = 1;
  3597.     }
  3598.  
  3599.   for (i = 0; i < max_idx; ++i)
  3600.     {
  3601.       int j;
  3602.  
  3603.       column_info[i].valid_len = 1;
  3604.       column_info[i].line_len = (i + 1) * MIN_COLUMN_WIDTH;
  3605.  
  3606.       if (allocate)
  3607.     column_info[i].col_arr = XMALLOC (int, i + 1);
  3608.  
  3609.       for (j = 0; j <= i; ++j)
  3610.     column_info[i].col_arr[j] = MIN_COLUMN_WIDTH;
  3611.     }
  3612. }
  3613.  
  3614. void
  3615. usage (int status)
  3616. {
  3617.   if (status != 0)
  3618.     fprintf (stderr, _("Try `%s --help' for more information.\n"),
  3619.          program_name);
  3620.   else
  3621.     {
  3622.       printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name);
  3623.       fputs (_("\
  3624. List information about the FILEs (the current directory by default).\n\
  3625. Sort entries alphabetically if none of -cftuSUX nor --sort.\n\
  3626. \n\
  3627. "), stdout);
  3628.       fputs (_("\
  3629. Mandatory arguments to long options are mandatory for short options too.\n\
  3630. "), stdout);
  3631.       fputs (_("\
  3632.  -a, --all                  do not hide entries starting with .\n\
  3633.  -A, --almost-all           do not list implied . and ..\n\
  3634.      --author               print the author of each file\n\
  3635.  -b, --escape               print octal escapes for nongraphic characters\n\
  3636. "), stdout);
  3637.       fputs (_("\
  3638.      --block-size=SIZE      use SIZE-byte blocks\n\
  3639.  -B, --ignore-backups       do not list implied entries ending with ~\n\
  3640.  -c                         with -lt: sort by, and show, ctime (time of last\n\
  3641.                               modification of file status information)\n\
  3642.                               with -l: show ctime and sort by name\n\
  3643.                               otherwise: sort by ctime\n\
  3644. "), stdout);
  3645.       fputs (_("\
  3646.  -C                         list entries by columns\n\
  3647.      --color[=WHEN]         control whether color is used to distinguish file\n\
  3648.                               types.  WHEN may be `never', `always', or `auto'\n\
  3649.  -d, --directory            list directory entries instead of contents\n\
  3650.  -D, --dired                generate output designed for Emacs' dired mode\n\
  3651. "), stdout);
  3652.       fputs (_("\
  3653.  -f                         do not sort, enable -aU, disable -lst\n\
  3654.  -F, --classify             append indicator (one of */=@|) to entries\n\
  3655.      --format=WORD          across -x, commas -m, horizontal -x, long -l,\n\
  3656.                               single-column -1, verbose -l, vertical -C\n\
  3657.      --full-time            like -l --time-style=full-iso\n\
  3658. "), stdout);
  3659.       fputs (_("\
  3660.  -g                         like -l, but do not list owner\n\
  3661.  -G, --no-group             inhibit display of group information\n\
  3662.  -h, --human-readable  print sizes in human readable format (e.g., 1K 234M 2G)\n\
  3663.      --si                   likewise, but use powers of 1000 not 1024\n\
  3664.  -H, --dereference-command-line  follow symbolic links on the command line\n\
  3665. "), stdout);
  3666.       fputs (_("\
  3667.      --indicator-style=WORD append indicator with style WORD to entry names:\n\
  3668.                               none (default), classify (-F), file-type (-p)\n\
  3669.  -i, --inode                print index number of each file\n\
  3670.  -I, --ignore=PATTERN       do not list implied entries matching shell PATTERN\n\
  3671.  -k                         like --block-size=1K\n\
  3672. "), stdout);
  3673.       fputs (_("\
  3674.  -l                         use a long listing format\n\
  3675.  -L, --dereference          when showing file information for a symbolic\n\
  3676.                               link, show information for the file the link\n\
  3677.                               references rather than for the link itself\n\
  3678.  -m                         fill width with a comma separated list of entries\n\
  3679. "), stdout);
  3680.       fputs (_("\
  3681.  -n, --numeric-uid-gid      like -l, but list numeric UIDs and GIDs\n\
  3682.  -N, --literal              print raw entry names (don't treat e.g. control\n\
  3683.                               characters specially)\n\
  3684.  -o                         like -l, but do not list group information\n\
  3685.  -p, --file-type            append indicator (one of /=@|) to entries\n\
  3686. "), stdout);
  3687.       fputs (_("\
  3688.  -q, --hide-control-chars   print ? instead of non graphic characters\n\
  3689.      --show-control-chars   show non graphic characters as-is (default\n\
  3690.                             unless program is `ls' and output is a terminal)\n\
  3691.  -Q, --quote-name           enclose entry names in double quotes\n\
  3692.      --quoting-style=WORD   use quoting style WORD for entry names:\n\
  3693.                               literal, locale, shell, shell-always, c, escape\n\
  3694. "), stdout);
  3695.       fputs (_("\
  3696.  -r, --reverse              reverse order while sorting\n\
  3697.  -R, --recursive            list subdirectories recursively\n\
  3698.  -s, --size                 print size of each file, in blocks\n\
  3699. "), stdout);
  3700.       fputs (_("\
  3701.  -S                         sort by file size\n\
  3702.      --sort=WORD            extension -X, none -U, size -S, time -t,\n\
  3703.                               version -v\n\
  3704.                             status -c, time -t, atime -u, access -u, use -u\n\
  3705.      --time=WORD            show time as WORD instead of modification time:\n\
  3706.                               atime, access, use, ctime or status; use\n\
  3707.                               specified time as sort key if --sort=time\n\
  3708. "), stdout);
  3709.       fputs (_("\
  3710.      --time-style=STYLE     show times using style STYLE:\n\
  3711.                               full-iso, long-iso, iso, locale, +FORMAT\n\
  3712.                             FORMAT is interpreted like `date'; if FORMAT is\n\
  3713.                             FORMAT1<newline>FORMAT2, FORMAT1 applies to\n\
  3714.                             non-recent files and FORMAT2 to recent files;\n\
  3715.                             if STYLE is prefixed with `posix-', STYLE\n\
  3716.                             takes effect only outside the POSIX locale\n\
  3717.  -t                         sort by modification time\n\
  3718.  -T, --tabsize=COLS         assume tab stops at each COLS instead of 8\n\
  3719. "), stdout);
  3720.       fputs (_("\
  3721.  -u                         with -lt: sort by, and show, access time\n\
  3722.                               with -l: show access time and sort by name\n\
  3723.                               otherwise: sort by access time\n\
  3724.  -U                         do not sort; list entries in directory order\n\
  3725.  -v                         sort by version\n\
  3726. "), stdout);
  3727.       fputs (_("\
  3728.  -w, --width=COLS           assume screen width instead of current value\n\
  3729.  -x                         list entries by lines instead of by columns\n\
  3730.  -X                         sort alphabetically by entry extension\n\
  3731.  -1                         list one file per line\n\
  3732. "), stdout);
  3733.       fputs (HELP_OPTION_DESCRIPTION, stdout);
  3734.       fputs (VERSION_OPTION_DESCRIPTION, stdout);
  3735.       fputs (_("\n\
  3736. SIZE may be (or may be an integer optionally followed by) one of following:\n\
  3737. kB 1000, K 1024, MB 1,000,000, M 1,048,576, and so on for G, T, P, E, Z, Y.\n\
  3738. "), stdout);
  3739.       fputs (_("\
  3740. \n\
  3741. By default, color is not used to distinguish types of files.  That is\n\
  3742. equivalent to using --color=none.  Using the --color option without the\n\
  3743. optional WHEN argument is equivalent to using --color=always.  With\n\
  3744. --color=auto, color codes are output only if standard output is connected\n\
  3745. to a terminal (tty).\n\
  3746. "), stdout);
  3747.       printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
  3748.     }
  3749.   exit (status);
  3750. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement