home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / fileutils-3.6 / src / ls.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-14  |  40.5 KB  |  1,877 lines

  1. /* `dir', `vdir' and `ls' directory listing programs for GNU.
  2.    Copyright (C) 1985, 1988, 1990, 1991 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
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* If the macro MULTI_COL is defined,
  19.    the multi-column format is the default regardless
  20.    of the type of output device.
  21.    This is for the `dir' program.
  22.  
  23.    If the macro LONG_FORMAT is defined,
  24.    the long format is the default regardless of the
  25.    type of output device.
  26.    This is for the `vdir' program.
  27.  
  28.    If neither is defined,
  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. #ifdef _AIX
  36.  #pragma alloca
  37. #endif
  38. #include <sys/types.h>
  39. #if !defined(_POSIX_SOURCE) || defined(_AIX)
  40. #include <sys/ioctl.h>
  41. #endif
  42. #include <stdio.h>
  43. #include <grp.h>
  44. #include <pwd.h>
  45. #include <getopt.h>
  46. #include "system.h"
  47. #include <fnmatch.h>
  48. #include "version.h"
  49.  
  50. #ifndef S_IEXEC
  51. #define S_IEXEC S_IXUSR
  52. #endif
  53.  
  54. /* Return an int indicating the result of comparing two longs. */
  55. #ifdef INT_16_BITS
  56. #define longdiff(a, b) ((a) < (b) ? -1 : (a) > (b) ? 1 : 0)
  57. #else
  58. #define longdiff(a, b) ((a) - (b))
  59. #endif
  60.  
  61. #ifndef STDC_HEADERS
  62. char *ctime ();
  63. time_t time ();
  64. #endif
  65.  
  66. void mode_string ();
  67.  
  68. char *xstrdup ();
  69. char *getgroup ();
  70. char *getuser ();
  71. char *xmalloc ();
  72. char *xrealloc ();
  73. int argmatch ();
  74. void error ();
  75. void invalid_arg ();
  76.  
  77. static char *make_link_path ();
  78. static int compare_atime ();
  79. static int rev_cmp_atime ();
  80. static int compare_ctime ();
  81. static int rev_cmp_ctime ();
  82. static int compare_mtime ();
  83. static int rev_cmp_mtime ();
  84. static int compare_size ();
  85. static int rev_cmp_size ();
  86. static int compare_name ();
  87. static int rev_cmp_name ();
  88. static int compare_extension ();
  89. static int rev_cmp_extension ();
  90. static int decode_switches ();
  91. static int file_interesting ();
  92. static int gobble_file ();
  93. static int is_not_dot_or_dotdot ();
  94. static int length_of_file_name_and_frills ();
  95. static void add_ignore_pattern ();
  96. static void attach ();
  97. static void clear_files ();
  98. static void extract_dirs_from_files ();
  99. static void get_link_name ();
  100. static void indent ();
  101. static void print_current_files ();
  102. static void print_dir ();
  103. static void print_file_name_and_frills ();
  104. static void print_horizontal ();
  105. static void print_long_format ();
  106. static void print_many_per_line ();
  107. static void print_name_with_quoting ();
  108. static void print_type_indicator ();
  109. static void print_with_commas ();
  110. static void queue_directory ();
  111. static void sort_files ();
  112. static void usage ();
  113.  
  114.  
  115. /* The name the program was run with, stripped of any leading path. */
  116. char *program_name;
  117.  
  118. enum filetype
  119. {
  120.   symbolic_link,
  121.   directory,
  122.   arg_directory,        /* Directory given as command line arg. */
  123.   normal            /* All others. */
  124. };
  125.  
  126. struct file
  127. {
  128.   /* The file name. */
  129.   char *name;
  130.  
  131.   struct stat stat;
  132.  
  133.   /* For symbolic link, name of the file linked to, otherwise zero. */
  134.   char *linkname;
  135.  
  136.   /* For symbolic link and long listing, st_mode of file linked to, otherwise
  137.      zero. */
  138.   unsigned int linkmode;
  139.  
  140.   enum filetype filetype;
  141. };
  142.  
  143. /* The table of files in the current directory:
  144.  
  145.    `files' points to a vector of `struct file', one per file.
  146.    `nfiles' is the number of elements space has been allocated for.
  147.    `files_index' is the number actually in use.  */
  148.  
  149. /* Address of block containing the files that are described.  */
  150.  
  151. static struct file *files;
  152.  
  153. /* Length of block that `files' points to, measured in files.  */
  154.  
  155. static int nfiles;
  156.  
  157. /* Index of first unused in `files'.  */
  158.  
  159. static int files_index;
  160.  
  161. /* Record of one pending directory waiting to be listed.  */
  162.  
  163. struct pending
  164. {
  165.   char *name;
  166.   /* If the directory is actually the file pointed to by a symbolic link we
  167.      were told to list, `realname' will contain the name of the symbolic
  168.      link, otherwise zero. */
  169.   char *realname;
  170.   struct pending *next;
  171. };
  172.  
  173. static struct pending *pending_dirs;
  174.  
  175. /* Current time (seconds since 1970).  When we are printing a file's time,
  176.    include the year if it is more than 6 months before this time.  */
  177.  
  178. static time_t current_time;
  179.  
  180. /* The number of digits to use for block sizes.
  181.    4, or more if needed for bigger numbers.  */
  182.  
  183. static int block_size_size;
  184.  
  185. /* Option flags */
  186.  
  187. /* long_format for lots of info, one per line.
  188.    one_per_line for just names, one per line.
  189.    many_per_line for just names, many per line, sorted vertically.
  190.    horizontal for just names, many per line, sorted horizontally.
  191.    with_commas for just names, many per line, separated by commas.
  192.  
  193.    -l, -1, -C, -x and -m control this parameter.  */
  194.  
  195. enum format
  196. {
  197.   long_format,            /* -l */
  198.   one_per_line,            /* -1 */
  199.   many_per_line,        /* -C */
  200.   horizontal,            /* -x */
  201.   with_commas            /* -m */
  202. };
  203.  
  204. static enum format format;
  205.  
  206. /* Type of time to print or sort by.  Controlled by -c and -u.  */
  207.  
  208. enum time_type
  209. {
  210.   time_mtime,            /* default */
  211.   time_ctime,            /* -c */
  212.   time_atime            /* -u */
  213. };
  214.  
  215. static enum time_type time_type;
  216.  
  217. /* print the full time, otherwise the standard unix heuristics. */
  218.  
  219. int full_time;
  220.  
  221. /* The file characteristic to sort by.  Controlled by -t, -S, -U, -X. */
  222.  
  223. enum sort_type
  224. {
  225.   sort_none,            /* -U */
  226.   sort_name,            /* default */
  227.   sort_extension,        /* -X */
  228.   sort_time,            /* -t */
  229.   sort_size            /* -S */
  230. };
  231.  
  232. static enum sort_type sort_type;
  233.  
  234. /* Direction of sort.
  235.    0 means highest first if numeric,
  236.    lowest first if alphabetic;
  237.    these are the defaults.
  238.    1 means the opposite order in each case.  -r  */
  239.  
  240. static int sort_reverse;
  241.  
  242. /* Nonzero means to NOT display group information.  -G  */
  243.  
  244. int inhibit_group;
  245.  
  246. /* Nonzero means print the user and group id's as numbers rather
  247.    than as names.  -n  */
  248.  
  249. static int numeric_users;
  250.  
  251. /* Nonzero means mention the size in 512 byte blocks of each file.  -s  */
  252.  
  253. static int print_block_size;
  254.  
  255. /* Nonzero means show file sizes in kilobytes instead of blocks
  256.    (the size of which is system-dependant).  -k */
  257.  
  258. static int kilobyte_blocks;
  259.  
  260. /* none means don't mention the type of files.
  261.    all means mention the types of all files.
  262.    not_programs means do so except for executables.
  263.  
  264.    Controlled by -F and -p.  */
  265.  
  266. enum indicator_style
  267. {
  268.   none,                /* default */
  269.   all,                /* -F */
  270.   not_programs            /* -p */
  271. };
  272.  
  273. static enum indicator_style indicator_style;
  274.  
  275. /* Nonzero means mention the inode number of each file.  -i  */
  276.  
  277. static int print_inode;
  278.  
  279. /* Nonzero means when a symbolic link is found, display info on
  280.    the file linked to.  -L  */
  281.  
  282. static int trace_links;
  283.  
  284. /* Nonzero means when a directory is found, display info on its
  285.    contents.  -R  */
  286.  
  287. static int trace_dirs;
  288.  
  289. /* Nonzero means when an argument is a directory name, display info
  290.    on it itself.  -d  */
  291.  
  292. static int immediate_dirs;
  293.  
  294. /* Nonzero means don't omit files whose names start with `.'.  -A */
  295.  
  296. static int all_files;
  297.  
  298. /* Nonzero means don't omit files `.' and `..'
  299.    This flag implies `all_files'.  -a  */
  300.  
  301. static int really_all_files;
  302.  
  303. /* A linked list of shell-style globbing patterns.  If a non-argument
  304.    file name matches any of these patterns, it is omitted.
  305.    Controlled by -I.  Multiple -I options accumulate.
  306.    The -B option adds `*~' and `.*~' to this list.  */
  307.  
  308. struct ignore_pattern
  309. {
  310.   char *pattern;
  311.   struct ignore_pattern *next;
  312. };
  313.  
  314. static struct ignore_pattern *ignore_patterns;
  315.  
  316. /* Nonzero means quote nongraphic chars in file names.  -b  */
  317.  
  318. static int quote_funny_chars;
  319.  
  320. /* Nonzero means output nongraphic chars in file names as `?'.  -q  */
  321.  
  322. static int qmark_funny_chars;
  323.  
  324. /* Nonzero means output each file name using C syntax for a string.
  325.    Always accompanied by `quote_funny_chars'.
  326.    This mode, together with -x or -C or -m,
  327.    and without such frills as -F or -s,
  328.    is guaranteed to make it possible for a program receiving
  329.    the output to tell exactly what file names are present.  -Q  */
  330.  
  331. static int quote_as_string;
  332.  
  333. /* The number of chars per hardware tab stop.  -T */
  334. static int tabsize;
  335.  
  336. /* Nonzero means we are listing the working directory because no
  337.    non-option arguments were given. */
  338.  
  339. static int dir_defaulted;
  340.  
  341. /* Nonzero means print each directory name before listing it. */
  342.  
  343. static int print_dir_name;
  344.  
  345. /* The line length to use for breaking lines in many-per-line format.
  346.    Can be set with -w.  */
  347.  
  348. static int line_length;
  349.  
  350. /* If nonzero, the file listing format requires that stat be called on
  351.    each file. */
  352.  
  353. static int format_needs_stat;
  354.  
  355. /* The exit status to use if we don't get any fatal errors. */
  356.  
  357. static int exit_status;
  358.  
  359. /* If non-zero, display usage information and exit.  */
  360. static int flag_help;
  361.  
  362. /* If non-zero, print the version on standard error.  */
  363. static int flag_version;
  364.  
  365. static struct option const long_options[] =
  366. {
  367.   {"all", no_argument, 0, 'a'},
  368.   {"escape", no_argument, 0, 'b'},
  369.   {"directory", no_argument, 0, 'd'},
  370.   {"full-time", no_argument, &full_time, 1},
  371.   {"inode", no_argument, 0, 'i'},
  372.   {"kilobytes", no_argument, 0, 'k'},
  373.   {"numeric-uid-gid", no_argument, 0, 'n'},
  374.   {"no-group", no_argument, 0, 'G'},
  375.   {"hide-control-chars", no_argument, 0, 'q'},
  376.   {"reverse", no_argument, 0, 'r'},
  377.   {"size", no_argument, 0, 's'},
  378.   {"width", required_argument, 0, 'w'},
  379.   {"almost-all", no_argument, 0, 'A'},
  380.   {"ignore-backups", no_argument, 0, 'B'},
  381.   {"classify", no_argument, 0, 'F'},
  382.   {"file-type", no_argument, 0, 'F'},
  383.   {"ignore", required_argument, 0, 'I'},
  384.   {"dereference", no_argument, 0, 'L'},
  385.   {"literal", no_argument, 0, 'N'},
  386.   {"quote-name", no_argument, 0, 'Q'},
  387.   {"recursive", no_argument, 0, 'R'},
  388.   {"format", required_argument, 0, 12},
  389.   {"sort", required_argument, 0, 10},
  390.   {"tabsize", required_argument, 0, 'T'},
  391.   {"time", required_argument, 0, 11},
  392.   {"help", no_argument, &flag_help, 1},
  393.   {"version", no_argument, &flag_version, 1},
  394.   {0, 0, 0, 0}
  395. };
  396.  
  397. static char const* const format_args[] =
  398. {
  399.   "verbose", "long", "commas", "horizontal", "across",
  400.   "vertical", "single-column", 0
  401. };
  402.  
  403. static enum format const formats[] =
  404. {
  405.   long_format, long_format, with_commas, horizontal, horizontal,
  406.   many_per_line, one_per_line
  407. };
  408.  
  409. static char const* const sort_args[] =
  410. {
  411.   "none", "time", "size", "extension", 0
  412. };
  413.  
  414. static enum sort_type const sort_types[] =
  415. {
  416.   sort_none, sort_time, sort_size, sort_extension
  417. };
  418.  
  419. static char const* const time_args[] =
  420. {
  421.   "atime", "access", "use", "ctime", "status", 0
  422. };
  423.  
  424. static enum time_type const time_types[] =
  425. {
  426.   time_atime, time_atime, time_atime, time_ctime, time_ctime
  427. };
  428.  
  429.  
  430. void
  431. main (argc, argv)
  432.      int argc;
  433.      char **argv;
  434. {
  435.   register int i;
  436.   register struct pending *thispend;
  437.  
  438.   exit_status = 0;
  439.   dir_defaulted = 1;
  440.   print_dir_name = 1;
  441.   pending_dirs = 0;
  442.   current_time = time ((time_t *) 0);
  443.  
  444.   program_name = argv[0];
  445.   i = decode_switches (argc, argv);
  446.  
  447.   if (flag_version)
  448.     {
  449.       fprintf (stderr, "%s\n", version_string);
  450.       exit (0);
  451.     }
  452.  
  453.   if (flag_help)
  454.     usage ();
  455.  
  456.   format_needs_stat = sort_type == sort_time || sort_type == sort_size
  457.     || format == long_format
  458.     || trace_links || trace_dirs || indicator_style != none
  459.     || print_block_size || print_inode;
  460.  
  461.   nfiles = 100;
  462.   files = (struct file *) xmalloc (sizeof (struct file) * nfiles);
  463.   files_index = 0;
  464.  
  465.   clear_files ();
  466.  
  467.   if (i < argc)
  468.     dir_defaulted = 0;
  469.   for (; i < argc; i++)
  470.     gobble_file (argv[i], 1, "");
  471.  
  472.   if (dir_defaulted)
  473.     {
  474.       if (immediate_dirs)
  475.     gobble_file (".", 1, "");
  476.       else
  477.     queue_directory (".", 0);
  478.     }
  479.  
  480.   if (files_index)
  481.     {
  482.       sort_files ();
  483.       if (!immediate_dirs)
  484.     extract_dirs_from_files ("", 0);
  485.       /* `files_index' might be zero now.  */
  486.     }
  487.   if (files_index)
  488.     {
  489.       print_current_files ();
  490.       if (pending_dirs)
  491.     putchar ('\n');
  492.     }
  493.   else if (pending_dirs && pending_dirs->next == 0)
  494.     print_dir_name = 0;
  495.  
  496.   while (pending_dirs)
  497.     {
  498.       thispend = pending_dirs;
  499.       pending_dirs = pending_dirs->next;
  500.       print_dir (thispend->name, thispend->realname);
  501.       free (thispend->name);
  502.       if (thispend->realname)
  503.     free (thispend->realname);
  504.       free (thispend);
  505.       print_dir_name = 1;
  506.     }
  507.  
  508.   exit (exit_status);
  509. }
  510.  
  511. /* Set all the option flags according to the switches specified.
  512.    Return the index of the first non-option argument.  */
  513.  
  514. static int
  515. decode_switches (argc, argv)
  516.      int argc;
  517.      char **argv;
  518. {
  519.   register char *p;
  520.   int c;
  521.   int i;
  522.  
  523.   qmark_funny_chars = 0;
  524.   quote_funny_chars = 0;
  525.  
  526.   /* initialize all switches to default settings */
  527.  
  528. #ifdef MULTI_COL
  529.   /* This is for the `dir' program.  */
  530.   format = many_per_line;
  531.   quote_funny_chars = 1;
  532. #else
  533. #ifdef LONG_FORMAT
  534.   /* This is for the `vdir' program.  */
  535.   format = long_format;
  536.   quote_funny_chars = 1;
  537. #else
  538.   /* This is for the `ls' program.  */
  539.   if (isatty (1))
  540.     {
  541.       format = many_per_line;
  542.       qmark_funny_chars = 1;
  543.     }
  544.   else
  545.     {
  546.       format = one_per_line;
  547.       qmark_funny_chars = 0;
  548.     }
  549. #endif
  550. #endif
  551.  
  552.   time_type = time_mtime;
  553.   full_time = 0;
  554.   sort_type = sort_name;
  555.   sort_reverse = 0;
  556.   numeric_users = 0;
  557.   print_block_size = 0;
  558.   kilobyte_blocks = getenv ("POSIXLY_CORRECT") == 0;
  559.   indicator_style = none;
  560.   print_inode = 0;
  561.   trace_links = 0;
  562.   trace_dirs = 0;
  563.   immediate_dirs = 0;
  564.   all_files = 0;
  565.   really_all_files = 0;
  566.   ignore_patterns = 0;
  567.   quote_as_string = 0;
  568.  
  569.   p = getenv ("COLUMNS");
  570.   line_length = p ? atoi (p) : 80;
  571.  
  572. #ifdef TIOCGWINSZ
  573.   {
  574.     struct winsize ws;
  575.  
  576.     if (ioctl (1, TIOCGWINSZ, &ws) != -1 && ws.ws_col != 0)
  577.       line_length = ws.ws_col;
  578.   }
  579. #endif
  580.  
  581.   p = getenv ("TABSIZE");
  582.   tabsize = p ? atoi (p) : 8;
  583.  
  584.   while ((c = getopt_long (argc, argv, "abcdfgiklmnpqrstuw:xABCFGI:LNQRST:UX1",
  585.                long_options, (int *) 0)) != EOF)
  586.     {
  587.       switch (c)
  588.     {
  589.     case 0:
  590.       break;
  591.  
  592.     case 'a':
  593.       all_files = 1;
  594.       really_all_files = 1;
  595.       break;
  596.       
  597.     case 'b':
  598.       quote_funny_chars = 1;
  599.       qmark_funny_chars = 0;
  600.       break;
  601.       
  602.     case 'c':
  603.       time_type = time_ctime;
  604.       break;
  605.       
  606.     case 'd':
  607.       immediate_dirs = 1;
  608.       break;
  609.  
  610.     case 'f':
  611.       /* Same as enabling -a -U and disabling -l -s.  */
  612.       all_files = 1;
  613.       really_all_files = 1;
  614.       sort_type = sort_none;
  615.       /* disable -l */
  616.       if (format == long_format)
  617.         format = (isatty (1) ? many_per_line : one_per_line);
  618.       print_block_size = 0;  /* disable -s */
  619.       break;
  620.  
  621.     case 'g':
  622.       /* No effect.  For BSD compatibility. */
  623.       break;
  624.  
  625.     case 'i':
  626.       print_inode = 1;
  627.       break;
  628.       
  629.     case 'k':
  630.       kilobyte_blocks = 1;
  631.       break;
  632.       
  633.     case 'l':
  634.       format = long_format;
  635.       break;
  636.       
  637.     case 'm':
  638.       format = with_commas;
  639.       break;
  640.       
  641.     case 'n':
  642.       numeric_users = 1;
  643.       break;
  644.       
  645.     case 'p':
  646.       indicator_style = not_programs;
  647.       break;
  648.       
  649.     case 'q':
  650.       qmark_funny_chars = 1;
  651.       quote_funny_chars = 0;
  652.       break;
  653.       
  654.     case 'r':
  655.       sort_reverse = 1;
  656.       break;
  657.       
  658.     case 's':
  659.       print_block_size = 1;
  660.       break;
  661.       
  662.     case 't':
  663.       sort_type = sort_time;
  664.       break;
  665.       
  666.     case 'u':
  667.       time_type = time_atime;
  668.       break;
  669.       
  670.     case 'w':
  671.       line_length = atoi (optarg);
  672.       if (line_length < 1)
  673.         error (1, 0, "invalid line width: %s", optarg);
  674.       break;
  675.       
  676.     case 'x':
  677.       format = horizontal;
  678.       break;
  679.       
  680.     case 'A':
  681.       all_files = 1;
  682.       break;
  683.       
  684.     case 'B':
  685.       add_ignore_pattern ("*~");
  686.       add_ignore_pattern (".*~");
  687.       break;
  688.       
  689.     case 'C':
  690.       format = many_per_line;
  691.       break;
  692.       
  693.     case 'F':
  694.       indicator_style = all;
  695.       break;
  696.       
  697.     case 'G':        /* inhibit display of group info */
  698.       inhibit_group = 1;
  699.       break;
  700.       
  701.     case 'I':
  702.       add_ignore_pattern (optarg);
  703.       break;
  704.       
  705.     case 'L':
  706.       trace_links = 1;
  707.       break;
  708.       
  709.     case 'N':
  710.       quote_funny_chars = 0;
  711.       qmark_funny_chars = 0;
  712.       break;
  713.       
  714.     case 'Q':
  715.       quote_as_string = 1;
  716.       quote_funny_chars = 1;
  717.       qmark_funny_chars = 0;
  718.       break;
  719.       
  720.     case 'R':
  721.       trace_dirs = 1;
  722.       break;
  723.       
  724.     case 'S':
  725.       sort_type = sort_size;
  726.       break;
  727.       
  728.     case 'T':
  729.       tabsize = atoi (optarg);
  730.       if (tabsize < 1)
  731.         error (1, 0, "invalid tab size: %s", optarg);
  732.       break;
  733.  
  734.     case 'U':
  735.       sort_type = sort_none;
  736.       break;
  737.  
  738.     case 'X':
  739.       sort_type = sort_extension;
  740.       break;
  741.  
  742.     case '1':
  743.       format = one_per_line;
  744.       break;
  745.  
  746.     case 10:        /* +sort */
  747.       i = argmatch (optarg, sort_args);
  748.       if (i < 0)
  749.         {
  750.           invalid_arg ("sort type", optarg, i);
  751.           usage ();
  752.         }
  753.       sort_type = sort_types[i];
  754.       break;
  755.  
  756.     case 11:        /* +time */
  757.       i = argmatch (optarg, time_args);
  758.       if (i < 0)
  759.         {
  760.           invalid_arg ("time type", optarg, i);
  761.           usage ();
  762.         }
  763.       time_type = time_types[i];
  764.       break;
  765.  
  766.     case 12:        /* +format */
  767.       i = argmatch (optarg, format_args);
  768.       if (i < 0)
  769.         {
  770.           invalid_arg ("format type", optarg, i);
  771.           usage ();
  772.         }
  773.       format = formats[i];
  774.       break;
  775.       
  776.     default:
  777.       usage ();
  778.     }
  779.     }
  780.  
  781.   return optind;
  782. }
  783.  
  784. /* Request that the directory named `name' have its contents listed later.
  785.    If `realname' is nonzero, it will be used instead of `name' when the
  786.    directory name is printed.  This allows symbolic links to directories
  787.    to be treated as regular directories but still be listed under their
  788.    real names. */
  789.  
  790. static void
  791. queue_directory (name, realname)
  792.      char *name;
  793.      char *realname;
  794. {
  795.   struct pending *new;
  796.  
  797.   new = (struct pending *) xmalloc (sizeof (struct pending));
  798.   new->next = pending_dirs;
  799.   pending_dirs = new;
  800.   new->name = xstrdup (name);
  801.   if (realname)
  802.     new->realname = xstrdup (realname);
  803.   else
  804.     new->realname = 0;
  805. }
  806.  
  807. /* Read directory `name', and list the files in it.
  808.    If `realname' is nonzero, print its name instead of `name';
  809.    this is used for symbolic links to directories. */
  810.  
  811. static void
  812. print_dir (name, realname)
  813.      char *name;
  814.      char *realname;
  815. {
  816.   register DIR *reading;
  817.   register struct dirent *next;
  818.   register int total_blocks = 0;
  819.  
  820.   errno = 0;
  821.   reading = opendir (name);
  822.   if (!reading)
  823.     {
  824.       error (0, errno, "%s", name);
  825.       exit_status = 1;
  826.       return;
  827.     }
  828.  
  829.   /* Read the directory entries, and insert the subfiles into the `files'
  830.      table.  */
  831.  
  832.   clear_files ();
  833.  
  834.   while ((next = readdir (reading)) != NULL)
  835.     if (file_interesting (next))
  836.       total_blocks += gobble_file (next->d_name, 0, name);
  837.  
  838.   if (CLOSEDIR (reading))
  839.     {
  840.       error (0, errno, "%s", name);
  841.       exit_status = 1;
  842.       /* Don't return; print whatever we got. */
  843.     }
  844.  
  845.   /* Sort the directory contents.  */
  846.   sort_files ();
  847.  
  848.   /* If any member files are subdirectories, perhaps they should have their
  849.      contents listed rather than being mentioned here as files.  */
  850.  
  851.   if (trace_dirs)
  852.     extract_dirs_from_files (name, 1);
  853.  
  854.   if (print_dir_name)
  855.     {
  856.       if (realname)
  857.     printf ("%s:\n", realname);
  858.       else
  859.     printf ("%s:\n", name);
  860.     }
  861.  
  862.   if (format == long_format || print_block_size)
  863.     printf ("total %u\n", total_blocks);
  864.  
  865.   if (files_index)
  866.     print_current_files ();
  867.  
  868.   if (pending_dirs)
  869.     putchar ('\n');
  870. }
  871.  
  872. /* Add `pattern' to the list of patterns for which files that match are
  873.    not listed.  */
  874.  
  875. static void
  876. add_ignore_pattern (pattern)
  877.      char *pattern;
  878. {
  879.   register struct ignore_pattern *ignore;
  880.  
  881.   ignore = (struct ignore_pattern *) xmalloc (sizeof (struct ignore_pattern));
  882.   ignore->pattern = pattern;
  883.   /* Add it to the head of the linked list. */
  884.   ignore->next = ignore_patterns;
  885.   ignore_patterns = ignore;
  886. }
  887.  
  888. /* Return nonzero if the file in `next' should be listed. */
  889.  
  890. static int
  891. file_interesting (next)
  892.      register struct dirent *next;
  893. {
  894.   register struct ignore_pattern *ignore;
  895.  
  896.   for (ignore = ignore_patterns; ignore; ignore = ignore->next)
  897.     if (fnmatch (ignore->pattern, next->d_name, FNM_PERIOD) == 0)
  898.       return 0;
  899.  
  900.   if (really_all_files
  901.       || next->d_name[0] != '.'
  902.       || (all_files
  903.       && next->d_name[1] != '\0'
  904.       && (next->d_name[1] != '.' || next->d_name[2] != '\0')))
  905.     return 1;
  906.  
  907.   return 0;
  908. }
  909.  
  910. /* Enter and remove entries in the table `files'.  */
  911.  
  912. /* Empty the table of files. */
  913.  
  914. static void
  915. clear_files ()
  916. {
  917.   register int i;
  918.  
  919.   for (i = 0; i < files_index; i++)
  920.     {
  921.       free (files[i].name);
  922.       if (files[i].linkname)
  923.     free (files[i].linkname);
  924.     }
  925.  
  926.   files_index = 0;
  927.   block_size_size = 4;
  928. }
  929.  
  930. /* Add a file to the current table of files.
  931.    Verify that the file exists, and print an error message if it does not.
  932.    Return the number of blocks that the file occupies.  */
  933.  
  934. static int
  935. gobble_file (name, explicit_arg, dirname)
  936.      char *name;
  937.      int explicit_arg;
  938.      char *dirname;
  939. {
  940.   register int blocks;
  941.   register int val;
  942.   register char *path;
  943.  
  944.   if (files_index == nfiles)
  945.     {
  946.       nfiles *= 2;
  947.       files = (struct file *) xrealloc (files, sizeof (struct file) * nfiles);
  948.     }
  949.  
  950.   files[files_index].linkname = 0;
  951.   files[files_index].linkmode = 0;
  952.  
  953.   if (explicit_arg || format_needs_stat)
  954.     {
  955.       /* `path' is the absolute pathname of this file. */
  956.  
  957.       if (name[0] == '/' || dirname[0] == 0)
  958.     path = name;
  959.       else
  960.     {
  961.       path = (char *) alloca (strlen (name) + strlen (dirname) + 2);
  962.       attach (path, dirname, name);
  963.     }
  964.  
  965.       if (trace_links)
  966.     {
  967.       val = stat (path, &files[files_index].stat);
  968.       if (val < 0)
  969.         /* Perhaps a symbolically-linked to file doesn't exist; stat
  970.            the link instead. */
  971.         val = lstat (path, &files[files_index].stat);
  972.     }
  973.       else
  974.     val = lstat (path, &files[files_index].stat);
  975.       if (val < 0)
  976.     {
  977.       error (0, errno, "%s", path);
  978.       exit_status = 1;
  979.       return 0;
  980.     }
  981.  
  982. #ifdef S_ISLNK
  983.       if (S_ISLNK (files[files_index].stat.st_mode)
  984.       && (explicit_arg || format == long_format))
  985.     {
  986.       char *linkpath;
  987.       struct stat linkstats;
  988.  
  989.       get_link_name (path, &files[files_index]);
  990.       linkpath = make_link_path (path, files[files_index].linkname);
  991.  
  992.       /* Avoid following symbolic links when possible, ie, when
  993.          they won't be traced and when no indicator is needed. */
  994.       if (linkpath
  995.           && ((explicit_arg && format != long_format)
  996.            || indicator_style != none)
  997.           && stat (linkpath, &linkstats) == 0)
  998.         {
  999.           /* Symbolic links to directories that are mentioned on the
  1000.          command line are automatically traced if not being
  1001.          listed as files.  */
  1002.           if (explicit_arg && format != long_format
  1003.           && S_ISDIR (linkstats.st_mode))
  1004.         {
  1005.           /* Substitute the linked-to directory's name, but
  1006.              save the real name in `linkname' for printing.  */
  1007.           if (!immediate_dirs)
  1008.             {
  1009.               char *tempname = name;
  1010.               name = linkpath;
  1011.               linkpath = files[files_index].linkname;
  1012.               files[files_index].linkname = tempname;
  1013.             }
  1014.           files[files_index].stat = linkstats;
  1015.         }
  1016.           else
  1017.         /* Get the linked-to file's mode for the filetype indicator
  1018.            in long listings.  */
  1019.         files[files_index].linkmode = linkstats.st_mode;
  1020.         }
  1021.       if (linkpath)
  1022.         free (linkpath);
  1023.     }
  1024. #endif
  1025.  
  1026. #ifdef S_ISLNK
  1027.       if (S_ISLNK (files[files_index].stat.st_mode))
  1028.     files[files_index].filetype = symbolic_link;
  1029.       else
  1030. #endif
  1031.     if (S_ISDIR (files[files_index].stat.st_mode))
  1032.       {
  1033.         if (explicit_arg && !immediate_dirs)
  1034.           files[files_index].filetype = arg_directory;
  1035.         else
  1036.           files[files_index].filetype = directory;
  1037.       }
  1038.     else
  1039.       files[files_index].filetype = normal;
  1040.  
  1041.       blocks = convert_blocks (ST_NBLOCKS (files[files_index].stat),
  1042.                    kilobyte_blocks);
  1043.       if (blocks >= 10000 && block_size_size < 5)
  1044.     block_size_size = 5;
  1045.       if (blocks >= 100000 && block_size_size < 6)
  1046.     block_size_size = 6;
  1047.       if (blocks >= 1000000 && block_size_size < 7)
  1048.     block_size_size = 7;
  1049.     }
  1050.   else
  1051.     blocks = 0;
  1052.  
  1053.   files[files_index].name = xstrdup (name);
  1054.   files_index++;
  1055.  
  1056.   return blocks;
  1057. }
  1058.  
  1059. #ifdef S_ISLNK
  1060.  
  1061. /* Put the name of the file that `filename' is a symbolic link to
  1062.    into the `linkname' field of `f'. */
  1063.  
  1064. static void
  1065. get_link_name (filename, f)
  1066.      char *filename;
  1067.      struct file *f;
  1068. {
  1069.   register char *linkbuf;
  1070. #ifdef _AIX
  1071.   register int bufsiz = PATH_MAX; /* st_size is wrong. */
  1072. #else
  1073.   register int bufsiz = f->stat.st_size;
  1074. #endif
  1075.   register int linksize;
  1076.  
  1077.   linkbuf = (char *) xmalloc (bufsiz + 1);
  1078.   /* Some automounters give incorrect st_size for mount points.
  1079.      I can't think of a good workaround for it, though.  */
  1080.   linksize = readlink (filename, linkbuf, bufsiz);
  1081.   if (linksize < 0)
  1082.     {
  1083.       error (0, errno, "%s", filename);
  1084.       exit_status = 1;
  1085.       free (linkbuf);
  1086.     }
  1087.   else
  1088.     {
  1089. #ifdef _AIX
  1090.       linkbuf = (char *) xrealloc (linkbuf, linksize + 1);
  1091. #endif
  1092.       linkbuf[linksize] = '\0';
  1093.       f->linkname = linkbuf;
  1094.     }
  1095. }
  1096.  
  1097. /* If `linkname' is a relative path and `path' contains one or more
  1098.    leading directories, return `linkname' with those directories
  1099.    prepended; otherwise, return a copy of `linkname'.
  1100.    If `linkname' is zero, return zero. */
  1101.  
  1102. static char *
  1103. make_link_path (path, linkname)
  1104.      char *path;
  1105.      char *linkname;
  1106. {
  1107.   char *linkbuf;
  1108.   int bufsiz;
  1109.  
  1110.   if (linkname == 0)
  1111.     return 0;
  1112.  
  1113.   if (*linkname == '/')
  1114.     return xstrdup (linkname);
  1115.  
  1116.   /* The link is to a relative path.  Prepend any leading path
  1117.      in `path' to the link name. */
  1118.   linkbuf = rindex (path, '/');
  1119.   if (linkbuf == 0)
  1120.     return xstrdup (linkname);
  1121.  
  1122.   bufsiz = linkbuf - path + 1;
  1123.   linkbuf = xmalloc (bufsiz + strlen (linkname) + 1);
  1124.   strncpy (linkbuf, path, bufsiz);
  1125.   strcpy (linkbuf + bufsiz, linkname);
  1126.   return linkbuf;
  1127. }
  1128. #endif
  1129.  
  1130. /* Remove any entries from `files' that are for directories,
  1131.    and queue them to be listed as directories instead.
  1132.    `dirname' is the prefix to prepend to each dirname
  1133.    to make it correct relative to ls's working dir.
  1134.    `recursive' is nonzero if we should not treat `.' and `..' as dirs.
  1135.    This is desirable when processing directories recursively.  */
  1136.  
  1137. static void
  1138. extract_dirs_from_files (dirname, recursive)
  1139.      char *dirname;
  1140.      int recursive;
  1141. {
  1142.   register int i, j;
  1143.   register char *path;
  1144.   int dirlen;
  1145.  
  1146.   dirlen = strlen (dirname) + 2;
  1147.   /* Queue the directories last one first, because queueing reverses the
  1148.      order.  */
  1149.   for (i = files_index - 1; i >= 0; i--)
  1150.     if ((files[i].filetype == directory || files[i].filetype == arg_directory)
  1151.     && (!recursive || is_not_dot_or_dotdot (files[i].name)))
  1152.       {
  1153.     if (files[i].name[0] == '/' || dirname[0] == 0)
  1154.       {
  1155.         queue_directory (files[i].name, files[i].linkname);
  1156.       }
  1157.     else
  1158.       {
  1159.         path = (char *) xmalloc (strlen (files[i].name) + dirlen);
  1160.         attach (path, dirname, files[i].name);
  1161.         queue_directory (path, files[i].linkname);
  1162.         free (path);
  1163.       }
  1164.     if (files[i].filetype == arg_directory)
  1165.       free (files[i].name);
  1166.       }
  1167.  
  1168.   /* Now delete the directories from the table, compacting all the remaining
  1169.      entries.  */
  1170.  
  1171.   for (i = 0, j = 0; i < files_index; i++)
  1172.     if (files[i].filetype != arg_directory)
  1173.       files[j++] = files[i];
  1174.   files_index = j;
  1175. }
  1176.  
  1177. /* Return non-zero if `name' doesn't end in `.' or `..'
  1178.    This is so we don't try to recurse on `././././. ...' */
  1179.  
  1180. static int
  1181. is_not_dot_or_dotdot (name)
  1182.      char *name;
  1183. {
  1184.   char *t;
  1185.  
  1186.   t = rindex (name, '/');
  1187.   if (t)
  1188.     name = t + 1;
  1189.  
  1190.   if (name[0] == '.'
  1191.       && (name[1] == '\0'
  1192.       || (name[1] == '.' && name[2] == '\0')))
  1193.     return 0;
  1194.  
  1195.   return 1;
  1196. }
  1197.  
  1198. /* Sort the files now in the table.  */
  1199.  
  1200. static void
  1201. sort_files ()
  1202. {
  1203.   int (*func) ();
  1204.  
  1205.   switch (sort_type)
  1206.     {
  1207.     case sort_none:
  1208.       return;
  1209.     case sort_time:
  1210.       switch (time_type)
  1211.     {
  1212.     case time_ctime:
  1213.       func = sort_reverse ? rev_cmp_ctime : compare_ctime;
  1214.       break;
  1215.     case time_mtime:
  1216.       func = sort_reverse ? rev_cmp_mtime : compare_mtime;
  1217.       break;
  1218.     case time_atime:
  1219.       func = sort_reverse ? rev_cmp_atime : compare_atime;
  1220.       break;
  1221.     }
  1222.       break;
  1223.     case sort_name:
  1224.       func = sort_reverse ? rev_cmp_name : compare_name;
  1225.       break;
  1226.     case sort_extension:
  1227.       func = sort_reverse ? rev_cmp_extension : compare_extension;
  1228.       break;
  1229.     case sort_size:
  1230.       func = sort_reverse ? rev_cmp_size : compare_size;
  1231.       break;
  1232.     }
  1233.  
  1234.   qsort (files, files_index, sizeof (struct file), func);
  1235. }
  1236.  
  1237. /* Comparison routines for sorting the files. */
  1238.  
  1239. static int
  1240. compare_ctime (file1, file2)
  1241.      struct file *file1, *file2;
  1242. {
  1243.   return longdiff (file2->stat.st_ctime, file1->stat.st_ctime);
  1244. }
  1245.  
  1246. static int
  1247. rev_cmp_ctime (file2, file1)
  1248.      struct file *file1, *file2;
  1249. {
  1250.   return longdiff (file2->stat.st_ctime, file1->stat.st_ctime);
  1251. }
  1252.  
  1253. static int
  1254. compare_mtime (file1, file2)
  1255.      struct file *file1, *file2;
  1256. {
  1257.   return longdiff (file2->stat.st_mtime, file1->stat.st_mtime);
  1258. }
  1259.  
  1260. static int
  1261. rev_cmp_mtime (file2, file1)
  1262.      struct file *file1, *file2;
  1263. {
  1264.   return longdiff (file2->stat.st_mtime, file1->stat.st_mtime);
  1265. }
  1266.  
  1267. static int
  1268. compare_atime (file1, file2)
  1269.      struct file *file1, *file2;
  1270. {
  1271.   return longdiff (file2->stat.st_atime, file1->stat.st_atime);
  1272. }
  1273.  
  1274. static int
  1275. rev_cmp_atime (file2, file1)
  1276.      struct file *file1, *file2;
  1277. {
  1278.   return longdiff (file2->stat.st_atime, file1->stat.st_atime);
  1279. }
  1280.  
  1281. static int
  1282. compare_size (file1, file2)
  1283.      struct file *file1, *file2;
  1284. {
  1285.   return longdiff (file2->stat.st_size, file1->stat.st_size);
  1286. }
  1287.  
  1288. static int
  1289. rev_cmp_size (file2, file1)
  1290.      struct file *file1, *file2;
  1291. {
  1292.   return longdiff (file2->stat.st_size, file1->stat.st_size);
  1293. }
  1294.  
  1295. static int
  1296. compare_name (file1, file2)
  1297.      struct file *file1, *file2;
  1298. {
  1299.   return strcmp (file1->name, file2->name);
  1300. }
  1301.  
  1302. static int
  1303. rev_cmp_name (file2, file1)
  1304.      struct file *file1, *file2;
  1305. {
  1306.   return strcmp (file1->name, file2->name);
  1307. }
  1308.  
  1309. /* Compare file extensions.  Files with no extension are `smallest'.
  1310.    If extensions are the same, compare by filenames instead. */
  1311.  
  1312. static int
  1313. compare_extension (file1, file2)
  1314.      struct file *file1, *file2;
  1315. {
  1316.   register char *base1, *base2;
  1317.   register int cmp;
  1318.  
  1319.   base1 = rindex (file1->name, '.');
  1320.   base2 = rindex (file2->name, '.');
  1321.   if (base1 == 0 && base2 == 0)
  1322.     return strcmp (file1->name, file2->name);
  1323.   if (base1 == 0)
  1324.     return -1;
  1325.   if (base2 == 0)
  1326.     return 1;
  1327.   cmp = strcmp (base1, base2);
  1328.   if (cmp == 0)
  1329.     return strcmp (file1->name, file2->name);
  1330.   return cmp;
  1331. }
  1332.  
  1333. static int
  1334. rev_cmp_extension (file2, file1)
  1335.      struct file *file1, *file2;
  1336. {
  1337.   register char *base1, *base2;
  1338.   register int cmp;
  1339.  
  1340.   base1 = rindex (file1->name, '.');
  1341.   base2 = rindex (file2->name, '.');
  1342.   if (base1 == 0 && base2 == 0)
  1343.     return strcmp (file1->name, file2->name);
  1344.   if (base1 == 0)
  1345.     return -1;
  1346.   if (base2 == 0)
  1347.     return 1;
  1348.   cmp = strcmp (base1, base2);
  1349.   if (cmp == 0)
  1350.     return strcmp (file1->name, file2->name);
  1351.   return cmp;
  1352. }
  1353.  
  1354. /* List all the files now in the table.  */
  1355.  
  1356. static void
  1357. print_current_files ()
  1358. {
  1359.   register int i;
  1360.  
  1361.   switch (format)
  1362.     {
  1363.     case one_per_line:
  1364.       for (i = 0; i < files_index; i++)
  1365.     {
  1366.       print_file_name_and_frills (files + i);
  1367.       putchar ('\n');
  1368.     }
  1369.       break;
  1370.  
  1371.     case many_per_line:
  1372.       print_many_per_line ();
  1373.       break;
  1374.  
  1375.     case horizontal:
  1376.       print_horizontal ();
  1377.       break;
  1378.  
  1379.     case with_commas:
  1380.       print_with_commas ();
  1381.       break;
  1382.  
  1383.     case long_format:
  1384.       for (i = 0; i < files_index; i++)
  1385.     {
  1386.       print_long_format (files + i);
  1387.       putchar ('\n');
  1388.     }
  1389.       break;
  1390.     }
  1391. }
  1392.  
  1393. static void
  1394. print_long_format (f)
  1395.      struct file *f;
  1396. {
  1397.   char modebuf[20];
  1398.   char timebuf[40];
  1399.   time_t when;
  1400.  
  1401.   mode_string (f->stat.st_mode, modebuf);
  1402.   modebuf[10] = 0;
  1403.  
  1404.   switch (time_type)
  1405.     {
  1406.     case time_ctime:
  1407.       when = f->stat.st_ctime;
  1408.       break;
  1409.     case time_mtime:
  1410.       when = f->stat.st_mtime;
  1411.       break;
  1412.     case time_atime:
  1413.       when = f->stat.st_atime;
  1414.       break;
  1415.     }
  1416.  
  1417.   strcpy (timebuf, ctime (&when));
  1418.  
  1419.   if (full_time)
  1420.     timebuf[24] = '\0';
  1421.   else
  1422.     {
  1423.       if (current_time > when + 6L * 30L * 24L * 60L * 60L /* Old. */
  1424.       || current_time < when - 60L * 60L) /* In the future. */
  1425.     {
  1426.       /* The file is fairly old or in the future.
  1427.          POSIX says the cutoff is 6 months old;
  1428.          approximate this by 6*30 days.
  1429.          Allow a 1 hour slop factor for what is considered "the future",
  1430.          to allow for NFS server/client clock disagreement.
  1431.          Show the year instead of the time of day.  */
  1432.       strcpy (timebuf + 11, timebuf + 19);
  1433.     }
  1434.       timebuf[16] = 0;
  1435.     }
  1436.  
  1437.   if (print_inode)
  1438.     printf ("%6u ", f->stat.st_ino);
  1439.  
  1440.   if (print_block_size)
  1441.     printf ("%*u ", block_size_size,
  1442.         convert_blocks (ST_NBLOCKS (f->stat), kilobyte_blocks));
  1443.  
  1444.   /* The space between the mode and the number of links is the POSIX
  1445.      "optional alternate access method flag". */
  1446.   printf ("%s %3u ", modebuf, f->stat.st_nlink);
  1447.  
  1448.   if (numeric_users)
  1449.     printf ("%-8u ", (unsigned int) f->stat.st_uid);
  1450.   else
  1451.     printf ("%-8.8s ", getuser (f->stat.st_uid));
  1452.  
  1453.   if (!inhibit_group)
  1454.     {
  1455.       if (numeric_users)
  1456.     printf ("%-8u ", (unsigned int) f->stat.st_gid);
  1457.       else
  1458.     printf ("%-8.8s ", getgroup (f->stat.st_gid));
  1459.     }
  1460.  
  1461.   if (S_ISCHR (f->stat.st_mode) || S_ISBLK (f->stat.st_mode))
  1462.     printf ("%3u, %3u ", major (f->stat.st_rdev),
  1463.         minor (f->stat.st_rdev));
  1464.   else
  1465.     printf ("%8lu ", f->stat.st_size);
  1466.  
  1467.   printf ("%s ", full_time ? timebuf : timebuf + 4);
  1468.  
  1469.   print_name_with_quoting (f->name);
  1470.  
  1471.   if (f->filetype == symbolic_link)
  1472.     {
  1473.       if (f->linkname)
  1474.     {
  1475.       fputs (" -> ", stdout);
  1476.       print_name_with_quoting (f->linkname);
  1477.       if (indicator_style != none)
  1478.         print_type_indicator (f->linkmode);
  1479.     }
  1480.     }
  1481.   else if (indicator_style != none)
  1482.     print_type_indicator (f->stat.st_mode);
  1483. }
  1484.  
  1485. static void
  1486. print_name_with_quoting (p)
  1487.      register char *p;
  1488. {
  1489.   register unsigned char c;
  1490.  
  1491.   if (quote_as_string)
  1492.     putchar ('"');
  1493.  
  1494.   while ((c = *p++))
  1495.     {
  1496.       if (quote_funny_chars)
  1497.     {
  1498.       switch (c)
  1499.         {
  1500.         case '\\':
  1501.           printf ("\\\\");
  1502.           break;
  1503.  
  1504.         case '\n':
  1505.           printf ("\\n");
  1506.           break;
  1507.  
  1508.         case '\b':
  1509.           printf ("\\b");
  1510.           break;
  1511.  
  1512.         case '\r':
  1513.           printf ("\\r");
  1514.           break;
  1515.  
  1516.         case '\t':
  1517.           printf ("\\t");
  1518.           break;
  1519.  
  1520.         case '\f':
  1521.           printf ("\\f");
  1522.           break;
  1523.  
  1524.         case ' ':
  1525.           printf ("\\ ");
  1526.           break;
  1527.  
  1528.         case '"':
  1529.           printf ("\\\"");
  1530.           break;
  1531.  
  1532.         default:
  1533.           if (c > 040 && c < 0177)
  1534.         putchar (c);
  1535.           else
  1536.         printf ("\\%03o", (unsigned int) c);
  1537.         }
  1538.     }
  1539.       else
  1540.     {
  1541.       if (c >= 040 && c < 0177)
  1542.         putchar (c);
  1543.       else if (!qmark_funny_chars)
  1544.         putchar (c);
  1545.       else
  1546.         putchar ('?');
  1547.     }
  1548.     }
  1549.  
  1550.   if (quote_as_string)
  1551.     putchar ('"');
  1552. }
  1553.  
  1554. /* Print the file name of `f' with appropriate quoting.
  1555.    Also print file size, inode number, and filetype indicator character,
  1556.    as requested by switches.  */
  1557.  
  1558. static void
  1559. print_file_name_and_frills (f)
  1560.      struct file *f;
  1561. {
  1562.   if (print_inode)
  1563.     printf ("%6u ", f->stat.st_ino);
  1564.  
  1565.   if (print_block_size)
  1566.     printf ("%*u ", block_size_size,
  1567.         convert_blocks (ST_NBLOCKS (f->stat), kilobyte_blocks));
  1568.  
  1569.   print_name_with_quoting (f->name);
  1570.  
  1571.   if (indicator_style != none)
  1572.     print_type_indicator (f->stat.st_mode);
  1573. }
  1574.  
  1575. static void
  1576. print_type_indicator (mode)
  1577.      unsigned int mode;
  1578. {
  1579.   if (S_ISDIR (mode))
  1580.     putchar ('/');
  1581.  
  1582. #ifdef S_ISLNK
  1583.   if (S_ISLNK (mode))
  1584.     putchar ('@');
  1585. #endif
  1586.  
  1587. #ifdef S_ISFIFO
  1588.   if (S_ISFIFO (mode))
  1589.     putchar ('|');
  1590. #endif
  1591.  
  1592. #ifdef S_ISSOCK
  1593.   if (S_ISSOCK (mode))
  1594.     putchar ('=');
  1595. #endif
  1596.  
  1597.   if (S_ISREG (mode) && indicator_style == all
  1598.       && (mode & (S_IEXEC | S_IEXEC >> 3 | S_IEXEC >> 6)))
  1599.     putchar ('*');
  1600. }
  1601.  
  1602. static int
  1603. length_of_file_name_and_frills (f)
  1604.      struct file *f;
  1605. {
  1606.   register char *p = f->name;
  1607.   register char c;
  1608.   register int len = 0;
  1609.  
  1610.   if (print_inode)
  1611.     len += 7;
  1612.  
  1613.   if (print_block_size)
  1614.     len += 1 + block_size_size;
  1615.  
  1616.   if (quote_as_string)
  1617.     len += 2;
  1618.  
  1619.   while ((c = *p++))
  1620.     {
  1621.       if (quote_funny_chars)
  1622.     {
  1623.       switch (c)
  1624.         {
  1625.         case '\\':
  1626.         case '\n':
  1627.         case '\b':
  1628.         case '\r':
  1629.         case '\t':
  1630.         case '\f':
  1631.         case ' ':
  1632.           len += 2;
  1633.           break;
  1634.  
  1635.         case '"':
  1636.           if (quote_as_string)
  1637.         len += 2;
  1638.           else
  1639.         len += 1;
  1640.           break;
  1641.  
  1642.         default:
  1643.           if (c >= 040 && c < 0177)
  1644.         len += 1;
  1645.           else
  1646.         len += 4;
  1647.         }
  1648.     }
  1649.       else
  1650.     len += 1;
  1651.     }
  1652.  
  1653.   if (indicator_style != none)
  1654.     {
  1655.       unsigned filetype = f->stat.st_mode;
  1656.  
  1657.       if (S_ISREG (filetype))
  1658.     {
  1659.       if (indicator_style == all
  1660.           && (f->stat.st_mode & (S_IEXEC | S_IEXEC >> 3 | S_IEXEC >> 6)))
  1661.         len += 1;
  1662.     }
  1663.       else if (S_ISDIR (filetype)
  1664. #ifdef S_ISLNK
  1665.            || S_ISLNK (filetype)
  1666. #endif
  1667. #ifdef S_ISFIFO
  1668.            || S_ISFIFO (filetype)
  1669. #endif
  1670. #ifdef S_ISSOCK
  1671.            || S_ISSOCK (filetype)
  1672. #endif
  1673.            )
  1674.     len += 1;
  1675.     }
  1676.  
  1677.   return len;
  1678. }
  1679.  
  1680. static void
  1681. print_many_per_line ()
  1682. {
  1683.   int filesno;            /* Index into files. */
  1684.   int row;            /* Current row. */
  1685.   int max_name_length;        /* Length of longest file name + frills. */
  1686.   int name_length;        /* Length of each file name + frills. */
  1687.   int pos;            /* Current character column. */
  1688.   int cols;            /* Number of files across. */
  1689.   int rows;            /* Maximum number of files down. */
  1690.  
  1691.   /* Compute the maximum file name length.  */
  1692.   max_name_length = 0;
  1693.   for (filesno = 0; filesno < files_index; filesno++)
  1694.     {
  1695.       name_length = length_of_file_name_and_frills (files + filesno);
  1696.       if (name_length > max_name_length)
  1697.     max_name_length = name_length;
  1698.     }
  1699.  
  1700.   /* Allow at least two spaces between names.  */
  1701.   max_name_length += 2;
  1702.  
  1703.   /* Calculate the maximum number of columns that will fit. */
  1704.   cols = line_length / max_name_length;
  1705.   if (cols == 0)
  1706.     cols = 1;
  1707.   /* Calculate the number of rows that will be in each column except possibly
  1708.      for a short column on the right. */
  1709.   rows = files_index / cols + (files_index % cols != 0);
  1710.   /* Recalculate columns based on rows. */
  1711.   cols = files_index / rows + (files_index % rows != 0);
  1712.  
  1713.   for (row = 0; row < rows; row++)
  1714.     {
  1715.       filesno = row;
  1716.       pos = 0;
  1717.       /* Print the next row.  */
  1718.       while (1)
  1719.     {
  1720.       print_file_name_and_frills (files + filesno);
  1721.       name_length = length_of_file_name_and_frills (files + filesno);
  1722.  
  1723.       filesno += rows;
  1724.       if (filesno >= files_index)
  1725.         break;
  1726.  
  1727.       indent (pos + name_length, pos + max_name_length);
  1728.       pos += max_name_length;
  1729.     }
  1730.       putchar ('\n');
  1731.     }
  1732. }
  1733.  
  1734. static void
  1735. print_horizontal ()
  1736. {
  1737.   int filesno;
  1738.   int max_name_length;
  1739.   int name_length;
  1740.   int cols;
  1741.   int pos;
  1742.  
  1743.   /* Compute the maximum file name length.  */
  1744.   max_name_length = 0;
  1745.   for (filesno = 0; filesno < files_index; filesno++)
  1746.     {
  1747.       name_length = length_of_file_name_and_frills (files + filesno);
  1748.       if (name_length > max_name_length)
  1749.     max_name_length = name_length;
  1750.     }
  1751.  
  1752.   /* Allow two spaces between names.  */
  1753.   max_name_length += 2;
  1754.  
  1755.   cols = line_length / max_name_length;
  1756.   if (cols == 0)
  1757.     cols = 1;
  1758.  
  1759.   pos = 0;
  1760.   name_length = 0;
  1761.  
  1762.   for (filesno = 0; filesno < files_index; filesno++)
  1763.     {
  1764.       if (filesno != 0)
  1765.     {
  1766.       if (filesno % cols == 0)
  1767.         {
  1768.           putchar ('\n');
  1769.           pos = 0;
  1770.         }
  1771.       else
  1772.         {
  1773.           indent (pos + name_length, pos + max_name_length);
  1774.           pos += max_name_length;
  1775.         }
  1776.     }
  1777.  
  1778.       print_file_name_and_frills (files + filesno);
  1779.  
  1780.       name_length = length_of_file_name_and_frills (files + filesno);
  1781.     }
  1782.   putchar ('\n');
  1783. }
  1784.  
  1785. static void
  1786. print_with_commas ()
  1787. {
  1788.   int filesno;
  1789.   int pos, old_pos;
  1790.  
  1791.   pos = 0;
  1792.  
  1793.   for (filesno = 0; filesno < files_index; filesno++)
  1794.     {
  1795.       old_pos = pos;
  1796.  
  1797.       pos += length_of_file_name_and_frills (files + filesno);
  1798.       if (filesno + 1 < files_index)
  1799.     pos += 2;        /* For the comma and space */
  1800.  
  1801.       if (old_pos != 0 && pos >= line_length)
  1802.     {
  1803.       putchar ('\n');
  1804.       pos -= old_pos;
  1805.     }
  1806.  
  1807.       print_file_name_and_frills (files + filesno);
  1808.       if (filesno + 1 < files_index)
  1809.     {
  1810.       putchar (',');
  1811.       putchar (' ');
  1812.     }
  1813.     }
  1814.   putchar ('\n');
  1815. }
  1816.  
  1817. /* Assuming cursor is at position FROM, indent up to position TO.  */
  1818.  
  1819. static void
  1820. indent (from, to)
  1821.      int from, to;
  1822. {
  1823.   while (from < to)
  1824.     {
  1825.       if (to / tabsize > from / tabsize)
  1826.     {
  1827.       putchar ('\t');
  1828.       from += tabsize - from % tabsize;
  1829.     }
  1830.       else
  1831.     {
  1832.       putchar (' ');
  1833.       from++;
  1834.     }
  1835.     }
  1836. }
  1837.  
  1838. /* Put DIRNAME/NAME into DEST, handling `.' and `/' properly. */
  1839.  
  1840. static void
  1841. attach (dest, dirname, name)
  1842.      char *dest, *dirname, *name;
  1843. {
  1844.   char *dirnamep = dirname;
  1845.  
  1846.   /* Copy dirname if it is not ".". */
  1847.   if (dirname[0] != '.' || dirname[1] != 0)
  1848.     {
  1849.       while (*dirnamep)
  1850.     *dest++ = *dirnamep++;
  1851.       /* Add '/' if `dirname' doesn't already end with it. */
  1852.       if (dirnamep > dirname && dirnamep[-1] != '/')
  1853.     *dest++ = '/';
  1854.     }
  1855.   while (*name)
  1856.     *dest++ = *name++;
  1857.   *dest = 0;
  1858. }
  1859.  
  1860. static void
  1861. usage ()
  1862. {
  1863.   fprintf (stderr, "\
  1864. Usage: %s [-abcdgiklmnpqrstuxABCFGLNQRSUX1] [-w cols] [-T cols] [-I pattern]\n\
  1865.        [--all] [--escape] [--directory] [--inode] [--kilobytes] [--literal]\n\
  1866.        [--numeric-uid-gid] [--hide-control-chars] [--reverse] [--size]\n\
  1867.        [--width=cols] [--tabsize=cols] [--almost-all] [--ignore-backups]\n",
  1868.        program_name);
  1869.   fprintf (stderr, "\
  1870.        [--classify] [--file-type] [--ignore=pattern] [--dereference]\n\
  1871.        [--quote-name] [--recursive] [--sort={none,time,size,extension}]\n\
  1872.        [--format={long,verbose,commas,across,vertical,single-column}]\n\
  1873.        [--time={atime,access,use,ctime,status}] [--no-group]\n\
  1874.        [--help] [--version] [path...]\n");
  1875.   exit (1);
  1876. }
  1877.