DirectoryStream.st
branchjv
changeset 18120 e3a375d5f6a8
parent 18011 deb0c3355881
parent 17302 a8f3099d0b64
child 18786 237a87b4fe8f
equal deleted inserted replaced
18119:cb7a12afe736 18120:e3a375d5f6a8
     9  other person.  No title to or ownership of the software is
     9  other person.  No title to or ownership of the software is
    10  hereby transferred.
    10  hereby transferred.
    11 "
    11 "
    12 "{ Package: 'stx:libbasic' }"
    12 "{ Package: 'stx:libbasic' }"
    13 
    13 
       
    14 "{ NameSpace: Smalltalk }"
       
    15 
    14 FileStream subclass:#DirectoryStream
    16 FileStream subclass:#DirectoryStream
    15 	instanceVariableNames:'dirPointer readAheadEntry'
    17 	instanceVariableNames:'dirPointer readAheadEntry'
    16 	classVariableNames:''
    18 	classVariableNames:''
    17 	poolDictionaries:''
    19 	poolDictionaries:''
    18 	category:'Streams-External'
    20 	category:'Streams-External'
    19 !
    21 !
    20 
    22 
    21 !DirectoryStream primitiveDefinitions!
    23 !DirectoryStream primitiveDefinitions!
    22 %{
    24 %{
    23 
    25 #include "stxOSDefs.h"
    24 #define UNIX_LIKE
       
    25 
    26 
    26 #if defined(WIN32)
    27 #if defined(WIN32)
    27 # undef UNIX_LIKE
    28 # undef UNIX_LIKE
    28 #endif
    29 #else
    29 
    30 # if defined(transputer)
    30 #if defined(transputer)
    31 #  undef UNIX_LIKE
    31 # undef UNIX_LIKE
    32 # else
       
    33 #  define UNIX_LIKE
       
    34 # endif
    32 #endif
    35 #endif
    33 
    36 
    34 #ifdef UNIX_LIKE
    37 #ifdef UNIX_LIKE
    35 # if defined(__GLIBC__) && (__GLIBC__ == 2)
    38 # if defined(__GLIBC__) && (__GLIBC__ == 2)
    36 #  if defined(__GLIBC_MINOR__) && (__GLIBC_MINOR__ == 1)
    39 #  if defined(__GLIBC_MINOR__) && (__GLIBC_MINOR__ == 1)
    66 # ifndef errno
    69 # ifndef errno
    67   extern errno;
    70   extern errno;
    68 # endif
    71 # endif
    69 
    72 
    70 #endif /* UNIX_LIKE */
    73 #endif /* UNIX_LIKE */
    71 
       
    72 
    74 
    73 #ifdef WIN32
    75 #ifdef WIN32
    74 
    76 
    75 # ifdef __i386__
    77 # ifdef __i386__
    76 #  define _X86_
    78 #  define _X86_
   140 
   142 
   141 # define __HANDLEVal(o)  (HANDLE)__externalAddressVal(o)
   143 # define __HANDLEVal(o)  (HANDLE)__externalAddressVal(o)
   142 #endif /* WIN32 */
   144 #endif /* WIN32 */
   143 
   145 
   144 #include "stxOSDefs.h"
   146 #include "stxOSDefs.h"
   145 
       
   146 %}
   147 %}
   147 ! !
   148 ! !
   148 
   149 
   149 !DirectoryStream primitiveFunctions!
   150 !DirectoryStream primitiveFunctions!
   150 %{
   151 %{
   506     ].
   507     ].
   507     ^ contents
   508     ^ contents
   508 !
   509 !
   509 
   510 
   510 nextLine
   511 nextLine
   511     "return the next filename as a string"
   512     "return the next filename as a string or nil"
   512 
   513 
   513     |prevEntry nextEntry isUnix|
   514     |linkInfo|
       
   515 
       
   516     linkInfo := self nextLinkInfo.
       
   517     linkInfo notNil ifTrue:[^ linkInfo sourcePath].
       
   518     ^ nil
       
   519 !
       
   520 
       
   521 nextLinkInfo
       
   522     "return the next FileStatusInfo or nil"
       
   523 
       
   524     |nextResult resultInfo|
       
   525 
       
   526     (hitEOF or:[readAheadEntry isNil]) ifTrue:[
       
   527         ^ self pastEndRead
       
   528     ].
       
   529 
       
   530     nextResult := OperatingSystem nextLinkInfoFrom:self dirPointer:dirPointer.
       
   531     nextResult isNil ifTrue:[
       
   532         hitEOF := true.
       
   533     ].
       
   534     readAheadEntry notNil ifTrue:[
       
   535         resultInfo := readAheadEntry.
       
   536         readAheadEntry := nextResult.
       
   537         ^ resultInfo
       
   538     ].
       
   539     nextResult isNil ifTrue:[
       
   540         ^ self pastEndRead
       
   541     ].
       
   542     ^ nextResult
       
   543 ! !
       
   544 
       
   545 !DirectoryStream protectedMethodsFor:'instance release'!
       
   546 
       
   547 closeFile
       
   548     "low level close of a directoryStream"
       
   549 
       
   550     |dp|
       
   551 
       
   552     dp := dirPointer.
       
   553     dp isNil ifTrue:[
       
   554 	^ self errorNotOpen.
       
   555     ].
       
   556     dirPointer := nil.
   514 %{
   557 %{
   515 #ifdef HAS_OPENDIR
   558 #ifdef HAS_OPENDIR
   516     DIR *d;
   559     closedir( (DIR *)(__FILEVal(dp)) );
   517     DIRENT_STRUCT *dp;
       
   518     OBJ dirP;
       
   519 
       
   520     if (__INST(hitEOF) != true && (dirP = __INST(dirPointer)) != nil) {
       
   521 	__INST(lastErrorNumber) = nil;
       
   522 	d = (DIR *)__FILEVal(dirP);
       
   523 
       
   524 	__BEGIN_INTERRUPTABLE__
       
   525 	do {
       
   526 	    do {
       
   527 		__threadErrno = 0;
       
   528 		dp = readdir(d);
       
   529 		/*
       
   530 		 * for compatibility with ST-80,
       
   531 		 * skip entries for '.' and '..'.
       
   532 		 * If wanted, these must be added synthetically.
       
   533 		 */
       
   534 	    } while (dp && ((strcmp(dp->d_name, ".")==0) || (strcmp(dp->d_name, "..")==0)));
       
   535 	} while ((dp == NULL) && (__threadErrno == EINTR));
       
   536 	__END_INTERRUPTABLE__
       
   537 
       
   538 	if (dp != NULL) {
       
   539 	    nextEntry = __MKSTRING((char *)(dp->d_name));
       
   540 	} else {
       
   541 	    if (__threadErrno) {
       
   542 		__INST(lastErrorNumber) = __mkSmallInteger(__threadErrno);
       
   543 	    } else {
       
   544 		__INST(hitEOF) = true;
       
   545 	    }
       
   546        }
       
   547     }
       
   548 #else /* no HAS_OPENDIR */
       
   549 # ifdef WIN32
       
   550     HANDLE d;
       
   551     WIN32_FIND_DATAW data;
       
   552     OBJ dirP;
       
   553     int rslt;
       
   554 
       
   555     if (__INST(hitEOF) != true && (dirP = __INST(dirPointer)) != nil) {
       
   556 	__INST(lastErrorNumber) = nil;
       
   557 	d = __HANDLEVal(dirP);
       
   558 
       
   559 	do {
       
   560 	    __threadErrno = 0;
       
   561 	    rslt = STX_API_NOINT_CALL2( "FindNextFileW", FindNextFileW, d, &data );
       
   562 	} while ((rslt < 0) && (__threadErrno == EINTR));
       
   563 
       
   564 	if (rslt > 0) {
       
   565 	    nextEntry = __MKU16STRING( data.cFileName );
       
   566 	} else {
       
   567 	   __INST(hitEOF) = true;
       
   568 	}
       
   569     }
       
   570 # endif /* WIN32 */
       
   571 #endif /* HAS_OPENDIR */
       
   572 
       
   573 #ifdef unix
       
   574     isUnix = true;
       
   575 #endif
       
   576 
       
   577 %}.
       
   578     lastErrorNumber notNil ifTrue:[^ self ioError].
       
   579     nextEntry notNil ifTrue:[
       
   580 	isUnix == true ifTrue:[
       
   581 	    nextEntry := OperatingSystem decodePath:nextEntry.
       
   582 	] ifFalse:[
       
   583 	    nextEntry := nextEntry asSingleByteStringIfPossible.
       
   584 	]
       
   585     ].
       
   586     prevEntry := readAheadEntry.
       
   587     readAheadEntry := nextEntry.
       
   588     prevEntry isNil ifTrue:[^ self pastEndRead].
       
   589     ^ prevEntry
       
   590 ! !
       
   591 
       
   592 !DirectoryStream methodsFor:'closing'!
       
   593 
       
   594 close
       
   595     "close the stream - tell operating system"
       
   596 
       
   597     dirPointer notNil ifTrue:[
       
   598 	Lobby unregister:self.
       
   599 	self closeFile.
       
   600 	dirPointer := nil
       
   601     ]
       
   602 ! !
       
   603 
       
   604 !DirectoryStream protectedMethodsFor:'instance release'!
       
   605 
       
   606 closeFile
       
   607     "low level close of a directoryStream"
       
   608 %{
       
   609 #ifdef HAS_OPENDIR
       
   610     OBJ dp;
       
   611 
       
   612     if ((dp = __INST(dirPointer)) != nil) {
       
   613 	__INST(dirPointer) = nil;
       
   614 	closedir( (DIR *)(__FILEVal(dp)) );
       
   615     }
       
   616 #else
   560 #else
   617 # ifdef WIN32
   561 # ifdef WIN32
   618     OBJ dp;
   562     FindClose( __HANDLEVal(dp) );
   619 
       
   620     if ((dp = __INST(dirPointer)) != nil) {
       
   621 	__INST(dirPointer) = nil;
       
   622 	FindClose( __HANDLEVal(dp) );
       
   623     }
       
   624 # endif
   563 # endif
   625 #endif
   564 #endif
   626 %}
   565 %}
   627 ! !
   566 ! !
   628 
   567 
   629 !DirectoryStream methodsFor:'private'!
   568 !DirectoryStream methodsFor:'private'!
   630 
   569 
   631 openForReading
   570 openForReading
   632     "open the file for readonly"
   571     "open the file for readonly"
   633 
   572 
   634     |ok entry encodedPathName|
   573     |ok encodedPathName error fileSize osPathname osModTime osCrtTime osAccTime osFileAttributes |
   635 
   574 
   636     encodedPathName := OperatingSystem encodePath:pathName.
   575     encodedPathName := OperatingSystem encodePath:pathName.
   637     mode := #readonly.
   576     mode := #readonly.
       
   577     hitEOF := false.
       
   578 
   638 %{
   579 %{
   639 #ifdef HAS_OPENDIR
   580 #ifdef HAS_OPENDIR
   640     DIR *d;
   581     DIR *d;
   641     OBJ path, dp;
   582     OBJ path, dp;
   642 
   583 
   649 		d = opendir((char *) __stringVal(encodedPathName));
   590 		d = opendir((char *) __stringVal(encodedPathName));
   650 	    } while ((d == NULL) && (__threadErrno == EINTR));
   591 	    } while ((d == NULL) && (__threadErrno == EINTR));
   651 	    __END_INTERRUPTABLE__
   592 	    __END_INTERRUPTABLE__
   652 
   593 
   653 	    if (d == NULL) {
   594 	    if (d == NULL) {
   654 		__INST(lastErrorNumber) = __mkSmallInteger(__threadErrno);
   595 		error = __mkSmallInteger(__threadErrno);
   655 	    } else {
   596 	    } else {
   656 		dp = __MKEXTERNALADDRESS(d); __INST(dirPointer) = dp; __STORE(self, dp);
   597 		dp = __MKEXTERNALADDRESS(d); __INST(dirPointer) = dp; __STORE(self, dp);
   657 		ok = true;
   598 		ok = true;
   658 	    }
   599 	    }
   659 	}
   600 	}
   660     }
   601     }
   661 #else
   602 #else
   662 # ifdef WIN32
   603 #ifdef WIN32
   663     HANDLE d;
   604     HANDLE d;
   664     OBJ path, dp;
   605     OBJ path, dp;
   665     union {
   606     union {
   666 	char pattern[MAXPATHLEN];
   607 	char pattern[MAXPATHLEN];
   667 	wchar_t wpattern[MAXPATHLEN];
   608 	wchar_t wpattern[MAXPATHLEN];
   685 		    __threadErrno = 0;
   626 		    __threadErrno = 0;
   686 		    d = STX_API_NOINT_CALL2( "FindFirstFileA", FindFirstFileA, uP.pattern, &uD.data );
   627 		    d = STX_API_NOINT_CALL2( "FindFirstFileA", FindFirstFileA, uP.pattern, &uD.data );
   687 		} while ((d < 0) && (__threadErrno == EINTR));
   628 		} while ((d < 0) && (__threadErrno == EINTR));
   688 
   629 
   689 		if (d == INVALID_HANDLE_VALUE) {
   630 		if (d == INVALID_HANDLE_VALUE) {
   690 		    __INST(lastErrorNumber) = __mkSmallInteger(GetLastError());
   631 		    error = __mkSmallInteger(GetLastError());
   691 		} else {
   632 		} else {
   692 		    dp = __MKEXTERNALADDRESS(d); __INST(dirPointer) = dp; __STORE(self, dp);
   633 		    dp = __MKEXTERNALADDRESS(d); __INST(dirPointer) = dp; __STORE(self, dp);
   693 		    entry = __MKSTRING( uD.data.cFileName );
   634 
       
   635 		    fileSize   = __MKLARGEINT64(1, uD.data.nFileSizeLow, uD.data.nFileSizeHigh );
       
   636 		    osPathname = __MKSTRING( uD.data.cFileName );
       
   637 		    osFileAttributes = __mkSmallInteger( uD.data.dwFileAttributes );
       
   638 
       
   639 		    osCrtTime = FileTimeToOsTime(&uD.data.ftCreationTime);
       
   640 		    osAccTime = FileTimeToOsTime(&uD.data.ftLastAccessTime);
       
   641 		    osModTime = FileTimeToOsTime(&uD.data.ftLastWriteTime);
   694 		    ok = true;
   642 		    ok = true;
   695 		}
   643 		}
   696 	    }
   644 	    }
   697 	}
   645 	}
   698 	else if (__isUnicode16String(path)) {
   646 	else if (__isUnicode16String(path)) {
   711 		    __threadErrno = 0;
   659 		    __threadErrno = 0;
   712 		    d = STX_API_NOINT_CALL2( "FindFirstFileW", FindFirstFileW, uP.wpattern, &uD.wdata );
   660 		    d = STX_API_NOINT_CALL2( "FindFirstFileW", FindFirstFileW, uP.wpattern, &uD.wdata );
   713 		} while ((d < 0) && (__threadErrno == EINTR));
   661 		} while ((d < 0) && (__threadErrno == EINTR));
   714 
   662 
   715 		if (d == INVALID_HANDLE_VALUE) {
   663 		if (d == INVALID_HANDLE_VALUE) {
   716 		    __INST(lastErrorNumber) = __mkSmallInteger(GetLastError());
   664 		    error = __mkSmallInteger(GetLastError());
   717 		} else {
   665 		} else {
   718 		    dp = __MKEXTERNALADDRESS(d); __INST(dirPointer) = dp; __STORE(self, dp);
   666 		    dp = __MKEXTERNALADDRESS(d); __INST(dirPointer) = dp; __STORE(self, dp);
   719 		    entry = __MKU16STRING( uD.wdata.cFileName );
   667 
       
   668 		    fileSize   = __MKLARGEINT64(1, uD.wdata.nFileSizeLow, uD.wdata.nFileSizeHigh );
       
   669 		    osPathname = __MKU16STRING( uD.wdata.cFileName );
       
   670 		    osFileAttributes = __mkSmallInteger( uD.data.dwFileAttributes );
       
   671 
       
   672 		    osCrtTime = FileTimeToOsTime(&uD.wdata.ftCreationTime);
       
   673 		    osAccTime = FileTimeToOsTime(&uD.wdata.ftLastAccessTime);
       
   674 		    osModTime = FileTimeToOsTime(&uD.wdata.ftLastWriteTime);
   720 		    ok = true;
   675 		    ok = true;
   721 		}
   676 		}
   722 	    }
   677 	    }
   723 	}
   678 	}
   724     }
   679     }
   725 # endif
   680 #endif
   726 #endif
   681 #endif
   727 %}.
   682 %}.
   728     ok isNil ifTrue:[
   683 
   729 	"
   684     ok == true ifTrue:[
   730 	 opendir not avalable - use slower pipe
       
   731 	"
       
   732 	^ PipeStream readingFrom:('cd ' , pathName , '; ls -a')
       
   733     ].
       
   734 
       
   735     (ok == true) ifTrue:[
       
   736 	Lobby register:self.
   685 	Lobby register:self.
   737 	entry isNil ifTrue:[
   686 	osPathname isNil ifTrue:[
   738 	    self nextLine. "read 1st entry into readAheadEntry buffer"
   687 	    "UNIX: does not automatically provide the first entry"
       
   688 
       
   689 	    StreamError handle:[:ex |
       
   690 		self close.
       
   691 		ex reject.
       
   692 	    ] do:[
       
   693 		readAheadEntry := OperatingSystem nextLinkInfoFrom:self dirPointer:dirPointer.
       
   694 	    ].
   739 	] ifFalse:[
   695 	] ifFalse:[
   740 	    readAheadEntry := entry.
   696 	    "Windows already provides the first entry's info"
       
   697 
       
   698 	    readAheadEntry := OperatingSystem
       
   699 		linkInfoFor:osPathname
       
   700 		fileSize:fileSize
       
   701 		fileAttributes:osFileAttributes
       
   702 		osCrtTime:osCrtTime
       
   703 		osAccTime:osAccTime
       
   704 		osModTime:osModTime
   741 	].
   705 	].
       
   706 
   742 	^ self
   707 	^ self
   743     ].
   708     ].
   744     dirPointer notNil ifTrue:[^ self errorAlreadyOpen].
   709 
   745     lastErrorNumber notNil ifTrue:[^ self openError:lastErrorNumber].
   710     ok notNil ifTrue:[
       
   711 	dirPointer notNil ifTrue:[^ self errorAlreadyOpen].
       
   712     ].
       
   713     error notNil ifTrue:[
       
   714 	^ self openError:(lastErrorNumber := error).
       
   715     ].
   746     ^ nil
   716     ^ nil
   747 !
   717 !
   748 
   718 
   749 reOpen
   719 reOpen
   750     "USERS WILL NEVER INVOKE THIS METHOD
   720     "USERS WILL NEVER INVOKE THIS METHOD
   781 	(DirectoryStream directoryNamed:'/') isEmpty
   751 	(DirectoryStream directoryNamed:'/') isEmpty
   782 	(DirectoryStream directoryNamed:'/var/tmp') isEmpty
   752 	(DirectoryStream directoryNamed:'/var/tmp') isEmpty
   783     "
   753     "
   784 
   754 
   785     "Modified: 18.9.1997 / 18:05:31 / stefan"
   755     "Modified: 18.9.1997 / 18:05:31 / stefan"
       
   756 !
       
   757 
       
   758 isOpen
       
   759     ^ dirPointer notNil.
   786 ! !
   760 ! !
   787 
   761 
   788 !DirectoryStream class methodsFor:'documentation'!
   762 !DirectoryStream class methodsFor:'documentation'!
   789 
   763 
   790 version
   764 version
   791     ^ '$Header: /cvs/stx/stx/libbasic/DirectoryStream.st,v 1.78 2013-01-10 11:43:30 cg Exp $'
   765     ^ '$Header: /cvs/stx/stx/libbasic/DirectoryStream.st,v 1.87 2015-01-15 15:24:41 cg Exp $'
   792 !
   766 !
   793 
   767 
   794 version_CVS
   768 version_CVS
   795     ^ '$Header: /cvs/stx/stx/libbasic/DirectoryStream.st,v 1.78 2013-01-10 11:43:30 cg Exp $'
   769     ^ '$Header: /cvs/stx/stx/libbasic/DirectoryStream.st,v 1.87 2015-01-15 15:24:41 cg Exp $'
   796 ! !
   770 ! !
       
   771