home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Info-Mac 3
/
Info_Mac_1994-01.iso
/
Development
/
Source
/
Dirent
/
dirent.doc
< prev
next >
Wrap
Text File
|
1993-07-04
|
7KB
|
163 lines
Macintosh Directory Scanning Routines
By George T. Talbot
After programming on Sun workstations, I learned the usefulness of the "dirent" routines.
These routines provide an easy, portable method of reading directory contents. So, I
implemented these routines on the Macintosh and tried to make them as close as possible
to the UNIX routines. Note that in this document I use the word "directory" instead of
the word "folder". Shoot me.
A couple of important notes before we begin:
Due to limitations in the Macintosh File System, all pathnames in this package are
limited to 255 characters (MAXPATHLEN). If you want longer pathnames, you'll have
to break the pathnames up yourself.
Any errors generated by these routines will be put in the global variable "dd_errno".
Here they are:
DIR *opendir(char *dirname);
This routine takes a Macintosh-style pathname and will open that directory and
make it ready for reading. You may also pass in nil instead of a pointer to
a string to open the current working directory.
If you've really got to use UNIX-style pathnames, you can set the variable
"dd_xform_seps" to true and "/" will be transformed to ":" by this routine. Note
that if the individual directory names have "/" in them, that this routine will
not be able to open any path with that directory name in them while this variable
is true. The default value of this variable is false.
It is important to remember that the pathname, whatever separator is used, is a
Macintosh pathname and not a UNIX pathname. This is important for relative pathnames.
".:", "..:" & "≈:" are supported if the pathname starts with
these strings. ".:" means "relative to current directory" and "..:" & "≈:" mean
relative to the current directory's parent directory.
This routine will return a pointer to a DIR structure:
typedef struct __dirdesc {
/* PRIVATE FIELDS. Use the fields & defines below PUBLIC */
...
/* PUBLIC */
long dd_fd; /* file descriptor (dirID) of this dir */
#define dd_parent ... /* dirID of parent */
#define dd_bsize ... /* amount of entries read at a time (always 1) */
#define dd_size ... /* amount of valid data in buffer (ignore) */
#define dd_loc ... /* Don't remember what this field means */
#define dd_name ... /* Directory name (C string) */
#define dd_volume ... /* vRefNum where this is located */
long dd_numents; /* Number of files/directories in this directory */
} DIR;
I do have one significant departure from the UNIX way of doing things. The field
"dd_fd" in UNIX will identify a particular folder, no matter what filesystem the
directory is in. On the Mac, you'll require that field and dd_volume to identify
the directory. Most programs won't have to look at those fields.
The default separator is held in the variable "dd_separator". This variable is a
pointer to a C string. You could probably be compatible with A/UX by setting this
variable to "/" and dd_xform_seps to false, but I haven't tried this.
struct dirent *readdir(DIR *dirp);
This routine reads the next directory entry in the directory (or the first one, if
opendir() has just been called). This routine will return nil and set dd_errno to
noErr when the end of the directory is reached. In case of error, it will also
return nil, but dd_errno will be set to some Mac error code.
The structure this routine returns a pointer to looks like this:
struct dirent {
/* PRIVATE FIELDS. Use fields after PUBLIC */
...
/* PUBLIC. */
long d_off; /* index (to seekdir()) of this entry */
long d_fileno; /* File number (dirID) of this entry */
#define d_parent ... /* File number (dirID) of parent */
#define d_reclen ... /* Size of this record */
#define d_namelen ... /* Length of the name */
#define d_name ... /* Name */
#define d_volume ... /* vRefNum where this is located */
};
The pointer you get to this structure is valid only while the directory is open. When
the directory is closed with closedir(), this pointer goes away.
extern int closedir(DIR *dirp);
This routine closes a directory opened with opendir(). It will return -1 in case of
error and set dd_errno. If you do get an error from this routine, get ready to crash
because the only errors that could happen are Memory Manager errors.
extern void seekdir(DIR *dirp, long loc);
In an open directory, this package indexes directory entries from 0 to the number
of entries in the directory-1 (0..n-1). This function will seek to a specific
directory entry. It's intended to be used before a call to readdir() or telldir().
extern long telldir(DIR *dirp);
This function will return the index of the next directory entry to be read from
the open directory specified by dirp, or -1 if the last entry has just been read.
extern void rewinddir(DIR *dirp);
This is equivalent to seekdir(dirp, 0). It will seek to the first entry in the
open directory.
These routines are not part of a standard dirent package, but are VERY useful,
nonetheless:
char *getwd(char *path);
This routine will get you a fully qualified pathname to the current working directory.
You'll pass in a pointer to a buffer of MAXPATHLEN characters. If the routine is
successful, it will return the pointer to the buffer you passed in. If it fails,
it will return nil and set dd_errno.
extern int chdir(char *path);
This routine will change the current working directory, given a path with the same
constraints as opendir(). It will return 0 on success, and will set dd_errno and
return -1 on failure.
extern char *pathdir(DIR *dirp, char *path);
Given a pointer to an open directory, this routine will generate a fully qualified
path name to that directory. You'll pass in a pointer to a buffer of MAXPATHLEN
characters. If the routine is successful, it will return the pointer to the buffer
you passed in. If it fails, it will return nil and set dd_errno.
That's about it. This code may be used freely with the following caveats:
1) If you distribute source code with this code in it, distribute this documentation
file also.
2) If you include this code in a commercial product, send me a copy of the product
and make me a registered user. If you feel that this is unfair, then send me
$10 U.S. and tell me why. If you can't abide by this clause, then don't use this
code in your commercial product.
3) I'd like to see how far this thing goes, so send me a postcard if you use it and
find it useful.
4) If you find bugs in this code, let me know. If you make any improvements, please
send me source so I can learn something.
This software was created with Think C 5.0.4 and tested on a Macintosh Centris 610 running
System 7. It should work with earlier Systems, but it probably won't work (and in fact
will probably crash) without HFS.
George T. Talbot
24 Judy Ave.
Franklinville, NJ 08322
<ugtalbot@mcs.drexel.edu>