home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / alde_c / misc / util / tools / ls.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-09-23  |  13.4 KB  |  498 lines

  1. /*
  2.  *  Attribute bits:
  3.  *      d - directory
  4.  *      r - read only file
  5.  *      h - hidden file
  6.  *      s - system file
  7.  *      a - archive bit
  8.  *
  9.  *  Files within each directory are sorted alphabetically.
  10.  *  Directories are listed separate from other files.
  11.  */
  12.  
  13. #include <stdio.h>              /* Standard I/O definitions */
  14. #include <ctype.h>              /* Character type macros */
  15. #include <dos.h>                /* Msdos definitions */
  16. #include <errno.h>              /* error codes */
  17. #include <string.h>
  18.  
  19. #define SIZE(x)         (sizeof(x)/sizeof(x[0]))
  20. #define A_RONLY         0x01    /* Read only file */
  21. #define A_HIDDEN        0x02    /* Hidden file */
  22. #define A_SYSTEM        0x04    /* System file */
  23. #define A_DIRECTORY     0x10    /* Directory file */
  24. #define A_ARCHIVE       0x20    /* Archive bit */
  25. #define FNLEN           80      /* Maximum filename length */
  26. #define MAXFILES        512     /* Max number of files/directory */
  27.  
  28. static char ID[]="## ls.c 2.0 K.van Houten 230987 ##";
  29. struct date {
  30. unsigned    d_sec:      5;      /* Time, 2 second intervals */
  31. unsigned    d_min:      6;      /* Time, minutes */
  32. unsigned    d_hour:     5;      /* Time, hours */
  33. unsigned    d_day:      5;      /* Date, day of month */
  34. unsigned    d_month:    4;      /* Date, month of year */
  35. unsigned    d_year:     7;      /* Date, year since 1980 */
  36. };
  37. struct find {
  38.     char    fnd_dosinfo[21];    /* Reserved for dos */
  39.     char    fnd_attr;           /* File attribute */
  40.     struct date fnd_date;       /* Date structure */
  41.     long    fnd_size;           /* File size */
  42.     char    fnd_name[13];       /* File name less path */
  43. };
  44. char   *nameptr ();
  45. char   *date ();
  46. char   *malloc ();
  47. char   *strrchr ();
  48. int     qscmp ();
  49. extern int clsize();            /* get cluster size */
  50. long clust();
  51. short   tmp;
  52. struct find f;                  /* Used to return data from msdos */
  53. union REGS r, o;                /* Contains register values for intcall() */
  54. int     count;                  /* Number of files/directory */
  55. char   *p;                      /* Pointer to filename */
  56. int     i;
  57. int     j;
  58. int     lflg = 0;               /* long */
  59. int     tflg = 0;               /* time sort */
  60. int     sflg = 0;               /* size in bloks */
  61. int     rflg = 0;               /* reverse sort */
  62. int     fflg = 0;               /* identify executables and subdirs */
  63. long    dirlen;                 /* Total length of one dir */
  64. char    line[FNLEN];            /* Filename buffer */
  65. char    dirs[20][50];           /* Subdir buffer */
  66. int     dirc;                   /* Subdir count */
  67. int drive;                      /* drive nr */
  68. char   *file;                   /* Command line argument */
  69. struct find *fnd[MAXFILES];     /* Pointers to file structures */
  70. int bsize;                      /* size of clusters */
  71. int spc;                        /* number of K's per cluster */
  72.  
  73. static struct atr {             /* Attribute structure */
  74.     int     a_mask;
  75.     int     a_name;
  76. } atr[] = {
  77.     A_DIRECTORY, 'd',
  78.     A_RONLY,     'r',
  79.     A_HIDDEN,    'h',
  80.     A_SYSTEM,    's',
  81.     A_ARCHIVE,   'a'
  82. };
  83.  
  84. main (argc, argv)
  85. int     argc;                   /* Number of command line arguments */
  86. char   *argv[];                 /* Array of pointers to arguments */
  87. {
  88.     char    buf[70];
  89.  
  90.     drive = defdrv();
  91.     bsize=clsize(drive);
  92.     spc=bsize/1024;
  93.     for (argc--,argv++; argc>0; argc--,argv++) {
  94.         if (**argv == '-') {
  95.             while (*++(*argv)) {
  96.                 switch (**argv) {
  97.                 case 'l':
  98.                     lflg++;
  99.                     break;
  100.                 case 't':
  101.                     tflg++;
  102.                     break;
  103.                 case 's':
  104.                     sflg++;
  105.                     break;
  106.                 case 'r':
  107.                     rflg++;
  108.                     break;
  109.                 case 'F':
  110.                     fflg++;
  111.                     break;
  112.                 default:
  113.                     printf("Usage: ls [-Flrst] [file [file ...]]\n");
  114.                     exit(1);
  115.                 }
  116.             }
  117.         }
  118.         else
  119.             break;
  120.     }
  121.  
  122.     r.h.ah = 0x1a;              /* SET DISK TRANSFER ADDRESS FUNCTION */
  123.     r.x.dx = (int) & f;
  124.     tmp = intdos (&r, &o);
  125. /*  Produces error 0 ???
  126.     if (o.x.cflag) {
  127.         perror ("SETTING DTA ");
  128.         exit (1);
  129.     }
  130. */
  131.     dirc = 0;
  132.     count = 0;
  133.  
  134.     if (argc == 0) {
  135.         strcpy(dirs[dirc++],".");
  136.     }
  137.     else {
  138.         while (file = *argv++, argc--) {
  139.             /* handle relative directorys */
  140.             if (strcmp(file,"..") == 0) {
  141.                 strcpy(dirs[dirc++],"..\\.");
  142.                 continue;
  143.             }
  144.             if (file[strlen(file)-1] == '.') {
  145.                 strcpy(dirs[dirc++],file);
  146.                 continue;
  147.             }
  148.             /* handle drive letters */
  149.             if (strlen(file) == 2 && file[1] == ':') {
  150.                 strcpy(dirs[dirc],file);
  151.                 strcat(dirs[dirc++],".");
  152.                 continue;
  153.             }
  154.             /* handle abs. dirs */
  155.             if (file[strlen(file)-1] == '\\') {
  156.                 strcpy(dirs[dirc], file);
  157.                 strcat(dirs[dirc++],".");
  158.                 continue;
  159.             }
  160.             findf ();
  161.             if (o.x.cflag) {
  162.                 continue;
  163.             }
  164.             for (;;) {
  165.                 if (o.x.cflag) {
  166.                     break;
  167.                 }
  168.                 if (f.fnd_attr & A_DIRECTORY) {
  169.                     if (f.fnd_name[0] == '.')
  170.                        goto next;
  171.                     *dirs[dirc]='\0';
  172.                     if (strrchr(file,'\\')!=NULL) {
  173.                        strncpy(dirs[dirc],file,((strrchr(file,'\\')-file)+1));
  174.                     }
  175.                     strcat (dirs[dirc++], f.fnd_name);/* save subdir name */
  176.                 }
  177.                 else {
  178.                     if ((fnd[count] =
  179.                        (struct find *)malloc(sizeof(struct find))) == NULL)
  180.                           fatal ("out of memory");
  181.                     *fnd[count] = f;
  182.                     /* Increment total size */
  183.                     dirlen += clust(fnd[count]->fnd_size);
  184.                     count++;
  185.                 }
  186. next:           findn ();
  187.             }
  188.         }
  189.         if (count == 0 && dirc == 0) {
  190.             printf("File not found\n");
  191.             exit(1);
  192.         }
  193.     }
  194.     /* All arguments done, now print simple files */
  195.     qsort (fnd, count, sizeof (struct find *), qscmp);
  196.  
  197.     for (i = 0; i < count; i++) {
  198.         printentry(i);
  199.         if ((lflg==0) && (((i+1) % (sflg?4:5)) == 0) && (i > 1))
  200.             printf("\n");
  201.     }
  202.     for (i = 0; i < dirc; i++)
  203.         printdir(i);
  204.     return (1);
  205. }
  206.  
  207. /*
  208.  * Print one entry, format depends on options selected.
  209.  */
  210. printentry(x)
  211. int x;
  212. {
  213.     long sz;
  214.     char pbuf[50];    /* print buffer */
  215.  
  216.     sz = fnd[x] -> fnd_size;
  217.  
  218.     /* block size */
  219.     if (sflg)
  220.     {
  221.         if ((fnd[x] -> fnd_attr & A_DIRECTORY) == 0)
  222.         {
  223.            printf("%3d ",clust(sz));
  224.         }
  225.         else
  226.            printf("  0 ");
  227.     }
  228.     if (lflg) {
  229.         /* mode bits */
  230.         for (j = 0; j < SIZE (atr); j++)
  231.             if (atr[j].a_mask & fnd[x] -> fnd_attr)
  232.                 putchar (atr[j].a_name);
  233.             else
  234.                 putchar ('-');
  235.  
  236.         /* file size */
  237.         printf (" %10ld  ", sz);
  238.  
  239.         /* file date */
  240.         printf ("%s  ", date (&fnd[x] -> fnd_date));
  241.     }
  242.  
  243.     /* file name */
  244.     if (fflg == 0)
  245.         printf ("%-12s  " , strlwr (fnd[x] -> fnd_name));
  246.  
  247.     /* executable / subdir info */
  248.     if (fflg)
  249.     {
  250.         if (fnd[x] -> fnd_attr & A_DIRECTORY)
  251.             sprintf (pbuf,"%s/" , strlwr (fnd[x] -> fnd_name));
  252.         else
  253.         {
  254.             if (isexe(fnd[x]->fnd_name))
  255.                 sprintf (pbuf,"%s*" , strlwr (fnd[x] -> fnd_name));
  256.             else
  257.                 sprintf (pbuf,"%s " , strlwr (fnd[x] -> fnd_name));
  258.         }
  259.         printf ("%-12s  " , pbuf);
  260.     }
  261.  
  262.     if (lflg)
  263.         printf("\n");
  264.  
  265.     free (fnd[x]);          /* Free find structure */
  266. }
  267.  
  268.  
  269. printdir (x)
  270. int x;
  271. {
  272.     int i;
  273.     char fbuf[80]; /* to assemble filename */
  274.  
  275.     /* Complex, but needed for DOS 2.11 compatibility */
  276.     if (dirs[x][strlen(dirs[x])-1] == '.') {
  277.         dirs[x][strlen(dirs[x])-1] = '\0';
  278.         strcpy(fbuf,dirs[x]);
  279.         strcat(fbuf,"*.*");
  280.     }
  281.     else {
  282.         strcpy(fbuf,dirs[x]);
  283.         strcat(fbuf,"\\*.*");
  284.     }
  285.     if (dirs[x][1] == ':') { /* other drive */
  286.         drive=tolower(*dirs[x])-'a';
  287.     }
  288.     else {
  289.         drive=defdrv();
  290.     }
  291.     bsize=clsize(drive);
  292.     spc=bsize/1024;
  293.     file = fbuf;
  294.     p = nameptr (file);
  295.     count = p - file;
  296.     if (count + sizeof (f.fnd_name) > FNLEN)
  297.         fatal ("filename too long: %s", file);
  298.     strncpy (line, file, count);
  299.     p = line + count;
  300.     count = 0;                  /* Init file count */
  301.     dirlen = 0;
  302.  
  303.     findf ();
  304.     for (;;) {
  305.         if (o.x.cflag)
  306.             break;
  307.         if (count >= MAXFILES)
  308.             fatal ("Too many files in one directory");
  309.         if ((fnd[count] =
  310.            (struct find *) malloc (sizeof (struct find))) == NULL)
  311.               fatal ("out of memory");
  312.         if (!((f.fnd_attr & A_DIRECTORY) &&
  313.                     ((strcmp (f.fnd_name, ".") == 0) ||
  314.                         (strcmp (f.fnd_name, "..") == 0)))) {
  315.             memcpy (fnd[count], &f, sizeof f);
  316.             /* Increment total size */
  317.             dirlen += clust(fnd[count] -> fnd_size);
  318.             count++;
  319.         }
  320.         findn ();
  321.     }
  322.     if (count)
  323.         qsort (fnd, count, sizeof (struct find *), qscmp);
  324.  
  325.     if (*dirs[x] != '\0')
  326.         printf("\n%s:\n", strlwr(dirs[x]));
  327.     if (lflg) {
  328.         printf ("Total %d\n",dirlen);
  329.     }
  330.     for (i = 0; i < count; i++) {
  331.         printentry(i);
  332.         if ((lflg==0) && (((i+1) % (sflg?4:5)) == 0) && (i > 1))
  333.             printf("\n");
  334.     }
  335. }
  336.  
  337. /*
  338.  * Find first entry, return info in find structure.
  339.  */
  340. findf ()
  341. {
  342.     r.h.ah = 0x4e;              /* FINDFIRST function */
  343.     r.x.cx = A_HIDDEN | A_SYSTEM | A_DIRECTORY |
  344.         A_RONLY | A_ARCHIVE;
  345.     r.x.dx = (int) file;
  346.     tmp = intdos (&r, &o);      /* Find first */
  347. }
  348.  
  349. /*
  350.  * Find next entry
  351.  */
  352. findn ()
  353. {
  354.     r.h.ah = 0x4f;              /* Now use FINDNEXT function */
  355.     tmp = intdos (&r, &o);      /* Find next */
  356. }
  357.  
  358. /*
  359.  * Return a pointer to an ascii date, given a pointer
  360.  * to a date structure
  361.  */
  362. char    ad[40];
  363.  
  364. char   *
  365.         date (dp)
  366. register struct date   *dp;
  367. {
  368.     static char *month[] = {
  369.         "Jan",
  370.         "Feb",
  371.         "Mar",
  372.         "Apr",
  373.         "May",
  374.         "Jun",
  375.         "Jul",
  376.         "Aug",
  377.         "Sep",
  378.         "Oct",
  379.         "Nov",
  380.         "Dec"
  381.     };
  382.  
  383.     sprintf (ad, "%2d %s %4d  %02d:%02d:%02d",
  384.             dp -> d_day,
  385.             month[dp -> d_month - 1],
  386.             dp -> d_year + 1980,
  387.             dp -> d_hour,
  388.             dp -> d_min,
  389.             dp -> d_sec * 2);
  390.     return (ad);
  391. }
  392.  
  393. /*
  394.  * Qsort compare routine
  395.  * Directories first, other files second, sort alphabetically.
  396.  * This routine is called by qsort and passed two pointers to
  397.  * find structure pointers.
  398.  */
  399. qscmp (p1, p2)
  400. struct find **p1;
  401. struct find **p2;
  402. {
  403.     register struct find   *f1 = *p1;
  404.     register struct find   *f2 = *p2;
  405.     register int    cmp;
  406.     int inv = 1;
  407.  
  408.     if (rflg)
  409.         inv=-1;
  410. /*
  411.     if (cmp = (f2 -> fnd_attr & A_DIRECTORY) - (f1 -> fnd_attr & A_DIRECTORY))
  412.         return (cmp);
  413.  */
  414.     if (tflg) {
  415.         if (cmp = (f2->fnd_date.d_year - f1->fnd_date.d_year))
  416.             return(inv * cmp);
  417.         if (cmp = (f2->fnd_date.d_month - f1->fnd_date.d_month))
  418.             return(inv * cmp);
  419.         if (cmp = (f2->fnd_date.d_day - f1->fnd_date.d_day))
  420.             return(inv * cmp);
  421.         if (cmp = (f2->fnd_date.d_hour - f1->fnd_date.d_hour))
  422.             return(inv * cmp);
  423.         if (cmp = (f2->fnd_date.d_min - f1->fnd_date.d_min))
  424.             return(inv * cmp);
  425.         if (cmp = (f2->fnd_date.d_sec - f1->fnd_date.d_sec))
  426.             return(inv * cmp);
  427.     }
  428.     return (inv * strcmp (f1 -> fnd_name, f2 -> fnd_name));
  429. }
  430.  
  431. /*
  432.  * Return a pointer to the beginning of the filename (past pathname if any)
  433.  */
  434. char   *
  435.         nameptr (name)
  436. char   *name;
  437. {
  438.     register char  *p1;
  439.  
  440.     if ((p1 = strrchr (name, '\\')) != NULL)
  441.         return (++p1);
  442.     else
  443.         if ((p1 = strrchr (name, ':')) != NULL)
  444.             return (++p1);
  445.     return (name);
  446. }
  447.  
  448. /*
  449.  * Fatal error
  450.  * The %r (recursive) printf format specifier is non-portable.
  451.  */
  452. fatal (p)
  453. char   *p;
  454. {
  455.     printf ("ls fatal error\n");
  456.     exit (0);
  457. }
  458.  
  459. long
  460. clust(sz)
  461. long sz;
  462. {
  463. return(spc*((sz % bsize) ? (sz / bsize + 1) : (sz / bsize)));
  464. }
  465.  
  466. int
  467. defdrv()
  468. {
  469.     int tmp;
  470.     union REGS r;
  471.  
  472.     r.h.ah = 0x19;  /* get default drive */
  473.     tmp = intdos(&r,&r);
  474.     if (r.x.cflag != 0) {
  475.         printf("Error reading def. drive: %d\n",tmp);
  476.         exit(1);
  477.     }
  478.     return(r.h.al);
  479. }
  480.  
  481. int
  482. isexe(n)
  483. char *n;
  484. {
  485.     char *p,*t;
  486.  
  487.     if ((p=strchr(n,'.')) == NULL)
  488.         return(0);
  489.     p++;
  490.     if (strncmp(p,"EXE",3) == 0)
  491.         return(1);
  492.     if (strncmp(p,"COM",3) == 0)
  493.         return(1);
  494.     if (strncmp(p,"BAT",3) == 0)
  495.         return(1);
  496.     return(0);
  497. }
  498.