Skip navigation.

Cdir

The compiler used was BDSC created by Leor Zolman. A recent tool of Leor is STLFilt: An STL Error Message Decryptor for C++.

See http://www.bdsoft.com/tools/stlfilt.html.

There was a time we had a multi-project computer in the Huygens Laboratory: a DEC VAX-11/750 I believe. Later it was replaced by a microVAX of some model.

With program cdir I tried to mimic some of the characteristics of the VMS dir command

/*
%cc1 cdir.c
%clink cdir.c
*/

/*		   VMS alike DIR program for CPM			*/

/*
	(C) 12-1986				Release : 1.00
						Date    : 27/01/86 
	M.J. Moene
	Linnaeusparkweg 46-III			Uncommented version
	1098 EC Amsterdam
*/

#define DRIVES    "AB"
#define NRDRIVES   2

#define NRUSER    16

#define FPERLINE   4	/* Nr. of files displayed on a line 		*/
#define LPERSCRN  24	/* Nr. of lines displayed when /PAGE switch on	*/

#define NUMNODES 128	/* max number of nodes of tree			*/
#define NIL        0	/* nil pointer					*/

#define TRUE       1	/* Boolean true					*/

struct  nodetype
	{
	char name[12],
	     driv;
	int  usnr,
	     prot;
	unsigned
	     nrec;
	int  left,right;
	}
	node[NUMNODES+1];

unsigned
     fperline,		/* filenames per line		*/
     lcount,		/* line-count			*/
     fcount,		/* file-count in directory	*/
     dircount,		/* number of nonempty dir.	*/
     dirsize,		/* total filesize in directory  */
     sizmin,		/* minimum filesize search for  */
     sizmax,		/* maximum filesize search for  */
     grandtotal,	/* total nr of files		*/
     grandsize,		/* total of filesizes		*/

     avail,		/* available nodes left		*/
     tree[NRDRIVES][NRUSER],	/* tree pointers	*/
     usr[NRUSER+1];	/* user directories to display  */
 
char drv[NRDRIVES+1],	/* drives to scan		*/
     fspec[15],		/* filename to scan		*/
     strexcl[15];	/* filename to skip		*/

int  tfull,		/* cdir tags			*/
     thelp,
     texcl,
     tsize,
     tsys,
     tpage,
     tprot,
     twprt,
     tarch,
     talpr,
     tsort,
     tsmax,
     tsmin,
     tsnam,
     tuser,
     twide;

int  fstsrch;
char fcb[33],		/* File Control Block		*/
     dirbuf[4][32];	/* Directory buffer		*/


main(argc,argv)
int  argc;
char *argv[];
{

	init();
	chck_arg(argc,argv);
	parse(argc,argv);
	tags();

	grow_forest();
	visit_forest();

	exit(0);				/* normal exit */
}


/*			Error exit					*/

error(n,s)
int  n;
char *s;
{
	switch(n){
	  case 1 : puts("Error-Option must start with '/'\n");       break;
	  case 2 : printf("Error-Unknown option : /%s\n",s);         break;
	  case 3 : puts("Error-/User='0,..15' or 'all' expected\n"); break;
	  case 4 : puts("Error-/Protection='read', 'system' or 'archive' expected\n"); break;
	  case 5 : puts("Error-/Sort=name expected\n");      	     break;
	  case 6 : puts("Error-/Size='maximum, 'minimum'=n (kbytes) expected\n");      break;
	  case 7 : puts("Error-/Exclude=filename.ext expected\n");   break;
	  default: puts("Error-Wrong CDIR syntax\n");
	}
	exit(1);
}

hlp()
{
	puts("\nSummary of CDIR options :\n\n");
	puts("/help .......................: this help message\n");
	puts("/full .......................: display all information of specified file(s)\n");
	puts("/page .......................: hold screen at 24 lines\n");
	puts("/sort=name ..................: display all specified files as one list\n");
	puts("/exclude=filename.ext .......: don't display these specified files\n");
	puts("/size=[[maximum][minimum]=n] : display\n");
	puts("                               - size of file in bytes\n");
	puts("                               - file-size <= maximum of n kbytes\n");
	puts("                               - file-size >= minimum of n kbytes\n");
	puts("/protection[=[read[,system][,archive]][all]]\n");
	puts("                             : display\n");
	puts("                               - protection of file\n");
	puts("                               - R/O      files\n");
	puts("                               - system   files\n");
	puts("                               - archived files\n");
	puts("                               - all      files\n");
	puts("/user[=[0,..15][all]] .......: display\n");
	puts("                               - current user nr.\n");
	puts("                               - files of user 0,..15\n");
	puts("                               - files of all users\n");
	exit(0);
}


