home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume14 / lc / part01 / lc.c next >
Encoding:
C/C++ Source or Header  |  1990-09-15  |  35.0 KB  |  1,516 lines

  1. /*
  2. ** This software is 
  3. **
  4. ** Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 by Kent Landfield.
  5. **
  6. ** Permission is hereby granted to copy, distribute or otherwise 
  7. ** use any part of this package as long as you do not try to make 
  8. ** money from it or pretend that you wrote it.  This copyright 
  9. ** notice must be maintained in any copy made.
  10. **
  11. ** Use of this software constitutes acceptance for use in an AS IS 
  12. ** condition. There are NO warranties with regard to this software.  
  13. ** In no event shall the author be liable for any damages whatsoever 
  14. ** arising out of or in connection with the use or performance of this 
  15. ** software.  Any use of this software is at the user's own risk.
  16. **
  17. **  If you make modifications to this software that you feel 
  18. **  increases it usefulness for the rest of the community, please 
  19. **  email the changes, enhancements, bug fixes as well as any and 
  20. **  all ideas to me. Thanks!
  21. **
  22. **              Kent Landfield
  23. **              kent@sparky.IMD.Sterling.COM
  24. **              sparky!kent
  25. **
  26. **  Subsystem:   lc - List Columnwise/Categories
  27. **
  28. **  Abstract :   lc -- categorize files in a directory and list columnwize
  29. **
  30. **  Usage:       lc [ options ] [ directory ... ]
  31. **
  32. **  Options:
  33. **               -a      List dot files as well.
  34. **               -b      List block special files only
  35. **               -c      List character special files only
  36. **               -d      List directories only
  37. **               -D      Do not display singular files
  38. **               -e      Mark executable files with '*'
  39. **               -f      List regular files only
  40. **               -F      List fifo files only
  41. **               -1      List files one per line instead of in columns
  42. **               -r      Do not sort the filenames before displaying.
  43. **               -m      List shared memory name space entry files only
  44. **               -M      List semaphore name space entry files only
  45. **               -S      List socket file only
  46. **               -s      List symbolic links only
  47. **               -L      Display symbolic links
  48. **               -l      Mark symbolic links with '@'
  49. **               -I      Suppress unresolved symbolic link messages.
  50. **
  51. ** The "only" options can not be combined.
  52. ** If there is no 'directory' specified, the current directory is used.
  53. ** Not all options are supported on every system. (e.g. no symbolic links
  54. ** on your system ? Options -s, -L or -l won't be available..)
  55. **
  56. **  History:
  57. **      Initially designed on an IBM-XT running Coherent in 1984.
  58. **      Ported to XENIX on an IBM-AT in 1984.
  59. **      Ported to System V on AT&T 3Bs in 1985.
  60. **      Ported to DEC Vax 11/750 running System V in 1986.
  61. **      Ported to BSD4.2 on a Sequent Balance 8000 in 1986.
  62. **      Jeff Minnig added the initial support for links. 
  63. **      Ported to SunOS 4.0 on a Sun 3/60 in 1988.
  64. **      Rick Ohnemus did major surgery to remove static storage
  65. **      and *greatly* enhanced the link support. Thanks rick!
  66. **      Tested with Ultrix 3.0 & 3.1 on a DECstation 3100 in 1989.
  67. **      Tested with Ultrix 3.0 & 3.1 on a VAXstation 3500 in 1989.
  68. **      Tested with UTek on a Tektronix 4319 in 1989.
  69. **      Tested with IRIX System V on a Silicon Graphics Iris 4D/210GTX in 1989.
  70. **      Tested with AmigaDOS 1.3 on an Amiga 1000 in 1989.
  71. **      Tested with SunOS 4.0.3 on a Sparkstation 1 in 1989.
  72. **      Tested with AIX 3.+ on a Risc System/6000 in 1990. 
  73. **                                                               
  74. */
  75. #ifndef lint
  76. static char *sccsid = "@(#)lc.c    1.23 9/7/90  Kent Landfield";
  77. #endif
  78.  
  79. #include <stdio.h>
  80. #ifdef BSD
  81. #  include <strings.h>
  82. #  include <sys/param.h>
  83. #else
  84. #  include <string.h>
  85. #  include <sys/types.h>
  86. #endif
  87. #include <sys/stat.h>
  88. #ifdef POSIX
  89. #  include <limits.h>
  90. #  include <dirent.h>
  91. #else
  92. #  ifdef BSD
  93. #    ifdef DIRECT
  94. #      include <sys/dir.h>
  95. #    else
  96. #      include <dirent.h>
  97. #    endif
  98. #  else
  99. #    include <sys/dir.h>
  100. #  endif
  101. #endif
  102.  
  103. #ifndef NAME_MAX
  104. #  ifdef BSD
  105. #    define NAME_MAX    MAXNAMLEN
  106. #  else
  107. #    ifdef DIRSIZ
  108. #      define NAME_MAX  DIRSIZ
  109. #    else
  110. #      define NAME_MAX  14
  111. #    endif
  112. #  endif
  113. #endif
  114.  
  115. #ifndef PATH_MAX
  116. #  ifdef MAXPATHLEN
  117. #    define PATH_MAX    MAXPATHLEN
  118. #  else
  119. #    ifdef MAXNAMLEN
  120. #      define PATH_MAX  MAXNAMLEN
  121. #    else
  122. #      define PATH_MAX  255
  123. #    endif
  124. #  endif
  125. #endif
  126.  
  127. #define BUFSIZE         PATH_MAX
  128.  
  129. #define NODES_PER_HUNK  256
  130.  
  131. #define TRUE            1
  132. #define FALSE           0
  133.  
  134. #ifndef S_IXUSR
  135. #  define S_IXUSR       S_IEXEC
  136. #endif
  137.  
  138. #ifndef S_IXGRP
  139. #  define S_IXGRP       (S_IEXEC >> 3)
  140. #endif
  141.  
  142. #ifndef S_IXOTH
  143. #  define S_IXOTH       (S_IEXEC >> 6)
  144. #endif
  145.  
  146. #define DIR_ONLY        1
  147. #define FILE_ONLY       2
  148. #ifdef S_IFCHR
  149. #  define CHAR_ONLY     3
  150. #endif
  151. #ifdef S_IFBLK
  152. #  define BLOCK_ONLY    4
  153. #endif
  154. #ifdef S_IFIFO
  155. #  define FIFO_ONLY     5
  156. #endif
  157. #ifdef S_IFLNK
  158. #  define LNK_ONLY      6
  159. #endif
  160. #ifdef S_IFSOCK
  161. #  define SOCK_ONLY     7
  162. #endif
  163. #ifdef S_IFNAM
  164. #  define SEM_ONLY      8
  165. #  define SD_ONLY       9
  166. #endif
  167.  
  168. #ifdef BSD
  169. #  define strrchr       rindex
  170. #  define strchr        index
  171. #endif
  172.  
  173.  
  174. struct list {
  175.     int num;
  176.     int max;
  177.     char **names;
  178. #ifdef LENS
  179.     int maxlen;
  180. #endif
  181. };
  182.  
  183. #ifdef LENS
  184.  
  185. #ifdef S_IFBLK
  186. struct list Blks = { 0, 0, (char **) NULL, 0 };
  187. #endif
  188.  
  189. #ifdef S_IFCHR
  190. struct list Chrs = { 0, 0, (char **) NULL, 0 };
  191. #endif
  192.  
  193. struct list Dirs = { 0, 0, (char **) NULL, 0 };
  194. struct list Fls = { 0, 0, (char **) NULL, 0 };
  195.  
  196. #ifdef S_IFIFO
  197. struct list Fifos = { 0, 0, (char **) NULL, 0 };
  198. #endif
  199.  
  200. #ifdef S_IFLNK
  201. struct list Lnks = { 0, 0, (char **) NULL, 0 };
  202. struct list Lnksn = { 0, 0, (char **) NULL, 0 };
  203. #endif
  204.  
  205. #ifdef S_IFSOCK
  206. struct list Socks = { 0, 0, (char **) NULL, 0 };
  207. #endif
  208.  
  209. #ifdef S_IFNAM
  210. struct list Sds = { 0, 0, (char **) NULL, 0 };
  211. struct list Sems = { 0, 0, (char **) NULL, 0 };
  212. #endif
  213.  
  214. #else   /* ifndef LENS */
  215.  
  216. #ifdef S_IFBLK
  217. struct list Blks = { 0, 0, (char **) NULL };
  218. #endif
  219.  
  220. #ifdef S_IFCHR
  221. struct list Chrs = { 0, 0, (char **) NULL };
  222. #endif
  223.  
  224. struct list Dirs = { 0, 0, (char **) NULL };
  225. struct list Fls = { 0, 0, (char **) NULL };
  226.  
  227. #ifdef S_IFIFO
  228. struct list Fifos = { 0, 0, (char **) NULL };
  229. #endif
  230.  
  231. #ifdef S_IFLNK
  232. struct list Lnks = { 0, 0, (char **) NULL };
  233. struct list Lnksn = { 0, 0, (char **) NULL };
  234. #endif
  235.  
  236. #ifdef S_IFSOCK
  237. struct list Socks = { 0, 0, (char **) NULL };
  238. #endif
  239.  
  240. #ifdef S_IFNAM
  241. struct list Sds = { 0, 0, (char **) NULL };
  242. struct list Sems = { 0, 0, (char **) NULL };
  243. #endif
  244.  
  245. #endif /* LENS */
  246.  
  247. char *Progname;
  248.  
  249. int Allfiles = FALSE;
  250. int Display_single = TRUE;
  251. int Executables = FALSE;
  252. int Ignore = FALSE;
  253. int Level = 0;
  254. int Maxlen = 0;
  255. int Only = FALSE;
  256. int Screen_width = 80;
  257. int Single = FALSE;
  258. int Sort_wanted = TRUE;
  259.  
  260. #ifdef S_IFLNK
  261. int Current = 0;
  262. int Disp_links = FALSE;
  263. int Mark_links = FALSE;
  264. int lstat();
  265. int readlink();
  266. #endif
  267.  
  268. #ifndef _BSD
  269. # ifdef BSD
  270.     extern char *sprintf();
  271.     extern int  exit();
  272.     extern int  free();
  273.     extern int  qsort();
  274. # else
  275.     extern int  sprintf();
  276.     extern void exit();
  277.     extern void free();
  278.     extern void qsort();
  279. # endif
  280.  extern int fprintf();
  281.  extern int printf();
  282.  extern int sscanf();
  283. #endif
  284.  
  285. void lc();
  286.  
  287. extern char *getenv();
  288. extern char *malloc();
  289. extern char *realloc();
  290. extern int access();
  291. extern int fputs();
  292. extern int puts();
  293. extern int stat();
  294.  
  295. /* S T R _ S A V  
  296.  *
  297.  *   str_sav() returns a pointer to a new string which is a dupli-
  298.  *   cate  of the string pointed to by s.  The space for the new
  299.  *   string is obtained using malloc(3).  If the new string  can-
  300.  *   not be created, the process prints an error message on stderr
  301.  *   and terminates.
  302.  */
  303.  
  304. char *str_sav(s)
  305.     char *s;
  306. {
  307.     char *p;
  308.  
  309.     if ((p = malloc((unsigned)(strlen(s) + 1))) == (char *) NULL) {
  310.         (void) fprintf(stderr, "%s: malloc: out of memory\n", Progname);
  311.         exit(1);
  312.     }
  313.     (void) strcpy(p, s);
  314.     return (p);
  315. }
  316.  
  317. /* D I R E C T O R Y
  318.  *
  319.  *  directory() is used to open and read the directory and pass
  320.  *  the filenames found to the routine lc();
  321.  */
  322. #if (POSIX || BSD)
  323. void directory(dname)
  324.     char *dname;
  325. {
  326.     register char *nbp;
  327.     register char *nep;
  328.     DIR *dstream;
  329.     int i;
  330. #ifdef DIRECT
  331.     struct direct *dp;
  332. #else
  333.     struct dirent *dp;
  334. #endif
  335.  
  336.     /* add a slash to the end of the directory name */
  337.     nbp = dname + strlen(dname);
  338. #ifdef AMIGA
  339.     if (*(nbp - 1) != ':') {
  340.         *nbp++ = '/';
  341.         *nbp = '\0';
  342.     }
  343. #else
  344.     *nbp++ = '/';
  345.     *nbp = '\0';
  346. #endif
  347.  
  348.     if ((dstream = opendir(dname)) == NULL) {
  349.         (void) fprintf(stderr, "%s: can't open %s\n", Progname, dname);
  350.         return;
  351.     }
  352.  
  353.     while ((dp = readdir(dstream)) != NULL) {
  354.         if (strcmp(dp->d_name, ".") == 0
  355.             || strcmp(dp->d_name, "..") == 0
  356.             || (!Allfiles && *(dp->d_name) == '.'))
  357.             continue;
  358.  
  359.         for (i = 0, nep = nbp; dp->d_name[i] && i < NAME_MAX; i++)
  360.             *nep++ = dp->d_name[i];
  361.         *nep++ = '\0';
  362.         lc(dname, 2);
  363.     }
  364.     (void) closedir(dstream);
  365.     *--nbp = '\0';
  366.     return;
  367. }
  368.  
  369. #else /* not POSIX or BSD */
  370.  
  371. /* D I R E C T O R Y
  372.  *
  373.  *  directory() is used to open and read the directory and pass
  374.  *  the filenames found to the routine lc();
  375.  */
  376. void directory(dname)
  377.     char *dname;
  378. {
  379.     register char *nbp;
  380.     register char *nep;
  381.     FILE *fd;
  382.     int i;
  383.     struct direct dir;
  384.  
  385.     /* add a slash to the end of the directory name */
  386.     nbp = dname + strlen(dname);
  387.     *nbp++ = '/';
  388.     *nbp = '\0';
  389.  
  390.     if ((nbp + NAME_MAX + 2) >= (dname + BUFSIZE))  { /* dname too long */
  391.         (void) fprintf(stderr, "%s: dirname too long: %s\n",
  392.                        Progname, dname);
  393.         return;
  394.     }
  395.  
  396.     if ((fd = fopen(dname, "r")) == (FILE *) NULL) { /* open the directory */
  397.         (void) fprintf(stderr, "%s: can't open %s\n", Progname, dname);
  398.         return;
  399.     }
  400.  
  401.     while (fread((char *) &dir, sizeof(dir), 1, fd) > 0) {
  402.         if (dir.d_ino == 0
  403.             || strcmp(dir.d_name, ".") == 0
  404.             || strcmp(dir.d_name, "..") == 0)
  405.             continue;
  406.         for (i = 0, nep = nbp; i < NAME_MAX; i++)
  407.             *nep++ = dir.d_name[i];
  408.         *nep++ = '\0';
  409.         lc(dname, 2);
  410.     }
  411.     (void) fclose(fd);
  412.     *--nbp = '\0';     /* restore dname */
  413.     return;
  414. }
  415. #endif
  416.  
  417. /* G E T L I N K
  418.  *
  419.  *  getlink() calls readlink() which places the contents of the 
  420.  *  symbolic link referred to by fn in the buffer wk. The contents 
  421.  *  of the link are null terminated and the path is returned to
  422.  *  the calling funtion as a pointer to a storage area created
  423.  *  by using malloc(3);
  424.  */
  425.  
  426. #ifdef S_IFLNK
  427. char *getlink(fn)
  428.     char *fn;
  429. {
  430.     char wk[PATH_MAX + 1];
  431.     int rc;
  432.  
  433.     rc = readlink(fn, wk, sizeof(wk));
  434.     if (rc < 0)
  435.         return ((char *) NULL);
  436.     wk[rc] = '\0';
  437.     return (str_sav(wk));
  438. }
  439. #endif
  440.  
  441. /* P R I N T _ L I N E 
  442.  *
  443.  *  print_line() is used to format and output the files previously 
  444.  *  located. This routine could use a lot more smarts but currently
  445.  *  it is rather crude...
  446.  */
  447.  
  448. int print_line(files, ind)
  449.     struct list *files;
  450.     int ind;
  451. {
  452.     register char *frmt;
  453.     char out_str[PATH_MAX + 3];
  454.     int i;
  455.     int prt_limit;
  456.  
  457.     if (Single) {
  458. #ifdef S_IFLNK
  459.         if (Current == LNK_ONLY) {
  460.             if (*(Lnksn.names + ind) != (char *) NULL)
  461.                 (void) printf("    %s -> %s\n",
  462.                               *(Lnks.names + ind), *(Lnksn.names + ind));
  463.             else
  464.                 (void) printf("    %s -> %s\n",
  465.                               *(Lnks.names + ind), "UNRESOLVED");
  466.             ind++;
  467.             return (ind);
  468.         }
  469. #endif
  470.         (void) puts(*(files->names + ind));
  471.         ind++;
  472.     }
  473.     else if (Maxlen > ((Screen_width - 4) / 2)) {
  474.         (void) printf("    %s\n", *(files->names + ind));
  475.         ind++;
  476.     }
  477.     else {
  478.          frmt = out_str;
  479.          for (i = 0; i < 4; i++)
  480.               *frmt++ = ' ';
  481.  
  482.         /* The prt_limit may need to be smarter */
  483.  
  484.          prt_limit = (Screen_width - 4) / (Maxlen + 1);
  485.          if (Maxlen == 3 || Maxlen == 1)
  486.              prt_limit--;
  487.  
  488.          while ((ind < files->num) && (prt_limit-- > 0)) {
  489.               i = 0;
  490.               do {
  491.                    if (*(*(files->names + ind) + i) == '\0') {
  492.                        while (i++ <= Maxlen)
  493.                              *frmt++ = ' ';
  494.                    }
  495.                    else
  496.                        *frmt++ = *(*(files->names + ind) + i);
  497.                    i++;
  498.               } while (i <= Maxlen);
  499.               ind++;
  500.          }
  501.          *frmt = '\0';
  502.          (void) puts(out_str);
  503.     }
  504.     return (ind);
  505. }
  506.  
  507. /* S T R _ C M P
  508.  *
  509.  *  str_cmp is the comparison routine used by
  510.  *  qsort(3) to order the filenames inplace.
  511.  */
  512.  
  513. int str_cmp(s1, s2)
  514.     char **s1;
  515.     char **s2;
  516. {
  517.     return strcmp(*s1, *s2);
  518. }
  519.  
  520. /* P R _ I N F O
  521.  *
  522.  *  pr_info() is used to sort the data if required
  523.  *  and then pass it to print_line to actually output
  524.  *  the data.`
  525.  */
  526.  
  527. int pr_info(strng, files, flg, sort_needed)
  528.     char *strng;
  529.     struct list *files;
  530.     int flg;
  531.     int sort_needed;
  532. {
  533.     int pnum = 0;
  534.  
  535. #ifdef LENS
  536.     Maxlen = files->maxlen;
  537. #endif
  538.  
  539. #ifdef S_IFLNK
  540.     if (!Single || Current == LNK_ONLY) {
  541.         if (flg)
  542.             (void) puts("");
  543.         (void) puts(strng);
  544.     }
  545. #else
  546.     if (!Single) {
  547.         if (flg)
  548.             (void) puts("");
  549.         (void) puts(strng);
  550.     }
  551. #endif
  552.  
  553.     if (sort_needed)
  554.         qsort((char *) (files->names), files->num,
  555.               sizeof(char *), str_cmp);
  556.  
  557.     do {
  558.         pnum = print_line(files, pnum);
  559.     } while (pnum < files->num);
  560.  
  561.     return (1);
  562. }
  563.  
  564. /* P R I N T _ I N F O
  565.  *
  566.  *  print_info() is called to display all the filenames
  567.  *  located in the directory reading and storage functions.
  568.  */
  569.  
  570. void print_info()
  571. {
  572.     int flag = 0;
  573.  
  574. #ifdef S_IFLNK
  575.     int ssing;
  576.  
  577.     Current = 0;
  578.  
  579.     if (Lnks.num > 0 && (Disp_links == TRUE || Only == LNK_ONLY)) {
  580.         ssing = Single;
  581.         Single = TRUE;
  582.         Current = LNK_ONLY;
  583.         flag = pr_info("Symbolic Links: ", &Lnks, flag, 0);
  584.         Single = ssing;
  585.     }
  586. #endif
  587.  
  588. #ifdef S_IFSOCK
  589.     if (Socks.num > 0 && (Only == 0 || Only == SOCK_ONLY))
  590.         flag = pr_info("Sockets: ", &Socks, flag, Sort_wanted);
  591. #endif
  592.  
  593. #ifdef S_IFNAM
  594.     if (Sems.num > 0 && (Only == 0 || Only == SEM_ONLY))
  595.         flag = pr_info("Semaphore Files: ", &Sems, flag, Sort_wanted);
  596.  
  597.     if (Sds.num > 0 && (Only == 0 || Only == SD_ONLY))
  598.         flag = pr_info("Shared Data Files: ", &Sds, flag, Sort_wanted);
  599. #endif
  600.  
  601. #ifdef S_IFIFO
  602.     if (Fifos.num > 0 && (Only == 0 || Only == FIFO_ONLY))
  603.         flag = pr_info("Fifo Files: ", &Fifos, flag, Sort_wanted);
  604. #endif
  605.  
  606. #ifdef S_IFCHR
  607.     if (Chrs.num > 0 && (Only == 0 || Only == CHAR_ONLY))
  608.         flag = pr_info("Character Special Files: ", &Chrs, flag, Sort_wanted);
  609. #endif
  610.  
  611. #ifdef S_IFBLK
  612.     if (Blks.num > 0 && (Only == 0 || Only == BLOCK_ONLY))
  613.         flag = pr_info("Block Special Files: ", &Blks, flag, Sort_wanted);
  614. #endif
  615.  
  616.     if (Dirs.num > 0 && (Only == 0 || Only == DIR_ONLY))
  617.         flag = pr_info("Directories: ", &Dirs, flag, Sort_wanted);
  618.  
  619.     if (Fls.num > 0 && (Only == 0 || Only == FILE_ONLY))
  620.         flag = pr_info("Files: ", &Fls, flag, Sort_wanted);
  621.  
  622.     return;
  623. }
  624.  
  625. /* B A S E N A M E
  626.  *
  627.  *  basename() is used to return the base file name of a
  628.  *  path refered to by name. The base file name is stored
  629.  *  into a storage location refered to by str. It is the
  630.  *  calling function's responsibility to assure adequate
  631.  *  storage is supplied.
  632.  */
  633.  
  634. void basename(name, str)
  635.     char *name;
  636.     char *str;
  637. {
  638.     char *p;
  639.  
  640.     if ((p = strrchr(name, '/')) == (char *) NULL) {
  641. #ifdef AMIGA
  642.         if ((p = strchr(name, ':')) == (char *) NULL)
  643.             (void) strcpy(str, name);
  644.         else
  645.             (void) strcpy(str, ++p);
  646. #else
  647.         (void) strcpy(str, name);
  648. #endif
  649.     }
  650.     else
  651.         (void) strcpy(str, ++p);
  652.     return;
  653. }
  654.  
  655. /* A D D _ T O _ L I S T
  656.  *
  657.  * add_to_list() is used to add the supplied filename refered to
  658.  * by str to the appropriate category storage array.
  659.  */
  660.  
  661. void add_to_list(files, str)
  662.     struct list *files;
  663.     char *str;
  664. {
  665.     if (files->max == 0) {
  666.         files->names = (char **) malloc(sizeof(char *) * NODES_PER_HUNK);
  667.         if (files->names == (char **) NULL) {
  668.             (void) fprintf(stderr,
  669.                            "%s: malloc: out of memory\n", Progname);
  670.             exit(1);
  671.         }
  672.         files->max = NODES_PER_HUNK;
  673.     }
  674.     else if (files->num == files->max) {
  675.         files->names =
  676.             (char **) realloc((char *) files->names,
  677.                               (unsigned) sizeof(char *)
  678.                               * (files->max + NODES_PER_HUNK));
  679.         if (files->names == (char **) NULL) {
  680.             (void) fprintf(stderr,
  681.                            "%s: realloc: out of memory\n", Progname);
  682.             exit(1);
  683.         }
  684.         files->max += NODES_PER_HUNK;
  685.     }
  686.     if (str == (char *) NULL)
  687.         *(files->names + files->num++) = (char *) NULL;
  688.     else
  689.         *(files->names + files->num++) = str_sav(str);
  690.     return;
  691. }
  692.  
  693. /* L C
  694.  *
  695.  * lc() is main function for determining the type of
  696.  * the file refered to by name.
  697.  */
  698.  
  699. void lc(name, cnt)
  700.     char *name;
  701.     int cnt;
  702. {
  703. #ifdef S_IFLNK
  704.     char *link;
  705. #endif
  706.     char sav_str[BUFSIZE + 2];
  707.     int mlen;
  708.     struct stat sbuf;
  709.  
  710. #ifdef S_IFLNK
  711.     if (lstat(name, &sbuf) < 0) {
  712.         (void) fprintf(stderr, "%s: can't stat %s\n", Progname, name);
  713.         return;
  714.     }
  715. #else
  716.     if (stat(name, &sbuf) == -1) {
  717.         (void) fprintf(stderr, "%s: can't stat %s\n", Progname, name);
  718.         return;
  719.     }
  720. #endif
  721.  
  722.     basename(name, sav_str);
  723.     mlen = strlen(sav_str);
  724.  
  725. #ifndef LENS
  726.     if (mlen > Maxlen)
  727.         Maxlen = mlen;
  728. #endif
  729.  
  730.     switch (sbuf.st_mode & S_IFMT) {
  731.  
  732.     case S_IFDIR:
  733.         if (!Allfiles && sav_str[0] == '.' && Level != 0)
  734.             break;
  735.         if (cnt != 1)        /* dont store the dir name on entry */
  736.             add_to_list(&Dirs, sav_str);
  737.         /* never called - left for expansion to recursive     */
  738.         /* searches of subdirectories. Right, re-write needed */
  739.         /* in output facilities first...                      */
  740.         if (Level++ == 0)
  741.             directory(name);
  742. #ifdef LENS
  743.         if (mlen > Dirs.maxlen)
  744.             Dirs.maxlen = mlen;
  745. #endif
  746.         break;
  747.  
  748.     case S_IFREG:
  749.         /* do not print .files unless enviromental variable */
  750.         /* or option set.                                   */
  751.         if (!Allfiles && sav_str[0] == '.')
  752.             break;
  753.         if (Executables
  754.             && (sbuf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) {
  755.             *(sav_str + mlen) = '*';
  756.             ++mlen;
  757.             *(sav_str + mlen) = '\0';
  758. #ifndef LENS
  759.             if (mlen > Maxlen)
  760.                 Maxlen = mlen;
  761. #endif
  762.         }
  763.         add_to_list(&Fls, sav_str);
  764. #ifdef LENS
  765.         if (mlen > Fls.maxlen)
  766.             Fls.maxlen = mlen;
  767. #endif
  768.         break;
  769.  
  770. #ifdef S_IFCHR
  771.     case S_IFCHR:
  772.         if (!Allfiles && sav_str[0] == '.')
  773.             break;
  774.         add_to_list(&Chrs, sav_str);
  775. #ifdef LENS
  776.         if (mlen > Chrs.maxlen)
  777.             Chrs.maxlen = mlen;
  778. #endif
  779.         break;
  780. #endif
  781.  
  782. #ifdef S_IFBLK
  783.     case S_IFBLK:
  784.         if (!Allfiles && sav_str[0] == '.')
  785.             break;
  786.         add_to_list(&Blks, sav_str);
  787. #ifdef LENS
  788.         if (mlen > Blks.maxlen)
  789.             Blks.maxlen = mlen;
  790. #endif
  791.         break;
  792. #endif
  793.  
  794. #ifdef S_IFIFO
  795.     case S_IFIFO:
  796.         if (!Allfiles && sav_str[0] == '.')
  797.             break;
  798.         add_to_list(&Fifos, sav_str);
  799. #ifdef LENS
  800.         if (mlen > Fifos.maxlen)
  801.             Fifos.maxlen = mlen;
  802. #endif
  803.         break;
  804. #endif
  805.  
  806. #ifdef S_IFLNK
  807.     case S_IFLNK:
  808.         if (!Allfiles && sav_str[0] == '.')
  809.             break;
  810.         add_to_list(&Lnks, sav_str);
  811.         link = getlink(name);
  812.         add_to_list(&Lnksn, link);
  813.         if (link != (char *) NULL)
  814.             free(link);
  815. #ifdef LENS
  816.         if (mlen > Lnks.maxlen)
  817.             Lnks.maxlen = mlen;
  818. #endif
  819.         if (stat(name, &sbuf) < 0) {
  820.             if (!Ignore) 
  821.                 (void) fprintf(stderr,
  822.                                "%s: %s: can't resolve symbolic link\n",
  823.                                Progname, name);
  824.         }
  825.         else {
  826.             if (Mark_links) {
  827.                 *(sav_str + mlen) = '@';
  828.                 ++mlen;
  829.                 *(sav_str + mlen) = '\0';
  830. #ifndef LENS
  831.                 if (mlen > Maxlen)
  832.                     Maxlen = mlen;
  833. #endif
  834.             }
  835.  
  836.             switch (sbuf.st_mode & S_IFMT) {
  837.  
  838.             case S_IFDIR:
  839.                 if (cnt != 1)        /*dont store the dir name on entry */
  840.                     add_to_list(&Dirs, sav_str);
  841.                 /* never called - left for expansion to recursive */
  842.                 /* searches of subdirectories                     */
  843.                 if (Level++ == 0)
  844.                     directory(name);
  845. #ifdef LENS
  846.                 if (mlen > Dirs.maxlen)
  847.                     Dirs.maxlen = mlen;
  848. #endif
  849.                 break;
  850.  
  851.             case S_IFREG:
  852.                 if (Executables
  853.                     && (sbuf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) {
  854.                     *(sav_str + mlen) = '*';
  855.                     ++mlen;
  856.                     *(sav_str + mlen) = '\0';
  857. #ifndef LENS
  858.                     if (mlen > Maxlen)
  859.                         Maxlen = mlen;
  860. #endif
  861.                 }
  862.                 add_to_list(&Fls, sav_str);
  863. #ifdef LENS
  864.                 if (mlen > Fls.maxlen)
  865.                     Fls.maxlen = mlen;
  866. #endif
  867.                 break;
  868.  
  869. #ifdef S_IFCHR
  870.             case S_IFCHR:
  871.                 add_to_list(&Chrs, sav_str);
  872. #ifdef LENS
  873.                 if (mlen > Chrs.maxlen)
  874.                     Chrs.maxlen = mlen;
  875. #endif
  876.                 break;
  877. #endif
  878.  
  879. #ifdef S_IFBLK
  880.             case S_IFBLK:
  881.                 add_to_list(&Blks, sav_str);
  882. #ifdef LENS
  883.                 if (mlen > Blks.maxlen)
  884.                     Blks.maxlen = mlen;
  885. #endif
  886.                 break;
  887. #endif
  888.  
  889. #ifdef S_IFIFO
  890.             case S_IFIFO:
  891.                 add_to_list(&Fifos, sav_str);
  892. #ifdef LENS
  893.                 if (mlen > Fifos.maxlen)
  894.                     Fifos.maxlen = mlen;
  895. #endif
  896.                 break;
  897. #endif
  898.  
  899. #ifdef S_IFSOCK
  900.             case S_IFSOCK :
  901.                 add_to_list(&Socks, sav_str);
  902. #ifdef LENS
  903.                 if (mlen > Socks.maxlen)
  904.                     Socks.maxlen = mlen;
  905. #endif
  906.                 break;
  907. #endif
  908.             }
  909.         }
  910.         break;
  911. #endif
  912.  
  913. #ifdef S_IFSOCK
  914.     case S_IFSOCK:
  915.         if (!Allfiles && sav_str[0] == '.')
  916.             break;
  917.         add_to_list(&Socks, sav_str);
  918. #ifdef LENS
  919.         if (mlen > Socks.maxlen)
  920.             Socks.maxlen = mlen;
  921. #endif
  922.         break;
  923. #endif
  924.  
  925. #ifdef S_IFNAM
  926.     case S_IFNAM:
  927.         switch (sbuf.st_rdev) {
  928.  
  929.         case S_INSEM:
  930.             if (!Allfiles && sav_str[0] == '.')
  931.                 break;
  932.             add_to_list(&Sems, sav_str);
  933. #ifdef LENS
  934.             if (mlen > Sems.maxlen)
  935.                 Sems.maxlen = mlen;
  936. #endif
  937.             break;
  938.  
  939.         case S_INSHD:
  940.             if (!Allfiles && sav_str[0] == '.')
  941.                 break;
  942.             add_to_list(&Sds, sav_str);
  943. #ifdef LENS
  944.             if (mlen > Sds.maxlen)
  945.                 Sds.maxlen = mlen;
  946. #endif
  947.             break;
  948.         }
  949.         break;
  950. #endif
  951.  
  952.     }
  953.     return;
  954. }
  955.  
  956. /* V A L I D _ O P T
  957.  *
  958.  * valid_opt() is used to translate user has supplied option
  959.  * letters into something that this process can use. It sets
  960.  * up the options and if a usage is requested, it sets up and
  961.  * prints a usage message for the user.
  962.  */
  963.  
  964. void valid_opt(c, usage)
  965.     char c;
  966.     int usage;
  967. {
  968.     char up[7];
  969.  
  970.     up[0] = '\0';
  971.  
  972.     switch(c) {
  973.  
  974.     case 'a':
  975.         Allfiles = TRUE;
  976.         break;
  977.  
  978.     case 'b':
  979.         Only = BLOCK_ONLY;
  980.         break;
  981.  
  982.     case 'c':
  983.         Only = CHAR_ONLY;
  984.         break;
  985.  
  986.     case 'd':
  987.         Only = DIR_ONLY;
  988.         break;
  989.  
  990.     case 'D':
  991.         Display_single = FALSE;
  992.         break;
  993.  
  994.     case 'e':
  995.         Executables = TRUE;
  996.         break;
  997.  
  998.     case 'f':
  999.         Only = FILE_ONLY;
  1000.         break;
  1001.  
  1002.     case 'r':
  1003.         Sort_wanted = FALSE;
  1004.         break;
  1005.  
  1006. #ifdef S_IFIFO
  1007.     case 'F':
  1008.         Only = FIFO_ONLY;
  1009.         break;
  1010. #endif
  1011.  
  1012.     case '1':
  1013.         Single = TRUE;
  1014.         break;
  1015.  
  1016. #ifdef S_IFLNK
  1017.     case 's':
  1018.         Only = LNK_ONLY;
  1019.         break;
  1020.  
  1021.     case 'l':
  1022.         Mark_links = TRUE;
  1023.         break;
  1024.  
  1025.     case 'I':
  1026.         Ignore = TRUE;
  1027.         break;
  1028.  
  1029.     case 'L':
  1030.         Disp_links = TRUE;
  1031.         break;
  1032. #endif
  1033.  
  1034. #ifdef S_IFSOCK
  1035.     case 'S':
  1036.         Only = SOCK_ONLY;
  1037.         break;
  1038. #endif
  1039.  
  1040. #ifdef S_IFNAM
  1041.     case 'm':
  1042.         Only = SD_ONLY;
  1043.         break;
  1044.  
  1045.     case 'M':
  1046.         Only = SEM_ONLY;
  1047.         break;
  1048. #endif
  1049.  
  1050.     default:
  1051.         if (usage == TRUE) {
  1052. #ifdef S_IFLNK
  1053.             (void) strcat(up, "IlLs");
  1054. #endif
  1055. #ifdef S_IFSOCK
  1056.             (void) strcat(up, "S");
  1057. #endif
  1058. #ifdef S_IFNAM
  1059.             (void) strcat(up, "mM");
  1060. #endif
  1061.             (void) fprintf(stderr,
  1062.                            "usage: %s [-abcdDefF1%s] [directories or files]\n",
  1063.                            Progname, up);
  1064.             exit(1);
  1065.         }
  1066.     }
  1067.  
  1068.     return;
  1069. }
  1070.  
  1071. /* S E T _ E N V _ V A R S
  1072.  *
  1073.  * set_env_vars() is used get the environment variables that
  1074.  * lc uses. The environment variable LC can be used to setup
  1075.  * the default way in which the user likes to see a directory
  1076.  * listing. Command line options override those specified in
  1077.  * the environment.
  1078.  */
  1079.  
  1080. void set_env_vars()
  1081. {
  1082.     char *ep;
  1083.  
  1084.     if ((ep = getenv("COLS")) != (char *) NULL) {
  1085.         if (sscanf(ep, "%d", &Screen_width) == 0
  1086.             || (Screen_width != 80 && Screen_width != 132))
  1087.             Screen_width = 80;
  1088.     }
  1089.  
  1090.     if ((ep = getenv("LC")) != (char *) NULL) {
  1091.         while (*ep != '\0') {
  1092.             valid_opt(*ep, FALSE);
  1093.             ep++;
  1094.         }
  1095.     }
  1096.  
  1097.     return;
  1098. }
  1099.  
  1100. /* S P D I S T:   return the distance between two names
  1101.  *
  1102.  * very rough spelling metric:
  1103.  *          0 if the strings are identical
  1104.  *          1 if two chars are transposed
  1105.  *          2 if 1 char wrong, added or deleted
  1106.  *          3 otherwise
  1107.  */
  1108. #define EQ(s, t) (strcmp(s, t) == 0)
  1109.  
  1110. int spdist(s, t)
  1111.     char *s;
  1112.     char *t;
  1113. {
  1114.     while (*s++ == *t) {
  1115.         if (*t++ == '\0')
  1116.             return 0;             /* exact match */
  1117.     }
  1118.     if (*--s) {
  1119.         if (*t) {
  1120.             if (s[1] && t[1] && *s == t[1] && *t == s[1] && EQ(s+2, t+2))
  1121.                 return 1;             /* transposition */
  1122.             if (EQ(s+1, t+1))
  1123.                 return 2;             /* 1 char mismatch */
  1124.         }
  1125.         if (EQ(s+1, t))
  1126.             return 2;                /* extra chacter */
  1127.     }
  1128.     if (*t && EQ(s, t+1))
  1129.         return 2;                   /* missing character */
  1130.     return 3;
  1131. }
  1132.  
  1133. /*    M I N D I S T       
  1134.  * 
  1135.  *  mindist() searches the directory for the best guess
  1136.  *  in the event the requested file was not located.
  1137.  */
  1138.  
  1139. #if (POSIX || BSD)
  1140. int mindist(dir, guess, best)    /* set best, return distance 0..3 */
  1141.     char *dir;
  1142.     char *guess;
  1143.     char *best;
  1144. {
  1145.     DIR *dfd;
  1146.     int d;
  1147.     int nd;
  1148. #ifdef DIRECT
  1149.     struct direct *dp;
  1150. #else
  1151.     struct dirent *dp;
  1152. #endif
  1153.  
  1154.     if (dir[0] == '\0')
  1155.         dir = ".";
  1156.     d = 3;                      /* minimum distance */
  1157.  
  1158.     if ((dfd = opendir(dir)) == NULL)
  1159.         return d;
  1160.  
  1161.     while ((dp = readdir(dfd)) != NULL) {
  1162.         if (dp->d_ino) {
  1163.             nd = spdist(dp->d_name, guess);
  1164.             if (nd <= d && nd != 3) {
  1165.                 (void) strcpy(best, dp->d_name);
  1166.                 d = nd;
  1167.                 if (d == 0)    /* exact match */
  1168.                     break;
  1169.             }
  1170.         }
  1171.     }
  1172.     (void) closedir(dfd);
  1173.     return d;
  1174. }
  1175.  
  1176. #else /* not POSIX or BSD */
  1177.  
  1178. /*    M I N D I S T       
  1179.  * 
  1180.  *  mindist() searches the directory for the best guess
  1181.  *  in the event the requested file was not located.
  1182.  */
  1183.  
  1184. int mindist(dir, guess, best)    /* set best, return distance 0..3 */
  1185.     char *dir;
  1186.     char *guess;
  1187.     char *best;
  1188. {
  1189.     FILE *fd;
  1190.     int d;
  1191.     int nd;
  1192.     struct {
  1193.         ino_t ino;
  1194.         char name[NAME_MAX + 1];   /* 1 more than in dir.h */
  1195.     } nbuf;
  1196.  
  1197.     nbuf.name[NAME_MAX] = '\0';   /* +1 for terminal '\0' */
  1198.     if (dir[0] == '\0')
  1199.         dir = ".";
  1200.     d = 3;                      /* minimum distance */
  1201.     if ((fd = fopen(dir, "r")) == (FILE *) NULL)
  1202.         return d;
  1203.     while (fread((char *) &nbuf, sizeof(struct direct), 1, fd) > 0) {
  1204.         if (nbuf.ino) {
  1205.             nd = spdist(nbuf.name, guess);
  1206.             if (nd <= d && nd != 3) {
  1207.                 (void) strcpy(best, nbuf.name);
  1208.                 d = nd;
  1209.                 if (d == 0)    /* exact match */
  1210.                     break;
  1211.             }
  1212.         }
  1213.     }
  1214.     (void) fclose(fd);
  1215.     return d;
  1216. }
  1217. #endif
  1218.  
  1219. /* S P N A M E:    return correctly spelled filename
  1220.  *
  1221.  * spname(oldname, newname) char *oldname, *newname;
  1222.  *      returns  -1 if no reasonable match to oldname,
  1223.  *                0 if exact match,
  1224.  *                1 if corrected.
  1225.  * stores corrected name in newname.
  1226.  */
  1227.  
  1228. int spname(oldname, newname)
  1229.     char *oldname;
  1230.     char *newname;
  1231. {
  1232.     char *new = newname;
  1233.     char *old = oldname;
  1234.     char *p;
  1235.     char best[NAME_MAX + 1];
  1236.     char guess[NAME_MAX + 1];
  1237.  
  1238.     for (;;) {
  1239.         while (*old == '/')   /* skip slashes */
  1240.             *new++ = *old++;
  1241.         *new = '\0';
  1242.         if (*old == '\0')     /* exact or corrected */
  1243.             return (strcmp(oldname, newname) != 0);
  1244.         p = guess;            /* copy next component into guess */
  1245.         for (/* void */ ; *old != '/' && *old != '\0'; old++) {
  1246.             if (p < (guess + NAME_MAX))
  1247.                 *p++ = *old;
  1248.         }
  1249.         *p = '\0';
  1250.         if (mindist(newname, guess, best) >= 3)
  1251.             return (-1);        /* hopeless */
  1252.         for (p = best; *new = *p++; new++)   /* add to end */
  1253.             /* void */;
  1254.     }
  1255. }
  1256.  
  1257. /*  I N _ C D P A T H
  1258.  * 
  1259.  *  in_cdpath() searches the CDPATH stored in the environment
  1260.  *  for the filename specified. If it is found, fill the
  1261.  *  storage area refered to by buffer with the corrected path.
  1262.  *  Return TRUE if located and FALSE if not located in the CDPATH.
  1263.  */
  1264.  
  1265. int in_cdpath(requested_dir, buffer)
  1266.     char *requested_dir;
  1267.     char *buffer;
  1268. {
  1269.     static char *cdpath;
  1270.     static int first = 1;
  1271.  
  1272.     char *cp;
  1273.     char *path;
  1274.     char patbuf[BUFSIZE + 1];
  1275.     int quit;
  1276.  
  1277.     if (first) {
  1278.         if ((cdpath = getenv("CDPATH")) != (char *) NULL)
  1279.             cdpath = str_sav(cdpath);
  1280.         first = 0;
  1281.     }
  1282.  
  1283.     if (cdpath == (char *) NULL)
  1284.         return (0);
  1285.  
  1286.     (void) strcpy(patbuf, cdpath);
  1287.     path = patbuf;
  1288.  
  1289.     quit = 0;
  1290.  
  1291.     while (!quit) {
  1292.         cp = strchr(path, ':');
  1293.         if (cp == (char *) NULL)
  1294.             quit++;
  1295.         else
  1296.             *cp = '\0';
  1297.  
  1298.         if (*(path + 1) == '\0' && *path == '/')
  1299.             (void) sprintf(buffer, "/%s", requested_dir);
  1300.         else
  1301.             (void) sprintf(buffer, "%s/%s",
  1302.                            (*path ? path : "."), requested_dir);
  1303.  
  1304.         if (access(buffer, 1) == 0)
  1305.             return (TRUE);
  1306.         path = ++cp;
  1307.     }
  1308.     return (FALSE);
  1309. }
  1310.  
  1311. /*  M A I N 
  1312.  * 
  1313.  *  Ye olde main();
  1314.  */
  1315.  
  1316. int main(argc, argv)
  1317.     int argc;
  1318.     char *argv[];
  1319. {
  1320.     char *argp;
  1321. #ifdef S_IFLNK
  1322.     char *link;
  1323. #endif
  1324.     char buf[BUFSIZE + 1];
  1325.     int idx;
  1326.     int nl;
  1327.     struct stat sbuf;
  1328.  
  1329.     nl = idx = FALSE;
  1330.  
  1331.     Progname = argv[0];
  1332.  
  1333.     set_env_vars();                       /* get environment variables */
  1334.  
  1335.     /* All command line arguments must be */
  1336.     /* lumped together such as `lc -aef`  */
  1337.  
  1338.     if (argc > 1 && argv[1][0] == '-') {  /* if first parm is command */
  1339.         argp = argv[1];
  1340.  
  1341.         while (*(++argp))
  1342.             valid_opt(*argp, TRUE);
  1343.  
  1344.         ++argv;
  1345.         --argc;
  1346.     }
  1347.  
  1348.     /*
  1349.     ** The user has not specified a file or directory 
  1350.     ** to be examined so assume that the current directory
  1351.     ** is what the user is requesting.
  1352.     */
  1353.     if (argc == 1) {
  1354.         (void) strcpy(buf, ".");
  1355.         lc(buf, 1);
  1356.         print_info();
  1357.         return(0);
  1358.     }
  1359.  
  1360.     /*
  1361.     ** The user has specified at least one file or 
  1362.     ** directory to be examined.
  1363.     */
  1364.     if (argc > 2)
  1365.         nl = TRUE;
  1366.     while (--argc > 0) {
  1367.         ++argv;
  1368.         (void) strcpy(buf, *argv);
  1369. skipit:
  1370.         if (stat(buf, &sbuf) == -1) {
  1371.             if (in_cdpath(*argv, buf) || (spname(*argv, buf) != -1)) {
  1372.                 /*
  1373.                  ** Check to see if the requested is in the CDPATH
  1374.                  ** and if not try to correct for typos. Always print
  1375.                  ** the name of what was found...
  1376.                  */
  1377.                 nl = TRUE;
  1378.                 goto skipit;
  1379.             }
  1380.             else
  1381.                 (void)fprintf(stderr, "%s: can't find %s\n",
  1382.                               Progname, *argv);
  1383.         }
  1384.         else {
  1385.             switch (sbuf.st_mode & S_IFMT) {
  1386.  
  1387.             case S_IFREG:
  1388.                 if (Display_single)
  1389.                    (void) printf("%s: file\n", buf);
  1390.                 break;
  1391.  
  1392. #ifdef S_IFCHR
  1393.             case S_IFCHR:
  1394.                 if (Display_single)
  1395.                    (void) printf("%s: character special file\n", buf);
  1396.                 break;
  1397. #endif
  1398.  
  1399. #ifdef S_IFBLK
  1400.             case S_IFBLK:
  1401.                 if (Display_single)
  1402.                    (void) printf("%s: block special file\n", buf);
  1403.                 break;
  1404. #endif
  1405.  
  1406. #ifdef S_IFIFO
  1407.             case S_IFIFO:
  1408.                 if (Display_single)
  1409.                    (void) printf("%s: fifo file\n", buf);
  1410.                 break;
  1411. #endif
  1412.  
  1413. #ifdef S_IFSOCK
  1414.             case S_IFSOCK:
  1415.                 if (Display_single)
  1416.                    (void) printf("%s: socket file\n", buf);
  1417.                 break;
  1418. #endif
  1419.  
  1420. #ifdef S_IFLNK
  1421.             case S_IFLNK:
  1422.                 if (Display_single) {
  1423.                    if ((link = getlink(buf)) != (char *) NULL) {
  1424.                        (void) printf("%s: symbolic link to %s\n",
  1425.                                      buf, link);
  1426.                        free(link);
  1427.                    }
  1428.                    else
  1429.                        (void) printf("%s: unresolved symbolic link\n",
  1430.                                      buf);
  1431.                 }
  1432.                 break;
  1433. #endif
  1434.  
  1435. #ifdef S_IFNAM
  1436.             case S_IFNAM:
  1437.                 if (Display_single) {
  1438.                    if (sbuf.st_rdev == S_INSHD)
  1439.                        (void) printf("%s: shared memory file\n", buf);
  1440.                    if (sbuf.st_rdev == S_INSEM)
  1441.                        (void) printf("%s: semaphore file\n", buf);
  1442.                 }
  1443.                 break;
  1444. #endif
  1445.  
  1446.             case S_IFDIR:
  1447.                 Maxlen = Level = 0;
  1448. #ifdef S_IFBLK
  1449.                 Blks.num = 0;
  1450. #ifdef LENS
  1451.                 Blks.maxlen = 0;
  1452. #endif
  1453. #endif
  1454.  
  1455. #ifdef S_IFCHR
  1456.                 Chrs.num = 0;
  1457. #ifdef LENS
  1458.                 Chrs.maxlen = 0;
  1459. #endif
  1460. #endif
  1461.  
  1462.                 Dirs.num = Fls.num = 0;
  1463. #ifdef LENS
  1464.                 Dirs.maxlen = Fls.maxlen = 0;
  1465. #endif
  1466.  
  1467. #ifdef S_IFIFO
  1468.                 Fifos.num = 0;
  1469. #ifdef LENS
  1470.                 Fifos.maxlen = 0;
  1471. #endif
  1472. #endif
  1473.  
  1474. #ifdef S_IFLNK
  1475.                 Lnks.num = Lnksn.num = 0;
  1476. #ifdef LENS
  1477.                 Lnks.maxlen = Lnksn.maxlen = 0;
  1478. #endif
  1479. #endif
  1480.  
  1481. #ifdef S_IFSOCK
  1482.                 Socks.num = 0;
  1483. #ifdef LENS
  1484.                 Socks.maxlen = 0;
  1485. #endif
  1486. #endif
  1487.  
  1488. #ifdef S_IFNAM
  1489.                 Sds.num = Sems.num = 0;
  1490. #ifdef LENS
  1491.                 Sds.maxlen = Sems.maxlen = 0;
  1492. #endif
  1493. #endif
  1494.  
  1495.                 if (nl == TRUE) {
  1496.                     if (idx > 0)
  1497.                         (void) puts("");
  1498.                     else
  1499.                         ++idx;
  1500.                     (void) fputs(": ", stdout);
  1501.                     (void) fputs(buf, stdout);
  1502.                     (void) puts(" :");
  1503.                 }
  1504.                 lc(buf, 1);
  1505.                 print_info();
  1506.                 break;
  1507.  
  1508.             default:
  1509.                 (void) printf("%s: unknown file type\n", buf);
  1510.                 break;
  1511.             }
  1512.         }
  1513.     }
  1514.     return(0);
  1515. }
  1516.