--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/FileStr.st Fri Jul 16 11:39:45 1993 +0200
@@ -0,0 +1,467 @@
+"
+ COPYRIGHT (c) 1989-93 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.
+"
+
+ExternalStream subclass:#FileStream
+ instanceVariableNames:'pathName'
+ classVariableNames:''
+ poolDictionaries:''
+ category:'Streams-External'
+!
+
+FileStream comment:'
+COPYRIGHT (c) 1989-93 by Claus Gittinger
+ All Rights Reserved
+
+This class provides access to the operating systems underlying file
+system (i.e. its an interface to the stdio library).
+
+%W% %E%
+'!
+
+%{
+#include <stdio.h>
+
+#ifdef transputer
+# include <iocntrl.h>
+# ifndef fileno
+ /* kludge: inmos forgot fileno */
+# define fileno(f) ((f)->__file)
+# endif
+#else
+# include <sys/types.h>
+# include <sys/stat.h>
+#endif
+%}
+
+!FileStream class methodsFor:'instance creation'!
+
+newFileNamed:filename
+ "return a FileStream for new file named filename, aString.
+ If the file exists, it is truncated, otherwise created.
+ The file is opened for write access only."
+
+ |newStream|
+ newStream := (self basicNew) pathName:filename.
+ newStream createForWriting isNil ifTrue:[^nil].
+ ^ newStream
+!
+
+newFileNamed:filename in:aDirectory
+ "return a FileStream for new file named filename, aString
+ in aDirectory, a FileDirectory.
+ If the file exists, it is truncated, otherwise created.
+ The file is opened for write access only."
+
+ |newStream|
+ newStream := (self basicNew) pathName:filename in:aDirectory.
+ newStream createForWriting isNil ifTrue:[^nil].
+ ^ newStream
+!
+
+oldFileNamed:filename
+ "return a FileStream for existing file named filename, aString.
+ The file is opened for read/write access."
+
+ |newStream|
+
+ (OperatingSystem isReadable:filename) ifFalse:[^nil].
+ newStream := (self basicNew) pathName:filename.
+ newStream readwrite.
+ newStream openForReadWrite isNil ifTrue:[^nil].
+ newStream readLimit:(newStream size).
+ ^ newStream
+!
+
+oldFileNamed:filename in:aDirectory
+ "return a FileStream for existing file named filename, aString
+ in aDirectory, a FileDirectory.
+ The file is opened for read/write access."
+
+ |newStream|
+ newStream := (self basicNew) pathName:filename in:aDirectory.
+ newStream openForReadWrite isNil ifTrue:[^nil].
+ newStream readLimit:(newStream size).
+ ^ newStream
+!
+
+fileNamed:filename
+ "return a stream on file filename - if the file does not
+ already exist, create it."
+
+ |stream|
+
+ stream := self oldFileNamed:filename.
+ stream isNil ifTrue:[
+ stream := self newFileNamed:filename
+ ].
+ ^ stream
+!
+
+fileNamed:filename in:aDirectory
+ "return a stream on file filename - if the file does not
+ already exist, create it."
+
+ |stream|
+
+ stream := self oldFileNamed:filename in:aDirectory.
+ stream isNil ifTrue:[
+ stream := self newFileNamed:filename in:aDirectory
+ ].
+ ^ stream
+!
+
+readonlyFileNamed:filename
+ "return a readonly FileStream for existing file named filename, aString"
+
+ |newStream|
+
+ (OperatingSystem isReadable:filename) ifFalse:[^nil].
+
+ newStream := (self basicNew) pathName:filename.
+ newStream openForReading isNil ifTrue:[^nil].
+ newStream readLimit:(newStream size).
+ ^ newStream
+!
+
+readonlyFileNamed:filename in:aDirectory
+ "return a readonly FileStream for existing file named filename, aString
+ in aDirectory, a FileDirectory"
+
+ |newStream|
+ newStream := (self basicNew) pathName:filename in:aDirectory.
+ newStream openForReading isNil ifTrue:[^nil].
+ newStream readLimit:(newStream size).
+ ^ newStream
+!
+
+appendingOldFileNamed:filename
+ "return a FileStream for existing file named filename, aString"
+
+ |newStream|
+ newStream := (self basicNew) pathName:filename.
+ newStream openForAppending isNil ifTrue:[^nil].
+ newStream readLimit:(newStream size).
+ ^ newStream
+!
+
+appendingOldFileNamed:filename in:aDirectory
+ "return a FileStream for existing file named filename, aString
+ in aDirectory, a FileDirectory"
+
+ |newStream|
+ newStream := (self basicNew) pathName:filename in:aDirectory.
+ newStream openForAppending isNil ifTrue:[^nil].
+ newStream readLimit:(newStream size).
+ ^ newStream
+! !
+
+!FileStream methodsFor:'accessing'!
+
+store:something
+ "what really should this do"
+
+ self nextPutAll:something
+!
+
+directoryName
+ "return the name of the directory I'm in"
+
+ |path lastIndex index|
+
+ path := pathName.
+ lastIndex := 0.
+ index := path indexOf:$/.
+ [index ~~ 0] whileTrue:[
+ lastIndex := index.
+ index := path indexOf:$/ startingAt:(index + 1)
+ ].
+ (lastIndex == 0) ifTrue:[^ '.'].
+ (lastIndex == 1) ifTrue:[^ '/'].
+ ^ path copyFrom:1 to:(lastIndex - 1)
+!
+
+name
+ "return my name without leading direcory-path"
+
+ |lastIndex index|
+
+ lastIndex := 1.
+ [true] whileTrue:[
+ index := pathName indexOf:$/ startingAt:lastIndex.
+ (index == 0) ifTrue:[
+ ^ pathName copyFrom:lastIndex
+ ].
+ lastIndex := index + 1
+ ]
+!
+
+pathName
+ "return the pathname"
+
+ ^ pathName
+! !
+
+!FileStream methodsFor:'private'!
+
+pathName:filename
+ "set the pathname"
+
+ pathName := filename
+!
+
+pathName:filename in:aDirectory
+ "set the pathname starting at aDirectory, a FileDirectory"
+
+ ((filename at:1) == $/) ifTrue:[
+ "filename may not start with a '/'"
+ pathName := nil
+ ] ifFalse:[
+ pathName := aDirectory pathName.
+ (pathName endsWith:'/') ifFalse:[
+ pathName := pathName , '/'
+ ].
+ pathName := pathName , filename
+ ]
+!
+
+open
+ "open the file"
+
+ pathName isNil ifTrue:[^nil].
+ (mode == #readonly) ifTrue: [
+ ^ self openForReading
+ ].
+ (mode == #writeonly) ifTrue: [
+ ^ self openForWriting
+ ].
+ ^ self openForReadWrite
+!
+
+openWithMode:openmode
+ "open the file; openmode is the string defining the way to open"
+
+ |retVal|
+%{
+ FILE *f;
+ OBJ path;
+ extern OBJ ErrorNumber, Filename;
+ extern errno;
+
+ if (_INST(filePointer) == nil) {
+ path = _INST(pathName);
+ if (_isString(path) || (_Class(path) == Filename)) {
+ f = (FILE *)fopen((char *) _stringVal(path), (char *) _stringVal(openmode));
+ if (f == NULL) {
+ ErrorNumber = _MKSMALLINT(errno);
+ _INST(position) = nil;
+ } else {
+ _INST(filePointer) = _MKSMALLINT((int)f);
+ _INST(position) = _MKSMALLINT(1);
+ retVal = self;
+ }
+ }
+ }
+%}
+.
+ retVal notNil ifTrue:[
+ lobby register:self
+ ].
+ ^ retVal
+!
+
+openForReading
+ "open the file for readonly"
+
+ mode := #readonly.
+ ^ self openWithMode:'r'
+!
+
+openForWriting
+ "open the file for writeonly"
+
+ mode := #writeonly.
+ ^ self openWithMode:'w'
+!
+
+openForAppending
+ "open the file for writeonly appending to the end"
+
+ mode := #writeonly.
+ ^ self openWithMode:'a+'
+!
+
+createForWriting
+ "create/truncate the file for writeonly"
+
+ mode := #writeonly.
+ ^ self openWithMode:'w+'
+!
+
+openForReadWrite
+ "open the file for read/write"
+
+ mode := #readwrite.
+ ^ self openWithMode:'r+w'
+!
+
+createForReadWrite
+ "create/truncate the file for read/write"
+
+ mode := #readwrite.
+ ^ self openWithMode:'rw+'
+!
+
+reOpen
+ "sent after snapin to reopen streams"
+
+ filePointer notNil ifTrue:[
+ "it was open, when snapped-out"
+ filePointer := nil.
+ self open.
+ filePointer isNil ifTrue:[
+ Transcript showCr:('could not reopen file: ', pathName)
+ ] ifFalse:[
+ self position:position
+ ]
+ ]
+!
+
+size
+ "return the size in bytes of the file"
+
+%{ /* NOCONTEXT */
+
+#ifdef transputer
+ FILE *f;
+ int size;
+
+ if (_INST(filePointer) != nil) {
+ f = (FILE *)_intVal(_INST(filePointer));
+ if ((size = filesize(fileno(f))) >= 0) {
+ RETURN ( _MKSMALLINT(size) );
+ }
+ }
+#else
+ FILE *f;
+ struct stat buf;
+
+ if (_INST(filePointer) != nil) {
+ f = (FILE *)_intVal(_INST(filePointer));
+ if (fstat(fileno(f), &buf) >= 0) {
+ RETURN ( _MKSMALLINT(buf.st_size) );
+ }
+ }
+#endif
+%}
+.
+ "could add a fall-back here:
+
+ oldPosition := self position.
+ self setToEnd.
+ sz := self position.
+ self position:oldPosition.
+ ^ sz
+ "
+ filePointer isNil ifTrue:[^ self errorNotOpen].
+ ^ self primitiveFailed
+!
+
+position
+ "return the read/write position in the file -
+ notice, in smalltalk indices start at 1 so begin of file is 1""
+
+%{ /* NOCONTEXT */
+
+ FILE *f;
+ long currentPosition;
+
+ if (_INST(filePointer) != nil) {
+ f = (FILE *)_intVal(_INST(filePointer));
+ currentPosition = ftell(f);
+ if (currentPosition >= 0) {
+ /*
+ * notice: Smalltalk index starts at 1
+ */
+ RETURN ( _MKSMALLINT(currentPosition + 1) );
+ }
+ }
+%}
+.
+ filePointer isNil ifTrue:[^ self errorNotOpen].
+ ^ self primitiveFailed
+!
+
+position:newPos
+ "set the read/write position in the file"
+
+%{ /* NOCONTEXT */
+
+ FILE *f;
+ extern OBJ ErrorNumber;
+ extern errno;
+
+ if (_INST(filePointer) != nil) {
+ if (_isSmallInteger(newPos)) {
+ f = (FILE *)_intVal(_INST(filePointer));
+ /*
+ * notice: Smalltalk index starts at 1
+ */
+ if (fseek(f, _intVal(newPos) - 1, 0) >= 0) {
+ _INST(position) = newPos;
+ RETURN ( self );
+ }
+ ErrorNumber = _MKSMALLINT(errno);
+ }
+ }
+%}
+.
+ filePointer isNil ifTrue:[^ self errorNotOpen].
+ ^ self primitiveFailed
+!
+
+setToEnd
+ "set the read/write position in the file to be at the end of the file"
+
+ filePointer isNil ifTrue:[^ self errorNotOpen].
+%{
+ FILE *f;
+ extern OBJ ErrorNumber;
+ extern errno;
+
+ f = (FILE *)_intVal(_INST(filePointer));
+ _INST(position) = nil;
+ if (fseek(f, 0, 2) >= 0) {
+ RETURN ( self );
+ }
+ ErrorNumber = _MKSMALLINT(errno);
+%}
+.
+ ^ self primitiveFailed
+! !
+
+!FileStream methodsFor:'printing & storing'!
+
+printOn:aStream
+ aStream nextPutAll:'(a FileStream for:'.
+ aStream nextPutAll:pathName.
+ aStream nextPut:$)
+!
+
+storeOn:aStream
+ aStream nextPutAll:'(FileStream oldFileNamed:'.
+ aStream nextPutAll:pathName.
+ (self position ~~ 1) ifTrue:[
+ aStream nextPutAll:'; position:'.
+ self position storeOn:aStream
+ ].
+ aStream nextPut:$)
+! !