[comp.sources.misc] {open,read,close}dir for MS-DOS

guido@cwi.nl.UUCP (Guido van Rossum) (07/18/87)

Since Rich Salz in comp.sources.unix asked for MS-DOS (and other)
implementations of Doug Gwyn's directory package, here's what I am using
myself.  It's only opendir, readdir and closedir, but I've written
several programs that use it and port problemless between several Unix
flavours, MS-DOS and the Apple Macintosh.
--
Guido van Rossum, Centre for Mathematics and Computer Science (CWI), Amsterdam
guido@cwi.nl or mcvax!guido or (from ARPAnet) guido%cwi.nl@seismo.css.gov

: This is a shell archive.
: Extract with 'sh this_file'.
echo 'Start of pack.out, part 01 out of 01:'
echo 'x - README'
sed 's/^X//' > 'README' << 'EOF'
XHere's something for MS-DOS that makes it easier to port Unix programs
Xthat scan directories: an implementation of opendir, readdir and
Xclosedir.
X
XIt's a rather minimal implementation, e.g., it allows only one open
Xdirectory at a time, and there are no rewinddir, telldir and seekdir,
Xbut I suspect these are much less used than readdir.
X
XThis works with Microsoft C 4.0 (and also used to work with 3.0).
XOwners of other compilers are on their own.
X
XBeing sick and tired of copyright wars I hereby place this code in the
Xpublic domain, although it would still be nice if my name remained in
Xredistributed or changed copies of the source.
X
XGuido van Rossum
XCWI, dept. AA
XKruislaan 413
X1098 SJ  Amsterdam
X
XPhone: + 20 - 5924138
X
XE-mail: guido@cwi.nl
EOF
echo 'x - dir.c'
sed 's/^X//' > 'dir.c' << 'EOF'
X/*
X * MS-DOS version of UNIX directory access package.
X * (opendir, readdir, closedir).
X * Public domain by Guido van Rossum, CWI, Amsterdam (July 1987).
X */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <errno.h>
X#include <dos.h>
Xextern int errno;
X#define MAXPATH 64
X
X#include "dir.h"
Xstatic char *firstf();
Xstatic char *nextf();
X
Xtypedef int bool;
X#define TRUE 1
X#define FALSE 0
X#define EOS '\0'
X#define NULL 0
X
Xstatic char dirpath[MAXPATH+1]= "";
Xstatic bool busy= FALSE;
X
X/*
X * Open a directory.
X * This MS-DOS version allows only one directory to be open at a time.
X * The path must exist and be a directory.
X * Then it only saves the file name and returns a pointer to it.
X */
X
Xchar *
Xopendir(path)
X	char *path;
X{
X	struct stat buffer;
X
X	if (dirpath[0] != EOS) {
X		 errno= EMFILE;
X		 return NULL; /* Only one directory can be open at a time */
X	}
X	if (stat(path, &buffer) == -1)
X		return NULL; /* Directory doesn't exist */
X	if ((buffer.st_mode & S_IFMT) != S_IFDIR) {
X		errno= ENOENT;
X		return NULL; /* Not a directory */
X	}
X	strcpy(dirpath, path);
X	path= dirpath + strlen(dirpath);
X	if (path > dirpath && path[-1] != ':' && path[-1] != '/' &&
X			path[-1] != '\\')
X		*path++ = '\\';
X	strcpy(path, "*.*");
X	busy= FALSE; /* Tell readdir this is the first time */
X	return dirpath;
X}
X
X/*
X * Close a directory.
X * We must clear the first char of dirpath to signal opendir that
X * no directory is open.
X */
X
Xclosedir(dirp)
X	char *dirp;
X{
X	dirp[0]= EOS;
X}
X
X/*
X * Read the next directory entry.
X */
X
Xstruct direct *
Xreaddir(dp)
X	char *dp;
X{
X	static struct direct buffer;
X	char *p;
X
X	if (!busy)
X		p= firstf(dp);
X	else
X		p= nextf();
X	busy= (p != NULL);
X	if (!busy)
X		return NULL;
X	strcpy(buffer.d_name, p);
X	buffer.d_namlen= strlen(p);
X	return &buffer;
X}
X
X
X/*
X * Low-level implementation -- access to DOS system calls FIRST and NEXT.
X */
X
Xstatic char dta[64]; /* Device Transfer Area */
X
X/* File attributes */
X#define READONLY	0x01
X#define HIDDEN		0x02
X#define SYSTEM		0x04
X#define VOLUMEID	0x08
X#define DIRECTORY	0x10
X#define ARCHIVE		0x20
X
X#define MATCHATTR	(HIDDEN|SYSTEM|DIRECTORY)
X
Xstatic char *
Xfirstf(pat)
X    char *pat;
X{
X    int flags;
X    union REGS regs;
X    struct SREGS segregs;
X
X    setdta(dta);
X
X    segread(&segregs);
X    regs.h.ah = 0x4e;
X    regs.x.cx = MATCHATTR;
X#ifdef M_I86LM /* Large Model -- far pointers */
X    regs.x.dx = FP_OFF(pat);
X    segregs.ds = FP_SEG(pat);
X#else
X    regs.x.dx = (int) pat;
X#endif
X    flags= intdosx(&regs, &regs, &segregs);
X    if (regs.x.cflag)
X	return NULL;
X    fixfile();
X    return dta + 30;
X}
X
Xstatic char *
Xnextf()
X{
X    int flags;
X    union REGS regs;
X
X    setdta(dta);
X
X    regs.h.ah = 0x4f;
X    flags= intdos(&regs, &regs);
X    if (regs.x.cflag)
X	return NULL;
X    fixfile();
X    return dta + 30;
X}
X
X/*
X * Convert the file name in the Device Transfer Area to lower case.
X */
X
Xstatic
Xfixfile()
X{
X	char *cp;
X
X	for (cp= dta+30; *cp != EOS; ++cp)
X		*cp= tolower(*cp);
X}
X
X/*
X * Tell MS-DOS where the Device Transfer Area is.
X */
X
Xstatic
Xsetdta(dta)
X    char *dta;
X{
X    union REGS regs;
X    struct SREGS segregs;
X
X    segread(&segregs);
X    regs.h.ah = 0x1a;
X#ifdef M_I86LM /* Large Model -- far pointers */
X    regs.x.dx = FP_OFF(dta);
X    segregs.ds = FP_SEG(dta);
X#else
X    regs.x.dx = (int) dta;
X#endif
X    intdosx(&regs, &regs, &segregs);
X}
EOF
echo 'x - dir.h'
sed 's/^X//' > 'dir.h' << 'EOF'
X/*
X * Interface for MS-DOS version of UNIX directory access package.
X * (opendir, readdir, closedir).
X * Public domain by Guido van Rossum, CWI, Amsterdam (July 1987).
X */
X
Xstruct direct {
X	char d_namlen;
X	char d_name[13];
X};
X
Xtypedef char DIR;
X
XDIR *opendir();
Xstruct direct *readdir();
EOF
echo 'Part 01 out of 01 of pack.out complete.'
exit 0