DirectoryStream.st
changeset 438 6c03b347369f
parent 437 a005e97d261e
child 475 b57530aa1b0a
--- a/DirectoryStream.st	Sat Sep 16 19:14:32 1995 +0200
+++ b/DirectoryStream.st	Sun Sep 17 19:57:55 1995 +0200
@@ -21,7 +21,7 @@
 COPYRIGHT (c) 1989 by Claus Gittinger
 	      All Rights Reserved
 
-$Header: /cvs/stx/stx/libbasic/DirectoryStream.st,v 1.22 1995-09-16 17:13:04 claus Exp $
+$Header: /cvs/stx/stx/libbasic/DirectoryStream.st,v 1.23 1995-09-17 17:56:01 claus Exp $
 '!
 
 !DirectoryStream class methodsFor:'documentation'!
@@ -42,7 +42,7 @@
 
 version
 "
-$Header: /cvs/stx/stx/libbasic/DirectoryStream.st,v 1.22 1995-09-16 17:13:04 claus Exp $
+$Header: /cvs/stx/stx/libbasic/DirectoryStream.st,v 1.23 1995-09-17 17:56:01 claus Exp $
 "
 !
 
@@ -73,7 +73,9 @@
 #  ifdef NEXT
 #   include <sys/dir.h>
 #  else
-#   include <dirent.h>
+#   ifndef VMS
+#    include <dirent.h>
+#   endif /* not VMS */
 #  endif
 # endif
 #endif
@@ -88,6 +90,285 @@
 %}
 ! !
 
