/* CDIR.C - A CP/M 2.2 utility that allows operators to switch between user numbers by specifiying a name, rather than a number. This has the effect of simulating sixteen named directories in a convenient manner. When used in conjunction with ZCPR, and DUPUSR, CDIR can make CP/M a lot more livable until an operating system with a nice directory structure arrives. CDIR.C - (C) 1982 by Barry A. Dobyns. Commercial use (sales) of this program is prohibited, however, private use by individuals is encouraged. ----------------------------------------------------------------- USAGE: cdir changes to the user number that corresponds to dirname cdir /l lists available dirnames and the corresponding numbers cdir /s sets dirname to correspond to number cdir /d deletes dirname cdir /z deletes all dirnames ----------------------------------------------------------------- Usage notes: CDIR keeps the correspondence table in a data area stored with the com file. a /s /z or /d operation forces CDIR to write itself back out to disk. Also, CDIR has a list of 'internal' names that are not kept in the list. This list includes names '0'-'15', 'a'-'f' and 'root'. Any name occuring in the internal list cannot be set or deleted. Remember to zero out the table before using CDIR. If using CDIR with ZCPR or any CP/M hack that searches other drives, be careful when using /s /d and /z. Also, CDIR restricts the use of these switches to user 0. ----- create: A>cc cdir.c ;compile A>l2 cdir.c ;link A>noboot cdir.c ;fix CP/M boot problem A>cdir /z ;zero out names table As best as I can determine, CP/M loses the user number set from within an application program iff the program terminates with a warm boot instead of a ret. In other words, in the code below, the program on the left leaves one in user 15, as expected. The program on the right leaves one in whatever the previously selected user area was. ;I win ;I lose ; ; org 100H org 100H mvi c,32 mvi c,32 mvi e,15 mvi e,15 call 5 call 5 ret jmp 0 Anyone know why?? Therefore, CDIR must be run over with NOBOOT so that it returns and does not boot, otherwise it isn't very useful. ----- */ #define ERROR (-1) #define FALSE 0 #define TRUE 1 #define CDIR "CDIR.COM" #define DIRMAX 50 struct entry { char dvalid; /* whether or not it is active. */ char dnumber; /* the corresponding user number */ char dname[20]; /* the directory name */ } dirlist[DIRMAX]; int tmp; main(argc,argv) int argc; char **argv; { if (argc == 2) { /* one argument */ if (match(argv[1],"/L")) { /* either list */ list(); } else if ( match(argv[1],"/Z") && inzero() ) { /* or zero */ zero(); } else switchto(argv[1]); /* or switch to */ } /* end (argc == 2) */ else if ( (argc == 3) && match(argv[1],"/D") && inzero() ) { /* delete */ delete(argv[2]); } /* end (argc == 3) */ else if ( (argc == 4) && match(argv[1],"/S") && inzero() ) { /* set */ set(argv[2],atoi(argv[3])); } else usage(); /* bad commands */ puts("Done."); } /* end of main */ list() /* print a list of all the names */ { for (tmp = 0; tmp < DIRMAX; tmp++){ if (dirlist[tmp].dvalid) printf("\t%s\t%d\n", dirlist[tmp].dname, dirlist[tmp].dnumber); } } /* end of list() */ zero() /* zero (initialize) the table */ { setmem(codend(),endext()-codend(),0); wrtcdir(); } /* end of zero() */ switchto(name) /* switch to the user area associated with name */ char *name; { if ( (tmp=internal(name)) != ERROR ) { /* if it's internal */ setuser(tmp); /* do it now */ return; } else for (tmp = 0; tmp < DIRMAX; tmp++){ /* find it in list */ if ( (dirlist[tmp].dvalid) && match(name,dirlist[tmp].dname) ){ setuser(dirlist[tmp].dnumber); return; } } /* can't find name */ printf("Can't find name %s \n",name); } /* end of switchto(name) */ delete(name) /* remove name from list */ char *name; { if ( (tmp=internal(name)) != ERROR ) return; else for (tmp = 0; tmp < DIRMAX; tmp++){ if ( (dirlist[tmp].dvalid) && match(name,dirlist[tmp].dname) ){ dirlist[tmp].dvalid = FALSE; wrtcdir(); return; } } /* can't find name */ printf("Can't find name %s \n",name); } /* end of delete(name) */ set(name,number) /* install name in list */ char *name,number; { if ( (tmp=internal(name)) != ERROR ) return; else for (tmp = 0; tmp < DIRMAX; tmp++){ if ( !(dirlist[tmp].dvalid) ){ dirlist[tmp].dvalid = TRUE; dirlist[tmp].dnumber = number & 0x0f; strcpy(dirlist[tmp].dname,name); wrtcdir(); return; } } /* no more space */ printf("No space to add name %s \n",name); } /* end of set(name,number) */ setuser(number) char number; { number &= 0x0F; /* mask it */ bdos(32,number); /* set it */ number = bdos(32,0xff); /* make sure. */ printf("user %d\n",number); } wrtcdir() { int nscts; nscts= (endext() + 128) / 128; if ( ( (tmp = open(CDIR,1)) == ERROR) || ( seek(tmp,0,0) == ERROR ) || ( write(tmp,0x100,nscts) != nscts) || ( close(tmp) == ERROR) ) printf("Fatal Error - cannot write %s !",CDIR); } /* end of wrtcdir() */ usage() { puts("USAGE:\n"); puts("\tcdir \n"); puts("\t\tchanges to the user number that corresponds to dirname\n\n"); puts("\tcdir /l\n"); puts("\t\tlists available dirnames and the corresponding numbers\n\n"); puts("\tcdir /s \n"); puts("\t\tsets dirname to correspond to number\n\n"); puts("\tcdir /d \n"); puts("\t\tdeletes dirname \n\n"); puts("\tcdir /z\n"); puts("\t\tdeletes all dirnames \n\n"); } /* end of usage() */ badob() { return("(C) Copyright 1982 by Barry A. Dobyns"); } /* end of badob() */ match (s1, s2) /* case-independent string equality */ char *s1, *s2; { while (TRUE) { if (toupper (*s1) != toupper (*s2)) return (FALSE); if (!*s1++ || !*s2++) return (TRUE); } } internal(name) char *name; { if ( (match(name,"root")) || (match(name,"0")) ) return(0); else if (match(name,"1")) return(1); else if (match(name,"2")) return(2); else if (match(name,"3")) return(3); else if (match(name,"4")) return(4); else if (match(name,"5")) return(5); else if (match(name,"6")) return(6); else if (match(name,"7")) return(7); else if (match(name,"8")) return(8); else if (match(name,"9")) return(9); else if (match(name,"9")) return(9); else if ( (match(name,"10")) || (match(name,"a")) ) return(10); else if ( (match(name,"11")) || (match(name,"b")) ) return(11); else if ( (match(name,"12")) || (match(name,"c")) ) return(12); else if ( (match(name,"13")) || (match(name,"d")) ) return(13); else if ( (match(name,"14")) || (match(name,"e")) ) return(14); else if ( (match(name,"15")) || (match(name,"f")) ) return(15); else return(ERROR); } /* end of internal(name) */ inzero() /* true if we're in user 0 */ { return(bdos(32,0xff) == 0); } /* end inzero() */ /* end of cdir.c */  .