home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / prof_c / 08file / ls.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-08-11  |  6.1 KB  |  252 lines

  1. /*
  2.  *    ls -- display a directory listing
  3.  */
  4.  
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <memory.h>
  9. #include <dos.h>
  10. #include <direct.h>
  11. #include <signal.h>
  12. #include <search.h>
  13. #include <local\std.h>
  14. #include <local\doslib.h>
  15. #include "ls.h"
  16.  
  17. /* allocation quantities */
  18. #define N_FILES    256
  19. #define N_DIRS    16
  20.  
  21. /* global data */
  22. int Multicol = 0;
  23. int Filetype = 0;
  24. int Hidden = 0;
  25. int Longlist = 0;
  26. int Reverse = 0;
  27. int Modtime = 0;
  28.  
  29. main(argc, argv)
  30. int argc;
  31. char *argv[];
  32. {
  33.     int ch, i;
  34.     int errflag;        /* error flag */
  35.     char *ep;        /* environment pointer */
  36.     int status = 0;        /* return status value */
  37.     int fileattr;        /* file attribute number */
  38.     struct DTA buf;        /* private disk buffer */
  39.     char path[MAXPATH + 1];    /* working pathname */
  40.     struct OUTBUF *fp, *fq;    /* pointers to file array */
  41.     char **dp, **dq;    /* pointer to directory pointer array */
  42.     int fbc = 1;        /* file memory block allocation count */
  43.     int dbc = 1;        /* directory memory block allocation count */
  44.     int nfiles;        /* number of file elements */
  45.     int ndirs;        /* number of directory elements */
  46.  
  47.     static char pgm[MAXNAME + 1] = { "ls" };
  48.  
  49.     /* function prototypes */
  50.     void getpname(char *, char *);
  51.     extern int getopt(int, char **, char *);
  52.     extern int optind, opterr;
  53.     extern char *optarg;
  54.     extern char *drvpath(char *);
  55.     extern void fatal(char *, char *, int);
  56.     extern void setdta(char *);
  57.     extern int first_fm(char *, int);
  58.     extern int next_fm();
  59.     extern int ls_fcomp(struct OUTBUF *, struct OUTBUF *);
  60.     extern int ls_dcomp(char *, char *);
  61.     extern int ls_single(struct OUTBUF *, int);
  62.     extern int ls_multi(struct OUTBUF *, int);
  63.     extern int ls_dirx(char *, char *);
  64.     int bailout();
  65.  
  66.     /* guarantee that needed DOS services are available */
  67.     if (_osmajor < 2)
  68.         fatal(pgm, "ls requires DOS 2.00 or later", 1);
  69.  
  70.     /* get program name from DOS (version 3.00 and later) */
  71.     if (_osmajor >= 3)
  72.         getpname(*argv, pgm);
  73.  
  74.     /* useful aliases (DOS version 3.00 and later) */
  75.     if (strcmp(pgm, "lc") == 0)
  76.         ++Multicol;
  77.     if (strcmp(pgm, "lf") == 0) {
  78.         ++Multicol;
  79.         ++Filetype;
  80.     }
  81.  
  82.     /* prepare for emergencies */
  83.     if (signal(SIGINT, bailout) == (int(*)())-1) {
  84.         perror("Can't set SIGINT");
  85.         exit(2);
  86.     }
  87.  
  88.     /* process optional arguments first */
  89.     errflag = 0;
  90.     while ((ch = getopt(argc, argv, "aCFlrt")) != EOF)
  91.         switch (ch) {
  92.         case 'a':
  93.             /* all files (hidden, system, etc.) */
  94.             ++Hidden;
  95.             break;
  96.         case 'C':
  97.             ++Multicol;
  98.             break;
  99.         case 'F':
  100.             /* show file types (/=directory, *=executable) */
  101.             ++Filetype;
  102.             break;
  103.         case 'l':
  104.             /* long list (overrides multicolumn) */
  105.             ++Longlist;
  106.             break;
  107.         case 'r':
  108.             /* reverse sort */
  109.             ++Reverse;
  110.             break;
  111.         case 't':
  112.             /* sort by file modification time */
  113.             ++Modtime;
  114.             break;
  115.         case '?':
  116.             errflag = TRUE;
  117.             break;
  118.         }
  119.     argc -= optind;
  120.     argv += optind;
  121.  
  122.     /* check for command-line errors */
  123.     if (argc < 0 || errflag) {
  124.         fprintf(stderr, "Usage: %s [-aCFlrt] [pathname ...]", pgm);
  125.         exit(3);
  126.     }
  127.  
  128.     /* allocate initial file and directory storage areas */
  129.     dp = dq = (char **)malloc(N_DIRS * sizeof (char *));
  130.     if (dp == NULL)
  131.         fatal(pgm, "Out of memory", 4);
  132.     fp = fq = (struct OUTBUF *)malloc(N_FILES * sizeof (struct OUTBUF));
  133.     if (fp == NULL)
  134.         fatal(pgm, "Out of memory", 4);
  135.     nfiles = ndirs = 0;
  136.  
  137.     /* use current directory if no args */
  138.     if (argc == 0) {
  139.         if (getcwd(path, MAXPATH) == NULL)
  140.             fatal(pgm, "Cannot get current directory", 5);
  141.         *dq = path;
  142.         ndirs = 1;
  143.     }
  144.     else {
  145.         /* use arguments as file and directory names */
  146.         for ( ; argc-- > 0; ++argv) {
  147.             strcpy(path, *argv);
  148.             if (path[0] == '\\') {
  149.                 /* prepend default drive name */
  150.                 memcpy(path + 2, path, strlen(path) + 1);
  151.                 path[0] = 'a' + getdrive();
  152.                 path[1] = ':';
  153.             }
  154.             if (path[1] == ':' && path[2] == '\0' && drvpath(path) == NULL) {
  155.                 fprintf(stderr, "%s: Cannot get drive path", pgm);
  156.                 continue;
  157.             }
  158.  
  159.             /* establish private disk transfer area */
  160.             setdta((char *)&buf);
  161.  
  162.             /* set file attribute for search */
  163.             if (Hidden)
  164.                 fileattr = SUBDIR | HIDDEN | SYSTEM | READONLY;
  165.             else
  166.                 fileattr = SUBDIR;
  167.             if (first_fm(path, fileattr) != 0 && path[3] != '\0') {
  168.                 fprintf(stderr, "%s -- No such file or directory\n", path);
  169.                 continue;
  170.             }
  171.             if ((buf.d_attr & SUBDIR) == SUBDIR || path[3] == '\0') {
  172.                 /* path is a (sub)directory */
  173.                 *dq = strdup(path);
  174.                 if (++ndirs == dbc * N_DIRS) {
  175.                     ++dbc;    /* increase space requirement */
  176.                     dp = (char **)realloc(dp, dbc * N_DIRS * sizeof (char *));
  177.                     if (dp == NULL)
  178.                         fatal(pgm, "Out of memory", 4);
  179.                     dq = dp + dbc * N_DIRS;
  180.                 }
  181.                 else
  182.                     ++dq;
  183.             }
  184.             else {
  185.                 fq->o_name = strdup(path);
  186.                 fq->o_mode = buf.d_attr;
  187.                 fq->o_date = buf.d_mdate;
  188.                 fq->o_time = buf.d_mtime;
  189.                 fq->o_size = buf.d_fsize;
  190.                 if (++nfiles == fbc * N_FILES) {
  191.                     ++fbc;
  192.                     fp = (struct OUTBUF *)realloc(fp, fbc * N_FILES * sizeof (struct OUTBUF));
  193.                     if (fp == NULL)
  194.                         fatal(pgm, "Out of memory", 4);
  195.                     fq = fp + fbc * N_FILES;
  196.                 }
  197.                 else
  198.                     ++fq;
  199.             }
  200.         }
  201.     }
  202.  
  203.     /* output file list, if any */
  204.     if (nfiles > 0) {
  205.         qsort(fp, nfiles, sizeof(struct OUTBUF), ls_fcomp);
  206.         if (Longlist)
  207.             ls_long(fp, nfiles);
  208.         else if (Multicol)
  209.             ls_multi(fp, nfiles);
  210.         else
  211.             ls_single(fp, nfiles);
  212.         putchar('\n');
  213.     }
  214.     free(fp);
  215.      
  216.     /* output directory lists, if any */
  217.     if (ndirs == 1 && nfiles == 0) {
  218.         /* expand directory and output without header */
  219.         if (ls_dirx(pgm, *dp))
  220.             fprintf(stderr, "%s -- empty directory\n", strlwr(*dp));
  221.     }
  222.     else if (ndirs > 0) {
  223.         /* expand each directory and output with headers */
  224.         dq = dp;
  225.         qsort(dp, ndirs, sizeof(char *), ls_dcomp);
  226.         while (ndirs-- > 0) {
  227.             fprintf(stdout, "%s:\n", strlwr(*dq));
  228.             if (ls_dirx(pgm, *dq++))
  229.                 fprintf(stderr, "%s -- empty directory\n",
  230.                     strlwr(*dq));
  231.             putchar('\n');
  232.         }
  233.     }
  234.  
  235.     exit(0);
  236. }
  237.  
  238. /*
  239.  *    bailout -- optionally terminate upon interrupt
  240.  */
  241. int
  242. bailout()
  243. {
  244.     char ch;
  245.  
  246.     signal(SIGINT, bailout);
  247.     printf("\nTerminate directory listing? ");
  248.     scanf("%1s", &ch);
  249.     if (ch == 'y' || ch == 'Y')
  250.         exit(1);
  251. }
  252.