+!DirectoryStream primitiveFunctions!
+
+%{
+#ifdef VMS
+
+/*
+**  VMS readdir() routines.
+**  Written by Rich $alz, <rsalz@bbn.com> in August, 1990.
+**  This code has no copyright.
+*/
+
+/* 12-NOV-1990 added d_namlen field and special case "." name -GJC@MITECH.COM 
+ */
+
+#ifndef _STDIO_H_INCLUDED_
+# include <stdio.h>
+# define _STDIO_H_INCLUDED_
+#endif
+
+#ifndef _CTYPE_H_INCLUDED_
+# include <ctype.h>
+# define _CTYPE_H_INCLUDED_
+#endif
+
+#ifndef _ERRNO_H_INCLUDED_
+# include <errno.h>
+# define _ERRNO_H_INCLUDED_
+#endif
+
+#ifndef _DESCRIP_H_INCLUDED_
+# include <descrip.h>
+# define _DESCRIP_H_INCLUDED_
+#endif
+
+#ifndef _RMSDEF_H_INCLUDED_
+# include <rmsdef.h>
+# define _RMSDEF_H_INCLUDED_
+#endif
+
+/*
+ * actually, the following has to go into dirent.h ...
+ */
+/* BEGIN dirent.h
+ *
+**  Header file for VMS readdir() routines.
+**  Written by Rich $alz, <rsalz@bbn.com> in August, 1990.
+**  This code has no copyright.
+**
+**  You must #include <descrip.h> before this file.
+*/
+
+/* 12-NOV-1990 added d_namlen field -GJC@MITECH.COM */
+
+    /* Data structure returned by READDIR(). */
+struct dirent {
+    char        d_name[100];            /* File name            */
+    int         d_namlen;
+    int                 vms_verscount;          /* Number of versions   */
+    int                 vms_versions[20];       /* Version numbers      */
+};
+
+    /* Handle returned by opendir(), used by the other routines.  You
+     * are not supposed to care what's inside this structure. */
+typedef struct _dirdesc {
+    long                        context;
+    int                                 vms_wantversions;
+    char                        *pattern;
+    struct dirent               entry;
+    struct dsc$descriptor_s     pat;
+} DIR;
+
+
+#define rewinddir(dirp)                 seekdir((dirp), 0L)
+
+
+extern DIR              *opendir();
+extern struct dirent    *readdir();
+extern long             telldir();
+extern void             seekdir();
+extern void             closedir();
+extern void             vmsreaddirversions();
+#define _DIRENT_H_INCLUDED_
+/*
+ * END dirent.h
+ */
+
+
+    /* Number of elements in vms_versions array */
+#define VERSIZE(e)      (sizeof e->vms_versions / sizeof e->vms_versions[0])
+
+    /* Linked in later. */
+extern char     *strrchr();
+extern char     *strcpy();
+/*  Don't need this when all these programs are lumped together.    RLD
+extern char     *malloc();
+*/
+
+/*
+**  Open a directory, return a handle for later use.
+*/
+DIR *
+opendir(name)
+    char        *name;
+{
+    DIR                 *dd;
+
+    /* Get memory for the handle, and the pattern. */
+    if ((dd = (DIR *)malloc(sizeof *dd)) == NULL) {
+	errno = ENOMEM;
+	return NULL;
+    }
+
+    if (strcmp(".",name) == 0) name = "";
+
+    dd->pattern = malloc((unsigned int)(strlen(name) + sizeof "*.*" + 1));
+    if (dd->pattern == NULL) {
+	free((char *)dd);
+	errno = ENOMEM;
+	return NULL;
+    }
+
+    /* Fill in the fields; mainly playing with the descriptor. */
+    (void)sprintf(dd->pattern, "%s*.*", name);
+    dd->context = 0;
+    dd->vms_wantversions = 0;
+    dd->pat.dsc$a_pointer = dd->pattern;
+    dd->pat.dsc$w_length = strlen(dd->pattern);
+    dd->pat.dsc$b_dtype = DSC$K_DTYPE_T;
+    dd->pat.dsc$b_class = DSC$K_CLASS_S;
+
+    return dd;
+}
+
+/*
+**  Set the flag to indicate we want versions or not.
+*/
+void
+vmsreaddirversions(dd, flag)
+    DIR                 *dd;
+    int                 flag;
+{
+    dd->vms_wantversions = flag;
+}
+
+/*
+**  Free up an opened directory.
+*/
+void
+closedir(dd)
+    DIR                 *dd;
+{
+    free(dd->pattern);
+    free((char *)dd);
+}
+
+/*
+**  Collect all the version numbers for the current file.
+*/
+static void
+collectversions(dd)
+    DIR                                 *dd;
+{
+    struct dsc$descriptor_s     pat;
+    struct dsc$descriptor_s     res;
+    struct dirent               *e;
+    char                        *p;
+    char                        buff[sizeof dd->entry.d_name];
+    int                                 i;
+    char                        *text;
+    long                        context;
+
+    /* Convenient shorthand. */
+    e = &dd->entry;
+
+    /* Add the version wildcard, ignoring the "*.*" put on before */
+    i = strlen(dd->pattern);
+    text = malloc((unsigned int)(i + strlen(e->d_name)+ 2 + 1));
+    if (text == NULL)
+	return;
+    (void)strcpy(text, dd->pattern);
+    (void)sprintf(&text[i - 3], "%s;*", e->d_name);
+
+    /* Set up the pattern descriptor. */
+    pat.dsc$a_pointer = text;
+    pat.dsc$w_length = strlen(text);
+    pat.dsc$b_dtype = DSC$K_DTYPE_T;
+    pat.dsc$b_class = DSC$K_CLASS_S;
+
+    /* Set up result descriptor. */
+    res.dsc$a_pointer = buff;
+    res.dsc$w_length = sizeof buff - 2;
+    res.dsc$b_dtype = DSC$K_DTYPE_T;
+    res.dsc$b_class = DSC$K_CLASS_S;
+
+    /* Read files, collecting versions. */
+    for (context = 0; e->vms_verscount < VERSIZE(e); e->vms_verscount++) {
+	if (lib$find_file(&pat, &res, &context) == RMS$_NMF || context == 0)
+	    break;
+	buff[sizeof buff - 1] = '\0';
+	if (p = strchr(buff, ';'))
+	    e->vms_versions[e->vms_verscount] = atoi(p + 1);
+	else
+	    e->vms_versions[e->vms_verscount] = -1;
+    }
+
+    free(text);
+}
+
+/*
+**  Read the next entry from the directory.
+*/
+struct dirent *
+readdir(dd)
+    DIR                                 *dd;
+{
+    struct dsc$descriptor_s     res;
+    char                        *p;
+    char                        buff[sizeof dd->entry.d_name];
+    int                                 i;
+
+    /* Set up result descriptor, and get next file. */
+    res.dsc$a_pointer = buff;
+    res.dsc$w_length = sizeof buff - 2;
+    res.dsc$b_dtype = DSC$K_DTYPE_T;
+    res.dsc$b_class = DSC$K_CLASS_S;
+    if (lib$find_file(&dd->pat, &res, &dd->context) == RMS$_NMF
+     || dd->context == 0L)
+	/* None left... */
+	return NULL;
+
+    /* Force the buffer to end with a NUL. */
+    buff[sizeof buff - 1] = '\0';
+    for (p = buff; !isspace(*p); p++)
+	;
+    *p = '\0';
+
+    /* Skip any directory component and just copy the name. */
+    if (p = strchr(buff, ']'))
+	(void)strcpy(dd->entry.d_name, p + 1);
+    else
+	(void)strcpy(dd->entry.d_name, buff);
+
+    /* Clobber the version. */
+    if (p = strchr(dd->entry.d_name, ';'))
+	*p = '\0';
+
+    dd->entry.d_namlen = strlen(dd->entry.d_name);
+
+    dd->entry.vms_verscount = 0;
+    if (dd->vms_wantversions)
+	collectversions(dd);
+    return &dd->entry;
+}
+
+/*
+**  Return something that can be used in a seekdir later.
+*/
+long
+telldir(dd)
+    DIR                 *dd;
+{
+    return dd->context;
+}
+
+/*
+**  Return to a spot where we used to be.
+*/
+void
+seekdir(dd, pos)
+    DIR                 *dd;
+    long        pos;
+{
+    dd->context = pos;
+}
+
+#endif /* VMS */
+%}
+! !
+
 !DirectoryStream methodsFor:'instance release'!
 
 closeFile