home *** CD-ROM | disk | FTP | other *** search
-
- DIRLIB for MS-DOS
- -----------------
-
- Enclosed is an implementation of the `dirlib' package for MS-DOS.
- The implementation is targeted for MS-C, although any reasonably
- competent C compiler should manage. The package consists of:
-
- dir.h the header file
- dir.c the functions
- testdir.c a q&d test program
-
- The package tries to view directory naming in a Un*x light; in particular,
- directories such as '/.' and '/..' (as well as `.' and `..' if your
- current directory is root) are understood. Indefinite paths like
- `/../.././../..' will correctly refer to the root (of the particular disk).
- Names such as `a:////./../' are okay too.
-
- I've tried to be as sensible about DTA's as possible, since you never
- know who will be using one; they are set before use, and reset afterwards.
-
- There is some cruft in the package, namely the way `seekdir' and
- `telldir' are done. The code was derived from a little experimentation,
- and may not work after a certain point (although I believe the 2.x version
- to be solid). Caveat utilitor.
-
- Documentation for the package is available in the public domain; the
- package's functionality was derived from this documentation.
-
- Bug reports and comments are welcome. Enjoy!
-
- - Matt
-
- -------
- UUCP: {ucbvax,ihnp4,randvax,trwrb!trwspp,ism780}!ucla-cs!matt
- ARPA: matt@LOCUS.UCLA.EDU
- Ph: (213) 825-2756
-
- ---------------------------- dirlib.h -------------------------------
-
- /* DIRLIB.H by M. J. Weinstein Released to public domain 1-Jan-89 */
-
- #define MAXNAMLEN 15
-
- struct direct {
- long d_ino;
- unsigned short d_reclen;
- unsigned short d_namlen;
- char d_name[MAXNAMLEN+1];
- };
-
- typedef struct {
- struct {
- char fcb[21];
- char attr;
- short time;
- short date;
- long size;
- char name[13];
- } dd_dta;
- short dd_dosver; /* which version of dos? */
- short dd_stat; /* status return from last lookup */
- char dd_name[1]; /* full name of file -- struct is extended */
- } DIR;
-
- #ifdef LINT_ARGS
- DIR *opendir(char *);
- struct direct *readdir(DIR *);
- long telldir(DIR *);
- void seekdir(DIR *, long);
- void closedir(DIR *);
- #else
- DIR *opendir();
- struct direct *readdir();
- long telldir();
- #endif LINT_ARGS
-
- #define rewinddir(dirp) seekdir(dirp,0L)
-
- --------------------------- dirlib.c ---------------------------------
-
- /*
- Directory Access Library
-
- DIRLIB.C by M. J. Weinstein
- Released to public domain 1-Jan-89
-
- The author may be contacted at:
- matt@cs.ucla.edu -or- POB 84524, L.A., CA 90073
- */
-
-
- /*
- * revision history:
- *
- * VER MM/DD/YY COMMENTS
- * ---- -------- --------
- * 0.99 02/24/86 Beta release to INTERNET
- */
-
- #define LINT_ARGS
-
- #include <stdlib.h>
- #include <ctype.h>
- #include <errno.h>
- #include <string.h>
- #include <dos.h>
- #include <malloc.h>
-
- #include "dir.h"
-
- #ifdef DEBUG
- # define PRIVATE
- #else
- # define PRIVATE static
- #endif DEBUG
-
- PRIVATE _err;
-
- PRIVATE DIR *_findfirst(char *, DIR *);
- PRIVATE DIR *_findnext(DIR *);
- PRIVATE char far *_getsetdta(char far *);
-
- #ifdef DEBUG
-
- #include <stdio.h>
-
- PRIVATE void _dumpdir(DIR *);
-
- PRIVATE void _dumpdir(dirp)
- DIR *dirp;
- {
- int i;
- char *cp;
-
- printf("\ndump of DIR at %xH: fcb:", dirp);
- for (i = 0, cp = (char *)&dirp->dd_dta;
- i < sizeof(dirp->dd_dta.fcb); i++, cp++) {
- if ((i%16) == 0)
- printf("\n%3.3d (%3.3xH): ", i);
- printf("%3d ", (unsigned) *cp & 0xff);
- }
- printf("\nattr %xH time %d date %d size %ld name %s\n",
- dirp->dd_dta.attr, dirp->dd_dta.time,
- dirp->dd_dta.date, dirp->dd_dta.size, dirp->dd_dta.name);
- printf("ver %d stat %d pattern %s\n\n",
- dirp->dd_dosver, dirp->dd_stat, dirp->dd_name);
- }
-
- #endif DEBUG
-
- /*
- * return dos major version #
- */
-
- PRIVATE int dosver()
- {
- union REGS r;
- r.h.ah = 0x30;
- intdos(&r, &r);
- return (int)r.h.al;
- }
-
- /*
- * get/set dta address
- */
-
- PRIVATE char far *_getsetdta(newdta)
- char far *newdta;
- {
- char far *olddta;
- union REGS r;
- struct SREGS s;
-
- /* get old dta */
- r.h.ah = 0x2f;
- intdos(&r, &r);
- segread(&s);
- FP_SEG(olddta) = s.es;
- FP_OFF(olddta) = r.x.bx;
-
- /* conditionally set new dta */
- if (newdta) {
- r.h.ah = 0x1a;
- s.ds = FP_SEG(newdta);
- r.x.dx = FP_OFF(newdta);
- intdosx(&r, &r, &s);
- }
-
- return olddta;
- }
-
- /*
- * dos findfirst
- */
-
- PRIVATE DIR *_findfirst(name, dirp)
- char *name;
- DIR *dirp;
- {
- union REGS r;
- struct SREGS s;
- char far *dtasave;
-
- dtasave = _getsetdta((char far *)dirp);
-
- /* do directory lookup */
- segread(&s);
- r.h.ah = 0x4e;
- r.x.cx = 0x10;
- r.x.dx = FP_OFF((char far *)name);
- s.es = FP_SEG((char far *)name);
- intdosx(&r, &r, &s);
- /* restore dta */
- _getsetdta(dtasave);
- _err = r.x.ax;
- if (r.x.cflag)
- return (DIR *) 0;
- #ifdef DEBUG
- _dumpdir(dirp);
- #endif DEBUG
- return dirp;
- }
-
- /*
- * dos findnext
- */
-
- PRIVATE DIR *_findnext(dirp)
- DIR *dirp;
- {
- union REGS r;
- struct SREGS s;
- char far *dtasave;
-
- dtasave = _getsetdta((char far *)dirp);
-
- /* do directory lookup */
- r.h.ah = 0x4f;
- intdos(&r, &r);
- /* restore old dta */
- _getsetdta(dtasave);
- _err = r.x.ax;
- if (r.x.cflag)
- return (DIR *) 0;
- #ifdef DEBUG
- _dumpdir(dirp);
- #endif DEBUG
- return dirp;
- }
-
- /*
- * get working directory for a particular drive
- */
-
- PRIVATE char *getdcwd(drive)
- int drive;
- {
- union REGS r;
- struct SREGS s;
- static char xcwd[64];
- char far *cwd = xcwd;
-
- r.h.ah = 0x47;
- r.h.dl = drive;
- r.x.si = FP_OFF(cwd);
- s.ds = FP_SEG(cwd);
- intdosx(&r, &r, &s);
- _err = r.x.ax;
- if (r.x.cflag)
- return (char *) 0;
- return xcwd;
- }
-
- /*
- * opendir
- */
-
- #define SUFFIX "\\*.*"
- #define SLASH "\\"
- #define streq(a,b) (strcmp(a,b)==0)
-
- DIR *opendir(name)
- char *name;
- {
- register DIR *nd;
- char *cwd;
- char drive[3];
- int atroot = 0;
- int rooted = 0;
-
- /*
- * hack off drive designator if present
- */
-
- if (name[1] == ':') {
- cwd = getdcwd(toupper(name[0]) - 'A' + 1);
- drive[0] = name[0]; drive[1] = ':'; drive[2] = '\0';
- name += 2;
- }
- else {
- cwd = getdcwd(0);
- drive[0] = '\0';
- }
-
- #ifdef DEBUG
- printf("working on drive %s = /%s\n", drive, cwd);
- #endif DEBUG
-
- /* is the name 'rooted'? */
- if ((*name == '/') || (*name == '\\')) ++rooted;
-
- /* see if we are at the root directory for this device */
- if (!*cwd) ++atroot;
-
- /*
- * MSDOS '/' doesn't have a '.' or '..'
- * also, double '/' sequences don't make sense.
- * many ported programs expect them to work, so we fix it up...
- */
-
- /* chop off leading . and .. if at root */
- if (atroot && (*name == '.')) {
- switch (*++name) {
- case '\0': case '/': case '\\':
- break;
- case '.':
- switch (*++name) {
- case '\0': case '/': case '\\':
- break;
- default:
- --name;
- --name;
- }
- break;
- default:
- --name;
- }
- }
-
- #ifdef DEBUG
- printf("after chopping leading .'s: %s\n", name);
- #endif DEBUG
-
- /* chop off leading /'s, /.'s and /..'s to make naming sensible */
- while (*name && ((*name == '/') || (*name == '\\'))) {
- if (*++name == '.') {
- switch (*++name) {
- case '\0': case '/': case '\\':
- break;
- case '.':
- switch (*++name) {
- case '\0': case '/': case '\\':
- break;
- default:
- --name;
- --name;
- }
- break;
- default:
- --name;
- }
- }
- }
-
- #ifdef DEBUG
- printf("after chopping /'s: %s\n", name);
- #endif DEBUG
-
- /*
- * name should now look like: path/path/path
- * we must now construct name based on whether or not it
- * was 'rooted' (started with a /)
- */
-
- if (rooted) cwd = "";
-
- /* construct DIR */
- if (!(nd = (DIR *)malloc(
- sizeof(DIR)+strlen(drive)+strlen(cwd)+strlen(SLASH)+
- strlen(name)+strlen(SUFFIX))))
- return (DIR *) 0;
- /* create long name */
- strcpy(nd->dd_name, drive);
- if (*cwd) {
- strcat(nd->dd_name, SLASH);
- strcat(nd->dd_name, cwd);
- }
- if (*name) {
- strcat(nd->dd_name, SLASH);
- strcat(nd->dd_name, name);
- }
- strcat(nd->dd_name, SUFFIX);
-
- #ifdef DEBUG
- printf("calling findfirst(%s)\n", nd->dd_name);
- #endif DEBUG
-
- /* search */
- if (!_findfirst(nd->dd_name, nd)) {
- free((char *)nd);
- errno = ENOENT;
- return (DIR *) 0;
- }
- nd->dd_stat = 0;
- nd->dd_dosver = dosver();
- return nd;
- }
-
- struct direct *readdir(dirp)
- DIR *dirp;
- {
- static struct direct dir;
-
- if (dirp->dd_stat)
- return (struct direct *) 0;
-
- /* format structure */
- dir.d_ino = 0; /* not valid for DOS */
- dir.d_reclen = 0;
- strcpy(dir.d_name, dirp->dd_dta.name);
- dir.d_namlen = strlen(dir.d_name);
- strlwr(dir.d_name); /* DOSism */
-
- /* read ahead */
- if (_findnext(dirp))
- dirp->dd_stat = 0;
- else
- dirp->dd_stat = _err;
-
- return &dir;
- }
-
- void closedir(dirp)
- DIR *dirp;
- {
- free((char *)dirp);
- }
-
- /*
- * fake seek for DOS 2.x
- */
-
- PRIVATE void dos2seek(dirp, pos)
- DIR *dirp;
- long pos;
- {
- /*
- * check against DOS limits
- */
-
- if ((pos < 0) || (pos > 4095)) {
- dirp->dd_stat = 1;
- return;
- }
-
- if (pos == 0) {
- if (_findfirst(dirp->dd_name, dirp))
- dirp->dd_stat = 0;
- else
- dirp->dd_stat = _err;
- }
- else {
- pos--;
- dirp->dd_dta.fcb[1] = 2 - (pos % 3);
- *(short *)&dirp->dd_dta.fcb[13] = pos;
- /* read ahead */
- if (_findnext(dirp))
- dirp->dd_stat = 0;
- else
- dirp->dd_stat = _err;
- }
- }
-
- /*
- * fake seek for DOS 3.x
- */
-
- PRIVATE void dos3seek(dirp, pos)
- DIR *dirp;
- long pos;
- {
- /*
- * check against DOS limits
- */
-
- if ((pos < 0) || (pos > 4095)) {
- dirp->dd_stat = 1;
- return;
- }
-
- *(short *)&dirp->dd_dta.fcb[13] = pos + 1;
- /* read ahead */
- if (_findnext(dirp))
- dirp->dd_stat = 0;
- else
- dirp->dd_stat = _err;
- }
-
- void seekdir(dirp, newpos)
- DIR *dirp;
- long newpos;
- {
- switch (dirp->dd_dosver) {
- case 2:
- dos2seek(dirp, newpos);
- break;
- case 3:
- dos3seek(dirp, newpos);
- break;
- default:
- abort();
- break;
- }
- }
-
- PRIVATE long dos2tell(dirp)
- DIR *dirp;
- {
- return (long) *(short *)&dirp->dd_dta.fcb[13];
-
- }
-
- PRIVATE long dos3tell(dirp)
- DIR *dirp;
- {
- return (long) (*(short *)&dirp->dd_dta.fcb[13] - 2);
- }
-
- long telldir(dirp)
- DIR *dirp;
- {
- switch (dirp->dd_dosver) {
- case 2:
- return dos2tell(dirp);
- case 3:
- return dos3tell(dirp);
- default:
- abort();
- }
- }
-
- ----------------------- testdir.c follows ------------------
- /*
- Directory Access Library Test Program
-
- TESTDIR.C by M. J. Weinstein
- Released to public domain 1-Jan-89
-
- The author may be contacted at:
- matt@cs.ucla.edu -or- POB 84524, L.A., CA 90073
- */
-
- #define LINT_ARGS
-
- #include <math.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #include "dir.h"
-
- #define streqi(a,b) (strcmpi(a,b) == 0)
-
- main()
- {
- char *token;
- char buff[128];
- DIR *dir = 0;
- struct direct *dp;
-
- while (1) {
- printf("> ");
- if (!gets(buff)) break;
- if (!(token = strtok(buff, " \t\n"))) {
- printf("eh?\n");
- }
- else if (streqi("open", token)) {
- if (dir) {
- closedir(dir);
- dir = 0;
- printf("previous directory closed\n");
- }
- if (!(token = strtok(NULL, "\n"))) {
- printf("please specify directory name\n");
- }
- else if (!(dir = opendir(token))) {
- perror(token);
- }
- else {
- printf("directory %s opened successfully\n", token);
- }
- }
- else if (streqi("close", token)) {
- if (!dir) {
- printf("no directory open\n");
- }
- else {
- closedir(dir);
- dir = 0;
- printf("directory closed\n");
- }
- }
- else if (streqi("rew", token)) {
- if (!dir) {
- printf("no directory open\n");
- }
- else {
- rewinddir(dir);
- printf("directory rewind completed\n");
- }
- }
- else if (streqi("seek", token)) {
- if (!dir) {
- printf("no directory open\n");
- }
- else if (!(token = strtok(NULL, "\n"))) {
- printf("specify an entry number\n");
- }
- else {
- seekdir(dir, atol(token));
- printf("seek completed\n");
- }
- }
- else if (streqi("read", token)) {
- if (!dir) {
- printf("no directory open\n");
- }
- else if (!(dp = readdir(dir))) {
- perror("couldn't read entry");
- }
- else {
- printf("ino=%2ld reclen=%2d namlen=%2d name=%s\n",
- dp->d_ino, dp->d_reclen, dp->d_namlen,
- dp->d_name);
- }
- }
- else if (streqi("tell", token)) {
- if (!dir) {
- printf("no directory open\n");
- }
- else {
- printf("positioned at %ld\n", telldir(dir));
- }
- }
- else if (streqi("dir", token)) {
- if (!dir) {
- printf("no directory open\n");
- }
- else {
- while (dp = readdir(dir)) {
- printf("%-16.16s", dp->d_name);
- }
- putchar('\n');
- }
- }
- else if (streqi("cd", token)) {
- if (!(token = strtok(NULL, "\n"))) {
- printf("specify a new directory\n");
- }
- else if (chdir(token) < 0) {
- perror(token);
- }
- else {
- char buff[128];
- printf("new directory is %s\n", getcwd(buff, sizeof(buff)));
- }
- }
- else if (streqi("quit", token) || streqi("exit", token)) {
- break;
- }
- else {
- printf("unknown command: %s\n", token);
- }
- }
- }
-