home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Professional
/
OS2PRO194.ISO
/
os2
/
prgramer
/
rcs
/
sources
/
dirent.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-03-06
|
8KB
|
297 lines
/*
* dirent.c - POSIX directory access routines for MS-DOS and OS/2
*
* Author: Frank Whaley (few@well.sf.ca.us)
*
* Copyright Frank Whaley 1992. All rights reserved.
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appears in all copies of the
* source code. The name of the author may not be used to endorse or
* promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* CAVEATS:
* The associated 'dirent.h' file should be copied into your system
* include directory if the '#include <dirent.h>' syntax will be used,
* otherwise a '-I.' switch must be added to command lines.
*
* This code was originally developed with Turbo C, and continues to
* use TC's function and structure names. Numerous macros make the
* code palatable to MSC 5.1/6.0 for MS-DOS and OS/2. The macros
* depend on four defines: __TURBOC__, __MSC__, __MSDOS__, and __OS2__.
* The TC and BC compilers provide __TURBOC__ and __MSDOS__ as
* appropriate; MSC doesn't provide any of these flags so they must
* be given on the command line. Sample commands for building test
* programs (see '#ifdef TEST' below):
* tcc -DTEST dirent.c
* cl -DTEST -D__MSC__ -D__MSDOS__ dirent.c
* cl -Lp -DTEST -D__MSC__ -D__OS2__ dirent.c
*
* This code reads an entire directory into memory, and thus is not
* a good choice for scanning very large directories.
*
* POSIX requires that the rewinddir() function re-scan the directory,
* so this code must preserve the original directory name. If the
* name given is a relative path (".", "..", etc.) and the current
* directory is changed, moved, or deleted between opendir() and
* rewinddir(), a different directory will be scanned by rewinddir().
* The directory name could be qualified by opendir(), but this process
* yields unusable names for network drives.
*
* This code provides only file names, as that is all that is required
* by POSIX. Considerable other information is available from the
* MS-DOS and OS/2 directory search functions. This package should not
* be considered as a general-purpose directory scanner, but rather as
* a tool to simplify porting other programs.
*/
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef __TURBOC__
# include <alloc.h>
# include <dir.h>
# include <mem.h>
typedef struct ffblk FIND_T;
# define findclose(f)
# define FA_RDONLY 0x01
# define FA_HIDDEN 0x02
# define FA_SYSTEM 0x04
# define FA_LABEL 0x08
# define FA_DIREC 0x10
# define FA_ARCH 0x20
#endif
#if defined(__MSC__) && defined(__MSDOS__)
# include <dos.h>
# include <malloc.h>
# include <memory.h>
typedef struct find_t FIND_T;
# define findfirst(n,f,a) _dos_findfirst(n,a,f)
# define findnext(f) _dos_findnext(f)
# define findclose(f)
# define ff_name name
# define FA_RDONLY _A_RDONLY
# define FA_HIDDEN _A_HIDDEN
# define FA_SYSTEM _A_SYSTEM
# define FA_LABEL _A_VOLID
# define FA_DIREC _A_SUBDIR
# define FA_ARCH _A_ARCH
#endif
#if defined(__MSC__) && defined(__OS2__)
# define INCL_DOS
# include <os2.h>
# include <malloc.h>
# include <memory.h>
typedef struct {
HDIR ft_handle;
FILEFINDBUF ft_ffb;
int ft_count;
} FIND_T;
# define findfirst(n,f,a) \
( \
(f)->ft_handle = HDIR_CREATE, \
(f)->ft_count = 1, \
DosFindFirst(n, &(f)->ft_handle, a, &(f)->ft_ffb, \
sizeof((f)->ft_ffb), &(f)->ft_count, 0L \
) \
)
# define findnext(f) \
DosFindNext( \
(f)->ft_handle, &(f)->ft_ffb, \
sizeof((f)->ft_ffb), &(f)->ft_count \
)
# define findclose(f) DosFindClose((f)->ft_handle);
# define ff_name ft_ffb.achName
# define FA_RDONLY 0x01
# define FA_HIDDEN 0x02
# define FA_SYSTEM 0x04
# define FA_LABEL 0x08
# define FA_DIREC 0x10
# define FA_ARCH 0x20
#endif
/* mask for all interesting files */
#define ALL (FA_RDONLY+FA_HIDDEN+FA_SYSTEM+FA_DIREC)
struct dirnames {
struct dirnames *next; /* next name in directory */
char name[1]; /* null terminated name; may be larger */
};
struct __DIRENT {
struct dirnames *names; /* list of names */
struct dirnames const *current; /* position (0 if at directory end) */
char path[1]; /* null terminated path name; may be larger */
};
static char const pattern[] = "\\*.*";
/* forward declarations */
static int loadDir(DIR *dir);
static void freenames(DIR *dir);
/* Open the directory NAME for reading. */
DIR *
opendir(char const *name)
{
DIR *dir;
if (!*name) {
errno = ENOENT;
return 0;
}
if (!(dir = malloc(sizeof(DIR) + strlen(name) + sizeof(pattern)-1))) {
errno = ENOMEM;
return 0;
}
strcpy(dir->path, name);
if (loadDir(dir) != 0) {
int e = errno;
free(dir);
errno = e;
return 0;
}
return dir;
}
/* Close the directory DIR. */
int
closedir(DIR *dir)
{
freenames(dir);
free(dir);
return 0;
}
/* Yield the next entry in the directory DIR. */
struct dirent *
readdir(DIR *dir)
{
struct dirnames const *c = dir->current;
if (!c)
return 0;
dir->current = c->next;
return (struct dirent *) c->name;
}
/* Rewind the directory DIR; this requires rereading it. */
void
rewinddir(DIR *dir)
{
freenames(dir);
loadDir(dir);
}
/* Load the directory DIR from disk. */
static int
loadDir(DIR *dir)
{
char *path = dir->path, *pathend = path + strlen(path);
int mode;
FIND_T ff;
struct stat statb;
/* Is it a directory? */
if (stat(path, &statb) != 0)
return -1;
if ((statb.st_mode & S_IFMT) != S_IFDIR) {
errno = ENOTDIR;
return -1;
}
/* Build pattern string. */
strcpy(pathend, pattern + !!strchr("\\/:", pathend[-1]));
if (findfirst(path, &ff, ALL) == 0) {
struct dirnames **np = &dir->names;
do {
/* Add name if not "." or ".." */
if (ff.ff_name[0]!='.' ||
ff.ff_name[1] && (ff.ff_name[1]!='.'||ff.ff_name[2])
) {
struct dirnames *p = malloc(
sizeof(struct dirnames)+strlen(ff.ff_name)
);
if (!p) {
freenames(dir);
errno = ENOMEM;
*pathend = 0;
return -1;
}
strcpy(p->name, ff.ff_name);
p->next = 0;
*np = p;
np = &p->next;
}
} while (findnext(&ff) == 0);
}
findclose(&ff);
dir->current = dir->names;
*pathend = 0;
return 0;
}
/* Free all names in the directory DIR. */
static void
freenames(DIR *dir)
{
struct dirnames *o = dir->names, *n;
for (o = dir->names; o; o = n) {
n = o->next;
free(o);
}
}
#ifdef TEST
int
main(int argc, char *argv[])
{
DIR *dir;
struct dirent const *d;
long pos;
/* Check arguments. */
if (argc != 2) {
fprintf(stderr, "Usage: dirent <directory>\n");
return 1;
}
/* Try to open the given directory. */
if (!(dir = opendir(argv[1]))) {
fprintf(stderr, "cannot open %s\n", argv[1]);
return 1;
}
/* Walk the directory once forward. */
while ((d = readdir(dir)))
printf("%s\n", d->d_name);
/* Rewind. */
rewinddir(dir);
/* Scan to the end again. */
while ((d = readdir(dir)))
continue;
/* Close and exit. */
printf("closedir() returns %d\n", closedir(dir));
return 0;
}
#endif