A readdir() implementation for VMS
Rich Salz
rsalz at bbn.com
Tue Aug 21 00:05:30 AEST 1990
I needed the "readdir" package for VMS. Other implementations I've seen
all seemed to have lots of knowledge of the internals of the VMS directory
structure (eww, gross!) or didn't really handle file versions the way that
I needed them done.
The following code is in the public domain. I hope it gets very widespread
use. Enjoy.
/r$
#! /bin/sh
# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix at uunet.uu.net if you want that tool.
# Contents: README dirent.h vmsreaddir.c
# Wrapped by rsalz at litchi.bbn.com on Mon Aug 20 09:53:15 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:
echo ' "shar: End of archive."'
if test -f 'README' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(3306 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X
XThis code implements the Berkeley Unix "readdir" package. Readdir is an
Xabstract interface for reading entries out of directories, and getting the
Xnames of the files (and directories, etc.) contained therein. Versions
Xexist for all Unix systems, MS-DOS, Amiga, and no doubt others as well.
X
XThis code was written by Rich $alz, <rsalz at bbn.com> in August, 1990, and
Xhas no copyright.
X
X #include <dirent.h>
XThis header file must be included by any files that use any of the routines
Xdescribed here. You must also #include <descrip.h> first.
X
X DIR *
X opendir(name)
X char *name;
XNAME is a filespec that names a directory. It does not have to be in
Xstrict canonical form -- logicals such as "sys$login:" will be expanded.
XOnce the directory has been opened, any of the other routines described
Xhere can be used on the handle that is returned.
X
X
X void
X vmsreaddirversions(dd, flag)
X DIR *dd;
X int flag;
XBy default, READDIR() ignores file versions, and returns a file name once,
Xno matter how many versions it has. This routine can be used to collect
Xthe version numbers in an that is returned with each file. The FLAG
Xargument should be non-zero to collect version information, or zero to
Xignore it. This routine can be called any number of times while the
Xdirectory is open.
X
X
X void
X closedir(dd)
X DIR *dd;
XOnce you are finished reading the contents of a directory, the CLOSEDIR()
Xroutine frees up all the storage associated with it, and invalidates the
Xhandle.
X
X
X struct dirent *
X readdir(dd)
X DIR *dd;
XThe READDIR() routine takes a handle returned by OPENDIR() and returns the
Xname of the next file in the directory, or a NULL pointer when there are
Xno more files. The STRUCT DIRENT returned by this routine will have the
Xfollowing fields that may be accessed by user code:
X d_name[] A C character string with the file name
X vms_verscount The number of versions the file has
X vms_versions[] An array of the version numbers; the number -1
X indicates a file-parsing error.
XNote that the fields starting with "vms_" are not part of the standard
XREADDIR() library available on other systems, so strictly portable code
Xshould take care to avoid using them except on VMS machines.
X
X long
X telldir(dd)
X DIR *dd;
XThis routine returns a "magic cookie" that can be used in a later
XSEEKDIR() call. This allows you to remember one or more spots while
Xreading through a directory and return to them later.
X
X
X void
X seekdir(dd, pos)
X DIR *dd;
X long pos;
XThe SEEKDIR() routine takes the "cookie" returned by a previous call to
XTELLDIR() and sets the internal state so that the next READDIR() call will
Xreturn the file read just after the TELLDIR() call.
X
X void
X rewinddir(dd)
X DIR *dd;
XThe REWINDDIR() routine resets the internal state of the DD handle so that
XREADDIR() starts reading over from the beginning of the directory.
X
XHere is a sample routine showing how to use the package:
X main()
X {
X DIR *dd;
X struct dirent *dp;
X int i;
X
X if ((dd = opendir("sys$login")) == NULL) {
X perror(buff);
X continue;
X }
X vmsreaddirversions(dd, 1);
X
X while (dp = readdir(dd)) {
X printf("%s", dp->d_name);
X for (i = 0; i < dp->vms_verscount; i++)
X printf(" %d", dp->vms_versions[i]);
X printf("\n");
X }
X closedir(dd);
X exit(0);
X }
END_OF_FILE
if test 3306 -ne `wc -c <'README'`; then
echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'dirent.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'dirent.h'\"
else
echo shar: Extracting \"'dirent.h'\" \(915 characters\)
sed "s/^X//" >'dirent.h' <<'END_OF_FILE'
X/*
X** Header file for VMS readdir() routines.
X** Written by Rich $alz, <rsalz at bbn.com> in August, 1990.
X** This code has no copyright.
X**
X** You must #include <descrip.h> before this file.
X*/
X
X /* Data structure returned by READDIR(). */
Xstruct dirent {
X char d_name[100]; /* File name */
X int vms_verscount; /* Number of versions */
X int vms_versions[20]; /* Version numbers */
X};
X
X /* Handle returned by opendir(), used by the other routines. You
X * are not supposed to care what's inside this structure. */
Xtypedef struct _dirdesc {
X long context;
X int vms_wantversions;
X char *pattern;
X struct dirent entry;
X struct dsc$descriptor_s pat;
X} DIR;
X
X
X#define rewinddir(dirp) seekdir((dirp), 0L)
X
X
Xextern DIR *opendir();
Xextern struct dirent *readdir();
Xextern long telldir();
Xextern void seekdir();
Xextern void closedir();
Xextern void vmsreaddirversions();
END_OF_FILE
if test 915 -ne `wc -c <'dirent.h'`; then
echo shar: \"'dirent.h'\" unpacked with wrong size!
fi
# end of 'dirent.h'
fi
if test -f 'vmsreaddir.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'vmsreaddir.c'\"
else
echo shar: Extracting \"'vmsreaddir.c'\" \(5014 characters\)
sed "s/^X//" >'vmsreaddir.c' <<'END_OF_FILE'
X/*
X** VMS readdir() routines.
X** Written by Rich $alz, <rsalz at bbn.com> in August, 1990.
X** This code has no copyright.
X*/
X#include <stdio.h>
X#include <ctype.h>
X#include <errno.h>
X#include <descrip.h>
X#include <rmsdef.h>
X#include "dirent.h"
X
X /* Uncomment the next line to get a test routine. */
X/*#define TEST*/
X
X /* Number of elements in vms_versions array */
X#define VERSIZE(e) (sizeof e->vms_versions / sizeof e->vms_versions[0])
X
X /* Linked in later. */
Xextern char *malloc();
Xextern char *strrchr();
Xextern char *strcpy();
X
X
X/*
X** Open a directory, return a handle for later use.
X*/
XDIR *
Xopendir(name)
X char *name;
X{
X DIR *dd;
X
X /* Get memory for the handle, and the pattern. */
X if ((dd = (DIR *)malloc(sizeof *dd)) == NULL) {
X errno = ENOMEM;
X return NULL;
X }
X dd->pattern = malloc((unsigned int)(strlen(name) + sizeof "*.*" + 1));
X if (dd->pattern == NULL) {
X free((char *)dd);
X errno = ENOMEM;
X return NULL;
X }
X
X /* Fill in the fields; mainly playing with the descriptor. */
X (void)sprintf(dd->pattern, "%s*.*", name);
X dd->context = 0;
X dd->vms_wantversions = 0;
X dd->pat.dsc$a_pointer = dd->pattern;
X dd->pat.dsc$w_length = strlen(dd->pattern);
X dd->pat.dsc$b_dtype = DSC$K_DTYPE_T;
X dd->pat.dsc$b_class = DSC$K_CLASS_S;
X
X return dd;
X}
X
X
X/*
X** Set the flag to indicate we want versions or not.
X*/
Xvoid
Xvmsreaddirversions(dd, flag)
X DIR *dd;
X int flag;
X{
X dd->vms_wantversions = flag;
X}
X
X
X/*
X** Free up an opened directory.
X*/
Xvoid
Xclosedir(dd)
X DIR *dd;
X{
X free(dd->pattern);
X free((char *)dd);
X}
X
X
X/*
X** Collect all the version numbers for the current file.
X*/
Xstatic void
Xcollectversions(dd)
X DIR *dd;
X{
X struct dsc$descriptor_s pat;
X struct dsc$descriptor_s res;
X struct dirent *e;
X char *p;
X char buff[sizeof dd->entry.d_name];
X int i;
X char *text;
X long context;
X
X /* Convenient shorthand. */
X e = &dd->entry;
X
X /* Add the version wildcard, ignoring the "*.*" put on before */
X i = strlen(dd->pattern);
X text = malloc((unsigned int)(i + strlen(e->d_name)+ 2 + 1));
X if (text == NULL)
X return;
X (void)strcpy(text, dd->pattern);
X (void)sprintf(&text[i - 3], "%s;*", e->d_name);
X
X /* Set up the pattern descriptor. */
X pat.dsc$a_pointer = text;
X pat.dsc$w_length = strlen(text);
X pat.dsc$b_dtype = DSC$K_DTYPE_T;
X pat.dsc$b_class = DSC$K_CLASS_S;
X
X /* Set up result descriptor. */
X res.dsc$a_pointer = buff;
X res.dsc$w_length = sizeof buff - 2;
X res.dsc$b_dtype = DSC$K_DTYPE_T;
X res.dsc$b_class = DSC$K_CLASS_S;
X
X /* Read files, collecting versions. */
X for (context = 0; e->vms_verscount < VERSIZE(e); e->vms_verscount++) {
X if (lib$find_file(&pat, &res, &context) == RMS$_NMF || context == 0)
X break;
X buff[sizeof buff - 1] = '\0';
X if (p = strchr(buff, ';'))
X e->vms_versions[e->vms_verscount] = atoi(p + 1);
X else
X e->vms_versions[e->vms_verscount] = -1;
X }
X
X free(text);
X}
X
X
X/*
X** Read the next entry from the directory.
X*/
Xstruct dirent *
Xreaddir(dd)
X DIR *dd;
X{
X struct dsc$descriptor_s res;
X char *p;
X char buff[sizeof dd->entry.d_name];
X int i;
X
X /* Set up result descriptor, and get next file. */
X res.dsc$a_pointer = buff;
X res.dsc$w_length = sizeof buff - 2;
X res.dsc$b_dtype = DSC$K_DTYPE_T;
X res.dsc$b_class = DSC$K_CLASS_S;
X if (lib$find_file(&dd->pat, &res, &dd->context) == RMS$_NMF
X || dd->context == 0L)
X /* None left... */
X return NULL;
X
X /* Force the buffer to end with a NUL. */
X buff[sizeof buff - 1] = '\0';
X for (p = buff; !isspace(*p); p++)
X ;
X *p = '\0';
X
X /* Skip any directory component and just copy the name. */
X if (p = strchr(buff, ']'))
X (void)strcpy(dd->entry.d_name, p + 1);
X else
X (void)strcpy(dd->entry.d_name, buff);
X
X /* Clobber the version. */
X if (p = strchr(dd->entry.d_name, ';'))
X *p = '\0';
X
X dd->entry.vms_verscount = 0;
X if (dd->vms_wantversions)
X collectversions(dd);
X return &dd->entry;
X}
X
X
X/*
X** Return something that can be used in a seekdir later.
X*/
Xlong
Xtelldir(dd)
X DIR *dd;
X{
X return dd->context;
X}
X
X
X/*
X** Return to a spot where we used to be.
X*/
Xvoid
Xseekdir(dd, pos)
X DIR *dd;
X long pos;
X{
X dd->context = pos;
X}
X
X
X#ifdef TEST
Xmain()
X{
X char buff[256];
X DIR *dd;
X struct dirent *dp;
X int i;
X int j;
X
X for ( ; ; ) {
X printf("\n\nEnter dir: ");
X (void)fflush(stdout);
X (void)gets(buff);
X if (buff[0] == '\0')
X break;
X if ((dd = opendir(buff)) == NULL) {
X perror(buff);
X continue;
X }
X
X /* Print the directory contents twice, the second time print
X * the versions. */
X for (i = 0; i < 2; i++) {
X while (dp = readdir(dd)) {
X printf("%s%s", i ? "\t" : " ", dp->d_name);
X for (j = 0; j < dp->vms_verscount; j++)
X printf(" %d", dp->vms_versions[j]);
X printf("\n");
X }
X rewinddir(dd);
X vmsreaddirversions(dd, 1);
X }
X closedir(dd);
X }
X exit(0);
X}
X#endif /* TEST */
END_OF_FILE
if test 5014 -ne `wc -c <'vmsreaddir.c'`; then
echo shar: \"'vmsreaddir.c'\" unpacked with wrong size!
fi
# end of 'vmsreaddir.c'
fi
echo shar: End of archive.
exit 0
--
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.
More information about the Alt.sources
mailing list