/* -*-c,save,tab:8,indent:4-*- */ /************************************************************************ * XDIR.C - eXtended DIRectory program. Does all kinds of good stuff * * Robert Heller 16-FEB-1985 - Media Research, Ltd. * * (c) 1985 Media Research, Ltd. * * (part of Media Research, Ltd UTILS-68K package) * ************************************************************************ * * Usage: * xdir [-r ][-cN ][-s ][-a ][-f ][-to ][-tr+/- ][-h+/- ][fname [fname ...]][>outfile] * -r - reverse alpha ordered * -cN - columns (default=5 iff -s,-a and -f NOT specified, else 1. also * iff -tr- and -h- BOTH specified then columns=1) * -s - size * -a - attributes (ie SYS/DIR, RW/RO, ARC/NOARC, etc.) * -f - fill (same as -s & -a) * -to - total - lists totals (incl. size if -s or -f) * -tr+/- - trailer (-tr+ [default]) or notrailer (-tr-) * -h+/- - header (-h+ [default]) or noheader (-h-) * fname - file name(s) format dr:name.type[user] - default spec is * curdrive:*.*[curuser] * >outfile - output file (CON: by default) * ************************************************************************ */ #include /* standard I/O defs */ #include /* character types */ #include /* O/S interface defs */ #include /* O/S interface error handling */ #include /* option defs */ NOWILDCARDS /* let use take care of wild cards ourselves */ /* missing OSIF functions: */ #define GETDRV 25 /* get current drive # */ #define GETLOG 24 /* get login vector */ #define GETDPB 31 /* get disk parameters */ #define SELDRV 14 /* select drive */ /* storage classes */ #define FAST register #define LOCAL static #define GLOBAL extern /* linked list - for file name list */ typedef struct names { char *name; struct names *next; } NAMES,*NAMESP; /* format for header */ #define HFORMAT "\nDirectory %c:[%d]\n\n" /* trailer formats */ #define TFORMAT1 (sflag?\ "\nTotal of %d files, %ld KBytes/%ld directory entries.\n":\ "\nTotal of %d files.\n") #define TFORMAT2 (sflag?\ "\nGrand Total of %d files in %d directories, %ld KBytes/%ld directory entries.\n":\ "\nGrand Total of %d files in %d directories.\n") /* file name format */ #define FLEN1 15 #define FLEN2 20 /* size format */ #define SFORMAT "%6ld/%-4ld " /* file search DMA block structure */ typedef struct { char dr; char xf[8]; char t[3]; char fill[20]; } SEABLK; /* DPB structure */ typedef struct { short int spt; /* sectors per track */ char bsh; /* block shift factor */ char blm; /* block mask */ char exm; /* extent mask */ char z; /* reserved byte */ short int dsm; /* disk storage mask (max block count - 1) */ short int drm; /* directory mask (max directory entry count - 1) */ short int zz; /* reserved word */ short int cks; /* size of the checksum vector */ short int off; /* number of reserved tracks */ } DPB; /* sign macro */ #define sign(i) (((i)<0)?(-1):(((i)>0)?(1):(0))) /* isfilech macro */ #define isfilech(c) ((index(" <>=,!|*?&/[]().:;+-\\",c) == NULL) &&\ (isprint(c))) /* search dir signs */ #define ASSENDING (-1) #define DESSENDING (1) #define DEFAULTCOLS 5 /* "global vars" */ int sortflg = ASSENDING; /* sort direction */ NAMESP filelist = NULL; /* file name list */ int columns = DEFAULTCOLS, /* # columns */ sflag = FALSE, /* size flag */ aflag = FALSE, /* attributes flag */ header = TRUE, /* header flag */ trailer = TRUE, /* trailer flag */ tflag = FALSE; /* totals flag */ /* attribute names */ char *attoffnames[] = {"","","","","","","","","RW","DIR",""}, *attonnames[] = {"F1","F2","F3","F4","F5","F6","F7","F8","RO","SYS","ARC"}; #define attname(num,ch) (((ch & 0x080) != 0)?attonnames[num]:attoffnames[num]) /* commonly used functions: */ long int __BDOS(); /* BDOS hook */ char *index(); /* index function */ /* main routine - process command line, fetch file names, and print results */ main(argc,argv) FAST int argc; FAST char **argv; { FAST NAMESP innames,x; NAMESP cons(); /* list constructor funs */ innames = NULL; while ((--argc)>0) { if (**(++argv) == '-') { /* switch? */ switch(*(++(*argv))) { case 'r' : sortflg = DESSENDING; break; case 'c' : columns = atoi(++(*argv)); break; case 's' : sflag = TRUE; break; case 'a' : aflag = TRUE; break; case 'f' : sflag = TRUE; aflag = TRUE; break; case 'h' : switch (*(++(*argv))) { case '-' : header = FALSE; break; case '+' : header = TRUE; break; default : usage(); } break; case 't' : switch (*(++(*argv))) { case 'o' : tflag = TRUE; break; case 'r' : switch (*(++(*argv))) { case '-' : trailer = FALSE; break; case '+' : trailer = TRUE; break; default : usage(); } break; default : usage(); } break; default : usage(); } } else innames = cons(*argv,innames); } if (innames == NULL) innames = cons("*.*",innames); while (innames != NULL) { fsearch(innames->name); innames = innames->next; } flushdu(); if (!header && !trailer) columns = 1; if (sflag || aflag) print1files(); else printfiles(); } NAMESP cons(nm,nml) FAST char *nm; FAST NAMESP nml; { FAST char *p; FAST int len; char *calloc(); FAST NAMESP newnl; p = calloc(strlen(nm)+1,sizeof(char)); if (p == NULL) {perror("xdir");abort(0);} strcpy(p,nm); newnl = (NAMESP) calloc(1,sizeof(NAMES)); if (newnl == NULL) {perror("xdir");abort(0);} newnl->name = p; newnl->next = nml; return(newnl); } fsearch(nm) FAST char *nm; { LOCAL struct fcbtab seafcb; FAST char *p,*q; FAST int i,j; FAST int user; FAST char dev; FAST int loginv; FAST int curuser; FAST char curdev; curuser = __OSIF(USER, 0x000000FFL); curdev = (__OSIF(GETDRV, 0L) + 'A'); loginv = __OSIF(GETLOG, 0L); j = 0; if (isalpha(*nm) && strlen(nm)>1 && *(nm+1) == ':') { dev = toupper(*nm); if (dev < 'A' || dev > 'P') badfile(q,0); nm = nm+2; j+=2; } else if (*nm == '*' && strlen(nm)>1 && *(nm+1) == ':') { dev = '*'; nm = nm+2; j+=2; } else dev = curdev; i=8+3; for(p=(&seafcb.fname[0]);i>0;i--) *p++='?'; p=(&seafcb.fname[0]); i = 0; while ((isfilech(*nm) || *nm == '?') && i<8) { *p++ = toupper(*nm); nm++; i++; j++; } if (*nm == '*') {nm++;j++;} else if (i>0 && i<8) while (i<8) {*p++ = ' '; i++;} while ((index(".[",*nm) == NULL) && (*nm != '\0')) {nm++;j++;} if (*nm == '.') { nm++;j++; p=(&seafcb.ftype[0]); i=0; while ((isfilech(*nm) || *nm == '?') && i<3) { *p++ = toupper(*nm); nm++; i++; j++; } if (*nm == '*') {nm++;j++;} else if (i>0 && i<3) while (i<3) {*p++ = ' '; i++;} } if (*nm == '[') {nm++;j++; p=nm; while (isdigit(*nm) || *nm == '*') {nm++;j++;} if (*nm != ']') badfile(q,j); *nm = '\0'; if (strlen(p) == 0) user = curuser; else if (strcmp(p,"*") == 0) user = -1; else user = atoi(p); *nm = ']'; nm++;j++; } else user = curuser; if (*nm != '\0') badfile(q,j); if (dev == '*') { for (i=0;i<16;i++) if ((loginv & (1 << i)) != 0) { seafcb.drive = i+1; sealop0(&seafcb,user,i+'A'); } } else { seafcb.drive = (dev - 'A')+1; sealop0(&seafcb,user,dev); } __OSIF(USER, curuser); } sealop0(fcb,user,dev) FAST struct fcbtab *fcb; FAST int user; FAST char dev; { int i; if (user == (-1)) for (i=0;i<16;i++) sealop(fcb,i,dev); else sealop(fcb,user,dev); } sealop(fcb,user,dev) FAST struct fcbtab *fcb; FAST int user; FAST char dev; { LOCAL SEABLK seadma[4]; FAST int status,i; FAST char *p,*q; LOCAL char nbuff[20]; NAMESP orderin(); /* list constructor funs */ __OSIF(USER, user); __OSIF(SETDMA, (&seadma[0])); status = __OSIF(SEARCHF, fcb); while (status != 0x00FF) { p = (&nbuff[0]); *p++ = dev; *p++ = ':'; q = (&seadma[status].xf[0]); i = 0; while ((*q & 0x7F) != ' ' && i <8) { *p++ = (*q++); i++; } *p++ = '.'; q = (&seadma[status].t[0]); i=0; while ((*q & 0x7F) != ' ' && i < 3) { *p++ = (*q++); i++; } *p++ = '['; if (user > 9) { *p++ = (user / 10) + '0'; *p++ = (user % 10) + '0'; } else { *p++ = '0'; *p++ = user + '0'; } *p++ = ']'; *p='\0'; filelist = orderin((&nbuff[0]),filelist); status = __OSIF(SEARCHN, 0L); } } NAMESP orderin(innm,nlist) FAST char *innm; FAST NAMESP nlist; { FAST NAMESP newnl,p,q; if (nlist == NULL) return(cons(innm,nlist)); else if (alfcmp(innm,nlist->name)) return(cons(innm,nlist)); else { p = nlist; q = nlist->next; while (q != NULL && !alfcmp(innm,q->name)) { p=q;q=p->next; } p->next = cons(innm,q); return(nlist); } } alfcmp(s1,s2) FAST char *s1,*s2; { FAST *u1,*u2; FAST int cmp,ucmp; u1 = index(s1,'['); u2 = index(s2,'['); cmp = strcmp(s1,s2); ucmp = strcmp(u1,u2); if (ucmp == 0) return(sign(cmp) == sortflg); else return(sign(ucmp) == sortflg); } flushdu() { FAST NAMESP p,*q; p = filelist; q = (&filelist); while (p!=NULL && (p->next) != NULL) { if (strcmp(p->name,(p->next)->name) == 0) { *q = p->next; q = &(p->next); p = p->next; } else { q = &(p->next); p = p->next; } } } printfiles() { FAST NAMESP p; FAST int curcol; FAST char curdev,dev,*t; FAST int curuser,user; FAST int dir,files,tfiles; curdev = '@'; curuser = (-1); curcol = 0; dir=0; files=0; tfiles=0; for (p=filelist;p!=NULL;p=p->next) { if (curcol == columns && !tflag) {printf("\n");curcol=0;} dev = *(p->name); t = index(p->name,'[')+1; user = ((*t - '0')*10) + (*(t+1) -'0'); if ((dev != curdev) || (user != curuser)) { if (curcol > 0 && !tflag) printf("\n"); curcol = 0; if (trailer && files>0) printf(TFORMAT1,files); dir++; curdev=dev; curuser=user; files=0; if (header) printf(HFORMAT,dev,user); } if ((header || trailer) && !tflag) { *(--t) = '\0'; prinfl((p->name)+2,FLEN1); *t = '['; } else if (!tflag) prinfl(p->name,FLEN2); curcol++;files++;tfiles++; } if (curcol>0 && !tflag) printf("\n"); if (trailer && files > 0) printf(TFORMAT1,files); if (trailer && dir >1) printf(TFORMAT2,tfiles,dir); } print1files() { FAST NAMESP p; FAST char curdev,dev,*t,*u; FAST int curuser,user; FAST int ai,comma; FAST int dir,files,tfiles; FAST long int size,fsize,tsize; FAST long int dire,fdire,tdire; LOCAL struct fcbtab fcb; LOCAL DPB dpb; int olduser,olddrv; olduser = __OSIF(USER, 0x00FF); olddrv = __OSIF(GETDRV, 0); fsize = 0L; tsize = 0L; fdire = 0L; tdire = 0L; curdev = '@'; curuser = (-1); dir=0; files=0; tfiles=0; for (p=filelist;p!=NULL;p=p->next) { dev = *(p->name); t = index(p->name,'[')+1; user = ((*t - '0')*10) + (*(t+1) -'0'); if ((dev != curdev) || (user != curuser)) { if (trailer && files>0) printf(TFORMAT1,files,fsize,fdire); dir++; curdev=dev; curuser=user; files=0; fsize = 0L; fdire=0L; if (header) printf(HFORMAT,dev,user); } if ((header || trailer) && !tflag) { *(--t) = '\0'; prinfl((p->name)+2,FLEN1); *t = '['; } else if (!tflag) prinfl(p->name,FLEN2); fcb.drive = (dev - 'A') + 1; t = (&fcb.fname[0]); for (ai=0;ai<(8+3);ai++) *t++ = ' '; t = (p->name)+2; u = (&fcb.fname[0]); while (*t != '.') *u++ = *t++; t++; u = (&fcb.ftype[0]); while (*t != '[') *u++ = *t++; if (sflag) { __OSIF(USER, user); __OSIF(FILSIZ ,&fcb); __OSIF(USER, olduser); __OSIF(SELDRV, dev - 'A'); __OSIF(GETDPB, &dpb); __OSIF(SELDRV, olddrv); size = (fcb.record + ((long) dpb.blm)) >> dpb.bsh; if (dpb.dsm > 255) dire = (size + 7L) >> 3; else dire = (size + 15L) >> 4; if (dpb.bsh>3) size = size << (dpb.bsh - 3); if (!tflag) printf(SFORMAT,size,dire); fsize += size; tsize += size; fdire += dire; tdire += dire; } if (aflag && !tflag) { __OSIF(USER, user); __OSIF(OPEN ,&fcb); /* __OSIF(CLOSE ,&fcb);*/ __OSIF(USER, olduser); t = (&fcb.fname[0]); printf("("); comma = FALSE; for(ai = 0;ai<(8+3);ai++) { if (comma && strlen(attname(ai,*t))>0) printf(","); printf("%s",attname(ai,*t)); if (strlen(attname(ai,*t))>0) comma = TRUE; t++; } printf(")"); } if (!tflag) printf("\n"); files++;tfiles++; } if (trailer && files > 0) printf(TFORMAT1,files,fsize,fdire); if (trailer && dir >1) printf(TFORMAT2,tfiles,dir,tsize,tdire); } usage() { fprintf(stderr, "Usage: xdir [-r ][-cN ][-s ][-a ][-f ][-to ][-tr+/- ][-h+/- ][fname [fname ...]][>outfile]\n"); abort(2); } badfile(n,np) FAST char *n; FAST int np; { fprintf(stderr,"Illegal file name: %s\n ",n); while ((np--)>0) fprintf(stderr," "); fprintf(stderr,"^- parse stoped here\n"); abort(1); } prinfl(s,l) FAST char *s; FAST int l; { while (*s != '\0') { printf("%c",(*s++) & 0x7F); l--; } while ((l--)>0) putchar(' '); }