.
"
COPYRIGHT (c) 1989 by Claus Gittinger
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
"
FileStream subclass:#DirectoryStream
instanceVariableNames:'dirPointer readAhead'
classVariableNames:''
poolDictionaries:''
category:'Streams-External'
!
DirectoryStream comment:'
COPYRIGHT (c) 1989 by Claus Gittinger
All Rights Reserved
$Header: /cvs/stx/stx/libbasic/Attic/DirStr.st,v 1.23 1995-09-17 17:56:01 claus Exp $
'!
!DirectoryStream class methodsFor:'documentation'!
copyright
"
COPYRIGHT (c) 1989 by Claus Gittinger
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
"
!
version
"
$Header: /cvs/stx/stx/libbasic/Attic/DirStr.st,v 1.23 1995-09-17 17:56:01 claus Exp $
"
!
documentation
"
Instances of DirectoryStream allow reading a file-directory,
as if it was a stream of filenames.
Basically, its an interface to opendir, readdir and closedir.
"
! !
!DirectoryStream primitiveDefinitions!
%{
#include <stdio.h>
#define _STDIO_H_INCLUDED_
#include <errno.h>
#define _ERRNO_H_INCLUDED_
#ifndef transputer
# include <sys/types.h>
# include <sys/stat.h>
# ifdef HAS_OPENDIR
# include <sys/types.h>
# ifdef NEXT
# include <sys/dir.h>
# else
# ifndef VMS
# include <dirent.h>
# endif /* not VMS */
# endif
# endif
#endif
/*
* on some systems errno is a macro ... check for it here
*/
#ifndef errno
extern errno;
#endif
%}
! !
!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
"low level close of a directoryStream"
%{
#ifdef HAS_OPENDIR
OBJ dp;
if ((dp = _INST(dirPointer)) != nil) {
_INST(dirPointer) = nil;
closedir( (DIR *)(MKFD(dp)) );
}
#endif
%}
! !
!DirectoryStream class methodsFor:'instance creation'!
directoryNamed:dirName
"return a DirectoryStream for directory named dirName, aString"
|newStream|
newStream := (self basicNew) pathName:dirName.
newStream openForReading isNil ifTrue:[^nil].
^ newStream
! !
!DirectoryStream methodsFor:'access reading'!
nextLine
"return the next filename as a string"
|prevEntry nextEntry|
%{
#ifdef HAS_OPENDIR
DIR *d;
#ifdef NEXT
struct direct *dp;
#else
struct dirent *dp;
#endif
OBJ dirP;
if ((dirP = _INST(dirPointer)) != nil) {
d = (DIR *)MKFD(dirP);
__BEGIN_INTERRUPTABLE__
errno = 0;
do {
dp = readdir(d);
} while ((dp == NULL) && (errno == EINTR));
__END_INTERRUPTABLE__
if (dp != NULL) {
nextEntry = _MKSTRING((char *)(dp->d_name) COMMA_CON);
} else {
_INST(hitEOF) = true;
if (errno) {
_INST(lastErrorNumber) = _MKSMALLINT(errno);
}
}
}
#endif
%}.
lastErrorNumber notNil ifTrue:[^ self ioError].
prevEntry := readAhead.
readAhead := nextEntry.
^ prevEntry
! !
!DirectoryStream methodsFor:'private'!
openForReading
"open the file for readonly"
|ok|
mode := #readonly.
%{
#ifdef HAS_OPENDIR
DIR *d;
OBJ path;
ok = false;
if (_INST(dirPointer) == nil) {
path = _INST(pathName);
if (__isString(path)) {
__BEGIN_INTERRUPTABLE__
errno = 0;
do {
d = opendir((char *) _stringVal(path));
} while ((d == NULL) && (errno == EINTR));
__END_INTERRUPTABLE__
if (d == NULL) {
_INST(lastErrorNumber) = _MKSMALLINT(errno);
} else {
_INST(dirPointer) = MKOBJ(d);
ok = true;
}
}
}
#endif
%}.
ok isNil ifTrue:[
"
opendir not avalable - use slower pipe
"
^ PipeStream readingFrom:('cd ' , pathName , '; ls -a')
].
(ok == true) ifTrue:[
Lobby register:self.
self nextLine. "read 1st entry into readAhead buffer"
^ self
].
dirPointer notNil ifTrue:[^ self errorOpen].
lastErrorNumber notNil ifTrue:[^ self openError].
^ nil
!
reOpen
"reOpen the stream after image restart"
dirPointer := nil.
super reOpen
! !
!DirectoryStream methodsFor:'testing'!
atEnd
"return true, if position is at end"
^ readAhead == nil
! !
!DirectoryStream methodsFor:'closing'!
close
"close the stream - tell operating system"
dirPointer notNil ifTrue:[
Lobby unregister:self.
self closeFile.
dirPointer := nil
]
! !