/*			general functions				*/


int currentuser()
{
	return (bdos(32,0x00FF));
}

selectuser(n)
int n;
{
	if (n<=15 && n>=0) bdos(32,n);
}
	
char currentdrive()
{
	return(bdos(25) + 'A');
}

selectdrive(d)
char d;
{
	if (isalpha(d)) bdos(14,d-'A');		/* select disk	*/
}

int isalnum(c)
char c;
{	return (isalpha(c) || isdigit(c));}

int isnumber(s)
char *s;
{	while (isdigit(*s) && *s!='\0') s++;
	return (*s=='\0' ? 1: 0);
}

/*			end general functions				*/


/*			command line functions				*/

char *arg_scan(p, argv)
char *p, *argv;
{
	while (!isalnum(*argv) && *argv != '\0') argv++;
	if (isalnum(*argv)){
	  while (isalnum(*argv)) *p++= *argv++;
	  *p= '\0';
	  return(argv);
	} else return(0);
}

char *arg_find(c, argv)
char c, *argv;
{
	while (*argv != c && *argv != '\0') argv++;
	return (*argv == c ? argv : 0);
}

int argcmp(p, q)
	char *p, *q;
{
	int i; i=0;
	if (strlen(p) <= strlen(q)){
       	  while (p[i] != '\0' && p[i]==q[i]) i++;
	  return (p[i]=='\0' ? i: 0);
	}
	else return (0);
}

chck_arg(argc,argv)
int argc;
char **argv;
{
	int i;
	for (i=1; i<argc-1; i++)
	  if (argv[i][0] != '/') error(1);
}

parse(argc,argv)
int  argc;
char **argv;
{
	int i;
	char tmp[20];
	if (argc==1) strcpy(fspec,"*.*");
	else{
	  if (argv[argc-1][0] != '/') { strcpy(fspec,argv[argc-1]); argc -= 1;}
	    else strcpy(fspec,"*.*");
	  for (i=1; i<argc; i++){
	    argv[i]= arg_scan(tmp, argv[i]);
	    if (argcmp(tmp,"HELP")       > 0) { thelp=1; hlp();}   /* never returning */
	    if (argcmp(tmp,"EXCLUDE")    > 1) { texcl=1; prs_excl(argv[i]); goto endf;}
	    if (argcmp(tmp,"USER")       > 1) { tuser=1; prs_usr (argv[i]); goto endf;}
	    if (argcmp(tmp,"PROTECTION") > 1) { tprot=1; prs_prot(argv[i]); goto endf;}
	    if (argcmp(tmp,"SIZE")       > 1) { tsize=1; prs_size(argv[i]); goto endf;}
	    if (argcmp(tmp,"FULL")       > 1) { tfull=1; goto endf;}
	    if (argcmp(tmp,"SORT")       > 1) { tsort=1; prs_sort(argv[i]); goto endf;}
	    if (argcmp(tmp,"PAGE")       > 1) { tpage=1; goto endf;}
	    error(2,tmp);
	    endf:;
	  }
	}
}

prs_excl(argv)
char *argv;
{
	char d; /* dummy d */
	if (argv= arg_find('=', argv)) {
	  if (*++argv !=0) {
	    strcpy(strexcl,argv);
	    form_spec(d,strexcl);
	  } else error(7);
	}   else error(7);
}

prs_usr(argv)
char *argv;
{
	int  i, done; i= done= 0;
	char tmp[10];
	if ((argv= arg_find('=',argv)) != 0)
	  if ((argv= arg_scan(tmp,argv)) != 0) {
	    if (argcmp(tmp,"ALL") > 1) usr_all();
	      else while (i<=15 && !done)
		if (isnumber(tmp)) {
		  usr[i]= atoi(tmp);
		  i+=1;
		  done= (argv= arg_scan(tmp,argv))== 0 ? 1 : 0;
	        }
	        else error(3);
	  }
	  else error(3);
}

usr_all()
{
	int i;
	for (i=0; i<16; usr[i]=i, i++);
}

prs_prot(argv)
char *argv;
{
	char tmp[10];
	if (argv= arg_find('=',argv)){
	  if (argv != 0)
	    while ((argv= arg_scan(tmp,argv)) != 0) prs_prt1(tmp);
	  else error(4);
	}
}

