DirectoryStream.st
author claus
Thu, 10 Aug 1995 14:32:31 +0200
changeset 379 5b5a130ccd09
parent 362 4131e87e79ec
child 384 cc3d110ea879
permissions -rw-r--r--
revision added

"
 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/DirectoryStream.st,v 1.20 1995-08-10 12:27:25 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/DirectoryStream.st,v 1.20 1995-08-10 12:27:25 claus Exp $
$Revision: 1.20 $
"
!

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>
#include <errno.h>

#ifndef transputer
# include <sys/types.h>
# include <sys/stat.h>
# ifdef HAS_OPENDIR
#  include <sys/types.h>
#  ifdef NEXT
#   include <sys/dir.h>
#  else
#   include <dirent.h>
#  endif
# endif
#endif

/*
 * on some systems errno is a macro ... check for it here
 */
#ifndef errno
 extern errno;
#endif

%}
! !

!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
    ]
! !