FileStream.st
changeset 159 514c749165c3
parent 92 0c73b48551ac
child 173 58e9778954bc
equal deleted inserted replaced
158:be947d4e7fb2 159:514c749165c3
     1 "
     1 "
     2  COPYRIGHT (c) 1989 by Claus Gittinger
     2  COPYRIGHT (c) 1989 by Claus Gittinger
     3               All Rights Reserved
     3 	      All Rights Reserved
     4 
     4 
     5  This software is furnished under a license and may be used
     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
     6  only in accordance with the terms of that license and with the
     7  inclusion of the above copyright notice.   This software may not
     7  inclusion of the above copyright notice.   This software may not
     8  be provided or otherwise made available to, or used by, any
     8  be provided or otherwise made available to, or used by, any
    10  hereby transferred.
    10  hereby transferred.
    11 "
    11 "
    12 
    12 
    13 ExternalStream subclass:#FileStream
    13 ExternalStream subclass:#FileStream
    14        instanceVariableNames:'pathName'
    14        instanceVariableNames:'pathName'
    15        classVariableNames:''
    15        classVariableNames:'OpenErrorSignal'
    16        poolDictionaries:''
    16        poolDictionaries:''
    17        category:'Streams-External'
    17        category:'Streams-External'
    18 !
    18 !
    19 
    19 
    20 FileStream comment:'
    20 FileStream comment:'
    21 COPYRIGHT (c) 1989 by Claus Gittinger
    21 COPYRIGHT (c) 1989 by Claus Gittinger
    22               All Rights Reserved
    22 	      All Rights Reserved
    23 
    23 
    24 $Header: /cvs/stx/stx/libbasic/FileStream.st,v 1.14 1994-08-05 00:54:46 claus Exp $
    24 $Header: /cvs/stx/stx/libbasic/FileStream.st,v 1.15 1994-10-10 00:26:04 claus Exp $
    25 '!
    25 '!
    26 
    26 
    27 !FileStream class methodsFor:'documentation'!
    27 !FileStream class methodsFor:'documentation'!
    28 
    28 
    29 copyright
    29 copyright
    30 "
    30 "
    31  COPYRIGHT (c) 1989 by Claus Gittinger
    31  COPYRIGHT (c) 1989 by Claus Gittinger
    32               All Rights Reserved
    32 	      All Rights Reserved
    33 
    33 
    34  This software is furnished under a license and may be used
    34  This software is furnished under a license and may be used
    35  only in accordance with the terms of that license and with the
    35  only in accordance with the terms of that license and with the
    36  inclusion of the above copyright notice.   This software may not
    36  inclusion of the above copyright notice.   This software may not
    37  be provided or otherwise made available to, or used by, any
    37  be provided or otherwise made available to, or used by, any
    40 "
    40 "
    41 !
    41 !
    42 
    42 
    43 version
    43 version
    44 "
    44 "
    45 $Header: /cvs/stx/stx/libbasic/FileStream.st,v 1.14 1994-08-05 00:54:46 claus Exp $
    45 $Header: /cvs/stx/stx/libbasic/FileStream.st,v 1.15 1994-10-10 00:26:04 claus Exp $
    46 "
    46 "
    47 !
    47 !
    48 
    48 
    49 documentation
    49 documentation
    50 "
    50 "
    86 # define SEEK_END       2
    86 # define SEEK_END       2
    87 #endif
    87 #endif
    88 
    88 
    89 %}
    89 %}
    90 
    90 
       
    91 !FileStream class methodsFor:'initialization'!
       
    92 
       
    93 initialize
       
    94     OpenErrorSignal isNil ifTrue:[
       
    95 	super initialize.
       
    96 
       
    97 	OpenErrorSignal := StreamErrorSignal newSignalMayProceed:true.
       
    98 	OpenErrorSignal nameClass:self message:#openErrorSignal.
       
    99 	OpenErrorSignal notifierString:'open error'.
       
   100     ].
       
   101 ! !
       
   102 
    91 !FileStream class methodsFor:'instance creation'!
   103 !FileStream class methodsFor:'instance creation'!
    92 
   104 
    93 newFileNamed:filename
   105 newFileNamed:filename
    94     "return a FileStream for new file named filename, aString.
   106     "return a FileStream for new file named filename, aString.
    95      If the file exists, it is truncated, otherwise created.
   107      If the file exists, it is truncated, otherwise created.
   177 
   189 
   178     |stream|
   190     |stream|
   179 
   191 
   180     stream := self oldFileNamed:filename.
   192     stream := self oldFileNamed:filename.
   181     stream isNil ifTrue:[
   193     stream isNil ifTrue:[
   182         stream := self newFileNamed:filename
   194 	stream := self newFileNamed:filename
   183     ].
   195     ].
   184     ^ stream
   196     ^ stream
   185 !
   197 !
   186 
   198 
   187 fileNamed:filename in:aDirectory
   199 fileNamed:filename in:aDirectory
   191 
   203 
   192     |stream|
   204     |stream|
   193 
   205 
   194     stream := self oldFileNamed:filename in:aDirectory.
   206     stream := self oldFileNamed:filename in:aDirectory.
   195     stream isNil ifTrue:[
   207     stream isNil ifTrue:[
   196         stream := self newFileNamed:filename in:aDirectory
   208 	stream := self newFileNamed:filename in:aDirectory
   197     ].
   209     ].
   198     ^ stream
   210     ^ stream
   199 !
   211 !
   200 
   212 
   201 readonlyFileNamed:filename
   213 readonlyFileNamed:filename
   259     newStream readLimit:(newStream size).
   271     newStream readLimit:(newStream size).
   260 "
   272 "
   261     ^ newStream
   273     ^ newStream
   262 ! !
   274 ! !
   263 
   275 
       
   276 !FileStream methodsFor:'error handling'!
       
   277 
       
   278 errorOpen
       
   279     "report an error, that the stream is already opened"
       
   280 
       
   281     ^ StreamErrorSignal
       
   282 	raiseRequestWith:self
       
   283 	errorString:(self class name , ' is already open')
       
   284 !
       
   285 
       
   286 openError
       
   287     "report an error, that file open failed"
       
   288 
       
   289     LastErrorNumber := lastErrorNumber.
       
   290 ^nil.
       
   291     ^ OpenErrorSignal
       
   292 	raiseRequestWith:self
       
   293 	errorString:('error on open: ' , self lastErrorString)
       
   294 ! !
       
   295 
   264 !FileStream methodsFor:'accessing'!
   296 !FileStream methodsFor:'accessing'!
   265 
   297 
   266 store:something
   298 store:something
   267     "what really should this do"
   299     "what really should this do"
   268 
   300 
   276 
   308 
   277     path := pathName.
   309     path := pathName.
   278     lastIndex := 0.
   310     lastIndex := 0.
   279     index := path indexOf:$/.
   311     index := path indexOf:$/.
   280     [index ~~ 0] whileTrue:[
   312     [index ~~ 0] whileTrue:[
   281         lastIndex := index.
   313 	lastIndex := index.
   282         index := path indexOf:$/ startingAt:(index + 1)
   314 	index := path indexOf:$/ startingAt:(index + 1)
   283     ].
   315     ].
   284     (lastIndex == 0) ifTrue:[^ '.'].
   316     (lastIndex == 0) ifTrue:[^ '.'].
   285     (lastIndex == 1) ifTrue:[^ '/'].
   317     (lastIndex == 1) ifTrue:[^ '/'].
   286     ^ path copyTo:(lastIndex - 1)
   318     ^ path copyTo:(lastIndex - 1)
   287 !
   319 !
   291 
   323 
   292     |lastIndex index|
   324     |lastIndex index|
   293 
   325 
   294     lastIndex := 1.
   326     lastIndex := 1.
   295     [true] whileTrue:[
   327     [true] whileTrue:[
   296         index := pathName indexOf:$/ startingAt:lastIndex.
   328 	index := pathName indexOf:$/ startingAt:lastIndex.
   297         (index == 0) ifTrue:[
   329 	(index == 0) ifTrue:[
   298             ^ pathName copyFrom:lastIndex
   330 	    ^ pathName copyFrom:lastIndex
   299         ].
   331 	].
   300         lastIndex := index + 1
   332 	lastIndex := index + 1
   301     ]
   333     ]
   302 !
   334 !
   303 
   335 
   304 pathName
   336 pathName
   305     "return the pathname"
   337     "return the pathname"
   317 
   349 
   318 pathName:filename in:aDirectory
   350 pathName:filename in:aDirectory
   319     "set the pathname starting at aDirectory, a FileDirectory"
   351     "set the pathname starting at aDirectory, a FileDirectory"
   320 
   352 
   321     ((filename at:1) == $/) ifTrue:[
   353     ((filename at:1) == $/) ifTrue:[
   322         "filename may not start with a '/'"
   354 	"filename may not start with a '/'"
   323         pathName := nil
   355 	pathName := nil
   324     ] ifFalse:[
   356     ] ifFalse:[
   325         pathName := aDirectory pathName.
   357 	pathName := aDirectory pathName.
   326         (pathName endsWith:'/') ifFalse:[
   358 	(pathName endsWith:'/') ifFalse:[
   327             pathName := pathName , '/'
   359 	    pathName := pathName , '/'
   328         ].
   360 	].
   329         pathName := pathName , filename
   361 	pathName := pathName , filename
   330     ]
   362     ]
   331 !
   363 !
   332 
   364 
   333 open
   365 open
   334     "open the file"
   366     "open the file"
   335 
   367 
   336     pathName isNil ifTrue:[^nil].
   368     pathName isNil ifTrue:[^nil].
   337     (mode == #readonly) ifTrue: [
   369     (mode == #readonly) ifTrue: [
   338         didWrite := false.
   370 	didWrite := false.
   339         ^ self openWithMode:'r'
   371 	^ self openWithMode:'r'
   340     ].
   372     ].
   341     (mode == #writeonly) ifTrue: [
   373     (mode == #writeonly) ifTrue: [
   342         didWrite := true.
   374 	didWrite := true.
   343         ^ self openWithMode:'w'
   375 	^ self openWithMode:'w'
   344     ].
   376     ].
   345     ^ self openWithMode:'r+'
   377     ^ self openWithMode:'r+'
   346 !
   378 !
   347 
   379 
   348 openWithMode:openmode
   380 openWithMode:openmode
   349     "open the file; openmode is the string defining the way to open"
   381     "open the file; openmode is the string defining the way to open"
   350 
   382 
   351     |retVal|
   383     |retVal|
       
   384 
       
   385     filePointer notNil ifTrue:[^ self errorOpen].
   352 %{
   386 %{
   353     FILE *f;
   387     FILE *f;
   354     OBJ path;
   388     OBJ path;
   355     extern OBJ Filename;
       
   356     extern errno;
   389     extern errno;
   357 
   390 
   358     if (_INST(filePointer) == nil) {
   391     if (_INST(filePointer) == nil) {
   359         path = _INST(pathName);
   392 	path = _INST(pathName);
   360         if (path != nil 
   393 	if (_isNonNilObject(path) && (_qClass(path)==String)) {
   361          && ((_qClass(path)==String) || (_qClass(path) == Filename))) {
   394 	    do {
   362             do {
       
   363 #ifdef LINUX
   395 #ifdef LINUX
   364                 /* LINUX returns a non-NULL f even when interrupted */
   396 		/* LINUX returns a non-NULL f even when interrupted */
   365                 errno = 0;
   397 		errno = 0;
   366                 f = (FILE *) fopen((char *) _stringVal(path), (char *) _stringVal(openmode));
   398 		f = (FILE *) fopen((char *) _stringVal(path), (char *) _stringVal(openmode));
   367                 if (errno == EINTR)
   399 		if (errno == EINTR)
   368                     f = NULL;
   400 		    f = NULL;
   369 #else
   401 #else
   370 
   402 
   371                 f = (FILE *) fopen((char *) _stringVal(path), (char *) _stringVal(openmode));
   403 		f = (FILE *) fopen((char *) _stringVal(path), (char *) _stringVal(openmode));
   372 #endif
   404 #endif
   373             } while ((f == NULL) && (errno == EINTR));
   405 	    } while ((f == NULL) && (errno == EINTR));
   374             if (f == NULL) {
   406 	    if (f == NULL) {
   375                 ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
   407 		_INST(lastErrorNumber) = _MKSMALLINT(errno);
   376                 _INST(position) = nil;
   408 		_INST(position) = nil;
   377             } else {
   409 	    } else {
   378                 _INST(filePointer) = MKOBJ((int)f);
   410 		_INST(filePointer) = MKOBJ((int)f);
   379                 _INST(position) = _MKSMALLINT(1);
   411 		_INST(position) = _MKSMALLINT(1);
   380                 retVal = self;
   412 		retVal = self;
   381             }
   413 	    }
   382         }
   414 	}
   383     }
   415     }
   384 %}
   416 %}.
   385 .
       
   386     retVal notNil ifTrue:[
   417     retVal notNil ifTrue:[
   387         buffered := true.       "default is buffered"
   418 	buffered := true.       "default is buffered"
   388         Lobby register:self
   419 	Lobby register:self
   389     ].
   420     ].
       
   421     lastErrorNumber notNil ifTrue:[^ self openError].
   390     ^ retVal
   422     ^ retVal
   391 !
   423 !
   392 
   424 
   393 openForReading
   425 openForReading
   394     "open the file for readonly.
   426     "open the file for readonly.
   449 
   481 
   450 reOpen
   482 reOpen
   451     "sent after snapin to reopen streams"
   483     "sent after snapin to reopen streams"
   452 
   484 
   453     filePointer notNil ifTrue:[
   485     filePointer notNil ifTrue:[
   454         "it was open, when snapped-out"
   486 	"it was open, when snapped-out"
   455         filePointer := nil.
   487 	filePointer := nil.
   456         Lobby unregister:self.
   488 	Lobby unregister:self.
   457         self open.
   489 	self open.
   458         filePointer isNil ifTrue:[
   490 	filePointer isNil ifTrue:[
   459             "this happens, if after a restart, the file is no longer accessable ..."
   491 	    "this happens, if after a restart, the file is no longer accessable ..."
   460 
   492 
   461             ('could not reopen file: ', pathName) errorPrintNewline.
   493 	    ('could not reopen file: ', pathName) errorPrintNewline.
   462         ] ifFalse:[
   494 	] ifFalse:[
   463             self position:position.
   495 	    self position:position.
   464         ]
   496 	]
   465     ]
   497     ]
   466 ! !
   498 ! !
   467 
   499 
   468 !FileStream methodsFor:'queries'!
   500 !FileStream methodsFor:'queries'!
   469 
   501 
   475 #ifdef transputer
   507 #ifdef transputer
   476     FILE *f;
   508     FILE *f;
   477     int size;
   509     int size;
   478 
   510 
   479     if (_INST(filePointer) != nil) {
   511     if (_INST(filePointer) != nil) {
   480         f = (FILE *)MKFD(_INST(filePointer));
   512 	f = (FILE *)MKFD(_INST(filePointer));
   481         if ((size = filesize(fileno(f))) >= 0) {
   513 	if ((size = filesize(fileno(f))) >= 0) {
   482             RETURN ( _MKSMALLINT(size) );
   514 	    RETURN ( _MKSMALLINT(size) );
   483         }
   515 	}
   484     }
   516     }
   485 #else
   517 #else
   486     FILE *f;
   518     FILE *f;
   487     struct stat buf;
   519     struct stat buf;
   488     int ret;
   520     int ret;
   489     extern errno;
   521     extern errno;
   490     int fd;
   522     int fd;
   491 
   523 
   492     if (_INST(filePointer) != nil) {
   524     if (_INST(filePointer) != nil) {
   493         f = (FILE *)MKFD(_INST(filePointer));
   525 	f = (FILE *)MKFD(_INST(filePointer));
   494         fd = fileno(f);
   526 	fd = fileno(f);
   495         do {
   527 	do {
   496             ret = fstat(fd, &buf);
   528 	    ret = fstat(fd, &buf);
   497         } while ((ret < 0) && (errno == EINTR));
   529 	} while ((ret < 0) && (errno == EINTR));
   498         if (ret >= 0) {
   530 	if (ret >= 0) {
   499             RETURN ( _MKSMALLINT(buf.st_size) );
   531 	    RETURN ( _MKSMALLINT(buf.st_size) );
   500         }
   532 	}
   501         ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
   533 	_INST(lastErrorNumber) = _MKSMALLINT(errno);
   502     }
   534     }
   503 #endif
   535 #endif
   504 %}
   536 %}.
   505 .
   537 
   506     "could add a fall-back here:
   538     "could add a fall-back here:
   507 
   539 
   508         oldPosition := self position.
   540 	oldPosition := self position.
   509         self setToEnd.
   541 	self setToEnd.
   510         sz := self position.
   542 	sz := self position.
   511         self position:oldPosition.
   543 	self position:oldPosition.
   512         ^ sz
   544 	^ sz
   513     "
   545     "
       
   546     lastErrorNumber notNil ifTrue:[^ self ioError].
   514     filePointer isNil ifTrue:[^ self errorNotOpen].
   547     filePointer isNil ifTrue:[^ self errorNotOpen].
   515     ^ self primitiveFailed
   548     ^ self primitiveFailed
   516 !
   549 !
   517 
   550 
   518 position
   551 position
   524     FILE *f;
   557     FILE *f;
   525     long currentPosition;
   558     long currentPosition;
   526     extern errno;
   559     extern errno;
   527 
   560 
   528     if (_INST(filePointer) != nil) {
   561     if (_INST(filePointer) != nil) {
   529         f = (FILE *)MKFD(_INST(filePointer));
   562 	f = (FILE *)MKFD(_INST(filePointer));
   530         do {
   563 	do {
   531             if (_INST(buffered) == true) {
   564 	    if (_INST(buffered) == true) {
   532                 currentPosition = (long) ftell(f);
   565 		currentPosition = (long) ftell(f);
   533             } else {
   566 	    } else {
   534                 currentPosition = (long) lseek(fileno(f), 0L, SEEK_CUR);
   567 		currentPosition = (long) lseek(fileno(f), 0L, SEEK_CUR);
   535             }
   568 	    }
   536         } while ((currentPosition < 0) && (errno == EINTR));
   569 	} while ((currentPosition < 0) && (errno == EINTR));
   537         if (currentPosition >= 0) {
   570 	if (currentPosition >= 0) {
   538             /*
   571 	    /*
   539              * notice: Smalltalk index starts at 1
   572 	     * notice: Smalltalk index starts at 1
   540              */
   573 	     */
   541             RETURN ( _MKSMALLINT(currentPosition + 1) );
   574 	    RETURN ( _MKSMALLINT(currentPosition + 1) );
   542         }
   575 	}
   543         ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
   576 	_INST(lastErrorNumber) = _MKSMALLINT(errno);
   544     }
   577     }
   545 %}
   578 %}.
   546 .
   579     lastErrorNumber notNil ifTrue:[^ self ioError].
   547     filePointer isNil ifTrue:[^ self errorNotOpen].
   580     filePointer isNil ifTrue:[^ self errorNotOpen].
   548     ^ self primitiveFailed
   581     ^ self primitiveFailed
   549 !
   582 !
   550 
   583 
   551 position:newPos
   584 position:newPos
   556     FILE *f;
   589     FILE *f;
   557     int ret;
   590     int ret;
   558     extern errno;
   591     extern errno;
   559 
   592 
   560     if (_INST(filePointer) != nil) {
   593     if (_INST(filePointer) != nil) {
   561         if (_isSmallInteger(newPos)) {
   594 	if (_isSmallInteger(newPos)) {
   562             f = (FILE *)MKFD(_INST(filePointer));
   595 	    f = (FILE *)MKFD(_INST(filePointer));
   563             /*
   596 	    /*
   564              * notice: Smalltalk index starts at 1
   597 	     * notice: Smalltalk index starts at 1
   565              */
   598 	     */
   566             do {
   599 	    do {
   567                 if (_INST(buffered) == true) {
   600 		if (_INST(buffered) == true) {
   568                     ret = fseek(f, (long) (_intVal(newPos) - 1), SEEK_SET);
   601 		    ret = fseek(f, (long) (_intVal(newPos) - 1), SEEK_SET);
   569                 } else {
   602 		} else {
   570                     ret = (long) lseek(fileno(f), (long)(_intVal(newPos) - 1), SEEK_SET);
   603 		    ret = (long) lseek(fileno(f), (long)(_intVal(newPos) - 1), SEEK_SET);
   571                 }
   604 		}
   572             } while ((ret < 0) && (errno == EINTR));
   605 	    } while ((ret < 0) && (errno == EINTR));
   573             if (ret >= 0) {
   606 	    if (ret >= 0) {
   574                 _INST(position) = newPos;
   607 		_INST(position) = newPos;
   575                 /*
   608 		/*
   576                  * just to make certain ...
   609 		 * just to make certain ...
   577                  */
   610 		 */
   578                 _INST(hitEOF) = false;
   611 		_INST(hitEOF) = false;
   579                 RETURN ( self );
   612 		RETURN ( self );
   580             }
   613 	    }
   581             ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
   614 	    _INST(lastErrorNumber) = _MKSMALLINT(errno);
   582         }
   615 	}
   583     }
   616     }
   584 %}
   617 %}.
   585 .
   618     lastErrorNumber notNil ifTrue:[^ self ioError].
   586     filePointer isNil ifTrue:[^ self errorNotOpen].
   619     filePointer isNil ifTrue:[^ self errorNotOpen].
   587     ^ self primitiveFailed
   620     ^ self primitiveFailed
   588 !
   621 !
   589 
   622 
   590 setToEnd
   623 setToEnd
   594     FILE *f;
   627     FILE *f;
   595     int ret;
   628     int ret;
   596     extern errno;
   629     extern errno;
   597 
   630 
   598     if (_INST(filePointer) != nil) {
   631     if (_INST(filePointer) != nil) {
   599         f = (FILE *)MKFD(_INST(filePointer));
   632 	f = (FILE *)MKFD(_INST(filePointer));
   600         _INST(position) = nil;
   633 	_INST(position) = nil;
   601         do {
   634 	do {
   602             if (_INST(buffered) == true) {
   635 	    if (_INST(buffered) == true) {
   603                 ret = fseek(f, 0L, SEEK_END);
   636 		ret = fseek(f, 0L, SEEK_END);
   604             } else {
   637 	    } else {
   605                 ret = (long)lseek(fileno(f), 0L, SEEK_END);
   638 		ret = (long)lseek(fileno(f), 0L, SEEK_END);
   606             }
   639 	    }
   607         } while ((ret < 0) && (errno == EINTR));
   640 	} while ((ret < 0) && (errno == EINTR));
   608         if (ret >= 0) {
   641 	if (ret >= 0) {
   609             RETURN ( self );
   642 	    RETURN ( self );
   610         }
   643 	}
   611         ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
   644 	_INST(lastErrorNumber) = _MKSMALLINT(errno);
   612     }
   645     }
   613 %}
   646 %}.
   614 .
   647     lastErrorNumber notNil ifTrue:[^ self ioError].
   615     filePointer isNil ifTrue:[^ self errorNotOpen].
   648     filePointer isNil ifTrue:[^ self errorNotOpen].
   616     DemoMode ifTrue:[^ self warn:'no save in Demo mode'].
   649     DemoMode ifTrue:[^ self warn:'no save in Demo mode'].
   617     ^ self primitiveFailed
   650     ^ self primitiveFailed
   618 ! !
   651 ! !
   619 
   652 
   636 
   669 
   637 storeOn:aStream
   670 storeOn:aStream
   638     aStream nextPutAll:'(FileStream oldFileNamed:'.
   671     aStream nextPutAll:'(FileStream oldFileNamed:'.
   639     aStream nextPutAll:pathName.
   672     aStream nextPutAll:pathName.
   640     (self position ~~ 1) ifTrue:[
   673     (self position ~~ 1) ifTrue:[
   641         aStream nextPutAll:'; position:'.
   674 	aStream nextPutAll:'; position:'.
   642         self position storeOn:aStream
   675 	self position storeOn:aStream
   643     ].
   676     ].
   644     aStream nextPut:$)
   677     aStream nextPut:$)
   645 ! !
   678 ! !