prs_prt1(tmp)
char *tmp;
{
	if (argcmp(tmp, "READ")   > 1) { twprt=1; goto endf;}
	if (argcmp(tmp, "SYSTEM") > 1) { tsys =1; goto endf;}
	if (argcmp(tmp, "ARCHIVE")> 1) { tarch=1; goto endf;}
	if (argcmp(tmp, "ALL")    > 1) { talpr=1; goto endf;}
	error(4);
	endf:;
}

prs_size(argv)
char *argv;
{
	char tmp[10];
	if (argv= arg_find('=', argv))
	  if (argv != 0)
	    if ((argv= arg_scan(tmp,argv)) != 0) prs_siz1(tmp);
	  else error(6);

	  if (tsmax) prs_smax(argv);
	  if (tsmin) prs_smin(argv);
}

prs_siz1(tmp)
char *tmp;
{
	if (argcmp(tmp, "MAXIMUM")> 2) { tsmax=1; goto endf;}
	if (argcmp(tmp, "MINIMUM")> 2) { tsmin=1; goto endf;}
	error(6);
	endf:;
}	

prs_smax(argv)
char *argv;
{
	char tmp[5];
	if (argv= arg_find('=', argv)) {
	  if (argv= arg_scan(tmp,argv)) {
	    if (isnumber(tmp)) sizmax= atoi(tmp) * 8;
	    else error(6);
	  } else error(6);
	}   else error(6);
}

prs_smin(argv)
char *argv;
{
	char tmp[5];

	if (argv= arg_find('=', argv)) {
	  if (argv= arg_scan(tmp,argv)) {
	    if (isnumber(tmp)) sizmin= atoi(tmp) * 8;
	    else error(6);
	  } else error(6);
	}   else error(6);
}

prs_sort(argv)
char *argv;
{
	char tmp[10];
	if (argv= arg_find('=', argv)) {
	  if (argv != 0)
	    while ((argv= arg_scan(tmp,argv)) != 0) prs_srt1(tmp);
	  else error(5);
	}
	else error(5);
}

prs_srt1(tmp)
char *tmp;
{
	if (argcmp(tmp, "NAME")   > 2) { tsnam=1; goto endf;}
	error(5);
	endf:;
}

tags()
{
	if (tfull) tsize= tprot= tuser= 1;
	twide= (tsize || tprot) ? 0 : 1;
	if (tsnam) {tuser= 1;twide= 0;}
}

/*			end command line functions			*/


/*			BINARY  TREE					*/

initavail()
{
	int i;
	avail = 1;
	for (i=1; i<NUMNODES; i++) node[i].right = i+1;
	node[NUMNODES].right = NIL;
}

int getnode()
{
	int n;
	if (avail==NIL) printf("List overflow\n");
	else {
	  n = avail;
	  avail = node[avail].right;
	  return(n);
	}
}

freenode(p)
	int p;
{
	node[p].right = avail;
	avail = p;
}

int maketree(x)
struct nodetype *x;
{
	int p;
	p = getnode();
	node[p].driv= x->driv;
	node[p].usnr= x->usnr;
	node[p].prot= x->prot;
	node[p].nrec= x->nrec;
	strcpy(node[p].name, x->name); 
	node[p].left = NIL;
	node[p].right= NIL;
	return(p);
}

setleft(p, x)
int p;
struct nodetype *x;
{
	int q;
	if (p==NIL) printf("Void insertion\n");
	  else if (node[p].left != NIL)
		 printf("Illegal setleft operation\n");
		 else {
			q = maketree(x);
			node[p].left = q;
		 }
}

setright(p, x)
int p;
struct nodetype *x;
{
	int q;
	if (p==NIL) printf("Void insertion\n");
	  else if (node[p].right != NIL)
		 printf("Illegal setright operation\n");
		 else {
			q = maketree(x);
			node[p].right = q;
		 }
}


place(p, x)
int  *p;
struct nodetype *x;
{
	int q,r;
	int cmp;

	if (*p == NIL) *p= maketree(x);
	  else {
	    r= *p;
	    while (r != NIL){
	      q = r;
	      cmp= strcmp(x->name,node[r].name);
	      if (cmp > 0) r = node[r].right;
	        else r = node[r].left;
	    }
	    if (cmp > 0) setright(q, x);
	      else setleft(q, x);
	  }
}

