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