home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / cpm / cpm68k / utils.lbr / XDIR.CQ / XDIR.C
Encoding:
C/C++ Source or Header  |  1986-05-22  |  13.5 KB  |  496 lines

  1. /* -*-c,save,tab:8,indent:4-*- */
  2. /************************************************************************
  3.  * XDIR.C - eXtended DIRectory program.  Does all kinds of good stuff    *
  4.  *        Robert Heller 16-FEB-1985 - Media Research, Ltd.        *
  5.  *        (c) 1985 Media Research, Ltd.                *
  6.  * (part of Media Research, Ltd UTILS-68K package)            *
  7.  ************************************************************************
  8.  *
  9.  * Usage:
  10.  * xdir [-r ][-cN ][-s ][-a ][-f ][-to ][-tr+/- ][-h+/- ][fname [fname ...]][>outfile]
  11.  * -r - reverse alpha ordered
  12.  * -cN - columns (default=5 iff -s,-a and -f NOT specified, else 1. also
  13.  *          iff -tr- and -h- BOTH specified then columns=1)
  14.  * -s - size
  15.  * -a - attributes (ie SYS/DIR, RW/RO, ARC/NOARC, etc.)
  16.  * -f - fill (same as -s & -a)
  17.  * -to - total - lists totals (incl. size if -s or -f)
  18.  * -tr+/- - trailer (-tr+ [default]) or notrailer (-tr-)
  19.  * -h+/- - header (-h+ [default]) or noheader (-h-)
  20.  * fname - file name(s) format dr:name.type[user] - default spec is 
  21.  *       curdrive:*.*[curuser]
  22.  * >outfile - output file (CON: by default)
  23.  *
  24.  ************************************************************************
  25.  */
  26. #include <stdio.h>    /* standard I/O defs */
  27. #include <ctype.h>    /* character types */
  28. #include <osif.h>    /* O/S interface defs */
  29. #include <osiferr.h>    /* O/S interface error handling */
  30. #include <option.h>    /* option defs */
  31. NOWILDCARDS        /* let use take care of wild cards ourselves */
  32. /* missing OSIF functions: */
  33. #define GETDRV 25                /* get current drive # */
  34. #define GETLOG 24                /* get login vector */
  35. #define GETDPB 31                /* get disk parameters */
  36. #define SELDRV 14                /* select drive */
  37.  
  38. /* storage classes */
  39. #define FAST register
  40. #define LOCAL static
  41. #define GLOBAL extern
  42.  
  43. /* linked list - for file name list */
  44. typedef struct names {
  45.     char *name;
  46.     struct names *next;
  47.     } NAMES,*NAMESP;
  48.  
  49. /* format for header */
  50. #define HFORMAT "\nDirectory %c:[%d]\n\n"
  51. /* trailer formats */
  52. #define TFORMAT1 (sflag?\
  53.     "\nTotal of %d files, %ld KBytes/%ld directory entries.\n":\
  54.     "\nTotal of %d files.\n")
  55. #define TFORMAT2 (sflag?\
  56. "\nGrand Total of %d files in %d directories, %ld KBytes/%ld directory entries.\n":\
  57. "\nGrand Total of %d files in %d directories.\n")
  58. /* file name format */
  59. #define FLEN1 15
  60. #define FLEN2 20
  61. /* size format */
  62. #define SFORMAT "%6ld/%-4ld "
  63.  
  64. /* file search DMA block structure */
  65. typedef struct {
  66.     char dr;
  67.     char xf[8];
  68.     char t[3];
  69.     char fill[20];
  70.     } SEABLK;
  71.  
  72. /* DPB structure */
  73. typedef struct {
  74.     short int spt;    /* sectors per track */
  75.     char bsh;        /* block shift factor */
  76.     char blm;        /* block mask */
  77.     char exm;        /* extent mask */
  78.     char z;        /* reserved byte */
  79.     short int dsm;    /* disk storage mask (max block count - 1) */
  80.     short int drm;    /* directory mask (max directory entry count - 1) */
  81.     short int zz;    /* reserved word */
  82.     short int cks;    /* size of the checksum vector */
  83.     short int off;    /* number of reserved tracks */
  84.     } DPB;
  85.  
  86. /* sign macro */
  87. #define sign(i) (((i)<0)?(-1):(((i)>0)?(1):(0)))
  88.  
  89. /* isfilech macro */
  90. #define isfilech(c) ((index(" <>=,!|*?&/[]().:;+-\\",c) == NULL) &&\
  91.              (isprint(c)))
  92. /* search dir signs */
  93. #define ASSENDING (-1)
  94. #define DESSENDING (1)
  95. #define DEFAULTCOLS 5
  96.  
  97. /* "global vars" */
  98. int sortflg = ASSENDING;    /* sort direction */
  99. NAMESP filelist = NULL;    /* file name list */
  100. int columns = DEFAULTCOLS, /* # columns */
  101.       sflag = FALSE,    /* size flag */
  102.       aflag = FALSE,    /* attributes flag */
  103.       header = TRUE,    /* header flag */
  104.       trailer = TRUE,    /* trailer flag */
  105.       tflag = FALSE;    /* totals flag */
  106. /* attribute names */
  107. char *attoffnames[] =  {"","","","","","","","","RW","DIR",""},
  108.        *attonnames[] = {"F1","F2","F3","F4","F5","F6","F7","F8","RO","SYS","ARC"};
  109. #define attname(num,ch) (((ch & 0x080) != 0)?attonnames[num]:attoffnames[num])
  110.  
  111. /* commonly used functions: */
  112. long int __BDOS();    /* BDOS hook */
  113. char *index();        /* index function */
  114.  
  115.  
  116.  
  117.  
  118. /* main routine - process command line, fetch file names, and print results */
  119.  
  120. main(argc,argv)
  121. FAST int argc;
  122. FAST char **argv;
  123. {
  124.     FAST NAMESP innames,x;
  125.     NAMESP cons(); /* list constructor funs */
  126.  
  127.     innames = NULL;
  128.     while ((--argc)>0) {
  129.     if (**(++argv) == '-') {    /* switch? */
  130.         switch(*(++(*argv))) {
  131.         case 'r' : sortflg = DESSENDING; break;
  132.         case 'c' : columns = atoi(++(*argv)); break;
  133.         case 's' : sflag = TRUE; break;
  134.         case 'a' : aflag = TRUE; break;
  135.         case 'f' : sflag = TRUE; aflag = TRUE; break;
  136.         case 'h' : switch (*(++(*argv))) {
  137.                    case '-' : header = FALSE; break;
  138.                    case '+' : header = TRUE; break;
  139.                    default : usage();
  140.                    } break;
  141.         case 't' : switch (*(++(*argv))) {
  142.                    case 'o' : tflag = TRUE; break;
  143.                    case 'r' : switch (*(++(*argv))) {
  144.                           case '-' : trailer = FALSE; 
  145.                              break;
  146.                           case '+' : trailer = TRUE;
  147.                              break;
  148.                           default : usage();
  149.                           } break;
  150.                 default : usage();
  151.                 } break;
  152.         default : usage();
  153.         }
  154.         }
  155.     else innames = cons(*argv,innames);
  156.     }
  157.     if (innames == NULL) innames = cons("*.*",innames);
  158.     while (innames != NULL) {
  159.     fsearch(innames->name);
  160.     innames = innames->next;
  161.     }
  162.     flushdu();
  163.     if (!header && !trailer) columns = 1;
  164.     if (sflag || aflag) print1files();
  165.     else printfiles();
  166.     }
  167. NAMESP cons(nm,nml)
  168. FAST char *nm;
  169. FAST NAMESP nml;
  170. {
  171.     FAST char *p;
  172.     FAST int len;
  173.     char *calloc();
  174.     FAST NAMESP newnl;
  175.  
  176.     p = calloc(strlen(nm)+1,sizeof(char));
  177.     if (p == NULL) {perror("xdir");abort(0);}
  178.     strcpy(p,nm);
  179.     newnl = (NAMESP) calloc(1,sizeof(NAMES));
  180.     if (newnl == NULL) {perror("xdir");abort(0);}
  181.     newnl->name = p;
  182.     newnl->next = nml;
  183.     return(newnl);
  184.     }
  185. fsearch(nm)
  186. FAST char *nm;
  187. {
  188.     LOCAL struct fcbtab seafcb;
  189.     FAST char *p,*q;
  190.     FAST int i,j;
  191.     FAST int user;
  192.     FAST char dev;
  193.     FAST int loginv;
  194.     FAST int curuser;
  195.     FAST char curdev;
  196.  
  197.     curuser = __OSIF(USER, 0x000000FFL);
  198.     curdev = (__OSIF(GETDRV, 0L) + 'A');
  199.     loginv = __OSIF(GETLOG, 0L);
  200.  
  201.     j = 0;
  202.     if (isalpha(*nm) && strlen(nm)>1 && *(nm+1) == ':') {
  203.     dev = toupper(*nm);
  204.     if (dev < 'A' || dev > 'P') badfile(q,0);
  205.     nm = nm+2; j+=2;
  206.     }
  207.     else if (*nm == '*' && strlen(nm)>1 && *(nm+1) == ':') {
  208.     dev = '*';
  209.     nm = nm+2; j+=2;
  210.     }
  211.     else dev = curdev;
  212.  
  213.     i=8+3;
  214.     for(p=(&seafcb.fname[0]);i>0;i--) *p++='?';
  215.  
  216.     p=(&seafcb.fname[0]); i = 0;
  217.     while ((isfilech(*nm) || *nm == '?') && i<8) {
  218.     *p++ = toupper(*nm); nm++; i++; j++;
  219.     }
  220.     if (*nm == '*') {nm++;j++;}
  221.     else if (i>0 && i<8) while (i<8) {*p++ = ' '; i++;}
  222.     while ((index(".[",*nm) == NULL) && (*nm != '\0')) {nm++;j++;}
  223.     if (*nm == '.') {
  224.     nm++;j++;
  225.     p=(&seafcb.ftype[0]); i=0;
  226.     while ((isfilech(*nm) || *nm == '?') && i<3) {
  227.         *p++ = toupper(*nm); nm++; i++; j++;
  228.         }
  229.     if (*nm == '*') {nm++;j++;}
  230.     else if (i>0 && i<3) while (i<3) {*p++ = ' '; i++;}
  231.     }
  232.     if (*nm == '[') {nm++;j++;
  233.     p=nm;
  234.     while (isdigit(*nm) || *nm == '*') {nm++;j++;}
  235.     if (*nm != ']') badfile(q,j);
  236.     *nm = '\0';
  237.     if (strlen(p) == 0) user = curuser;
  238.     else if (strcmp(p,"*") == 0) user = -1;
  239.     else user = atoi(p);
  240.     *nm = ']';
  241.     nm++;j++;
  242.     }
  243.     else user = curuser;
  244.     if (*nm != '\0') badfile(q,j);
  245.  
  246.     if (dev == '*') {
  247.     for (i=0;i<16;i++)
  248.         if ((loginv & (1 << i)) != 0) {
  249.         seafcb.drive = i+1;
  250.         sealop0(&seafcb,user,i+'A');
  251.         }
  252.     }
  253.     else {
  254.     seafcb.drive = (dev - 'A')+1;
  255.     sealop0(&seafcb,user,dev);
  256.     }
  257.     __OSIF(USER, curuser);
  258.     }
  259. sealop0(fcb,user,dev)
  260. FAST struct fcbtab *fcb;
  261. FAST int user;
  262. FAST char dev;
  263. {
  264.     int i;
  265.  
  266.     if (user == (-1)) 
  267.     for (i=0;i<16;i++) sealop(fcb,i,dev);
  268.     else sealop(fcb,user,dev);
  269.     }
  270. sealop(fcb,user,dev)
  271. FAST struct fcbtab *fcb;
  272. FAST int user;
  273. FAST char dev;
  274. {
  275.     LOCAL SEABLK seadma[4];
  276.     FAST int status,i;
  277.     FAST char *p,*q;
  278.     LOCAL char nbuff[20];
  279.     NAMESP orderin(); /* list constructor funs */
  280.  
  281.     __OSIF(USER, user);
  282.     __OSIF(SETDMA, (&seadma[0]));
  283.     status = __OSIF(SEARCHF, fcb);
  284.     while (status != 0x00FF) {
  285.     p = (&nbuff[0]);
  286.     *p++ = dev;
  287.     *p++ = ':';
  288.     q = (&seadma[status].xf[0]);
  289.     i = 0;
  290.     while ((*q & 0x7F) != ' ' && i <8) {
  291.         *p++ = (*q++);
  292.         i++;
  293.         }
  294.     *p++ = '.';
  295.     q = (&seadma[status].t[0]);
  296.     i=0;
  297.     while ((*q & 0x7F) != ' ' && i < 3) {
  298.         *p++ = (*q++);
  299.         i++;
  300.         }
  301.     *p++ = '[';
  302.     if (user > 9) {
  303.         *p++ = (user / 10) + '0';
  304.         *p++ = (user % 10) + '0';
  305.         }
  306.     else {
  307.         *p++ = '0';
  308.         *p++ = user + '0';
  309.         }
  310.     *p++ = ']';
  311.     *p='\0';
  312.     filelist = orderin((&nbuff[0]),filelist);
  313.     status = __OSIF(SEARCHN, 0L);
  314.     }
  315.     }
  316. NAMESP orderin(innm,nlist)
  317. FAST char *innm;
  318. FAST NAMESP nlist;
  319. {
  320.     FAST NAMESP newnl,p,q;
  321.  
  322.     if (nlist == NULL) return(cons(innm,nlist));
  323.     else if (alfcmp(innm,nlist->name)) return(cons(innm,nlist));
  324.     else {
  325.     p = nlist;
  326.     q = nlist->next;
  327.     while (q != NULL && !alfcmp(innm,q->name)) {
  328.         p=q;q=p->next;
  329.         }
  330.     p->next = cons(innm,q);
  331.     return(nlist);
  332.     }
  333.     }
  334. alfcmp(s1,s2)
  335. FAST char *s1,*s2;
  336. {
  337.     FAST *u1,*u2;
  338.     FAST int cmp,ucmp;
  339.  
  340.     u1 = index(s1,'['); u2 = index(s2,'[');
  341.     cmp = strcmp(s1,s2);
  342.     ucmp = strcmp(u1,u2);
  343.     if (ucmp == 0) return(sign(cmp) == sortflg);
  344.     else return(sign(ucmp) == sortflg);
  345.     }
  346. flushdu()
  347. {
  348.     FAST NAMESP p,*q;
  349.  
  350.     p = filelist; q = (&filelist);
  351.     while (p!=NULL && (p->next) != NULL) {
  352.         if (strcmp(p->name,(p->next)->name) == 0) {
  353.         *q = p->next;
  354.         q = &(p->next);
  355.         p = p->next;
  356.         }
  357.     else {
  358.         q = &(p->next);
  359.         p = p->next;
  360.         }
  361.     }
  362.     }
  363. printfiles()
  364. {
  365.     FAST NAMESP p;
  366.     FAST int curcol;
  367.     FAST char curdev,dev,*t;
  368.     FAST int curuser,user;
  369.     FAST int dir,files,tfiles;
  370.  
  371.     curdev = '@'; curuser = (-1); curcol = 0; dir=0; files=0; tfiles=0;
  372.     for (p=filelist;p!=NULL;p=p->next) {
  373.     if (curcol == columns && !tflag) {printf("\n");curcol=0;}
  374.     dev = *(p->name);
  375.     t = index(p->name,'[')+1;
  376.     user = ((*t - '0')*10) + (*(t+1) -'0');
  377.     if ((dev != curdev) || (user != curuser)) {
  378.         if (curcol > 0 && !tflag) printf("\n");
  379.         curcol = 0;
  380.         if (trailer && files>0) printf(TFORMAT1,files);
  381.         dir++; curdev=dev; curuser=user; files=0;
  382.         if (header) printf(HFORMAT,dev,user);
  383.         }
  384.     if ((header || trailer) && !tflag) {
  385.         *(--t) = '\0';
  386.         prinfl((p->name)+2,FLEN1);
  387.         *t = '[';
  388.         }
  389.     else if (!tflag) prinfl(p->name,FLEN2);
  390.     curcol++;files++;tfiles++;
  391.     }
  392.     if (curcol>0 && !tflag) printf("\n");
  393.     if (trailer && files > 0) printf(TFORMAT1,files);
  394.     if (trailer && dir >1) printf(TFORMAT2,tfiles,dir);
  395.     }
  396. print1files()
  397. {
  398.     FAST NAMESP p;
  399.     FAST char curdev,dev,*t,*u;
  400.     FAST int curuser,user;
  401.     FAST int ai,comma;
  402.     FAST int dir,files,tfiles;
  403.     FAST long int size,fsize,tsize;
  404.     FAST long int dire,fdire,tdire;
  405.     LOCAL struct fcbtab fcb;
  406.     LOCAL DPB dpb;
  407.     int olduser,olddrv;
  408.  
  409.     olduser = __OSIF(USER, 0x00FF);
  410.     olddrv = __OSIF(GETDRV, 0);
  411.     fsize = 0L; tsize = 0L;
  412.     fdire = 0L; tdire = 0L;
  413.     curdev = '@'; curuser = (-1); dir=0; files=0; tfiles=0;
  414.     for (p=filelist;p!=NULL;p=p->next) {
  415.     dev = *(p->name);
  416.     t = index(p->name,'[')+1;
  417.     user = ((*t - '0')*10) + (*(t+1) -'0');
  418.     if ((dev != curdev) || (user != curuser)) {
  419.         if (trailer && files>0) printf(TFORMAT1,files,fsize,fdire);
  420.         dir++; curdev=dev; curuser=user; files=0; fsize = 0L; fdire=0L;
  421.         if (header) printf(HFORMAT,dev,user);
  422.         }
  423.     if ((header || trailer) && !tflag) {
  424.         *(--t) = '\0';
  425.         prinfl((p->name)+2,FLEN1);
  426.         *t = '[';
  427.         }
  428.     else if (!tflag) prinfl(p->name,FLEN2);
  429.     fcb.drive = (dev - 'A') + 1;
  430.     t = (&fcb.fname[0]); for (ai=0;ai<(8+3);ai++) *t++ = ' ';
  431.     t = (p->name)+2; u = (&fcb.fname[0]);
  432.     while (*t != '.') *u++ = *t++;
  433.     t++; u = (&fcb.ftype[0]);
  434.     while (*t != '[') *u++ = *t++;
  435.     if (sflag) {
  436.         __OSIF(USER, user);
  437.         __OSIF(FILSIZ ,&fcb);
  438.         __OSIF(USER, olduser);
  439.         __OSIF(SELDRV, dev - 'A');
  440.         __OSIF(GETDPB, &dpb);
  441.         __OSIF(SELDRV, olddrv);
  442.         size = (fcb.record + ((long) dpb.blm)) >> dpb.bsh;
  443.         if (dpb.dsm > 255) dire = (size + 7L) >> 3;
  444.         else dire = (size + 15L) >> 4;
  445.         if (dpb.bsh>3) size = size << (dpb.bsh - 3);
  446.         if (!tflag) printf(SFORMAT,size,dire);
  447.         fsize += size; tsize += size;
  448.         fdire += dire; tdire += dire;
  449.         }
  450.     if (aflag && !tflag) {
  451.         __OSIF(USER, user);
  452.         __OSIF(OPEN ,&fcb);
  453. /*        __OSIF(CLOSE ,&fcb);*/
  454.         __OSIF(USER, olduser);
  455.         t = (&fcb.fname[0]);
  456.         printf("("); comma = FALSE;
  457.         for(ai = 0;ai<(8+3);ai++) {
  458.         if (comma && strlen(attname(ai,*t))>0) printf(",");
  459.         printf("%s",attname(ai,*t));
  460.         if (strlen(attname(ai,*t))>0) comma = TRUE;
  461.         t++;
  462.         }
  463.         printf(")");
  464.         }
  465.     if (!tflag) printf("\n"); 
  466.     files++;tfiles++;
  467.     }
  468.     if (trailer && files > 0) printf(TFORMAT1,files,fsize,fdire);
  469.     if (trailer && dir >1) printf(TFORMAT2,tfiles,dir,tsize,tdire);
  470.     }
  471. usage()
  472. {
  473.     fprintf(stderr,
  474. "Usage: xdir [-r ][-cN ][-s ][-a ][-f ][-to ][-tr+/- ][-h+/- ][fname [fname ...]][>outfile]\n");
  475.     abort(2);
  476.     }
  477. badfile(n,np)
  478. FAST char *n;
  479. FAST int np;
  480. {
  481.     fprintf(stderr,"Illegal file name: %s\n                   ",n);
  482.     while ((np--)>0) fprintf(stderr," ");
  483.     fprintf(stderr,"^- parse stoped here\n");
  484.     abort(1);
  485.     }
  486. prinfl(s,l)
  487. FAST char *s;
  488. FAST int l;
  489. {
  490.     while (*s != '\0') {
  491.     printf("%c",(*s++) & 0x7F);
  492.     l--;
  493.     }
  494.     while ((l--)>0) putchar(' ');
  495.     }
  496.