visit_forest()
{
	int i, k;

	if (tsnam) visit_snam(tree[0][0]);
	else {
	  for (i=0; i < NRDRIVES; i++)
	    for (k=0; k < NRUSER; k++)
	      if (tree[i][k]  != NIL){
		line();
	        printf("Directory [user %c%d]",drv[i],usr[k]);
		line(); line();
	        visit(tree[i][k]);
	        dircount++;
	      }		/* if(tree) */
	}		/* else     */
	if (grandtotal == 0) puts("NO FILE\n");
	else
	  if (dircount > 1) {
	    line();
	    printf("Grand total of %d directories, %d files", dircount, grandtotal);
	    if (tsize) printf(", %d kbytes",grandsize);
	    puts("."); line();
	  }
}

visit_snam(t)
int t;
{
	intrav(t);
	grandsize = dirsize;
	grandtotal= fcount;
}

visit(t)
int t;
{
	fcount= dirsize= fperline= 0;

	intrav(t);
	if (twide) if (fcount % FPERLINE != 0) line();
	if (fcount>1) {
	  line();
	  printf("Total of %d files",fcount);
	  if (tsize) printf(", %d kbytes", dirsize);
	  puts(".");
	  line();
	}

	grandsize  += dirsize;
	grandtotal += fcount;	
}

intrav(t)
int t;
{
	if (t != NIL){
	  intrav(node[t].left);
	  write_info(t);
	  intrav(node[t].right);
	}
}

/*			end tree functions				*/


write_info(t)
int t;
{
	unsigned allocsize;

	write_name(node[t].name);

	if (twide) {
	  if (++fperline >= FPERLINE) {
	    fperline= 0;
	    line();
	  } else puts("       ");
	}
	else {
	  if (tprot) {
	    puts("   (R");
	    printf((node[t].prot & 1) == 0 ? ",W" : ", ");
	    printf((node[t].prot & 2) == 0 ? ", " : ",S");
	    printf((node[t].prot & 4) == 0 ? ", " : ",A");
	    putchar(')');
	  }
	  if (tsnam) printf("   [user %c%2u]",node[t].driv, node[t].usnr);
	  if (tsize) {
	    allocsize= ((node[t].nrec+15)/16)*2;
	    if (node[t].nrec <= 512)
	      printf("   %5u bytes",node[t].nrec * 128);
	      else printf("   %5u kbytes",(node[t].nrec+4)/8);
	    printf("   (%3uk)",allocsize);
	    dirsize += allocsize;
	  }
	  line();
	}
	fcount++;
}

write_name(s)
char *s;
{
	int i;
	for (i=0; i<8; i++) putchar(s[i] & 0x7F);
	putchar('.');
	for (i=8; i<11;i++) putchar(s[i] & 0x7F);
}

line()
{
	if (tpage && ++lcount >= LPERSCRN) {
	  puts("\nHit any key to continue...");
	  while(!kbhit());
	  puts("\r                          \r");
	  lcount=0;
	}
	else putchar('\n');
}


/*			miscellaneous cdir functions			*/

init()
{
/*	puts("Init()\n");
*/	int i, k;

	fperline=
	lcount=
	fcount=
	dircount=
	dirsize=
	grandtotal=
	grandsize=0;

	twide=
	tpage=
	texcl=
	tfull=
	tuser=
	tsize=
	tprot=
	twprt=
	tsys=
	talpr=
	tarch=
	tsort=
	tsmax=
	tsmin=
	tsnam=0;

	sizmin=0;
	sizmax=0xFFFF;

	initavail();

	for (i=0; i<NRDRIVES; i++)
	  for (k=0; k<NRUSER; k++) tree[i][k]= NIL;

	for (i=0; i<NRDRIVES; drv[i]= 0, i++);   drv[0]= currentdrive();
	for (i=0; i<NRUSER  ; usr[i]= 127, i++); usr[0]= currentuser();
}

fltrsiz1(t1,t2)
int *t1,t2;
{
	if (t2 != NIL){
	  fltrsiz1(t1,node[t2].left);
	  fltrsiz1(t1,node[t2].right);
	  if (node[t2].nrec >= sizmin && node[t2].nrec <= sizmax) place(t1,&node[t2]);
	  freenode(t2);
	}
}

fltrsize()
{
	int t,i,k;
	for (i=0; i<NRDRIVES; i++)
 	  for (k=0; k<NRUSER; k++) {
	    t= NIL; 
	    fltrsiz1(&t,tree[i][k]);
	    tree[i][k]= t;
	  }
}
	

addtree(t1,t2)
int *t1,t2;
{
	if (t2 != NIL) {
	  addtree(t1,node[t2].left);
	  addtree(t1,node[t2].right);
	  place(t1,&node[t2]);
	  freenode(t2);
	}
}

