OpenVMSOperatingSystem.st
changeset 17283 877a84a76a52
parent 13778 8e34483d10dd
child 18120 e3a375d5f6a8
child 19860 324edacff5cc
--- a/OpenVMSOperatingSystem.st	Mon Jan 12 13:44:34 2015 +0100
+++ b/OpenVMSOperatingSystem.st	Mon Jan 12 13:50:08 2015 +0100
@@ -571,6 +571,289 @@
     return 0;
 }
 
+# ifndef HAS_OPENDIR
+
+#  define lib$find_file LIB$FIND_FILE
+
+/*
+**  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 included 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();
+/*
+ * END dirent.h
+ */
+#define _DIRENT_H_INCLUDED_
+
+
+    /* 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) {
+	__threadErrno = ENOMEM;
+	return NULL;
+    }
+
+    if (strcmp(".",name) == 0) name = "";
+
+    dd->pattern = malloc((unsigned int)(strlen(name) + sizeof "*.*" + 1));
+    if (dd->pattern == NULL) {
+	free((char *)dd);
+	__threadErrno = 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 + 10];
+    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';
+
+    /* claus: empty dirs seems to leave *.* in the buffer ... */
+    if (strcmp(dd->entry.d_name, "*.*") == 0) {
+	return NULL;
+    }
+
+    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;
+}
+
+#  define HAS_OPENDIR
+
+# endif /* not HAS_OPENDIR */
+
 #endif /* __VMS__ */
 %}
 ! !
@@ -2927,6 +3210,62 @@
     "Modified: 15.7.1997 / 16:03:51 / stefan"
 ! !
 
+!OpenVMSOperatingSystem class methodsFor:'directory access'!
+
+nextLinkInfoFrom:aDirectoryStream dirPointer:dirPointer
+    "return a FileStatusInfo entry for the next entry, when reading from a directory.
+     Under UNIX, the returned fileStatuInfo ONLY contains the name of the file,
+     whereas under Windows, it contains the full info (incl. fileSize, access rights etc.).
+     The reason is that under wndows, the ReadNextEntry system call does this, whereas the
+     the corresponding unix read from a readdir only returns the name."
+
+    |entry isUnix error|
+%{
+#ifdef HAS_OPENDIR
+    DIR *d;
+    DIRENT_STRUCT *dp;
+
+    if ((dirPointer != nil)
+     && __isExternalAddressLike(dirPointer)) {
+	d = (DIR *)__FILEVal(dirPointer);
+
+	__BEGIN_INTERRUPTABLE__
+	do {
+	    do {
+		__threadErrno = 0;
+		dp = readdir(d);
+		/*
+		 * for compatibility with ST-80,
+		 * skip entries for '.' and '..'.
+		 * If wanted, these must be added synthetically.
+		 */
+	    } while (dp && ((strcmp(dp->d_name, ".")==0) || (strcmp(dp->d_name, "..")==0)));
+	} while ((dp == NULL) && (__threadErrno == EINTR));
+	__END_INTERRUPTABLE__
+
+	if (dp != NULL) {
+	    entry = __MKSTRING((char *)(dp->d_name));
+	} else {
+	    if (__threadErrno) {
+		error = __mkSmallInteger(__threadErrno);
+	    }
+       }
+    }
+#endif /* HAS_OPENDIR */
+%}.
+    error notNil ifTrue:[
+	^ StreamIOError newException
+	    errorCode:error;
+	    osErrorHolder:(OperatingSystem errorHolderForNumber:error);
+	    parameter:aDirectoryStream;
+	    raiseRequest
+    ].
+    entry notNil ifTrue:[
+	^ entry.
+    ].
+    ^ aDirectoryStream pastEndRead
+! !
+
 !OpenVMSOperatingSystem class methodsFor:'file access'!
 
 closeFd:anInteger
@@ -7515,6 +7854,6 @@
 !OpenVMSOperatingSystem class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic/OpenVMSOperatingSystem.st,v 1.17 2011-10-07 13:57:55 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/OpenVMSOperatingSystem.st,v 1.18 2015-01-12 12:50:08 cg Exp $'
 ! !
 OpenVMSOperatingSystem initialize!