/* 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 -------- Modified for use in dmake by Dennis Vadura. Mostly just clean up and an effort to make correctly typed objects are passed to functions in find.c. Also deleted all dos version 2.0 specific code. It is not required any more. */ /* * revision history: * * VER MM/DD/YY COMMENTS * ---- -------- -------- * 0.99 02/24/86 Beta release to INTERNET */ #include #include #include #include #include #include "dirent.h" extern int find_err; static 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); find_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'; } /* 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; } } /* 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; } } } /* * 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); /* search */ if (!findfirst(&nd->dd_name[0], &nd->dd_dta)) { free((char *)nd); errno = ENOENT; return (DIR *) 0; } nd->dd_stat = 0; return nd; } struct dirent * readdir(dirp) DIR *dirp; { static struct dirent dir; if (dirp->dd_stat) return (struct dirent *) 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->dd_dta) != NULL) dirp->dd_stat = 0; else dirp->dd_stat = find_err; return &dir; } void closedir(dirp) DIR *dirp; { free((char *)dirp); } void seekdir(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->dd_dta)) dirp->dd_stat = 0; else dirp->dd_stat = find_err; } long telldir(dirp) DIR *dirp; { return (long) (*(short *)&dirp->dd_dta.fcb[13] - 2); }