sortnam()
{
	int oak,i,k;
	oak= NIL; i=k=0;

	puts("Sorting... \r");

	for(i=0; i< NRDRIVES; i++)
	  for (k=0; k< NRUSER; k++)
	    if (tree[i][k] != NIL) {
	      dircount++;
	      addtree(&oak,tree[i][k]);
	      tree[i][k]= NIL;
	    }
	tree[0][0]= oak;
}

unsigned fsizrec(n)
char *n;
{
	int i;
	char lfcb[36];
	unsigned *s;

	s= &lfcb[33];
	for (i=0; i<=35; i++) lfcb[i]= 0;

	strcpy(&lfcb[1], n);
	bdos(35,lfcb);
	return(*s);
}

calcsize(t)
int t;
{
	if (t != NIL) {
	  node[t].nrec= fsizrec(node[t].name);
	  calcsize(node[t].left);
	  calcsize(node[t].right);
	}
}

form_spec(d,n)
char *d, *n;
{
	char tmp[15];
	int i, *nn; i=0; nn=n;
	strcpy(tmp,"           ");

	if (n[1] == ':') {
	  if (isalpha(n[0])) { d[0]= n[0]; d[1]= '\0';}
	  else strcpy(d, DRIVES);
	  n= &n[2];
	}

	while (*n != '*' && *n != '.' && *n) tmp[i++]= *n++;
	if (*n== '*') {
	  while (*n != '.' && *++n);
	  while (i < 8) tmp[i++]= '?';
	  while (*--n != '*') tmp[--i]= *n;
	}
	i=8;
	while (*n != '.' && *n++);
	if (*n++ == '.') {
	  while (*n != '*' && *n) tmp[i++]= *n++;
	  if (*n== '*') {
	    while (*++n);
	    while (i<11) tmp[i++]= '?';
	    while (*--n != '*') tmp[--i]= *n;
	  }
	}
	n=nn;
	strcpy(n,tmp);
}

int srchfst(s)
char *s;
{
	int i;

	for (i= 0; i<=32; i++) fcb[i]= '\0';	/* fcb[0] : def.drive() */
	for (i= 1; i<=11; i++) fcb[i]= s[i-1];

	bdos(26,dirbuf);	/* set DMA address		*/

	return(bdos(17,fcb));	/* search-first directory entry	*/
}

char *search(s)
char *s;
{
	int A;
	if (fstsrch) {
	  fstsrch=0;		/* before using 'search' fstsrch to 1	*/
	  A= srchfst(s);
	}
	else A= bdos(18,fcb);	/* search-next dir. entry function	*/

	if (A>3) return(0);
	else {
	  dirbuf[A][12]= '\0';
	  return(&dirbuf[A][1]);
	}
}

exclcmp(s1,s2)
char *s1,*s2;
{
	while (*s2 && (*s2 == '?' || (*s1 & 0x7F)== *s2)) { s1++; s2++;}
	if (*s2) return(*s2 - *s1);
	else return(0);
}

condplace(t,d,u,n)
int *t, u;
char d, *n;
{
	struct nodetype x;

	x.prot= 0;
	if (n[8] > 127) x.prot |= 1;
	if (n[9] > 127) x.prot |= 2;
	if (n[10]> 127) x.prot |= 4;

	if (!(texcl && exclcmp(n,strexcl)== 0))
	if(
	  (talpr) ||
	  ((twprt && x.prot & 1) !=0 ) ||
	  ((tsys  && x.prot & 2) !=0 ) ||
	  ((tarch && x.prot & 4) !=0 ) ||
	  ((x.prot & 2)==0 && !twprt && !tsys && !tarch)
	  ) {
	  x.driv= d;
	  x.usnr= u;
	  strcpy(x.name,n);
	  place(t,&x);
	}
}

int grow_forest()
{
	int i, k, defusr;
	char defdrv, *name;

	puts("Working... \r");
	defdrv= currentdrive();
	defusr= currentuser();
	form_spec(drv,fspec);

	i= 0;
	while (drv[i] !=0 && i< NRDRIVES) {
	  selectdrive(drv[i]);
	  k= 0;
	  while (usr[k] <= 15 && k< NRUSER) {
	    selectuser(usr[k]);
	    fstsrch    = TRUE;
	    while (name= search(fspec)) condplace(&tree[i][k], drv[i], usr[k], name);
	    if (tsize) calcsize(tree[i][k]);
	    k++;
	  }
	  i++;
	}
	if (tsnam) sortnam();
	if (tsmin || tsmax) fltrsize();

	selectdrive(defdrv);
	selectuser(defusr);

	puts("          \r");
}