FileStream.st
changeset 1 a27a279701f8
child 2 6526dde5f3ac
equal deleted inserted replaced
0:aa2498ef6470 1:a27a279701f8
       
     1 "
       
     2  COPYRIGHT (c) 1989-93 by Claus Gittinger
       
     3               All Rights Reserved
       
     4 
       
     5  This software is furnished under a license and may be used
       
     6  only in accordance with the terms of that license and with the
       
     7  inclusion of the above copyright notice.   This software may not
       
     8  be provided or otherwise made available to, or used by, any
       
     9  other person.  No title to or ownership of the software is
       
    10  hereby transferred.
       
    11 "
       
    12 
       
    13 ExternalStream subclass:#FileStream
       
    14        instanceVariableNames:'pathName'
       
    15        classVariableNames:''
       
    16        poolDictionaries:''
       
    17        category:'Streams-External'
       
    18 !
       
    19 
       
    20 FileStream comment:'
       
    21 COPYRIGHT (c) 1989-93 by Claus Gittinger
       
    22               All Rights Reserved
       
    23 
       
    24 This class provides access to the operating systems underlying file
       
    25 system (i.e. its an interface to the stdio library).
       
    26 
       
    27 %W% %E%
       
    28 '!
       
    29 
       
    30 %{
       
    31 #include <stdio.h>
       
    32 
       
    33 #ifdef transputer
       
    34 # include <iocntrl.h>
       
    35 # ifndef fileno
       
    36    /* kludge: inmos forgot fileno */
       
    37 #  define fileno(f)     ((f)->__file)
       
    38 # endif
       
    39 #else
       
    40 # include <sys/types.h>
       
    41 # include <sys/stat.h>
       
    42 #endif
       
    43 %}
       
    44 
       
    45 !FileStream class methodsFor:'instance creation'!
       
    46 
       
    47 newFileNamed:filename
       
    48     "return a FileStream for new file named filename, aString.
       
    49      If the file exists, it is truncated, otherwise created.
       
    50      The file is opened for write access only."
       
    51 
       
    52     |newStream|
       
    53     newStream := (self basicNew) pathName:filename.
       
    54     newStream createForWriting isNil ifTrue:[^nil].
       
    55     ^ newStream
       
    56 !
       
    57 
       
    58 newFileNamed:filename in:aDirectory
       
    59     "return a FileStream for new file named filename, aString
       
    60      in aDirectory, a FileDirectory.
       
    61      If the file exists, it is truncated, otherwise created.
       
    62      The file is opened for write access only."
       
    63 
       
    64     |newStream|
       
    65     newStream := (self basicNew) pathName:filename in:aDirectory.
       
    66     newStream createForWriting isNil ifTrue:[^nil].
       
    67     ^ newStream
       
    68 !
       
    69 
       
    70 oldFileNamed:filename
       
    71     "return a FileStream for existing file named filename, aString.
       
    72      The file is opened for read/write access."
       
    73 
       
    74     |newStream|
       
    75 
       
    76     (OperatingSystem isReadable:filename) ifFalse:[^nil].
       
    77     newStream := (self basicNew) pathName:filename.
       
    78     newStream readwrite.
       
    79     newStream openForReadWrite isNil ifTrue:[^nil].
       
    80     newStream readLimit:(newStream size).
       
    81     ^ newStream
       
    82 !
       
    83 
       
    84 oldFileNamed:filename in:aDirectory
       
    85     "return a FileStream for existing file named filename, aString
       
    86      in aDirectory, a FileDirectory.
       
    87      The file is opened for read/write access."
       
    88 
       
    89     |newStream|
       
    90     newStream := (self basicNew) pathName:filename in:aDirectory.
       
    91     newStream openForReadWrite isNil ifTrue:[^nil].
       
    92     newStream readLimit:(newStream size).
       
    93     ^ newStream
       
    94 !
       
    95 
       
    96 fileNamed:filename
       
    97     "return a stream on file filename - if the file does not
       
    98      already exist, create it."
       
    99 
       
   100     |stream|
       
   101 
       
   102     stream := self oldFileNamed:filename.
       
   103     stream isNil ifTrue:[
       
   104         stream := self newFileNamed:filename
       
   105     ].
       
   106     ^ stream
       
   107 !
       
   108 
       
   109 fileNamed:filename in:aDirectory
       
   110     "return a stream on file filename - if the file does not
       
   111      already exist, create it."
       
   112 
       
   113     |stream|
       
   114 
       
   115     stream := self oldFileNamed:filename in:aDirectory.
       
   116     stream isNil ifTrue:[
       
   117         stream := self newFileNamed:filename in:aDirectory
       
   118     ].
       
   119     ^ stream
       
   120 !
       
   121 
       
   122 readonlyFileNamed:filename
       
   123     "return a readonly FileStream for existing file named filename, aString"
       
   124 
       
   125     |newStream|
       
   126 
       
   127     (OperatingSystem isReadable:filename) ifFalse:[^nil].
       
   128 
       
   129     newStream := (self basicNew) pathName:filename.
       
   130     newStream openForReading isNil ifTrue:[^nil].
       
   131     newStream readLimit:(newStream size).
       
   132     ^ newStream
       
   133 !
       
   134 
       
   135 readonlyFileNamed:filename in:aDirectory
       
   136     "return a readonly FileStream for existing file named filename, aString
       
   137      in aDirectory, a FileDirectory"
       
   138 
       
   139     |newStream|
       
   140     newStream := (self basicNew) pathName:filename in:aDirectory.
       
   141     newStream openForReading isNil ifTrue:[^nil].
       
   142     newStream readLimit:(newStream size).
       
   143     ^ newStream
       
   144 !
       
   145 
       
   146 appendingOldFileNamed:filename
       
   147     "return a FileStream for existing file named filename, aString"
       
   148 
       
   149     |newStream|
       
   150     newStream := (self basicNew) pathName:filename.
       
   151     newStream openForAppending isNil ifTrue:[^nil].
       
   152     newStream readLimit:(newStream size).
       
   153     ^ newStream
       
   154 !
       
   155 
       
   156 appendingOldFileNamed:filename in:aDirectory
       
   157     "return a FileStream for existing file named filename, aString
       
   158      in aDirectory, a FileDirectory"
       
   159 
       
   160     |newStream|
       
   161     newStream := (self basicNew) pathName:filename in:aDirectory.
       
   162     newStream openForAppending isNil ifTrue:[^nil].
       
   163     newStream readLimit:(newStream size).
       
   164     ^ newStream
       
   165 ! !
       
   166 
       
   167 !FileStream methodsFor:'accessing'!
       
   168 
       
   169 store:something
       
   170     "what really should this do"
       
   171 
       
   172     self nextPutAll:something
       
   173 !
       
   174 
       
   175 directoryName
       
   176     "return the name of the directory I'm in"
       
   177 
       
   178     |path lastIndex index|
       
   179 
       
   180     path := pathName.
       
   181     lastIndex := 0.
       
   182     index := path indexOf:$/.
       
   183     [index ~~ 0] whileTrue:[
       
   184         lastIndex := index.
       
   185         index := path indexOf:$/ startingAt:(index + 1)
       
   186     ].
       
   187     (lastIndex == 0) ifTrue:[^ '.'].
       
   188     (lastIndex == 1) ifTrue:[^ '/'].
       
   189     ^ path copyFrom:1 to:(lastIndex - 1)
       
   190 !
       
   191 
       
   192 name
       
   193     "return my name without leading direcory-path"
       
   194 
       
   195     |lastIndex index|
       
   196 
       
   197     lastIndex := 1.
       
   198     [true] whileTrue:[
       
   199         index := pathName indexOf:$/ startingAt:lastIndex.
       
   200         (index == 0) ifTrue:[
       
   201             ^ pathName copyFrom:lastIndex
       
   202         ].
       
   203         lastIndex := index + 1
       
   204     ]
       
   205 !
       
   206 
       
   207 pathName
       
   208     "return the pathname"
       
   209 
       
   210     ^ pathName
       
   211 ! !
       
   212 
       
   213 !FileStream methodsFor:'private'!
       
   214 
       
   215 pathName:filename
       
   216     "set the pathname"
       
   217 
       
   218     pathName := filename
       
   219 !
       
   220 
       
   221 pathName:filename in:aDirectory
       
   222     "set the pathname starting at aDirectory, a FileDirectory"
       
   223 
       
   224     ((filename at:1) == $/) ifTrue:[
       
   225         "filename may not start with a '/'"
       
   226         pathName := nil
       
   227     ] ifFalse:[
       
   228         pathName := aDirectory pathName.
       
   229         (pathName endsWith:'/') ifFalse:[
       
   230             pathName := pathName , '/'
       
   231         ].
       
   232         pathName := pathName , filename
       
   233     ]
       
   234 !
       
   235 
       
   236 open
       
   237     "open the file"
       
   238 
       
   239     pathName isNil ifTrue:[^nil].
       
   240     (mode == #readonly) ifTrue: [
       
   241         ^ self openForReading
       
   242     ].
       
   243     (mode == #writeonly) ifTrue: [
       
   244         ^ self openForWriting
       
   245     ].
       
   246     ^ self openForReadWrite
       
   247 !
       
   248 
       
   249 openWithMode:openmode
       
   250     "open the file; openmode is the string defining the way to open"
       
   251 
       
   252     |retVal|
       
   253 %{
       
   254     FILE *f;
       
   255     OBJ path;
       
   256     extern OBJ ErrorNumber, Filename;
       
   257     extern errno;
       
   258 
       
   259     if (_INST(filePointer) == nil) {
       
   260         path = _INST(pathName);
       
   261         if (_isString(path) || (_Class(path) == Filename)) {
       
   262             f = (FILE *)fopen((char *) _stringVal(path), (char *) _stringVal(openmode));
       
   263             if (f == NULL) {
       
   264                 ErrorNumber = _MKSMALLINT(errno);
       
   265                 _INST(position) = nil;
       
   266             } else {
       
   267                 _INST(filePointer) = _MKSMALLINT((int)f);
       
   268                 _INST(position) = _MKSMALLINT(1);
       
   269                 retVal = self;
       
   270             }
       
   271         }
       
   272     }
       
   273 %}
       
   274 .
       
   275     retVal notNil ifTrue:[
       
   276         lobby register:self
       
   277     ].
       
   278     ^ retVal
       
   279 !
       
   280 
       
   281 openForReading
       
   282     "open the file for readonly"
       
   283 
       
   284     mode := #readonly.
       
   285     ^ self openWithMode:'r'
       
   286 !
       
   287 
       
   288 openForWriting
       
   289     "open the file for writeonly"
       
   290 
       
   291     mode := #writeonly.
       
   292     ^ self openWithMode:'w'
       
   293 !
       
   294 
       
   295 openForAppending
       
   296     "open the file for writeonly appending to the end"
       
   297 
       
   298     mode := #writeonly.
       
   299     ^ self openWithMode:'a+'
       
   300 !
       
   301 
       
   302 createForWriting
       
   303     "create/truncate the file for writeonly"
       
   304 
       
   305     mode := #writeonly.
       
   306     ^ self openWithMode:'w+'
       
   307 !
       
   308 
       
   309 openForReadWrite
       
   310     "open the file for read/write"
       
   311 
       
   312     mode := #readwrite.
       
   313     ^ self openWithMode:'r+w'
       
   314 !
       
   315 
       
   316 createForReadWrite
       
   317     "create/truncate the file for read/write"
       
   318 
       
   319     mode := #readwrite.
       
   320     ^ self openWithMode:'rw+'
       
   321 !
       
   322 
       
   323 reOpen
       
   324     "sent after snapin to reopen streams"
       
   325 
       
   326     filePointer notNil ifTrue:[
       
   327         "it was open, when snapped-out"
       
   328         filePointer := nil.
       
   329         self open.
       
   330         filePointer isNil ifTrue:[
       
   331             Transcript showCr:('could not reopen file: ', pathName)
       
   332         ] ifFalse:[
       
   333             self position:position
       
   334         ]
       
   335     ]
       
   336 !
       
   337 
       
   338 size
       
   339     "return the size in bytes of the file"
       
   340 
       
   341 %{  /* NOCONTEXT */
       
   342 
       
   343 #ifdef transputer
       
   344     FILE *f;
       
   345     int size;
       
   346 
       
   347     if (_INST(filePointer) != nil) {
       
   348         f = (FILE *)_intVal(_INST(filePointer));
       
   349         if ((size = filesize(fileno(f))) >= 0) {
       
   350             RETURN ( _MKSMALLINT(size) );
       
   351         }
       
   352     }
       
   353 #else
       
   354     FILE *f;
       
   355     struct stat buf;
       
   356 
       
   357     if (_INST(filePointer) != nil) {
       
   358         f = (FILE *)_intVal(_INST(filePointer));
       
   359         if (fstat(fileno(f), &buf) >= 0) {
       
   360             RETURN ( _MKSMALLINT(buf.st_size) );
       
   361         }
       
   362     }
       
   363 #endif
       
   364 %}
       
   365 .
       
   366     "could add a fall-back here:
       
   367 
       
   368         oldPosition := self position.
       
   369         self setToEnd.
       
   370         sz := self position.
       
   371         self position:oldPosition.
       
   372         ^ sz
       
   373     "
       
   374     filePointer isNil ifTrue:[^ self errorNotOpen].
       
   375     ^ self primitiveFailed
       
   376 !
       
   377 
       
   378 position
       
   379     "return the read/write position in the file -
       
   380      notice, in smalltalk indices start at 1 so begin of file is 1""
       
   381 
       
   382 %{  /* NOCONTEXT */
       
   383 
       
   384     FILE *f;
       
   385     long currentPosition;
       
   386 
       
   387     if (_INST(filePointer) != nil) {
       
   388         f = (FILE *)_intVal(_INST(filePointer));
       
   389         currentPosition = ftell(f);
       
   390         if (currentPosition >= 0) {
       
   391             /*
       
   392              * notice: Smalltalk index starts at 1
       
   393              */
       
   394             RETURN ( _MKSMALLINT(currentPosition + 1) );
       
   395         }
       
   396     }
       
   397 %}
       
   398 .
       
   399     filePointer isNil ifTrue:[^ self errorNotOpen].
       
   400     ^ self primitiveFailed
       
   401 !
       
   402 
       
   403 position:newPos
       
   404     "set the read/write position in the file"
       
   405 
       
   406 %{  /* NOCONTEXT */
       
   407 
       
   408     FILE *f;
       
   409     extern OBJ ErrorNumber;
       
   410     extern errno;
       
   411 
       
   412     if (_INST(filePointer) != nil) {
       
   413         if (_isSmallInteger(newPos)) {
       
   414             f = (FILE *)_intVal(_INST(filePointer));
       
   415             /*
       
   416              * notice: Smalltalk index starts at 1
       
   417              */
       
   418             if (fseek(f, _intVal(newPos) - 1, 0) >= 0) {
       
   419                 _INST(position) = newPos;
       
   420                 RETURN ( self );
       
   421             }
       
   422             ErrorNumber = _MKSMALLINT(errno);
       
   423         }
       
   424     }
       
   425 %}
       
   426 .
       
   427     filePointer isNil ifTrue:[^ self errorNotOpen].
       
   428     ^ self primitiveFailed
       
   429 !
       
   430 
       
   431 setToEnd
       
   432     "set the read/write position in the file to be at the end of the file"
       
   433 
       
   434     filePointer isNil ifTrue:[^ self errorNotOpen].
       
   435 %{
       
   436     FILE *f;
       
   437     extern OBJ ErrorNumber;
       
   438     extern errno;
       
   439 
       
   440     f = (FILE *)_intVal(_INST(filePointer));
       
   441     _INST(position) = nil;
       
   442     if (fseek(f, 0, 2) >= 0) {
       
   443         RETURN ( self );
       
   444     }
       
   445     ErrorNumber = _MKSMALLINT(errno);
       
   446 %}
       
   447 .
       
   448     ^ self primitiveFailed
       
   449 ! !
       
   450 
       
   451 !FileStream methodsFor:'printing & storing'!
       
   452 
       
   453 printOn:aStream
       
   454     aStream nextPutAll:'(a FileStream for:'.
       
   455     aStream nextPutAll:pathName.
       
   456     aStream nextPut:$)
       
   457 !
       
   458 
       
   459 storeOn:aStream
       
   460     aStream nextPutAll:'(FileStream oldFileNamed:'.
       
   461     aStream nextPutAll:pathName.
       
   462     (self position ~~ 1) ifTrue:[
       
   463         aStream nextPutAll:'; position:'.
       
   464         self position storeOn:aStream
       
   465     ].
       
   466     aStream nextPut:$)
       
   467 ! !