ExtStream.st
changeset 159 514c749165c3
parent 108 634ca035d22c
child 188 454ed0ee733e
equal deleted inserted replaced
158:be947d4e7fb2 159:514c749165c3
     1 "
     1 "
     2  COPYRIGHT (c) 1988 by Claus Gittinger
     2  COPYRIGHT (c) 1988 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
     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 
    12 
    13 ReadWriteStream subclass:#ExternalStream
    13 ReadWriteStream subclass:#ExternalStream
    14        instanceVariableNames:'filePointer mode buffered binary useCRLF hitEOF didWrite'
    14        instanceVariableNames:'filePointer mode buffered binary useCRLF hitEOF didWrite lastErrorNumber'
    15        classVariableNames:'Lobby LastErrorNumber'
    15        classVariableNames:'Lobby LastErrorNumber
       
    16 			   StreamErrorSignal ReadErrorSignal WriteErrorSignal
       
    17 			   InvalidReadSignal InvalidWriteSignal InvalidModeSignal
       
    18 			   StreamNotOpenSignal'
    16        poolDictionaries:''
    19        poolDictionaries:''
    17        category:'Streams-External'
    20        category:'Streams-External'
    18 !
    21 !
    19 
    22 
    20 ExternalStream comment:'
    23 ExternalStream comment:'
    21 COPYRIGHT (c) 1988 by Claus Gittinger
    24 COPYRIGHT (c) 1988 by Claus Gittinger
    22               All Rights Reserved
    25 	      All Rights Reserved
    23 
    26 
    24 $Header: /cvs/stx/stx/libbasic/Attic/ExtStream.st,v 1.20 1994-08-11 21:36:34 claus Exp $
    27 $Header: /cvs/stx/stx/libbasic/Attic/ExtStream.st,v 1.21 1994-10-10 00:25:47 claus Exp $
    25 '!
    28 '!
    26 
    29 
    27 %{
    30 %{
    28 #include <stdio.h>
    31 #include <stdio.h>
    29 #include <fcntl.h>
    32 #include <fcntl.h>
    37 !ExternalStream class methodsFor:'documentation'!
    40 !ExternalStream class methodsFor:'documentation'!
    38 
    41 
    39 copyright
    42 copyright
    40 "
    43 "
    41  COPYRIGHT (c) 1988 by Claus Gittinger
    44  COPYRIGHT (c) 1988 by Claus Gittinger
    42               All Rights Reserved
    45 	      All Rights Reserved
    43 
    46 
    44  This software is furnished under a license and may be used
    47  This software is furnished under a license and may be used
    45  only in accordance with the terms of that license and with the
    48  only in accordance with the terms of that license and with the
    46  inclusion of the above copyright notice.   This software may not
    49  inclusion of the above copyright notice.   This software may not
    47  be provided or otherwise made available to, or used by, any
    50  be provided or otherwise made available to, or used by, any
    50 "
    53 "
    51 !
    54 !
    52 
    55 
    53 version
    56 version
    54 "
    57 "
    55 $Header: /cvs/stx/stx/libbasic/Attic/ExtStream.st,v 1.20 1994-08-11 21:36:34 claus Exp $
    58 $Header: /cvs/stx/stx/libbasic/Attic/ExtStream.st,v 1.21 1994-10-10 00:25:47 claus Exp $
    56 "
    59 "
    57 !
    60 !
    58 
    61 
    59 documentation
    62 documentation
    60 "
    63 "
    61     ExternalStream defines protocol common to Streams which have a file-descriptor and 
    64     ExternalStream defines protocol common to Streams which have a file-descriptor and 
    62     represent some file or communicationChannel of the underlying OperatingSystem.
    65     represent some file or communicationChannel of the underlying OperatingSystem.
    63     ExternalStream is abstract; concrete classes are FileStream, PipeStream etc.
    66     ExternalStream is abstract; concrete classes are FileStream, PipeStream etc.
    64 
    67 
    65     ExternalStreams can be in two modes: text (the default) and binary.
    68     ExternalStreams can be in two modes: text- (the default) and binary-mode.
    66     In text-mode, the elements read/written are characters; 
    69     In text-mode, the elements read/written are characters; 
    67     while in binary-mode the basic elements are bytes which read/write as SmallIntegers 
    70     while in binary-mode the basic elements are bytes which read/write as SmallIntegers 
    68     in the range 0..255.
    71     in the range 0..255.
    69 
    72 
    70     Also, the stream can be either in buffered or unbuffered mode. In buffered mode,
    73     Also, the stream can be either in buffered or unbuffered mode. In buffered mode,
    73 
    76 
    74     The underlying OperatingSystem streams may either be closed explicitely (sending a close)
    77     The underlying OperatingSystem streams may either be closed explicitely (sending a close)
    75     or just forgotten - in this case, the garbage collector will eventually collect the
    78     or just forgotten - in this case, the garbage collector will eventually collect the
    76     object AND a close will be performed automatically (but you will NOT know when this 
    79     object AND a close will be performed automatically (but you will NOT know when this 
    77     happens - so it is recommended, that you close your files when no longer needed).
    80     happens - so it is recommended, that you close your files when no longer needed).
    78     Closing is also suggested since if smalltalk is finished (be it by purpose, or due to
    81     Closing is also suggested, since if smalltalk is finished (be it by purpose, or due to
    79     some crash) the data will not be in the file, if unclosed. 
    82     some crash) the data will not be in the file, if unclosed. 
    80     All streams understand the close message, so it never hurts to use it (it is defined as 
    83     All streams understand the close message, so it never hurts to use it (it is defined as 
    81     a noop in one of the superclasses).
    84     a noop in one of the superclasses).
    82 
    85 
    83     Most of the methods found here redefine inherited methods for better performance,
    86     Most of the methods found here redefine inherited methods for better performance,
    89     For streams sitting on some communication channel (i.e. Pipes and Sockets) you should
    92     For streams sitting on some communication channel (i.e. Pipes and Sockets) you should
    90     reestablish the stream upon image restart (make someone dependent on ObjectMemory).
    93     reestablish the stream upon image restart (make someone dependent on ObjectMemory).
    91 
    94 
    92     Instance variables:
    95     Instance variables:
    93 
    96 
    94         filePointer     <Integer>       the unix FILE*; somehow mapped to an integer
    97 	filePointer     <Integer>       the unix FILE*; somehow mapped to an integer
    95                                         (notice: not the fd)
    98 					(notice: not the fd)
    96         mode            <Symbol>        #readwrite, #readonly or #writeonly
    99 	mode            <Symbol>        #readwrite, #readonly or #writeonly
    97         buffered        <Boolean>       true, if buffered (i.e. collects characters - does
   100 	buffered        <Boolean>       true, if buffered (i.e. collects characters - does
    98                                         not output immediately)
   101 					not output immediately)
    99         binary          <Boolean>       true if in binary mode (reads bytes instead of chars)
   102 	binary          <Boolean>       true if in binary mode (reads bytes instead of chars)
   100         useCRLF         <Boolean>       true, if lines should be terminated with crlf instead
   103 	useCRLF         <Boolean>       true, if lines should be terminated with crlf instead
   101                                         of lf. (i.e. if file is an MSDOS-type file)
   104 					of lf. (i.e. if file is an MSDOS-type file)
   102         hitEOF          <Boolean>       true, if EOF was reached
   105 	hitEOF          <Boolean>       true, if EOF was reached
   103 
   106 
       
   107 	lastErrorNumber <Integer>       the value of errno (only valid right after the error -
       
   108 					updated with next i/o operation)
   104 
   109 
   105     Class variables:
   110     Class variables:
   106         Lobby           <Registry>      keeps track of used ext-streams (to free up FILE*'s)
   111 	Lobby           <Registry>      keeps track of used ext-streams (to free up FILE*'s)
   107 
   112 
   108         LastErrorNumber <Integer>       the value of errno (only valid right after the error -
   113 	StreamErrorSignal       <Signal> parent of all stream errors
   109                                         updated with next i/o operation)
   114 	ReadErrorSignal         <Signal> raised on read errors
   110 
   115 	WriteErrorSignal        <Signal> raised on write errors
   111     Question: should lastErrorNumber be kept instance-specific ?
   116 	InvalidReadSignal       <Signal> raised on read from writeonly stream
       
   117 	InvalidWriteSignal      <Signal> raised on write to readonly stream 
       
   118 	InvalidModeSignal       <Signal> raised on text I/O with binary-stream
       
   119 					 or binary I/O with text-stream
       
   120 	StreamNotOpenSignal     <Signal> raised on I/O with non-open stream
       
   121 
       
   122     Additional notes:
       
   123       This class is implemented using the underlying stdio-c library package, which
       
   124       has both advantages and disadvantages: since it is portable (posix defined), porting
       
   125       ST/X to non-Unix machines is simplified. The disadvantage is that the stdio library
       
   126       has big problems handling unbounded Streams, since the EOF handling in stdio is
       
   127       not prepared for data to arrive after EOF has been reached - time will show, if we need
       
   128       a complete rewrite for UnboundedStream ...
   112 "
   129 "
   113 ! !
   130 ! !
   114 
   131 
   115 !ExternalStream class methodsFor:'initialization'!
   132 !ExternalStream class methodsFor:'initialization'!
   116 
   133 
   117 initialize
   134 initialize
       
   135     StreamErrorSignal isNil ifTrue:[
       
   136 	super initialize.
       
   137 
       
   138 	StreamErrorSignal := Object errorSignal newSignalMayProceed:false.
       
   139 	StreamErrorSignal nameClass:self message:#streamErrorSignal.
       
   140 	StreamErrorSignal notifierString:'I/O error'.
       
   141 
       
   142 	ReadErrorSignal := StreamErrorSignal newSignalMayProceed:false.
       
   143 	ReadErrorSignal nameClass:self message:#readErrorSignal.
       
   144 	ReadErrorSignal notifierString:'read error'.
       
   145 
       
   146 	WriteErrorSignal := StreamErrorSignal newSignalMayProceed:false.
       
   147 	WriteErrorSignal nameClass:self message:#writeErrorSignal.
       
   148 	WriteErrorSignal notifierString:'write error'.
       
   149 
       
   150 	InvalidReadSignal := ReadErrorSignal newSignalMayProceed:false.
       
   151 	InvalidReadSignal nameClass:self message:#invalidReadSignal.
       
   152 	InvalidReadSignal notifierString:'write error'.
       
   153 
       
   154 	InvalidWriteSignal := WriteErrorSignal newSignalMayProceed:false.
       
   155 	InvalidWriteSignal nameClass:self message:#invalidWriteSignal.
       
   156 	InvalidWriteSignal notifierString:'write error'.
       
   157 
       
   158 	InvalidModeSignal :=  StreamErrorSignal newSignalMayProceed:false.
       
   159 	InvalidModeSignal nameClass:self message:#invalidModeSignal.
       
   160 	InvalidModeSignal notifierString:'binary/text mode mismatch'.
       
   161 
       
   162 	StreamNotOpenSignal := StreamErrorSignal newSignalMayProceed:false.
       
   163 	StreamNotOpenSignal nameClass:self message:#streamNotOpenSignal.
       
   164 	StreamNotOpenSignal notifierString:'stream is not open'.
       
   165     ].
       
   166 
   118     Lobby isNil ifTrue:[
   167     Lobby isNil ifTrue:[
   119         Lobby := Registry new.
   168 	Lobby := Registry new.
   120 
   169 
   121         "want to get informed when returning from snapshot"
   170 	"want to get informed when returning from snapshot"
   122         ObjectMemory addDependent:self
   171 	ObjectMemory addDependent:self
   123     ]
   172     ]
   124 !
   173 !
   125 
   174 
   126 reOpenFiles
   175 reOpenFiles
   127     "reopen all files (if possible) after a snapShot load"
   176     "reopen all files (if possible) after a snapShot load"
   128 
   177 
   129     Lobby contentsDo:[:aFileStream |
   178     Lobby contentsDo:[:aFileStream |
   130         aFileStream reOpen
   179 	aFileStream reOpen
   131     ]
   180     ]
   132 !
   181 !
   133 
   182 
   134 update:something
   183 update:something
   135     "have to reopen files when returning from snapshot"
   184     "have to reopen files when returning from snapshot"
   136 
   185 
   137     something == #returnFromSnapshot ifTrue:[
   186     something == #returnFromSnapshot ifTrue:[
   138         self reOpenFiles
   187 	self reOpenFiles
   139     ]
   188     ]
       
   189 ! !
       
   190 
       
   191 !ExternalStream class methodsFor:'signal access '!
       
   192 
       
   193 streamErrorSignal
       
   194     "return the parent of all stream errors;
       
   195      handling this one also handles all other errors.
       
   196      Also, this one is raised for errors not related to read/write
       
   197      operations, such as failed ioctls"
       
   198 
       
   199     ^ StreamErrorSignal
       
   200 !
       
   201 
       
   202 readErrorSignal
       
   203     "return the signal raised on read errors"
       
   204 
       
   205     ^ ReadErrorSignal
       
   206 !
       
   207 
       
   208 writeErrorSignal
       
   209     "return the signal raised on write errors"
       
   210 
       
   211     ^ WriteErrorSignal
       
   212 !
       
   213 
       
   214 invalidReadSignal
       
   215     "return the signal raised when reading from writeonly streams"
       
   216 
       
   217     ^ InvalidReadSignal
       
   218 !
       
   219 
       
   220 invalidWriteSignal
       
   221     "return the signal raised when writing to readonly streams"
       
   222 
       
   223     ^ InvalidWriteSignal
       
   224 !
       
   225 
       
   226 invalidModeSignal
       
   227     "return the signal raised when doing text-I/O with a binary stream
       
   228      or binary-I/O with a text stream"
       
   229 
       
   230     ^ InvalidModeSignal
       
   231 !
       
   232 
       
   233 streamNotOpenSignal
       
   234     "return the signal raised on I/O with closed streams"
       
   235 
       
   236     ^ StreamNotOpenSignal
   140 ! !
   237 ! !
   141 
   238 
   142 !ExternalStream class methodsFor:'instance creation'!
   239 !ExternalStream class methodsFor:'instance creation'!
   143 
   240 
   144 new
   241 new
   150 ! !
   247 ! !
   151 
   248 
   152 !ExternalStream class methodsFor:'error handling'!
   249 !ExternalStream class methodsFor:'error handling'!
   153 
   250 
   154 lastErrorNumber
   251 lastErrorNumber
   155     "return the last error"
   252     "return the errno of the last error"
   156 
   253 
   157     ^ LastErrorNumber
   254     ^ LastErrorNumber
       
   255 
       
   256     "
       
   257      ExternalStream lastErrorNumber
       
   258     "
   158 !
   259 !
   159 
   260 
   160 lastErrorString
   261 lastErrorString
   161     "return a message string describing the last error"
   262     "return a message string describing the last error"
   162 
   263 
   167     "
   268     "
   168 ! !
   269 ! !
   169 
   270 
   170 !ExternalStream methodsFor:'instance release'!
   271 !ExternalStream methodsFor:'instance release'!
   171 
   272 
       
   273 shallowCopyForFinalization
       
   274     "return a copy for finalization-registration;
       
   275      since all we need at finalization time is the fileDescriptor,
       
   276      a cheaper copy is possible."
       
   277 
       
   278     ^ self class basicNew setFilePointer:filePointer
       
   279 !
       
   280 
       
   281 setFilePointer:anInteger
       
   282     filePointer := anInteger
       
   283 !
       
   284 
   172 disposed
   285 disposed
   173     "some Stream has been collected - close the file if not already done"
   286     "some Stream has been collected - close the file if not already done"
   174 
   287 
   175     self closeFile
   288     self closeFile
   176 !
   289 !
   179     "low level close - may be redefined in subclasses"
   292     "low level close - may be redefined in subclasses"
   180 
   293 
   181 %{  /* NOCONTEXT */
   294 %{  /* NOCONTEXT */
   182 
   295 
   183     if (_INST(filePointer) != nil) {
   296     if (_INST(filePointer) != nil) {
   184         extern int _immediateInterrupt;
   297 	extern int _immediateInterrupt;
   185 
   298 
   186         _immediateInterrupt = 1;
   299 	_immediateInterrupt = 1;
   187         fclose(MKFD(_INST(filePointer)));
   300 	fclose(MKFD(_INST(filePointer)));
   188         _immediateInterrupt = 0;
   301 	_immediateInterrupt = 0;
   189     }
   302     }
   190 %}
   303 %}
   191 ! !
   304 ! !
   192 
   305 
   193 !ExternalStream methodsFor:'private'!
   306 !ExternalStream methodsFor:'private'!
   201      cannot reopen here since I am abstract and have no device knowledge"
   314      cannot reopen here since I am abstract and have no device knowledge"
   202 
   315 
   203     self class name errorPrint. ': cannot reOpen stream - stream closed' errorPrintNewline.
   316     self class name errorPrint. ': cannot reOpen stream - stream closed' errorPrintNewline.
   204     filePointer := nil.
   317     filePointer := nil.
   205     Lobby unregister:self.
   318     Lobby unregister:self.
       
   319 !
       
   320 
       
   321 setLastError:aNumber
       
   322     lastErrorNumber := aNumber
   206 ! !
   323 ! !
   207 
   324 
   208 !ExternalStream methodsFor:'error handling'!
   325 !ExternalStream methodsFor:'error handling'!
   209 
   326 
   210 lastErrorNumber
   327 lastErrorNumber
   211     "return the last error"
   328     "return the last error"
   212 
   329 
   213     ^ LastErrorNumber
   330     ^ lastErrorNumber
   214 !
   331 !
   215 
   332 
   216 lastErrorString
   333 lastErrorString
   217     "return a message string describing the last error"
   334     "return a message string describing the last error"
   218 
   335 
   219     ^ self class lastErrorString
   336     (lastErrorNumber isNil or:[lastErrorNumber == 0]) ifTrue:[
       
   337 	^ 'I/O error'
       
   338     ].
       
   339     ^ OperatingSystem errorTextForNumber:lastErrorNumber
   220 !
   340 !
   221 
   341 
   222 errorNotOpen
   342 errorNotOpen
   223     "report an error, that the stream has not been opened"
   343     "report an error, that the stream has not been opened"
   224 
   344 
   225     ^ self error:(self class name , ' not open')
   345     ^ StreamNotOpenSignal
       
   346 	raiseRequestWith:self
       
   347 	errorString:(self class name , ' not open')
   226 !
   348 !
   227 
   349 
   228 errorReadOnly
   350 errorReadOnly
   229     "report an error, that the stream is a readOnly stream"
   351     "report an error, that the stream is a readOnly stream"
   230 
   352 
   231     ^ self error:(self class name , ' is readonly')
   353     ^ InvalidWriteSignal
       
   354 	raiseRequestWith:self
       
   355 	errorString:(self class name , ' is readonly')
   232 !
   356 !
   233 
   357 
   234 errorWriteOnly
   358 errorWriteOnly
   235     "report an error, that the stream is a writeOnly stream"
   359     "report an error, that the stream is a writeOnly stream"
   236 
   360 
   237     ^ self error:(self class name , ' is writeonly')
   361     ^ InvalidReadSignal
       
   362 	raiseRequestWith:self
       
   363 	errorString:(self class name , ' is writeonly')
   238 !
   364 !
   239 
   365 
   240 errorNotBinary
   366 errorNotBinary
   241     "report an error, that the stream is not in binary mode"
   367     "report an error, that the stream is not in binary mode"
   242 
   368 
   243     ^ self error:(self class name , ' is not in binary mode')
   369     ^ InvalidModeSignal
       
   370 	raiseRequestWith:self
       
   371 	errorString:(self class name , ' is not in binary mode')
   244 !
   372 !
   245 
   373 
   246 errorBinary
   374 errorBinary
   247     "report an error, that the stream is in binary mode"
   375     "report an error, that the stream is in binary mode"
   248 
   376 
   249     ^ self error:(self class name , ' is in binary mode')
   377     ^ InvalidModeSignal
       
   378 	raiseRequestWith:self
       
   379 	errorString:(self class name , ' is in binary mode')
   250 !
   380 !
   251 
   381 
   252 errorNotBuffered
   382 errorNotBuffered
   253     "report an error, that the stream is not in buffered mode"
   383     "report an error, that the stream is not in buffered mode"
   254 
   384 
   255     ^ self error:(self class name , ' is unbuffered - operation not allowed')
   385     ^ StreamErrorSignal
       
   386 	raiseRequestWith:self
       
   387 	errorString:(self class name , ' is unbuffered - operation not allowed')
       
   388 !
       
   389 
       
   390 ioError
       
   391     "report an error, that some I/O error occured"
       
   392 
       
   393     ^ StreamErrorSignal
       
   394 	raiseRequestWith:self
       
   395 	errorString:('I/O error: ' , self lastErrorString)
       
   396 !
       
   397 
       
   398 readError
       
   399     "report an error, that some read error occured"
       
   400 
       
   401     ^ ReadErrorSignal
       
   402 	raiseRequestWith:self
       
   403 	errorString:('read error: ' , self lastErrorString)
       
   404 !
       
   405 
       
   406 writeError
       
   407     "report an error, that some write error occured"
       
   408 
       
   409     ^ WriteErrorSignal
       
   410 	raiseRequestWith:self
       
   411 	errorString:('write error: ' , self lastErrorString)
   256 !
   412 !
   257 
   413 
   258 argumentMustBeInteger
   414 argumentMustBeInteger
   259     "report an error, that the argument must be an integer"
   415     "report an error, that the argument must be an integer"
   260 
   416 
   310 %{  /* NOCONTEXT */
   466 %{  /* NOCONTEXT */
   311 
   467 
   312     FILE *f;
   468     FILE *f;
   313 
   469 
   314     if (_INST(filePointer) != nil) {
   470     if (_INST(filePointer) != nil) {
   315         f = MKFD(_INST(filePointer));
   471 	f = MKFD(_INST(filePointer));
   316         RETURN ( MKOBJ(fileno(f)) );
   472 	RETURN ( MKOBJ(fileno(f)) );
   317     }
   473     }
   318 %}
   474 %}
   319 .
   475 .
   320     ^ self errorNotOpen
   476     ^ self errorNotOpen
   321 !
   477 !
   347 contentsSpecies
   503 contentsSpecies
   348     "return the kind of object to be returned by sub-collection builders
   504     "return the kind of object to be returned by sub-collection builders
   349      (such as upTo)"
   505      (such as upTo)"
   350 
   506 
   351     binary ifTrue:[
   507     binary ifTrue:[
   352         ^ ByteArray
   508 	^ ByteArray
   353     ].
   509     ].
   354     ^ String
   510     ^ String
   355 !
   511 !
   356 
   512 
   357 contents
   513 contents
   362      is returned."
   518      is returned."
   363 
   519 
   364     |text l chunks sizes chunk byteCount cnt bytes offset|
   520     |text l chunks sizes chunk byteCount cnt bytes offset|
   365 
   521 
   366     binary ifTrue:[
   522     binary ifTrue:[
   367         "adding to a ByteArray produces quadratic time-space
   523 	"adding to a ByteArray produces quadratic time-space
   368          behavior - therefore we allocate chunks, and concatenate them
   524 	 behavior - therefore we allocate chunks, and concatenate them
   369          at the end."
   525 	 at the end."
   370 
   526 
   371         chunks := OrderedCollection new.
   527 	chunks := OrderedCollection new.
   372         sizes := OrderedCollection new.
   528 	sizes := OrderedCollection new.
   373         byteCount := 0.
   529 	byteCount := 0.
   374         [self atEnd] whileFalse:[
   530 	[self atEnd] whileFalse:[
   375             chunk := ByteArray uninitializedNew:4096.
   531 	    chunk := ByteArray uninitializedNew:4096.
   376             cnt := self nextBytes:(chunk size) into:chunk.
   532 	    cnt := self nextBytes:(chunk size) into:chunk.
   377             cnt notNil ifTrue:[
   533 	    cnt notNil ifTrue:[
   378                 chunks add:chunk.
   534 		chunks add:chunk.
   379                 sizes add:cnt.
   535 		sizes add:cnt.
   380                 byteCount := byteCount + cnt
   536 		byteCount := byteCount + cnt
   381             ]
   537 	    ]
   382         ].
   538 	].
   383 
   539 
   384         "now, create one big ByteArray"
   540 	"now, create one big ByteArray"
   385         bytes := ByteArray uninitializedNew:byteCount.
   541 	bytes := ByteArray uninitializedNew:byteCount.
   386         offset := 1.
   542 	offset := 1.
   387         1 to:chunks size do:[:index |
   543 	1 to:chunks size do:[:index |
   388             chunk := chunks at:index.
   544 	    chunk := chunks at:index.
   389             cnt := sizes at:index. 
   545 	    cnt := sizes at:index. 
   390             bytes replaceFrom:offset to:(offset + cnt - 1) with:chunk.
   546 	    bytes replaceFrom:offset to:(offset + cnt - 1) with:chunk.
   391             offset := offset + cnt
   547 	    offset := offset + cnt
   392         ].
   548 	].
   393         ^ bytes
   549 	^ bytes
   394     ].
   550     ].
   395 
   551 
   396     text := Text new.
   552     text := Text new.
   397     [self atEnd] whileFalse:[
   553     [self atEnd] whileFalse:[
   398         l := self nextLine.
   554 	l := self nextLine.
   399         l notNil ifTrue:[
   555 	l notNil ifTrue:[
   400             text add:l
   556 	    text add:l
   401         ]
   557 	]
   402     ].
   558     ].
   403     ^ text
   559     ^ text
   404 ! !
   560 ! !
   405 
   561 
   406 !ExternalStream methodsFor:'misc functions'!
   562 !ExternalStream methodsFor:'misc functions'!
   445 backStep
   601 backStep
   446     "step back one element -
   602     "step back one element -
   447      redefined, since position is redefined here"
   603      redefined, since position is redefined here"
   448 
   604 
   449     self position:(self position - 1)
   605     self position:(self position - 1)
       
   606 !
       
   607 
       
   608 reset
       
   609     "set the read position to the beginning of the collection"
       
   610 
       
   611     self position:"0" 1
       
   612 !
       
   613 
       
   614 setToEnd
       
   615     "redefined since it must be implemented differently"
       
   616 
       
   617     ^ self subclassResponsibility
   450 !
   618 !
   451 
   619 
   452 blocking:aBoolean
   620 blocking:aBoolean
   453     "set/clear the blocking attribute - if set (which is the default)
   621     "set/clear the blocking attribute - if set (which is the default)
   454      a read (using next) on the receiver will block until data is available.
   622      a read (using next) on the receiver will block until data is available.
   462 async:aBoolean
   630 async:aBoolean
   463     "set/clear the async attribute - if set the availability of data on 
   631     "set/clear the async attribute - if set the availability of data on 
   464      the receiver will trigger an ioInterrupt.
   632      the receiver will trigger an ioInterrupt.
   465      If cleared (which is the default) no special notification is made."
   633      If cleared (which is the default) no special notification is made."
   466 
   634 
   467     filePointer isNil ifTrue:[^ self errorNotOpen].
   635     |fd|
       
   636 
       
   637     filePointer isNil ifTrue:[^ self errorNotOpen].
       
   638     fd := self fileDescriptor.
   468     aBoolean ifTrue:[
   639     aBoolean ifTrue:[
   469         ^ OperatingSystem enableIOInterruptsOn:(self fileDescriptor)
   640 	^ OperatingSystem enableIOInterruptsOn:fd
   470     ].
   641     ].
   471     ^ OperatingSystem disableIOInterruptsOn:(self fileDescriptor)
   642     ^ OperatingSystem disableIOInterruptsOn:fd
   472 !
   643 !
   473 
   644 
   474 ioctl:ioctlNumber
   645 ioctl:ioctlNumber
   475     "to provide a simple ioctl facility - an ioctl is performed
   646     "to provide a simple ioctl facility - an ioctl is performed
   476      on the underlying file; no arguments are passed."
   647      on the underlying file; no arguments are passed."
   480     FILE *f;
   651     FILE *f;
   481     int ret, ioNum, ioArg;
   652     int ret, ioNum, ioArg;
   482     extern int _immediateInterrupt;
   653     extern int _immediateInterrupt;
   483     extern errno;
   654     extern errno;
   484 
   655 
       
   656     _INST(lastErrorNumber) = nil;
   485     if (_INST(filePointer) != nil) {
   657     if (_INST(filePointer) != nil) {
   486         if (_isSmallInteger(ioctlNumber)) {
   658 	if (_isSmallInteger(ioctlNumber)) {
   487             ioNum = _intVal(ioctlNumber);
   659 	    ioNum = _intVal(ioctlNumber);
   488             f = MKFD(_INST(filePointer));
   660 	    f = MKFD(_INST(filePointer));
   489 
   661 
   490             _immediateInterrupt = 1;
   662 	    _immediateInterrupt = 1;
   491             do {
   663 	    do {
   492                 ret = ioctl(fileno(f), ioNum);
   664 		ret = ioctl(fileno(f), ioNum);
   493             } while ((ret < 0) && (errno == EINTR));
   665 	    } while ((ret < 0) && (errno == EINTR));
   494             _immediateInterrupt = 0;
   666 	    _immediateInterrupt = 0;
   495 
   667 
   496             if (ret >= 0) {
   668 	    if (ret >= 0) {
   497                 RETURN ( _MKSMALLINT(ret) );
   669 		RETURN ( _MKSMALLINT(ret) );
   498             }
   670 	    }
   499             ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
   671 	    _INST(position) = nil;
   500             RETURN ( nil );
   672 	    _INST(lastErrorNumber) = _MKSMALLINT(errno);
   501         }
   673 	}
   502     }
   674     }
   503 %}
   675 %}.
   504 .
   676     lastErrorNumber notNil ifTrue:[^ self ioError].
   505     filePointer isNil ifTrue:[^ self errorNotOpen].
   677     filePointer isNil ifTrue:[^ self errorNotOpen].
   506     self primitiveFailed
   678     "
       
   679      ioctl-number is not an integer
       
   680     "
       
   681     ^ self primitiveFailed
   507 !
   682 !
   508 
   683 
   509 ioctl:ioctlNumber with:arg
   684 ioctl:ioctlNumber with:arg
   510     "to provide a simple ioctl facility - an ioctl is performed
   685     "to provide a simple ioctl facility - an ioctl is performed
   511      on the underlying file; the argument is passed as argument.
   686      on the underlying file; the argument is passed as argument.
   512      If the argument is a number, its directly passed; if its a
   687      If the argument is a number, its directly passed; if its a
   513      kind of ByteArray (ByteArray, String or Structure) a pointer to
   688      kind of ByteArray (ByteArray, String or Structure) a pointer to
   514      the data is passed. This allows performing most ioctls - however,
   689      the data is passed. This allows performing most ioctls - however,
   515      it might be tricky to setup the buffer."
   690      it might be tricky to setup the buffer."
   516 
   691 
   517     |isStructure|
   692 %{  /* NOCONTEXT */
   518 
       
   519     isStructure := arg isKindOf:ByteArray.
       
   520 %{
       
   521     FILE *f;
   693     FILE *f;
   522     int ret, ioNum;
   694     int ret, ioNum;
   523     extern int _immediateInterrupt;
   695     extern int _immediateInterrupt;
   524     extern errno;
   696     extern errno;
   525 
   697 
       
   698     _INST(lastErrorNumber) = nil;
   526     if (_INST(filePointer) != nil) {
   699     if (_INST(filePointer) != nil) {
   527         if (_isSmallInteger(ioctlNumber) 
   700 	if (_isSmallInteger(ioctlNumber) 
   528          && (_isSmallInteger(arg) || (isStructure == true))) {
   701 	 && (_isSmallInteger(arg) || __isBytes(arg))) {
   529             f = MKFD(_INST(filePointer));
   702 	    f = MKFD(_INST(filePointer));
   530             ioNum = _intVal(ioctlNumber);
   703 	    ioNum = _intVal(ioctlNumber);
   531 
   704 
   532             _immediateInterrupt = 1;
   705 	    _immediateInterrupt = 1;
   533             do {
   706 	    do {
   534                 if (isStructure == true) {
   707 		if (_isSmallInteger(arg)) {
   535                     ret = ioctl(fileno(f), ioNum, _ByteArrayInstPtr(arg)->ba_element);
   708 		    ret = ioctl(fileno(f), ioNum, _intVal(arg));
   536                 } else {
   709 		} else {
   537                     ret = ioctl(fileno(f), ioNum, _intVal(arg));
   710 		    ret = ioctl(fileno(f), ioNum, _ByteArrayInstPtr(arg)->ba_element);
   538                 }
   711 		}
   539             } while ((ret < 0) && (errno == EINTR));
   712 	    } while ((ret < 0) && (errno == EINTR));
   540             _immediateInterrupt = 0;
   713 	    _immediateInterrupt = 0;
   541 
   714 
   542             if (ret >= 0) {
   715 	    if (ret >= 0) {
   543                 RETURN ( _MKSMALLINT(ret) );
   716 		RETURN ( _MKSMALLINT(ret) );
   544             }
   717 	    }
   545             ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
   718 	    _INST(position) = nil;
   546             RETURN ( nil );
   719 	    _INST(lastErrorNumber) = _MKSMALLINT(errno);
   547         }
   720 	}
   548     }
   721     }
   549 %}
   722 %}.
   550 .
   723     lastErrorNumber notNil ifTrue:[^ self ioError].
   551     filePointer isNil ifTrue:[^ self errorNotOpen].
   724     filePointer isNil ifTrue:[^ self errorNotOpen].
   552     self primitiveFailed
   725     "
       
   726      ioctl-number is not an integer or argument is not byteArray-like
       
   727     "
       
   728     ^ self primitiveFailed
   553 ! !
   729 ! !
   554 
   730 
   555 !ExternalStream methodsFor:'non homogenous reading'!
   731 !ExternalStream methodsFor:'non homogenous reading'!
   556 
   732 
   557 nextByte
   733 nextByte
   565     unsigned char byte;
   741     unsigned char byte;
   566     int cnt;
   742     int cnt;
   567     extern errno;
   743     extern errno;
   568     extern int _immediateInterrupt;
   744     extern int _immediateInterrupt;
   569 
   745 
   570     if ((_INST(filePointer) != nil) && (_INST(mode) != _writeonly)) {
   746     _INST(lastErrorNumber) = nil;
   571         f = MKFD(_INST(filePointer));
   747     if ((_INST(filePointer) != nil)
   572 
   748      && (_INST(mode) != @symbol(writeonly))) {
   573         _immediateInterrupt = 1;
   749 	f = MKFD(_INST(filePointer));
   574         do {
   750 
   575             if (_INST(buffered) == false) {
   751 	_immediateInterrupt = 1;
   576                 cnt = read(fileno(f), &byte, 1);
   752 	do {
   577             } else {
   753 	    if (_INST(buffered) == false) {
   578                 if ((_INST(didWrite) != false) && (_INST(mode) == _readwrite)) {
   754 		cnt = read(fileno(f), &byte, 1);
   579                     _INST(didWrite) = false;
   755 	    } else {
   580                     fseek(f, 0L, 1); /* needed in stdio */
   756 		if ((_INST(didWrite) != false)
   581                 }
   757 		 && (_INST(mode) == @symbol(readwrite))) {
   582                 cnt = fread(&byte, 1, 1, f);
   758 		    _INST(didWrite) = false;
   583             }
   759 		    fseek(f, 0L, 1); /* needed in stdio */
   584         } while ((cnt < 0) && (errno == EINTR));
   760 		}
   585         _immediateInterrupt = 0;
   761 		cnt = fread(&byte, 1, 1, f);
   586 
   762 	    }
   587         if (cnt == 1) {
   763 	} while ((cnt < 0) && (errno == EINTR));
   588             if (_INST(position) != nil)
   764 	_immediateInterrupt = 0;
   589                 _INST(position) = _MKSMALLINT(_intVal(_INST(position)) + 1);
   765 
   590             RETURN ( _MKSMALLINT(byte) );
   766 	if (cnt == 1) {
   591         }
   767 	    if (_INST(position) != nil)
   592         if (cnt < 0) {
   768 		_INST(position) = _MKSMALLINT(_intVal(_INST(position)) + 1);
   593             ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
   769 	    RETURN ( _MKSMALLINT(byte) );
   594         }
   770 	}
   595         _INST(hitEOF) = true;
   771 	if (cnt == 0) {
   596         RETURN ( nil );
   772 	    _INST(hitEOF) = true;
   597     }
   773 	    RETURN (nil);
   598 %}
   774 	}
   599 .
   775 	_INST(position) = nil;
   600     filePointer isNil ifTrue:[^ self errorNotOpen].
   776 	_INST(lastErrorNumber) = _MKSMALLINT(errno);
   601     self errorWriteOnly
   777     }
       
   778 %}.
       
   779     lastErrorNumber notNil ifTrue:[^ self readError].
       
   780     filePointer isNil ifTrue:[^ self errorNotOpen].
       
   781     ^ self errorWriteOnly
   602 !
   782 !
   603 
   783 
   604 nextBytesInto:anObject
   784 nextBytesInto:anObject
   605     "read bytes into an object, regardless of binary/text mode.
   785     "read bytes into an object, regardless of binary/text mode.
   606      The number of bytes to read is defined by the objects size.
   786      The number of bytes to read is defined by the objects size.
   640     ^ self nextBytes:count into:anObject startingAt:1
   820     ^ self nextBytes:count into:anObject startingAt:1
   641 !
   821 !
   642 
   822 
   643 nextBytes:count into:anObject startingAt:start
   823 nextBytes:count into:anObject startingAt:start
   644     "read the next count bytes into an object and return the number of
   824     "read the next count bytes into an object and return the number of
   645      bytes read or nil on error. On EOF, 0 is returned.
   825      bytes read or 0 on EOF. Notice, that in contrast to other methods
   646      The object must have non-pointer indexed instvars (i.e. it must be 
   826      here, this does NOT return nil on EOF, but the actual count.
   647      a ByteArray, String, Float- or DoubleArray).
   827      Thus allowing read of partial blocks.
   648      Use with care - non object oriented i/o."
   828 
       
   829      The object must have non-pointer indexed instvars 
       
   830      (i.e. it must be a ByteArray, String, Float- or DoubleArray).
       
   831      Use with care - non object oriented I/O."
   649 
   832 
   650 %{  /* NOCONTEXT */
   833 %{  /* NOCONTEXT */
   651 
   834 
   652     FILE *f;
   835     FILE *f;
   653     int cnt, offs;
   836     int cnt, offs;
   656     extern errno;
   839     extern errno;
   657     OBJ pos;
   840     OBJ pos;
   658     extern int _immediateInterrupt;
   841     extern int _immediateInterrupt;
   659     OBJ oClass;
   842     OBJ oClass;
   660 
   843 
   661     if ((_INST(filePointer) != nil) && (_INST(mode) != _writeonly)) {
   844     _INST(lastErrorNumber) = nil;
   662         if (_isSmallInteger(count) && _isSmallInteger(start)) {
   845     if ((_INST(filePointer) != nil)
   663             oClass = _Class(anObject);
   846      && (_INST(mode) != @symbol(writeonly))) {
   664             switch (_intVal(_ClassInstPtr(oClass)->c_flags) & ARRAYMASK) {
   847 	if (_isSmallInteger(count) && _isSmallInteger(start)) {
   665                 case BYTEARRAY:
   848 	    oClass = _Class(anObject);
   666                 case WORDARRAY:
   849 	    switch (_intVal(_ClassInstPtr(oClass)->c_flags) & ARRAYMASK) {
   667                 case LONGARRAY:
   850 		case BYTEARRAY:
   668                 case FLOATARRAY:
   851 		case WORDARRAY:
   669                 case DOUBLEARRAY:
   852 		case LONGARRAY:
   670                     break;
   853 		case FLOATARRAY:
   671                 default:
   854 		case DOUBLEARRAY:
   672                     goto bad;
   855 		    break;
   673             }
   856 		default:
   674             cnt = _intVal(count);
   857 		    goto bad;
   675             offs = _intVal(start) - 1;
   858 	    }
   676             f = MKFD(_INST(filePointer));
   859 	    cnt = _intVal(count);
   677             nInstVars = _intVal(_ClassInstPtr(oClass)->c_ninstvars);
   860 	    offs = _intVal(start) - 1;
   678             nInstBytes = OHDR_SIZE + __OBJS2BYTES__(nInstVars);
   861 	    f = MKFD(_INST(filePointer));
   679             objSize = _Size(anObject) - nInstBytes;
   862 	    nInstVars = _intVal(_ClassInstPtr(oClass)->c_ninstvars);
   680             if ((offs >= 0) && (cnt >= 0) && (objSize >= (cnt + offs))) {
   863 	    nInstBytes = OHDR_SIZE + __OBJS2BYTES__(nInstVars);
   681                 cp = (char *)_InstPtr(anObject) + nInstBytes + offs;
   864 	    objSize = _Size(anObject) - nInstBytes;
   682 
   865 	    if ((offs >= 0) && (cnt >= 0) && (objSize >= (cnt + offs))) {
   683                 _immediateInterrupt = 1;
   866 		cp = (char *)_InstPtr(anObject) + nInstBytes + offs;
   684                 do {
   867 
   685                     if (_INST(buffered) == false) {
   868 		_immediateInterrupt = 1;
   686                         cnt = read(fileno(f), cp, cnt);
   869 		do {
   687                     } else {
   870 		    if (_INST(buffered) == false) {
   688                         if ((_INST(didWrite) != false) && (_INST(mode) == _readwrite)) {
   871 			cnt = read(fileno(f), cp, cnt);
   689                             _INST(didWrite) = false;
   872 		    } else {
   690                             fseek(f, 0L, 1); /* needed in stdio */
   873 			if ((_INST(didWrite) != false)
   691                         }
   874 			 && (_INST(mode) == @symbol(readwrite))) {
   692                         cnt = fread(cp, 1, cnt, f);
   875 			    _INST(didWrite) = false;
   693                     }
   876 			    fseek(f, 0L, 1); /* needed in stdio */
   694                 } while ((cnt < 0) && (errno == EINTR));
   877 			}
   695                 _immediateInterrupt = 0;
   878 			cnt = fread(cp, 1, cnt, f);
   696 
   879 		    }
   697                 if (cnt >= 0) {
   880 		} while ((cnt < 0) && (errno == EINTR));
   698                     if (cnt == 0)
   881 		_immediateInterrupt = 0;
   699                         _INST(hitEOF) = true;
   882 
   700                     else {
   883 		if (cnt >= 0) {
   701                         pos = _INST(position);
   884 		    if (cnt == 0)
   702                         if (pos != nil)
   885 			_INST(hitEOF) = true;
   703                             _INST(position) = _MKSMALLINT(_intVal(pos) + cnt);
   886 		    else {
   704                     }
   887 			pos = _INST(position);
   705                     RETURN ( _MKSMALLINT(cnt) );
   888 			if (pos != nil)
   706                 }
   889 			    _INST(position) = _MKSMALLINT(_intVal(pos) + cnt);
   707                 ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
   890 		    }
   708                 RETURN ( nil );
   891 		    RETURN (_MKSMALLINT(cnt));
   709             }
   892 		}
   710         }
   893 		_INST(position) = nil;
       
   894 		_INST(lastErrorNumber) = _MKSMALLINT(errno);
       
   895 	    }
       
   896 	}
   711     }
   897     }
   712 bad: ;
   898 bad: ;
   713 %}
   899 %}.
   714 .
   900     lastErrorNumber notNil ifTrue:[^ self readError].
   715     filePointer isNil ifTrue:[^ self errorNotOpen].
   901     filePointer isNil ifTrue:[^ self errorNotOpen].
   716     (mode == #writeonly) ifTrue:[^ self errorWriteOnly].
   902     (mode == #writeonly) ifTrue:[^ self errorWriteOnly].
   717     self primitiveFailed
   903     "
   718 !
   904      count not integer or arg not bit-like (String, ByteArray etc)
   719 
   905     "
   720 nextWord
   906     ^ self primitiveFailed
   721     "in text-mode:
   907 !
   722          read the next word (i.e. up to non letter-or-digit).
   908 
   723          return a string containing those characters.
   909 nextShortMSB:msbFlag
   724      in binary-mode:
   910     "Read two bytes and return the value as a 16-bit signed Integer.
   725          read two bytes (msb-first) and return the value as a 16-bit unsigned Integer
   911      If msbFlag is true, value is read with most-significant byte first, 
   726          (for compatibility with other smalltalks)"
   912      otherwise least-significant byte comes first.
       
   913      A nil is returned if EOF is reached (also when EOF is hit after the first byte).
       
   914      Works in both binary and text modes."
   727 
   915 
   728 %{  /* NOCONTEXT */
   916 %{  /* NOCONTEXT */
   729     extern int _immediateInterrupt;
   917     extern int _immediateInterrupt;
   730     int _buffered;
   918 
   731 
   919     _INST(lastErrorNumber) = nil;
   732     _buffered = (_INST(buffered) == true);
   920     if ((_INST(filePointer) != nil)
   733     /*
   921      && (_INST(mode) != @symbol(writeonly))) {
   734      * binary mode
   922 	FILE *f;
   735      */
   923 	int first, second, err;
   736     if (_INST(binary) == true) {
   924 	short value;
   737         if ((_INST(filePointer) != nil) && (_INST(mode) != _writeonly)) {
   925 
   738             FILE *f;
   926 	f = MKFD(_INST(filePointer));
   739             unsigned char hi, low;
   927 
   740             int cnt;
   928 	_immediateInterrupt = 1;
   741             OBJ pos;
   929 	if ((_INST(didWrite) != false)
   742 
   930 	 && (_INST(mode) == @symbol(readwrite))) {
   743             f = MKFD(_INST(filePointer));
   931 	    _INST(didWrite) = false;
   744 
   932 	    fseek(f, 0L, 1); /* needed in stdio */
   745             _immediateInterrupt = 1;
   933 	}
   746 
   934 	first = getc(f);
   747             if (_buffered) {
   935 	if (first != EOF) {
   748                 if ((_INST(didWrite) != false) && (_INST(mode) == _readwrite)) {
   936 	    second = getc(f);
   749                     _INST(didWrite) = false;
   937 	    _immediateInterrupt = 0;
   750                     fseek(f, 0L, 1); /* needed in stdio */
   938 	    if (second != EOF) {
   751                 }
   939 		if (_INST(position) != nil) {
   752             }
   940 		    _INST(position) = _MKSMALLINT(_intVal(_INST(position)) + 2);
   753 
   941 		}
   754             do {
   942 		if (msbFlag == true) {
   755                 if (! _buffered) {
   943 		    value = ((first & 0xFF) << 8) | (second & 0xFF);
   756                     cnt = read(fileno(f), &hi, 1);
   944 		} else {
   757                 } else {
   945 		    value = ((second & 0xFF) << 8) | (first & 0xFF);
   758                     cnt = fread(&hi, 1, 1, f);
   946 		}
   759                 }
   947 		RETURN (_MKSMALLINT(value));
   760             } while ((cnt < 0) && (errno == EINTR));
   948 	    }
   761 
   949 	}
   762             if (cnt <= 0) {
   950 	_immediateInterrupt = 0;
   763                 _INST(hitEOF) = true;
   951 
   764                 if (cnt < 0)
   952 	if (ferror(f)) {
   765                     ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
   953 	    _INST(position) = nil;
   766                 _immediateInterrupt = 0;
   954 	    _INST(lastErrorNumber) = _MKSMALLINT(errno);
   767                 RETURN ( nil );
   955 	} else {
   768             }
   956 	    _INST(hitEOF) = true;
   769 
   957 	    RETURN (nil);
   770             do {
   958 	}
   771                 if (! _buffered) {
   959     }
   772                     cnt = read(fileno(f), &low, 1);
   960 %}.
   773                 } else {
       
   774                     cnt = fread(&low, 1, 1, f);
       
   775                 }
       
   776             } while ((cnt < 0) && (errno == EINTR));
       
   777 
       
   778             _immediateInterrupt = 0;
       
   779 
       
   780             pos = _INST(position);
       
   781             if (cnt <= 0) {
       
   782                 if (pos != nil) {
       
   783                     _INST(position) = _MKSMALLINT(_intVal(pos) + 1);
       
   784                 }
       
   785                 _INST(hitEOF) = true;
       
   786                 if (cnt < 0)
       
   787                     ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
       
   788                 RETURN ( _MKSMALLINT(hi & 0xFF) );
       
   789             }
       
   790             if (pos != nil) {
       
   791                 _INST(position) = _MKSMALLINT(_intVal(pos) + 2);
       
   792             }
       
   793             RETURN ( _MKSMALLINT(((hi & 0xFF)<<8) | (low & 0xFF)) );
       
   794         }
       
   795     }
       
   796 %}
       
   797 .
       
   798 %{  /* STACK: 2000 */
       
   799     FILE *f;
       
   800     int len;
       
   801     char buffer[1024];
       
   802     int ch;
       
   803     int cnt = 0;
       
   804     extern int _immediateInterrupt;
       
   805 
       
   806     /*
       
   807      * text mode
       
   808      */
       
   809     if ((_INST(filePointer) != nil) && (_INST(mode) != _writeonly)) {
       
   810         f = MKFD(_INST(filePointer));
       
   811 
       
   812         _immediateInterrupt = 1;
       
   813 
       
   814         if ((_INST(didWrite) != false) && (_INST(mode) == _readwrite)) {
       
   815             _INST(didWrite) = false;
       
   816             fseek(f, 0L, 1); /* needed in stdio */
       
   817         }
       
   818 
       
   819         for (;;) {
       
   820             ch = getc(f);
       
   821             cnt++;
       
   822 
       
   823             if (ch >= ' ') break;
       
   824             if ((ch != ' ') && (ch != '\t') && (ch != '\r')
       
   825              && (ch != '\n') && (ch != 0x0b)) break;
       
   826         }
       
   827         ungetc(ch, f);
       
   828         cnt--;
       
   829 
       
   830         len = 0;
       
   831         for (;;) {
       
   832             ch = getc(f);
       
   833             if (ch == EOF) {
       
   834                 _INST(hitEOF) = true;
       
   835                 break;
       
   836             }
       
   837 
       
   838             ch &= 0xFF;
       
   839             if (! (((ch >= 'a') && (ch <= 'z')) ||
       
   840                    ((ch >= 'A') && (ch <= 'Z')) ||
       
   841                    ((ch >= '0') && (ch <= '9')))) {
       
   842                 ungetc(ch, f);
       
   843                 break;
       
   844             }
       
   845             cnt++;
       
   846             buffer[len++] = ch;
       
   847             if (len >= sizeof(buffer)-1) {
       
   848                 /* emergency */
       
   849                 break;
       
   850             }
       
   851         }
       
   852         _immediateInterrupt = 0;
       
   853 
       
   854         if (_INST(position) != nil) {
       
   855             _INST(position) = _MKSMALLINT(_intVal(_INST(position)) + cnt);
       
   856         }
       
   857         buffer[len] = '\0';
       
   858         if (len != 0) {
       
   859             RETURN ( _MKSTRING(buffer COMMA_CON) );
       
   860         }
       
   861         RETURN ( nil );
       
   862     }
       
   863 %}
       
   864 .
       
   865     filePointer isNil ifTrue:[^ self errorNotOpen].
       
   866     self errorWriteOnly
       
   867 !
       
   868 
       
   869 nextShortMSB:msbFlag
       
   870     "Read two bytes and return the value as a 16-bit signed Integer.
       
   871      If msbFlag is true, value is read with most-significant byte first, otherwise
       
   872      least-significant byte comes first.
       
   873      A nil is also returned, if endOfFile occurs after the first byte.
       
   874      Works in both binary and text modes."
       
   875 
       
   876 %{  /* NOCONTEXT */
       
   877     extern int _immediateInterrupt;
       
   878 
       
   879     if ((_INST(filePointer) != nil) && (_INST(mode) != _writeonly)) {
       
   880         FILE *f;
       
   881         int first, second;
       
   882         short value;
       
   883 
       
   884         f = MKFD(_INST(filePointer));
       
   885 
       
   886         _immediateInterrupt = 1;
       
   887         if ((_INST(didWrite) != false) && (_INST(mode) == _readwrite)) {
       
   888             _INST(didWrite) = false;
       
   889             fseek(f, 0L, 1); /* needed in stdio */
       
   890         }
       
   891         first = getc(f);
       
   892         if (first == EOF) {
       
   893             _immediateInterrupt = 0;
       
   894             _INST(hitEOF) = true;
       
   895             RETURN ( nil );
       
   896         }
       
   897         second = getc(f);
       
   898         _immediateInterrupt = 0;
       
   899 
       
   900         if (second == EOF) {
       
   901             _INST(hitEOF) = true;
       
   902             RETURN ( nil );
       
   903         }
       
   904         if (_INST(position) != nil) {
       
   905             _INST(position) = _MKSMALLINT(_intVal(_INST(position)) + 2);
       
   906         }
       
   907         if (msbFlag == true) {
       
   908             RETURN ( _MKSMALLINT(((first & 0xFF)<<8) | (second & 0xFF)) );
       
   909         }
       
   910         RETURN ( _MKSMALLINT(((second & 0xFF)<<8) | (first & 0xFF)) );
       
   911     }
       
   912 %}
       
   913 .
       
   914     filePointer isNil ifTrue:[^ self errorNotOpen].
   961     filePointer isNil ifTrue:[^ self errorNotOpen].
   915     (mode == #writeonly) ifTrue:[^ self errorWriteOnly].
   962     (mode == #writeonly) ifTrue:[^ self errorWriteOnly].
   916     self primitiveFailed
   963     ^ self readError.
   917 !
   964 !
   918 
   965 
   919 nextUnsignedShortMSB:msbFlag
   966 nextUnsignedShortMSB:msbFlag
   920     "Read two bytes and return the value as a 16-bit unsigned Integer.
   967     "Read two bytes and return the value as a 16-bit unsigned Integer.
   921      If msbFlag is true, value is read with most-significant byte first, otherwise
   968      If msbFlag is true, value is read with most-significant byte first, otherwise
   922      least-significant byte comes first.
   969      least-significant byte comes first.
   923      A nil is also returned, if endOfFile occurs after the first byte.
   970      A nil is returned if EOF is reached (also when EOF is hit after the first byte).
   924      Works in both binary and text modes."
   971      Works in both binary and text modes."
   925 
   972 
   926 %{  /* NOCONTEXT */
   973 %{  /* NOCONTEXT */
   927     extern int _immediateInterrupt;
   974     extern int _immediateInterrupt;
   928 
   975 
   929     if ((_INST(filePointer) != nil) && (_INST(mode) != _writeonly)) {
   976     _INST(lastErrorNumber) = nil;
   930         FILE *f;
   977     if ((_INST(filePointer) != nil)
   931         int first, second;
   978      && (_INST(mode) != @symbol(writeonly))) {
   932 
   979 	FILE *f;
   933         _immediateInterrupt = 1;
   980 	int first, second;
   934 
   981 	unsigned value;
   935         f = MKFD(_INST(filePointer));
   982 	_immediateInterrupt = 1;
   936 
   983 
   937         if ((_INST(didWrite) != false) && (_INST(mode) == _readwrite)) {
   984 	f = MKFD(_INST(filePointer));
   938             _INST(didWrite) = false;
   985 
   939             fseek(f, 0L, 1); /* needed in stdio */
   986 	if ((_INST(didWrite) != false)
   940         }
   987 	 && (_INST(mode) == @symbol(readwrite))) {
   941 
   988 	    _INST(didWrite) = false;
   942         first = getc(f);
   989 	    fseek(f, 0L, 1); /* needed in stdio */
   943         if (first == EOF) {
   990 	}
   944             _immediateInterrupt = 0;
   991 
   945             _INST(hitEOF) = true;
   992 	first = getc(f);
   946             RETURN ( nil );
   993 	if (first != EOF) {
   947         }
   994 	    second = getc(f);
   948         second = getc(f);
   995 	    _immediateInterrupt = 0;
   949         _immediateInterrupt = 0;
   996 	    if (second != EOF) {
   950 
   997 		if (_INST(position) != nil) {
   951         if (second == EOF) {
   998 		    _INST(position) = _MKSMALLINT(_intVal(_INST(position)) + 2);
   952             _INST(hitEOF) = true;
   999 		}
   953             RETURN ( nil );
  1000 		if (msbFlag == true) {
   954         }
  1001 		    value = ((first & 0xFF) << 8) | (second & 0xFF);
   955         if (_INST(position) != nil) {
  1002 		} else {
   956             _INST(position) = _MKSMALLINT(_intVal(_INST(position)) + 2);
  1003 		    value = ((second & 0xFF) << 8) | (first & 0xFF);
   957         }
  1004 		}
   958         if (msbFlag == true) {
  1005 		RETURN (_MKSMALLINT(value));
   959             RETURN ( _MKSMALLINT(((first & 0xFF)<<8) | (second & 0xFF)) );
  1006 	    }
   960         }
  1007 	}
   961         RETURN ( _MKSMALLINT(((second & 0xFF)<<8) | (first & 0xFF)) );
  1008 	_immediateInterrupt = 0;
   962     }
  1009 
   963 %}
  1010 	if (ferror(f)) {
   964 .
  1011 	    _INST(position) = nil;
       
  1012 	    _INST(lastErrorNumber) = _MKSMALLINT(errno);
       
  1013 	} else {
       
  1014 	    _INST(hitEOF) = true;
       
  1015 	    RETURN (nil);
       
  1016 	}
       
  1017     }
       
  1018 %}.
   965     filePointer isNil ifTrue:[^ self errorNotOpen].
  1019     filePointer isNil ifTrue:[^ self errorNotOpen].
   966     (mode == #writeonly) ifTrue:[^ self errorWriteOnly].
  1020     (mode == #writeonly) ifTrue:[^ self errorWriteOnly].
   967     self primitiveFailed
  1021     ^ self readError.
   968 !
  1022 !
   969 
  1023 
   970 nextLongMSB:msbFlag
  1024 nextLongMSB:msbFlag
   971     "Read four bytes and return the value as a 32-bit signed Integer, which may be
  1025     "Read four bytes and return the value as a 32-bit signed Integer, 
   972      a LargeInteger.
  1026      which may be a LargeInteger.
   973      If msbFlag is true, value is read with most-significant byte first, otherwise
  1027      If msbFlag is true, value is read with most-significant byte first, 
   974      least-significant byte comes first.
  1028      otherwise least-significant byte comes first.
   975      A nil is returned, if endOfFile occurs before all 4 bytes have been read.
  1029      A nil is returned, if EOF is hit before all 4 bytes have been read.
   976      Works in both binary and text modes."
  1030      Works in both binary and text modes."
   977 
  1031 
   978 %{  /* NOCONTEXT */
  1032 %{  /* NOCONTEXT */
   979     extern int _immediateInterrupt;
  1033     extern int _immediateInterrupt;
   980 
  1034 
   981     if ((_INST(filePointer) != nil) && (_INST(mode) != _writeonly)) {
  1035     _INST(lastErrorNumber) = nil;
   982         FILE *f;
  1036     if ((_INST(filePointer) != nil)
   983         int first, second, third, fourth;
  1037      && (_INST(mode) != @symbol(writeonly))) {
   984         int value;
  1038 	FILE *f;
   985 
  1039 	int first, second, third, fourth;
   986         _immediateInterrupt = 1;
  1040 	int value;
   987         f = MKFD(_INST(filePointer));
  1041 
   988 
  1042 	_immediateInterrupt = 1;
   989         if ((_INST(didWrite) != false) && (_INST(mode) == _readwrite)) {
  1043 	f = MKFD(_INST(filePointer));
   990             _INST(didWrite) = false;
  1044 
   991             fseek(f, 0L, 1); /* needed in stdio */
  1045 	if ((_INST(didWrite) != false)
   992         }
  1046 	 && (_INST(mode) == @symbol(readwrite))) {
   993 
  1047 	    _INST(didWrite) = false;
   994         first = getc(f);
  1048 	    fseek(f, 0L, 1); /* needed in stdio */
   995         if (first == EOF) {
  1049 	}
   996             _INST(hitEOF) = true;
  1050 
   997             _immediateInterrupt = 0;
  1051 	first = getc(f);
   998             RETURN ( nil );
  1052 	if (first != EOF) {
   999         }
  1053 	    second = getc(f);
  1000         second = getc(f);
  1054 	    if (second != EOF) {
  1001         if (second == EOF) {
  1055 		third = getc(f);
  1002             _INST(hitEOF) = true;
  1056 		if (third != EOF) {
  1003             _immediateInterrupt = 0;
  1057 		    fourth = getc(f);
  1004             RETURN ( nil );
  1058 		    if (fourth != EOF) {
  1005         }
  1059 			_immediateInterrupt = 0;
  1006         third = getc(f);
  1060 			if (msbFlag == true) {
  1007         if (third == EOF) {
  1061 			    value = (first & 0xFF);
  1008             _INST(hitEOF) = true;
  1062 			    value = (value<<8) | (second & 0xFF);
  1009             _immediateInterrupt = 0;
  1063 			    value = (value<<8) | (third & 0xFF);
  1010             RETURN ( nil );
  1064 			    value = (value<<8) | (fourth & 0xFF);
  1011         }
  1065 			} else {
  1012         fourth = getc(f);
  1066 			    value = (fourth & 0xFF);
  1013         _immediateInterrupt = 0;
  1067 			    value = (value<<8) | (third & 0xFF);
  1014 
  1068 			    value = (value<<8) | (second & 0xFF);
  1015         if (fourth == EOF) {
  1069 			    value = (value<<8) | (first & 0xFF);
  1016             _INST(hitEOF) = true;
  1070 			}
  1017             RETURN ( nil );
  1071 			if (_INST(position) != nil) {
  1018         }
  1072 			    _INST(position) = _MKSMALLINT(_intVal(_INST(position)) + 4);
  1019         if (_INST(position) != nil) {
  1073 			}
  1020             _INST(position) = _MKSMALLINT(_intVal(_INST(position)) + 4);
  1074 			if ((value >= _MIN_INT) && (value <= _MAX_INT)) {
  1021         }
  1075 			    RETURN ( _MKSMALLINT(value));
  1022         if (msbFlag == true) {
  1076 			}
  1023             value = ((first & 0xFF) << 24)
  1077 			RETURN ( _makeLarge(value) );
  1024                     | ((second & 0xFF) << 16)
  1078 		    }
  1025                     | ((third & 0xFF) << 8)
  1079 		}
  1026                     | (fourth & 0xFF);
  1080 	    }
  1027         } else {
  1081 	}
  1028             value = ((fourth & 0xFF) << 24)
  1082 	if (ferror(f)) {
  1029                     | ((third & 0xFF) << 16)
  1083 	    _INST(lastErrorNumber) = _MKSMALLINT(errno);
  1030                     | ((second & 0xFF) << 8)
  1084 	    _INST(position) = nil;
  1031                     | (first & 0xFF);
  1085 	} else {
  1032         }
  1086 	    _INST(hitEOF) = true;
  1033         if ((value >= _MIN_INT) && (value <= _MAX_INT)) {
  1087 	    RETURN (nil);
  1034             RETURN ( _MKSMALLINT(value));
  1088 	}
  1035         }
  1089     }
  1036         RETURN ( _makeLarge(value) );
  1090 %}.
  1037     }
       
  1038 %}
       
  1039 .
       
  1040     filePointer isNil ifTrue:[^ self errorNotOpen].
  1091     filePointer isNil ifTrue:[^ self errorNotOpen].
  1041     (mode == #writeonly) ifTrue:[^ self errorWriteOnly].
  1092     (mode == #writeonly) ifTrue:[^ self errorWriteOnly].
  1042     self primitiveFailed
  1093     ^ self readError.
  1043 !
  1094 !
  1044 
  1095 
  1045 nextUnsignedLongMSB:msbFlag
  1096 nextUnsignedLongMSB:msbFlag
  1046     "Read four bytes and return the value as a 32-bit unsigned Integer, which may be
  1097     "Read four bytes and return the value as a 32-bit unsigned Integer, which may be
  1047      a LargeInteger.
  1098      a LargeInteger.
  1052 
  1103 
  1053 %{  /* NOCONTEXT */
  1104 %{  /* NOCONTEXT */
  1054     extern int _immediateInterrupt;
  1105     extern int _immediateInterrupt;
  1055     extern OBJ _makeULarge();
  1106     extern OBJ _makeULarge();
  1056 
  1107 
  1057     if ((_INST(filePointer) != nil) && (_INST(mode) != _writeonly)) {
  1108     _INST(lastErrorNumber) = nil;
  1058         FILE *f;
  1109     if ((_INST(filePointer) != nil)
  1059         int first, second, third, fourth;
  1110      && (_INST(mode) != @symbol(writeonly))) {
  1060         unsigned int value;
  1111 	FILE *f;
  1061 
  1112 	int first, second, third, fourth;
  1062         _immediateInterrupt = 1;
  1113 	unsigned int value;
  1063         f = MKFD(_INST(filePointer));
  1114 
  1064 
  1115 	_immediateInterrupt = 1;
  1065         if ((_INST(didWrite) != false) && (_INST(mode) == _readwrite)) {
  1116 	f = MKFD(_INST(filePointer));
  1066             _INST(didWrite) = false;
  1117 
  1067             fseek(f, 0L, 1); /* needed in stdio */
  1118 	if ((_INST(didWrite) != false)
  1068         }
  1119 	 && (_INST(mode) == @symbol(readwrite))) {
  1069 
  1120 	    _INST(didWrite) = false;
  1070         first = getc(f);
  1121 	    fseek(f, 0L, 1); /* needed in stdio */
  1071         if (first == EOF) {
  1122 	}
  1072             _INST(hitEOF) = true;
  1123 
  1073             _immediateInterrupt = 0;
  1124 	first = getc(f);
  1074             RETURN ( nil );
  1125 	if (first != EOF) {
  1075         }
  1126 	    second = getc(f);
  1076         second = getc(f);
  1127 	    if (second != EOF) {
  1077         if (second == EOF) {
  1128 		third = getc(f);
  1078             _INST(hitEOF) = true;
  1129 		if (third != EOF) {
  1079             _immediateInterrupt = 0;
  1130 		    fourth = getc(f);
  1080             RETURN ( nil );
  1131 		    if (fourth != EOF) {
  1081         }
  1132 			_immediateInterrupt = 0;
  1082         third = getc(f);
  1133 			if (msbFlag == true) {
  1083         if (third == EOF) {
  1134 			    value = (first & 0xFF);
  1084             _INST(hitEOF) = true;
  1135 			    value = (value<<8) | (second & 0xFF);
  1085             _immediateInterrupt = 0;
  1136 			    value = (value<<8) | (third & 0xFF);
  1086             RETURN ( nil );
  1137 			    value = (value<<8) | (fourth & 0xFF);
  1087         }
  1138 			} else {
  1088         fourth = getc(f);
  1139 			    value = (fourth & 0xFF);
  1089         _immediateInterrupt = 0;
  1140 			    value = (value<<8) | (third & 0xFF);
  1090         if (fourth == EOF) {
  1141 			    value = (value<<8) | (second & 0xFF);
  1091             _INST(hitEOF) = true;
  1142 			    value = (value<<8) | (first & 0xFF);
  1092             RETURN ( nil );
  1143 			}
  1093         }
  1144 			if (_INST(position) != nil) {
  1094         if (_INST(position) != nil) {
  1145 			    _INST(position) = _MKSMALLINT(_intVal(_INST(position)) + 4);
  1095             _INST(position) = _MKSMALLINT(_intVal(_INST(position)) + 4);
  1146 			}
  1096         }
  1147 			if (value <= _MAX_INT) {
  1097         if (msbFlag == true) {
  1148 			    RETURN ( _MKSMALLINT(value));
  1098             value = ((first & 0xFF) << 24)
  1149 			}
  1099                     | ((second & 0xFF) << 16)
  1150 			RETURN ( _makeULarge(value) );
  1100                     | ((third & 0xFF) << 8)
  1151 		    }
  1101                     | (fourth & 0xFF);
  1152 		}
  1102         } else {
  1153 	    }
  1103             value = ((fourth & 0xFF) << 24)
  1154 	}
  1104                     | ((third & 0xFF) << 16)
  1155 	if (ferror(f)) {
  1105                     | ((second & 0xFF) << 8)
  1156 	    _INST(lastErrorNumber) = _MKSMALLINT(errno);
  1106                     | (first & 0xFF);
  1157 	    _INST(position) = nil;
  1107         }
  1158 	} else {
  1108         if (value <= _MAX_INT) {
  1159 	    _INST(hitEOF) = true;
  1109             RETURN ( _MKSMALLINT(value));
  1160 	    RETURN (nil);
  1110         }
  1161 	}
  1111         RETURN ( _makeULarge(value) );
  1162     }
  1112     }
  1163 %}.
  1113 %}
       
  1114 .
       
  1115     filePointer isNil ifTrue:[^ self errorNotOpen].
  1164     filePointer isNil ifTrue:[^ self errorNotOpen].
  1116     (mode == #writeonly) ifTrue:[^ self errorWriteOnly].
  1165     (mode == #writeonly) ifTrue:[^ self errorWriteOnly].
  1117     self primitiveFailed
  1166     ^ self readError.
       
  1167 !
       
  1168 
       
  1169 nextWord
       
  1170     "in text-mode:
       
  1171 	 read the alphaNumeric next word (i.e. up to non letter-or-digit).
       
  1172 	 return a string containing those characters.
       
  1173      in binary-mode:
       
  1174 	 read two bytes (msb-first) and return the value as a 16-bit unsigned Integer
       
  1175 	 (for compatibility with other smalltalks)"
       
  1176 
       
  1177     binary ifTrue:[
       
  1178 	^ self nextShortMSB:true
       
  1179     ].
       
  1180     ^ self nextAlphaNumericWord
  1118 !
  1181 !
  1119 
  1182 
  1120 nextLong
  1183 nextLong
  1121     "Read four bytes (msb-first) and return the value as a 32-bit signed Integer.
  1184     "Read four bytes (msb-first) and return the value as a 32-bit signed Integer.
  1122      The returned value may be a LargeInteger.
  1185      The returned value may be a LargeInteger.
  1138     extern errno;
  1201     extern errno;
  1139     OBJ pos;
  1202     OBJ pos;
  1140     int cnt;
  1203     int cnt;
  1141     extern int _immediateInterrupt;
  1204     extern int _immediateInterrupt;
  1142 
  1205 
  1143     if ((_INST(filePointer) != nil) && (_INST(mode) != _readonly)) {
  1206     _INST(lastErrorNumber) = nil;
  1144         if (_isSmallInteger(aByteValue)) {
  1207     if ((_INST(filePointer) != nil)
  1145             c = _intVal(aByteValue);
  1208      && (_INST(mode) != @symbol(readonly))) {
  1146             f = MKFD(_INST(filePointer));
  1209 	if (_isSmallInteger(aByteValue)) {
  1147             _immediateInterrupt = 1;
  1210 	    c = _intVal(aByteValue);
       
  1211 	    f = MKFD(_INST(filePointer));
       
  1212 	    _immediateInterrupt = 1;
  1148 #ifdef OLD
  1213 #ifdef OLD
  1149             if (_INST(buffered) == false) {
  1214 	    if (_INST(buffered) == false) {
  1150                 cnt = write(fileno(f), &c, 1);
  1215 		cnt = write(fileno(f), &c, 1);
  1151             } else 
  1216 	    } else 
  1152 #endif
  1217 #endif
  1153             {
  1218 	    {
  1154                 if ((_INST(didWrite) != true) && (_INST(mode) == _readwrite)) {
  1219 		if ((_INST(didWrite) != true)
  1155                     _INST(didWrite) = true;
  1220 		 && (_INST(mode) == @symbol(readwrite))) {
  1156                     fseek(f, 0L, 1); /* needed in stdio */
  1221 		    _INST(didWrite) = true;
  1157                 }
  1222 		    fseek(f, 0L, 1); /* needed in stdio */
  1158                 cnt = fwrite(&c, 1, 1, f);
  1223 		}
       
  1224 		cnt = fwrite(&c, 1, 1, f);
  1159 #ifndef OLD
  1225 #ifndef OLD
  1160                 if (_INST(buffered) == false) {
  1226 		if (_INST(buffered) == false) {
  1161                     fflush(f);
  1227 		    fflush(f);
  1162                 }
  1228 		}
  1163 #endif
  1229 #endif
  1164             }
  1230 	    }
  1165             _immediateInterrupt = 0;
  1231 	    _immediateInterrupt = 0;
  1166             if (cnt == 1) {
  1232 	    if (cnt == 1) {
  1167                 pos = _INST(position);
  1233 		pos = _INST(position);
  1168                 if (pos != nil)
  1234 		if (pos != nil)
  1169                     _INST(position) = _MKSMALLINT(_intVal(pos) + 1);
  1235 		    _INST(position) = _MKSMALLINT(_intVal(pos) + 1);
  1170                 RETURN ( self );
  1236 		RETURN (self);
  1171             }
  1237 	    }
  1172             ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
  1238 	    if (cnt < 0) {
  1173             RETURN (nil);
  1239 		_INST(lastErrorNumber) = _MKSMALLINT(errno);
  1174         }
  1240 	    }
  1175     }
  1241 	}
  1176 %}
  1242     }
  1177 .
  1243 %}.
  1178     filePointer isNil ifTrue:[^ self errorNotOpen].
  1244     filePointer isNil ifTrue:[^ self errorNotOpen].
  1179     (mode == #readonly) ifTrue:[^ self errorReadOnly].
  1245     (mode == #readonly) ifTrue:[^ self errorReadOnly].
  1180     self primitiveFailed
  1246     ^ self writeError.
  1181 !
  1247 !
  1182 
  1248 
  1183 nextPutBytesFrom:anObject
  1249 nextPutBytesFrom:anObject
  1184     "write bytes from an object; the number of bytes is defined by
  1250     "write bytes from an object; the number of bytes is defined by
  1185      the objects size.
  1251      the objects size.
  1201     ^ self nextPutBytes:count from:anObject startingAt:1
  1267     ^ self nextPutBytes:count from:anObject startingAt:1
  1202 !
  1268 !
  1203 
  1269 
  1204 nextPutBytes:count from:anObject startingAt:start
  1270 nextPutBytes:count from:anObject startingAt:start
  1205     "write count bytes from an object starting at index start.
  1271     "write count bytes from an object starting at index start.
  1206      return the number of bytes written or nil on error.
  1272      return the number of bytes written - which could be 0.
  1207      The object must have non-pointer indexed instvars 
  1273      The object must have non-pointer indexed instvars 
  1208      (i.e. be a ByteArray, String, Float- or DoubleArray).     
  1274      (i.e. be a ByteArray, String, Float- or DoubleArray).     
  1209      Use with care - non object oriented i/o"
  1275      Use with care - non object oriented i/o"
  1210 
  1276 
  1211 %{  /* NOCONTEXT */
  1277 %{  /* NOCONTEXT */
  1217     extern errno;
  1283     extern errno;
  1218     OBJ oClass;
  1284     OBJ oClass;
  1219     OBJ pos;
  1285     OBJ pos;
  1220     extern int _immediateInterrupt;
  1286     extern int _immediateInterrupt;
  1221 
  1287 
  1222     if ((_INST(filePointer) != nil) && (_INST(mode) != _readonly)) {
  1288     _INST(lastErrorNumber) = nil;
  1223         if (_isSmallInteger(count) && _isSmallInteger(start)) {
  1289     if ((_INST(filePointer) != nil)
  1224             oClass = _Class(anObject);
  1290      && (_INST(mode) != @symbol(readonly))) {
  1225             switch (_intVal(_ClassInstPtr(oClass)->c_flags) & ARRAYMASK) {
  1291 	if (_isSmallInteger(count) && _isSmallInteger(start)) {
  1226                 case BYTEARRAY:
  1292 	    oClass = _Class(anObject);
  1227                 case WORDARRAY:
  1293 	    switch (_intVal(_ClassInstPtr(oClass)->c_flags) & ARRAYMASK) {
  1228                 case LONGARRAY:
  1294 		case BYTEARRAY:
  1229                 case FLOATARRAY:
  1295 		case WORDARRAY:
  1230                 case DOUBLEARRAY:
  1296 		case LONGARRAY:
  1231                     break;
  1297 		case FLOATARRAY:
  1232                 default:
  1298 		case DOUBLEARRAY:
  1233                     goto bad;
  1299 		    break;
  1234             }
  1300 		default:
  1235             cnt = _intVal(count);
  1301 		    goto bad;
  1236             offs = _intVal(start) - 1;
  1302 	    }
  1237             f = MKFD(_INST(filePointer));
  1303 	    cnt = _intVal(count);
  1238 
  1304 	    offs = _intVal(start) - 1;
  1239             nInstVars = _intVal(_ClassInstPtr(oClass)->c_ninstvars);
  1305 	    f = MKFD(_INST(filePointer));
  1240             nInstBytes = OHDR_SIZE + __OBJS2BYTES__(nInstVars);
  1306 
  1241             objSize = _Size(anObject) - nInstBytes;
  1307 	    nInstVars = _intVal(_ClassInstPtr(oClass)->c_ninstvars);
  1242             if ( (offs >= 0) && (cnt >= 0) && (objSize >= (cnt + offs)) ) {
  1308 	    nInstBytes = OHDR_SIZE + __OBJS2BYTES__(nInstVars);
  1243                 cp = (char *)_InstPtr(anObject) + nInstBytes + offs;
  1309 	    objSize = _Size(anObject) - nInstBytes;
  1244                 _immediateInterrupt = 1;
  1310 	    if ( (offs >= 0) && (cnt >= 0) && (objSize >= (cnt + offs)) ) {
       
  1311 		cp = (char *)_InstPtr(anObject) + nInstBytes + offs;
       
  1312 		_immediateInterrupt = 1;
  1245 #ifdef OLD
  1313 #ifdef OLD
  1246                 if (_INST(buffered) == false) {
  1314 		if (_INST(buffered) == false) {
  1247                     cnt = write(fileno(f), cp, cnt);
  1315 		    cnt = write(fileno(f), cp, cnt);
  1248                 } else
  1316 		} else
  1249 #endif
  1317 #endif
  1250                 {
  1318 		{
  1251                     if ((_INST(didWrite) != true) && (_INST(mode) == _readwrite)) {
  1319 		    if ((_INST(didWrite) != true)
  1252                         _INST(didWrite) = true;
  1320 		     && (_INST(mode) == @symbol(readwrite))) {
  1253                         fseek(f, 0L, 1); /* needed in stdio */
  1321 			_INST(didWrite) = true;
  1254                     }
  1322 			fseek(f, 0L, 1); /* needed in stdio */
  1255                     cnt = fwrite(cp, 1, cnt, f);
  1323 		    }
  1256                 }
  1324 		    cnt = fwrite(cp, 1, cnt, f);
       
  1325 		}
  1257 #ifndef OLD
  1326 #ifndef OLD
  1258                 if (_INST(buffered) == false) {
  1327 		if (_INST(buffered) == false) {
  1259                     fflush(f);
  1328 		    fflush(f);
  1260                 }
  1329 		}
  1261 #endif
  1330 #endif
  1262                 _immediateInterrupt = 0;
  1331 		_immediateInterrupt = 0;
  1263                 if (cnt >= 0) {
  1332 		if (cnt >= 0) {
  1264                     pos = _INST(position);
  1333 		    pos = _INST(position);
  1265                     if (pos != nil)
  1334 		    if (pos != nil)
  1266                         _INST(position) = _MKSMALLINT(_intVal(pos) + cnt);
  1335 			_INST(position) = _MKSMALLINT(_intVal(pos) + cnt);
  1267                     RETURN ( _MKSMALLINT(cnt) );
  1336 		    RETURN ( _MKSMALLINT(cnt) );
  1268                 }
  1337 		}
  1269                 ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
  1338 		_INST(lastErrorNumber) = _MKSMALLINT(errno);
  1270                 RETURN ( nil );
  1339 	    }
  1271             }
  1340 	}
  1272         }
       
  1273     }
  1341     }
  1274 bad: ;
  1342 bad: ;
  1275 %}
  1343 %}.
  1276 .
  1344     lastErrorNumber notNil ifTrue:[^ self writeError].
  1277     filePointer isNil ifTrue:[^ self errorNotOpen].
  1345     filePointer isNil ifTrue:[^ self errorNotOpen].
  1278     (mode == #readonly) ifTrue:[^ self errorReadOnly].
  1346     (mode == #readonly) ifTrue:[^ self errorReadOnly].
  1279     self primitiveFailed
  1347     ^ self primitiveFailed
  1280 !
  1348 !
  1281 
  1349 
  1282 nextPutShort:aNumber MSB:msbFlag
  1350 nextPutShort:aNumber MSB:msbFlag
  1283     "Write the argument, aNumber as a short (two bytes). If msbFlag is
  1351     "Write the argument, aNumber as a short (two bytes). If msbFlag is
  1284      true, data is written most-significant byte first; otherwise least
  1352      true, data is written most-significant byte first; otherwise least
  1285      first. Returns the receiver on ok, nil on error.
  1353      first.
  1286      Works in both binary and text modes."
  1354      Works in both binary and text modes."
  1287 
  1355 
  1288 %{  /* NOCONTEXT */
  1356 %{  /* NOCONTEXT */
  1289 
  1357 
  1290     int num;
  1358     int num;
  1292     FILE *f;
  1360     FILE *f;
  1293     extern errno;
  1361     extern errno;
  1294     extern int _immediateInterrupt;
  1362     extern int _immediateInterrupt;
  1295     int cnt;
  1363     int cnt;
  1296 
  1364 
  1297     if ((_INST(filePointer) != nil) && (_INST(mode) != _readonly)) {
  1365     _INST(lastErrorNumber) = nil;
  1298         if (_isSmallInteger(aNumber)) {
  1366     if ((_INST(filePointer) != nil)
  1299             num = _intVal(aNumber);
  1367      && (_INST(mode) != @symbol(readonly))
  1300             if (msbFlag == true) {
  1368      && _isSmallInteger(aNumber)) {
  1301                 bytes[0] = (num >> 8) & 0xFF;
  1369 	num = _intVal(aNumber);
  1302                 bytes[1] = num & 0xFF;
  1370 	if (msbFlag == true) {
  1303             } else {
  1371 	    bytes[0] = (num >> 8) & 0xFF;
  1304                 bytes[1] = (num >> 8) & 0xFF;
  1372 	    bytes[1] = num & 0xFF;
  1305                 bytes[0] = num & 0xFF;
  1373 	} else {
  1306             }
  1374 	    bytes[1] = (num >> 8) & 0xFF;
  1307 
  1375 	    bytes[0] = num & 0xFF;
  1308             f = MKFD(_INST(filePointer));
  1376 	}
  1309             _immediateInterrupt = 1;
  1377 
       
  1378 	f = MKFD(_INST(filePointer));
       
  1379 	_immediateInterrupt = 1;
  1310 #ifdef OLD
  1380 #ifdef OLD
  1311             if (_INST(buffered) == false) {
  1381 	if (_INST(buffered) == false) {
  1312                 cnt = write(fileno(f), bytes, 2);
  1382 	    cnt = write(fileno(f), bytes, 2);
  1313             } else 
  1383 	} else 
  1314 #endif
  1384 #endif
  1315             {
  1385 	{
  1316                 if ((_INST(didWrite) != true) && (_INST(mode) == _readwrite)) {
  1386 	    if ((_INST(didWrite) != true)
  1317                     _INST(didWrite) = true;
  1387 	     && (_INST(mode) == @symbol(readwrite))) {
  1318                     fseek(f, 0L, 1); /* needed in stdio */
  1388 		_INST(didWrite) = true;
  1319                 }
  1389 		fseek(f, 0L, 1); /* needed in stdio */
  1320                 cnt = fwrite(bytes, 1, 2, f);
  1390 	    }
  1321             }
  1391 	    cnt = fwrite(bytes, 1, 2, f);
       
  1392 	}
  1322 #ifndef OLD
  1393 #ifndef OLD
  1323             if (_INST(buffered) == false) {
  1394 	if (_INST(buffered) == false) {
  1324                 fflush(f);
  1395 	    fflush(f);
  1325             }
  1396 	}
  1326 #endif
  1397 #endif
  1327             _immediateInterrupt = 0;
  1398 	_immediateInterrupt = 0;
  1328             if (cnt == 2) {
  1399 	if (cnt == 2) {
  1329                 if (_INST(position) != nil) {
  1400 	    if (_INST(position) != nil) {
  1330                     _INST(position) = _MKSMALLINT(_intVal(_INST(position)) + 2);
  1401 		_INST(position) = _MKSMALLINT(_intVal(_INST(position)) + 2);
  1331                 }
  1402 	    }
  1332                 RETURN ( self );
  1403 	    RETURN ( self );
  1333             }
  1404 	}
  1334             ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
  1405 	_INST(lastErrorNumber) = _MKSMALLINT(errno);
  1335             return ( nil );
  1406     }
  1336         }
  1407 %}.
  1337     }
  1408     lastErrorNumber notNil ifTrue:[^ self writeError].
  1338 %}
       
  1339 .
       
  1340     filePointer isNil ifTrue:[^ self errorNotOpen].
  1409     filePointer isNil ifTrue:[^ self errorNotOpen].
  1341     (mode == #readonly) ifTrue:[^ self errorReadOnly].
  1410     (mode == #readonly) ifTrue:[^ self errorReadOnly].
  1342     self argumentMustBeInteger
  1411     self argumentMustBeInteger
  1343 !
  1412 !
  1344 
  1413 
  1345 nextPutLong:aNumber MSB:msbFlag
  1414 nextPutLong:aNumber MSB:msbFlag
  1346     "Write the argument, aNumber as a long (four bytes). If msbFlag is
  1415     "Write the argument, aNumber as a long (four bytes). If msbFlag is
  1347      true, data is written most-significant byte first; otherwise least
  1416      true, data is written most-significant byte first; otherwise least
  1348      first. Returns the receiver on ok, nil on error.
  1417      first.
  1349      Works in both binary and text modes."
  1418      Works in both binary and text modes."
  1350 
  1419 
  1351 %{  /* NOCONTEXT */
  1420 %{  /* NOCONTEXT */
  1352 
  1421 
  1353     int num;
  1422     int num;
  1355     FILE *f;
  1424     FILE *f;
  1356     extern errno;
  1425     extern errno;
  1357     int cnt;
  1426     int cnt;
  1358     extern int _immediateInterrupt;
  1427     extern int _immediateInterrupt;
  1359 
  1428 
  1360     if ((_INST(filePointer) != nil) && (_INST(mode) != _readonly)) {
  1429     _INST(lastErrorNumber) = nil;
  1361         if (_isSmallInteger(aNumber)) {
  1430     if ((_INST(filePointer) != nil)
  1362             num = _intVal(aNumber);
  1431      && (_INST(mode) != @symbol(readonly))
  1363             if (msbFlag == true) {
  1432      && _isSmallInteger(aNumber)) {
  1364                 bytes[0] = (num >> 24) & 0xFF;
  1433 	num = _intVal(aNumber);
  1365                 bytes[1] = (num >> 16) & 0xFF;
  1434 	if (msbFlag == true) {
  1366                 bytes[2] = (num >> 8) & 0xFF;
  1435 	    bytes[0] = (num >> 24) & 0xFF;
  1367                 bytes[3] = num & 0xFF;
  1436 	    bytes[1] = (num >> 16) & 0xFF;
  1368             } else {
  1437 	    bytes[2] = (num >> 8) & 0xFF;
  1369                 bytes[3] = (num >> 24) & 0xFF;
  1438 	    bytes[3] = num & 0xFF;
  1370                 bytes[2] = (num >> 16) & 0xFF;
  1439 	} else {
  1371                 bytes[1] = (num >> 8) & 0xFF;
  1440 	    bytes[3] = (num >> 24) & 0xFF;
  1372                 bytes[0] = num & 0xFF;
  1441 	    bytes[2] = (num >> 16) & 0xFF;
  1373             }
  1442 	    bytes[1] = (num >> 8) & 0xFF;
  1374 
  1443 	    bytes[0] = num & 0xFF;
  1375             f = MKFD(_INST(filePointer));
  1444 	}
  1376             _immediateInterrupt = 1;
  1445 
       
  1446 	f = MKFD(_INST(filePointer));
       
  1447 	_immediateInterrupt = 1;
  1377 #ifdef OLD
  1448 #ifdef OLD
  1378             if (_INST(buffered) == false) {
  1449 	if (_INST(buffered) == false) {
  1379                 cnt = write(fileno(f), bytes, 4);
  1450 	    cnt = write(fileno(f), bytes, 4);
  1380             } else 
  1451 	} else 
  1381 #endif
  1452 #endif
  1382             {
  1453 	{
  1383                 cnt = fwrite(bytes, 1, 4, f);
  1454 	    if ((_INST(didWrite) != true)
  1384             }
  1455 	     && (_INST(mode) == @symbol(readwrite))) {
       
  1456 		_INST(didWrite) = true;
       
  1457 		fseek(f, 0L, 1); /* needed in stdio */
       
  1458 	    }
       
  1459 	    cnt = fwrite(bytes, 1, 4, f);
       
  1460 	}
  1385 #ifndef OLD
  1461 #ifndef OLD
  1386             if (_INST(buffered) == false) {
  1462 	if (_INST(buffered) == false) {
  1387                 fflush(f);
  1463 	    fflush(f);
  1388             }
  1464 	}
  1389 #endif
  1465 #endif
  1390             _immediateInterrupt = 0;
  1466 	_immediateInterrupt = 0;
  1391             if (cnt == 4) {
  1467 	if (cnt == 4) {
  1392                 if (_INST(position) != nil) {
  1468 	    if (_INST(position) != nil) {
  1393                     _INST(position) = _MKSMALLINT(_intVal(_INST(position)) + 4);
  1469 		_INST(position) = _MKSMALLINT(_intVal(_INST(position)) + 4);
  1394                 }
  1470 	    }
  1395                 RETURN ( self );
  1471 	    RETURN ( self );
  1396             }
  1472 	}
  1397             ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
  1473 	_INST(lastErrorNumber) = _MKSMALLINT(errno);
  1398             return ( nil );
  1474     }
  1399         }
  1475 %}.
  1400     }
       
  1401 %}
       
  1402 .
       
  1403     filePointer isNil ifTrue:[^ self errorNotOpen].
  1476     filePointer isNil ifTrue:[^ self errorNotOpen].
  1404     (mode == #readonly) ifTrue:[^ self errorReadOnly].
  1477     (mode == #readonly) ifTrue:[^ self errorReadOnly].
       
  1478     lastErrorNumber notNil ifTrue:[^ self writeError].
  1405 
  1479 
  1406     aNumber isInteger ifTrue:[
  1480     aNumber isInteger ifTrue:[
  1407         msbFlag ifTrue:[
  1481 	msbFlag ifTrue:[
  1408             "high word first"
  1482 	    "high word first"
  1409             (self nextShortPut:(aNumber // 16r10000) MSB:true) isNil ifTrue:[^ nil].
  1483 	    (self nextShortPut:(aNumber // 16r10000) MSB:true) isNil ifTrue:[^ nil].
  1410             ^ self nextShortPut:(aNumber \\ 16r10000) MSB:true
  1484 	    ^ self nextShortPut:(aNumber \\ 16r10000) MSB:true
  1411         ].
  1485 	].
  1412         "low word first"
  1486 	"low word first"
  1413         (self nextShortPut:(aNumber \\ 16r10000) MSB:false) isNil ifTrue:[^ nil].
  1487 	(self nextShortPut:(aNumber \\ 16r10000) MSB:false) isNil ifTrue:[^ nil].
  1414         ^ self nextShortPut:(aNumber // 16r10000) MSB:false.
  1488 	^ self nextShortPut:(aNumber // 16r10000) MSB:false.
  1415     ].
  1489     ].
  1416     self argumentMustBeInteger
  1490     self argumentMustBeInteger
  1417 ! !
  1491 ! !
  1418 
  1492 
  1419 !ExternalStream methodsFor:'reading'!
  1493 !ExternalStream methodsFor:'reading'!
  1428 
  1502 
  1429     FILE *f;
  1503     FILE *f;
  1430     REGISTER int c;
  1504     REGISTER int c;
  1431     extern int _immediateInterrupt;
  1505     extern int _immediateInterrupt;
  1432 
  1506 
  1433     if (_INST(filePointer) != nil) {
  1507     _INST(lastErrorNumber) = nil;
  1434         if (_INST(mode) != _writeonly) {
  1508     if ((_INST(filePointer) != nil)
       
  1509      && (_INST(mode) != @symbol(writeonly))) {
  1435 #ifdef OLD
  1510 #ifdef OLD
  1436             if (_INST(buffered) == true) 
  1511 	if (_INST(buffered) == true) 
  1437 #endif
  1512 #endif
  1438             {
  1513 	{
  1439                 f = MKFD(_INST(filePointer));
  1514 	    f = MKFD(_INST(filePointer));
  1440 
  1515 
  1441                 if ((_INST(didWrite) != false) && (_INST(mode) == _readwrite)) {
  1516 	    if ((_INST(didWrite) != false)
  1442                     _INST(didWrite) = false;
  1517 	     && (_INST(mode) == @symbol(readwrite))) {
  1443                     fseek(f, 0L, 1); /* needed in stdio */
  1518 		_INST(didWrite) = false;
  1444                 }
  1519 		fseek(f, 0L, 1); /* needed in stdio */
  1445 
  1520 	    }
  1446                 _immediateInterrupt = 1;
  1521 
  1447                 c = getc(f);
  1522 	    _immediateInterrupt = 1;
  1448                 _immediateInterrupt = 0;
  1523 	    c = getc(f);
  1449 
  1524 	    _immediateInterrupt = 0;
  1450                 if (c != EOF) {
  1525 
  1451                     ungetc(c, f);
  1526 	    if (c != EOF) {
  1452                     if (_INST(binary) == true) {
  1527 		ungetc(c, f);
  1453                         RETURN ( _MKSMALLINT(c & 0xFF) );
  1528 		if (_INST(binary) == true) {
  1454                     }
  1529 		    RETURN ( _MKSMALLINT(c & 0xFF) );
  1455                     RETURN ( _MKCHARACTER(c & 0xFF) );
  1530 		}
  1456                 }
  1531 		RETURN ( _MKCHARACTER(c & 0xFF) );
  1457                 _INST(hitEOF) = true;
  1532 	    }
  1458                 RETURN ( nil );
  1533 	    if (ferror(f)) {
  1459             }
  1534 		_INST(lastErrorNumber) = _MKSMALLINT(errno);
  1460         }
  1535 	    } else {
  1461     }
  1536 		_INST(hitEOF) = true;
  1462 %}
  1537 		RETURN ( nil );
  1463 .
  1538 	    }
       
  1539 	}
       
  1540     }
       
  1541 %}.
       
  1542     lastErrorNumber notNil ifTrue:[^ self readError].
  1464     filePointer isNil ifTrue:[^ self errorNotOpen].
  1543     filePointer isNil ifTrue:[^ self errorNotOpen].
  1465     buffered ifFalse:[^ self errorNotBuffered].
  1544     buffered ifFalse:[^ self errorNotBuffered].
  1466     self errorWriteOnly
  1545     ^ self errorWriteOnly
  1467 !
  1546 !
  1468 
  1547 
  1469 next
  1548 next
  1470     "return the next element; advance read position.
  1549     "return the next element; advance read position.
  1471      In binary mode, an integer is returned, otherwise a character.
  1550      In binary mode, an integer is returned, otherwise a character.
  1478     OBJ pos;
  1557     OBJ pos;
  1479     unsigned char ch;
  1558     unsigned char ch;
  1480 
  1559 
  1481     extern int _immediateInterrupt;
  1560     extern int _immediateInterrupt;
  1482 
  1561 
  1483     if (_INST(filePointer) != nil) {
  1562     _INST(lastErrorNumber) = nil;
  1484         if (_INST(mode) != _writeonly) {
  1563     if ((_INST(filePointer) != nil)
  1485             f = MKFD(_INST(filePointer));
  1564      && (_INST(mode) != @symbol(writeonly))) {
  1486             _immediateInterrupt = 1;
  1565 	f = MKFD(_INST(filePointer));
  1487             do {
  1566 	_immediateInterrupt = 1;
       
  1567 	do {
  1488 #ifdef OLD
  1568 #ifdef OLD
  1489                 if (_INST(buffered) == false) {
  1569 	    if (_INST(buffered) == false) {
  1490                     if (read(fileno(f), &ch, 1) != 1)
  1570 		if (read(fileno(f), &ch, 1) != 1)
  1491                         c = EOF;
  1571 		    c = EOF;
  1492                     else
  1572 		else
  1493                         c = ch;
  1573 		    c = ch;
  1494                 } else 
  1574 	    } else 
  1495 #endif
  1575 #endif
  1496                 {
  1576 	    {
  1497                     if ((_INST(didWrite) != false) && (_INST(mode) == _readwrite)) {
  1577 		if ((_INST(didWrite) != false)
  1498                         _INST(didWrite) = false;
  1578 		 && (_INST(mode) == @symbol(readwrite))) {
  1499                         fseek(f, 0L, 1); /* needed in stdio */
  1579 		    _INST(didWrite) = false;
  1500                     }
  1580 		    fseek(f, 0L, 1); /* needed in stdio */
  1501                     c = getc(f);
  1581 		}
  1502                 }
  1582 		c = getc(f);
  1503             } while ((c < 0) && (errno == EINTR));
  1583 	    }
  1504 
  1584 	} while ((c < 0) && (errno == EINTR));
  1505             _immediateInterrupt = 0;
  1585 
  1506             if (c != EOF) {
  1586 	_immediateInterrupt = 0;
  1507                 pos = _INST(position);
  1587 
  1508                 if (_isSmallInteger(pos)) {
  1588 	if (c != EOF) {
  1509                     _INST(position) = _MKSMALLINT(_intVal(pos) + 1);
  1589 	    pos = _INST(position);
  1510                 } else {
  1590 	    if (_isSmallInteger(pos)) {
  1511                     _INST(position) = nil;
  1591 		_INST(position) = _MKSMALLINT(_intVal(pos) + 1);
  1512                 }
  1592 	    } else {
  1513                 if (_INST(binary) == true) {
  1593 		_INST(position) = nil;
  1514                     RETURN ( _MKSMALLINT(c & 0xFF) );
  1594 	    }
  1515                 }
  1595 	    if (_INST(binary) == true) {
  1516                 RETURN ( _MKCHARACTER(c & 0xFF) );
  1596 		RETURN ( _MKSMALLINT(c & 0xFF) );
  1517             }
  1597 	    }
  1518             _INST(hitEOF) = true;
  1598 	    RETURN ( _MKCHARACTER(c & 0xFF) );
  1519             _INST(position) = nil;
  1599 	}
  1520             RETURN ( nil );
  1600 	_INST(position) = nil;
  1521         }
  1601 	if (ferror(f)) {
  1522     }
  1602 	    _INST(lastErrorNumber) = _MKSMALLINT(errno);
  1523 %}
  1603 	} else {
  1524 .
  1604 	    _INST(hitEOF) = true;
       
  1605 	    RETURN ( nil );
       
  1606 	}
       
  1607     }
       
  1608 %}.
       
  1609     lastErrorNumber notNil ifTrue:[^ self readError].
  1525     filePointer isNil ifTrue:[^ self errorNotOpen].
  1610     filePointer isNil ifTrue:[^ self errorNotOpen].
  1526     self errorWriteOnly
  1611     self errorWriteOnly
  1527 !
  1612 !
  1528 
  1613 
  1529 next:count
  1614 next:count
  1531      Redefined to return a String or ByteArray instead of the default Array."
  1616      Redefined to return a String or ByteArray instead of the default Array."
  1532 
  1617 
  1533     |coll|
  1618     |coll|
  1534 
  1619 
  1535     binary ifTrue:[
  1620     binary ifTrue:[
  1536         coll := ByteArray new:count
  1621 	coll := ByteArray new:count
  1537     ] ifFalse:[
  1622     ] ifFalse:[
  1538         coll := String new:count
  1623 	coll := String new:count
  1539     ].
  1624     ].
  1540     1 to:count do: [:index |
  1625     1 to:count do: [:index |
  1541         coll at:index put:(self next)
  1626 	coll at:index put:(self next)
  1542     ].
  1627     ].
  1543     ^ coll
  1628     ^ coll
  1544 ! !
  1629 ! !
  1545 
  1630 
  1546 !ExternalStream methodsFor:'writing'!
  1631 !ExternalStream methodsFor:'writing'!
  1548 synchronizeOutput
  1633 synchronizeOutput
  1549     "write all buffered data - for buffered mode only"
  1634     "write all buffered data - for buffered mode only"
  1550 
  1635 
  1551 %{  /* NOCONTEXT */
  1636 %{  /* NOCONTEXT */
  1552 
  1637 
       
  1638     _INST(lastErrorNumber) = nil;
  1553     if (_INST(filePointer) != nil) {
  1639     if (_INST(filePointer) != nil) {
  1554         if (_INST(mode) != _readonly) {
  1640 	if (_INST(mode) != @symbol(readonly)) {
  1555             if (_INST(buffered) == true) {
  1641 	    if (_INST(buffered) == true) {
  1556                 fflush( MKFD(_INST(filePointer)) );
  1642 		fflush( MKFD(_INST(filePointer)) );
  1557             }
  1643 	    }
  1558         }
  1644 	}
  1559     }
  1645     }
  1560 %}
  1646 %}
  1561 !
  1647 !
  1562 
  1648 
  1563 nextPut:aCharacter
  1649 nextPut:aCharacter
  1570     extern errno;
  1656     extern errno;
  1571     int cnt;
  1657     int cnt;
  1572     OBJ pos;
  1658     OBJ pos;
  1573     extern int _immediateInterrupt;
  1659     extern int _immediateInterrupt;
  1574 
  1660 
  1575     if (_INST(filePointer) != nil) {
  1661     _INST(lastErrorNumber) = nil;
  1576         if (_INST(mode) != _readonly) {
  1662     if ((_INST(filePointer) != nil) 
  1577             if (_INST(binary) != true) {
  1663      && (_INST(mode) != @symbol(readonly))) {
  1578                 if (__isCharacter(aCharacter)) {
  1664 	if (_INST(binary) != true) {
  1579                     c = _intVal(_CharacterInstPtr(aCharacter)->c_asciivalue);
  1665 	    if (__isCharacter(aCharacter)) {
       
  1666 		c = _intVal(_CharacterInstPtr(aCharacter)->c_asciivalue);
  1580     doWrite:
  1667     doWrite:
  1581                     f = MKFD(_INST(filePointer));
  1668 		f = MKFD(_INST(filePointer));
  1582 
  1669 
  1583                     _immediateInterrupt = 1;
  1670 		_immediateInterrupt = 1;
  1584 #ifdef OLD
  1671 
  1585                     if (_INST(buffered) == false) {
  1672 		if ((_INST(didWrite) != true)
  1586                         cnt = write(fileno(f), &c, 1);
  1673 		 && (_INST(mode) == @symbol(readwrite))) {
  1587                     } else 
  1674 		    _INST(didWrite) = true;
  1588 #endif
  1675 		    fseek(f, 0L, 1); /* needed in stdio */
  1589                     { 
  1676 		}
  1590                         if ((_INST(didWrite) != true) && (_INST(mode) == _readwrite)) {
  1677 
  1591                             _INST(didWrite) = true;
  1678 		do {
  1592                             fseek(f, 0L, 1); /* needed in stdio */
  1679 		    cnt = fwrite(&c, 1, 1, f);
  1593                         }
  1680 	    	} while ((cnt != 1) && (errno == EINTR));
  1594                         cnt = fwrite(&c, 1, 1, f);
  1681 
  1595                     }
  1682 		if (_INST(buffered) == false) {
  1596 #ifndef OLD
  1683 		    fflush(f);
  1597                     if (_INST(buffered) == false) {
  1684 		}
  1598                         fflush(f);
  1685 
  1599                     }
  1686 		_immediateInterrupt = 0;
  1600 #endif
  1687 		if (cnt == 1) {
  1601                     _immediateInterrupt = 0;
  1688 		    pos = _INST(position);
  1602                     if (cnt == 1) {
  1689 		    if (pos != nil) {
  1603                         pos = _INST(position);
  1690 			_INST(position) = _MKSMALLINT(_intVal(pos) + 1);
  1604                         if (pos != nil) {
  1691 		    }
  1605                             _INST(position) = _MKSMALLINT(_intVal(pos) + 1);
  1692 		    RETURN ( self );
  1606                         }
  1693 		}
  1607                         RETURN ( self );
  1694 		_INST(lastErrorNumber) = _MKSMALLINT(errno);
  1608                     }
  1695 	    }
  1609                     ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
  1696 	} else {
  1610                     RETURN ( nil );
  1697 	    if (_isSmallInteger(aCharacter)) {
  1611                 }
  1698 		c = _intVal(aCharacter);
  1612             } else {
  1699 		goto doWrite;
  1613                 if (_isSmallInteger(aCharacter)) {
  1700 	    }
  1614                     c = _intVal(aCharacter);
  1701 	}
  1615                     goto doWrite;
  1702     }
  1616                 }
  1703 %}.
  1617             }
  1704     lastErrorNumber notNil ifTrue:[^ self writeError].
  1618         }
       
  1619     }
       
  1620 %}
       
  1621 .
       
  1622     filePointer isNil ifTrue:[^ self errorNotOpen].
  1705     filePointer isNil ifTrue:[^ self errorNotOpen].
  1623     (mode == #readonly) ifTrue:[^ self errorReadOnly].
  1706     (mode == #readonly) ifTrue:[^ self errorReadOnly].
  1624     binary ifFalse:[^ self argumentMustBeCharacter].
  1707     binary ifFalse:[^ self argumentMustBeCharacter].
  1625     ^ self argumentMustBeInteger.
  1708     ^ self argumentMustBeInteger.
  1626 !
  1709 !
  1637     int len, cnt;
  1720     int len, cnt;
  1638     extern errno;
  1721     extern errno;
  1639     OBJ pos;
  1722     OBJ pos;
  1640     extern int _immediateInterrupt;
  1723     extern int _immediateInterrupt;
  1641 
  1724 
  1642     if ((_INST(filePointer) != nil) && (_INST(mode) != _readonly)) {
  1725     _INST(lastErrorNumber) = nil;
  1643         cp = NULL;
  1726     if ((_INST(filePointer) != nil)
  1644         if (__isString(aCollection) || __isSymbol(aCollection)) {
  1727      && (_INST(mode) != @symbol(readonly))) {
  1645             cp = _stringVal(aCollection);
  1728 	cp = NULL;
  1646             len = _stringSize(aCollection);
  1729 	if (__isString(aCollection) || __isSymbol(aCollection)) {
  1647         } else {
  1730 	    cp = _stringVal(aCollection);
  1648             if (_INST(binary) == true) {
  1731 	    len = _stringSize(aCollection);
  1649                 if (__isByteArray(aCollection)) {
  1732 	} else {
  1650                     cp = _ByteArrayInstPtr(aCollection)->ba_element;
  1733 	    if (_INST(binary) == true) {
  1651                     len = _byteArraySize(aCollection);
  1734 		if (__isByteArray(aCollection)) {
  1652                 } else {
  1735 		    cp = _ByteArrayInstPtr(aCollection)->ba_element;
  1653                     if (__isBytes(aCollection)) {
  1736 		    len = _byteArraySize(aCollection);
  1654                         int nInst;
  1737 		} else {
  1655 
  1738 		    if (__isBytes(aCollection)) {
  1656                         cp = _ByteArrayInstPtr(aCollection)->ba_element;
  1739 			int nInst;
  1657                         len = _byteArraySize(aCollection);
  1740 
  1658                         nInst = _intVal(_ClassInstPtr(_qClass(aCollection))->c_ninstvars);
  1741 			cp = _ByteArrayInstPtr(aCollection)->ba_element;
  1659                         cp += __OBJS2BYTES__(nInst);
  1742 			len = _byteArraySize(aCollection);
  1660                         len -= __OBJS2BYTES__(nInst);
  1743 			nInst = _intVal(_ClassInstPtr(_qClass(aCollection))->c_ninstvars);
  1661                     }
  1744 			cp += __OBJS2BYTES__(nInst);
  1662                 }
  1745 			len -= __OBJS2BYTES__(nInst);
  1663             }
  1746 		    }
  1664         }
  1747 		}
  1665         if (cp != NULL) {
  1748 	    }
  1666             f = MKFD(_INST(filePointer));
  1749 	}
  1667 
  1750 	if (cp != NULL) {
  1668             _immediateInterrupt = 1;
  1751 	    f = MKFD(_INST(filePointer));
       
  1752 
       
  1753 	    _immediateInterrupt = 1;
  1669 #ifdef OLD
  1754 #ifdef OLD
  1670             if (_INST(buffered) == false) {
  1755 	    if (_INST(buffered) == false) {
  1671                 cnt = write(fileno(f), cp, len);
  1756 		cnt = write(fileno(f), cp, len);
  1672             } else 
  1757 	    } else 
  1673 #endif
  1758 #endif
  1674             { 
  1759 	    { 
  1675                 if ((_INST(didWrite) != true) && (_INST(mode) == _readwrite)) {
  1760 		if ((_INST(didWrite) != true)
  1676                     _INST(didWrite) = true;
  1761 		 && (_INST(mode) == @symbol(readwrite))) {
  1677                     fseek(f, 0L, 1); /* needed in stdio */
  1762 		    _INST(didWrite) = true;
  1678                 }
  1763 		    fseek(f, 0L, 1); /* needed in stdio */
  1679                 cnt = fwrite(cp, 1, len, f);
  1764 		}
  1680             }
  1765 		do {
       
  1766 		    cnt = fwrite(cp, 1, len, f);
       
  1767 		    if (cnt != len) {
       
  1768 			if (cnt >= 0) {
       
  1769 			    if (errno == EINTR) {
       
  1770 			   	cp += cnt;
       
  1771 				len -= cnt;
       
  1772 			    }
       
  1773 			}
       
  1774 		    }
       
  1775 	        } while ((cnt != len) && (errno == EINTR));
       
  1776 	    }
  1681 #ifndef OLD
  1777 #ifndef OLD
  1682                     if (_INST(buffered) == false) {
  1778 		    if (_INST(buffered) == false) {
  1683                         fflush(f);
  1779 			fflush(f);
  1684                     }
  1780 		    }
  1685 #endif
  1781 #endif
  1686             _immediateInterrupt = 0;
  1782 	    _immediateInterrupt = 0;
  1687             if (cnt == len) {
  1783 	    if (cnt == len) {
  1688                 pos = _INST(position);
  1784 		pos = _INST(position);
  1689                 if (pos != nil) {
  1785 		if (pos != nil) {
  1690                     _INST(position) = _MKSMALLINT(_intVal(pos) + len);
  1786 		    _INST(position) = _MKSMALLINT(_intVal(pos) + len);
  1691                 }
  1787 		}
  1692                 RETURN ( self );
  1788 		RETURN ( self );
  1693             }
  1789 	    }
  1694             ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
  1790 	    _INST(lastErrorNumber) = _MKSMALLINT(errno);
  1695             RETURN ( nil );
  1791 	}
  1696         }
  1792     }
  1697     }
  1793 %}.
  1698 %}
  1794     lastErrorNumber notNil ifTrue:[^ self writeError].
  1699 .
       
  1700     ^ super nextPutAll:aCollection
  1795     ^ super nextPutAll:aCollection
  1701 !
  1796 !
  1702 
  1797 
  1703 nextPutAll:aCollection startingAt:start to:stop
  1798 nextPutAll:aCollection startingAt:start to:stop
  1704     "write a range of elements of the argument, aCollection.
  1799     "write a range of elements of the argument, aCollection.
  1711     unsigned char *cp;
  1806     unsigned char *cp;
  1712     int len, cnt, index1, index2;
  1807     int len, cnt, index1, index2;
  1713     extern errno;
  1808     extern errno;
  1714     extern int _immediateInterrupt;
  1809     extern int _immediateInterrupt;
  1715 
  1810 
  1716     if ((_INST(filePointer) != nil) && (_INST(mode) != _readonly)) {
  1811     _INST(lastErrorNumber) = nil;
  1717         if (_isSmallInteger(start) && _isSmallInteger(stop)) {
  1812     if ((_INST(filePointer) != nil)
  1718             cp = NULL;
  1813      && (_INST(mode) != @symbol(readonly))) {
  1719             if (_INST(binary) != true) {
  1814 	if (_isSmallInteger(start) && _isSmallInteger(stop)) {
  1720                 if (__isString(aCollection) || __isSymbol(aCollection)) {
  1815 	    cp = NULL;
  1721                     cp = _stringVal(aCollection);
  1816 	    if (_INST(binary) != true) {
  1722                     len = _stringSize(aCollection);
  1817 		if (__isString(aCollection) || __isSymbol(aCollection)) {
  1723                 }
  1818 		    cp = _stringVal(aCollection);
  1724             } else {
  1819 		    len = _stringSize(aCollection);
  1725                 if (__isByteArray(aCollection)) {
  1820 		}
  1726                     cp = _ByteArrayInstPtr(aCollection)->ba_element;
  1821 	    } else {
  1727                     len = _byteArraySize(aCollection);
  1822 		if (__isByteArray(aCollection)) {
  1728                 } else {
  1823 		    cp = _ByteArrayInstPtr(aCollection)->ba_element;
  1729                     if (__isBytes(aCollection)) {
  1824 		    len = _byteArraySize(aCollection);
  1730                         int nInst;
  1825 		} else {
  1731 
  1826 		    if (__isBytes(aCollection)) {
  1732                         cp = _ByteArrayInstPtr(aCollection)->ba_element;
  1827 			int nInst;
  1733                         len = _byteArraySize(aCollection);
  1828 
  1734                         nInst = _intVal(_ClassInstPtr(_qClass(aCollection))->c_ninstvars);
  1829 			cp = _ByteArrayInstPtr(aCollection)->ba_element;
  1735                         cp += __OBJS2BYTES__(nInst);
  1830 			len = _byteArraySize(aCollection);
  1736                         len -= __OBJS2BYTES__(nInst);
  1831 			nInst = _intVal(_ClassInstPtr(_qClass(aCollection))->c_ninstvars);
  1737                     }
  1832 			cp += __OBJS2BYTES__(nInst);
  1738                 }
  1833 			len -= __OBJS2BYTES__(nInst);
  1739             }
  1834 		    }
  1740             if (cp != NULL) {
  1835 		}
  1741                 f = MKFD(_INST(filePointer));
  1836 	    }
  1742                 index1 = _intVal(start);
  1837 	    if (cp != NULL) {
  1743                 index2 = _intVal(stop);
  1838 		f = MKFD(_INST(filePointer));
  1744                 if ((index1 < 1) || (index2 > len) || (index2 < index1)) {
  1839 		index1 = _intVal(start);
  1745                     RETURN ( self );
  1840 		index2 = _intVal(stop);
  1746                 }
  1841 		if ((index1 < 1) || (index2 > len) || (index2 < index1)) {
  1747                 if (index2 > len)
  1842 		    RETURN ( self );
  1748                     index2 = len;
  1843 		}
  1749 
  1844 		if (index2 > len)
  1750                 _immediateInterrupt = 1;
  1845 		    index2 = len;
  1751                 len = index2 - index1 + 1;
  1846 
  1752 #ifdef OLD
  1847 		_immediateInterrupt = 1;
  1753                 if (_INST(buffered) == false) {
  1848 		len = index2 - index1 + 1;
  1754                     cnt = write(fileno(f), cp + index1 - 1, len);
  1849 
  1755                 } else 
  1850 		if ((_INST(didWrite) != true)
  1756 #endif
  1851 		 && (_INST(mode) == @symbol(readwrite))) {
  1757                 { 
  1852 		    _INST(didWrite) = true;
  1758                     if ((_INST(didWrite) != true) && (_INST(mode) == _readwrite)) {
  1853 		    fseek(f, 0L, 1); /* needed in stdio */
  1759                         _INST(didWrite) = true;
  1854 		}
  1760                         fseek(f, 0L, 1); /* needed in stdio */
  1855 		
  1761                     }
  1856 		do {
  1762                     cnt = fwrite(cp + index1 - 1, 1, len, f);
  1857 		    cnt = fwrite(cp + index1 - 1, 1, len, f);
  1763                 }
  1858 		    if (cnt != len) {
  1764 #ifndef OLD
  1859 		        if (cnt >= 0) {
  1765                     if (_INST(buffered) == false) {
  1860 			    if (errno == EINTR) {
  1766                         fflush(f);
  1861 			   	cp += cnt;
  1767                     }
  1862 				len -= cnt;
  1768 #endif
  1863 			    }
  1769                 _immediateInterrupt = 0;
  1864 			}
  1770                 if (cnt == len) {
  1865 		    }
  1771                     if (_INST(position) != nil) {
  1866 	        } while ((cnt != len) && (errno == EINTR));
  1772                         _INST(position) = _MKSMALLINT(_intVal(_INST(position)) + len);
  1867 
  1773                     }
  1868 		if (_INST(buffered) == false) {
  1774                     RETURN ( self );
  1869 		    fflush(f);
  1775                 }
  1870 		}
  1776                 ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
  1871 
  1777                 RETURN ( nil );
  1872 		_immediateInterrupt = 0;
  1778             }
  1873 		if (cnt == len) {
  1779         }
  1874 		    if (_INST(position) != nil) {
  1780     }
  1875 			_INST(position) = _MKSMALLINT(_intVal(_INST(position)) + len);
  1781 %}
  1876 		    }
  1782 .
  1877 		    RETURN ( self );
       
  1878 		}
       
  1879 		_INST(lastErrorNumber) = _MKSMALLINT(errno);
       
  1880 	    }
       
  1881 	}
       
  1882     }
       
  1883 %}.
       
  1884     lastErrorNumber notNil ifTrue:[^ self writeError].
  1783     ^ super nextPutAll:aCollection startingAt:start to:stop
  1885     ^ super nextPutAll:aCollection startingAt:start to:stop
  1784 !
  1886 !
  1785 
  1887 
  1786 cr
  1888 cr
  1787     "reimplemented for speed"
  1889     "reimplemented for speed"
  1791     FILE *f;
  1893     FILE *f;
  1792     extern errno;
  1894     extern errno;
  1793     extern int _immediateInterrupt;
  1895     extern int _immediateInterrupt;
  1794     int cnt;
  1896     int cnt;
  1795 
  1897 
  1796     if ((_INST(filePointer) != nil) && (_INST(mode) != _readonly)) {
  1898     _INST(lastErrorNumber) = nil;
  1797         if (_INST(binary) != true) {
  1899     if ((_INST(filePointer) != nil)
  1798             f = MKFD(_INST(filePointer));
  1900      && (_INST(mode) != @symbol(readonly))) {
  1799 
  1901 	if (_INST(binary) != true) {
  1800             _immediateInterrupt = 1;
  1902 	    f = MKFD(_INST(filePointer));
  1801 #ifdef OLD
  1903 
  1802             if (_INST(buffered) == false) {
  1904 	    _immediateInterrupt = 1;
  1803                 cnt = write(fileno(f), "\n", 1);
  1905 
  1804             } else 
  1906 	    if ((_INST(didWrite) != true)
  1805 #endif
  1907 	     && (_INST(mode) == @symbol(readwrite))) {
  1806             { 
  1908 		_INST(didWrite) = true;
  1807                 if ((_INST(didWrite) != true) && (_INST(mode) == _readwrite)) {
  1909 		fseek(f, 0L, 1); /* needed in stdio */
  1808                     _INST(didWrite) = true;
  1910 	    }
  1809                     fseek(f, 0L, 1); /* needed in stdio */
  1911 
  1810                 }
  1912 	    do {
  1811                 cnt = fwrite("\n", 1, 1, f);
  1913 		cnt = fwrite("\n", 1, 1, f);
  1812             }
  1914 	    } while ((cnt != 1) && (errno == EINTR));
  1813 #ifndef OLD
  1915 
  1814                     if (_INST(buffered) == false) {
  1916 	    if (_INST(buffered) == false) {
  1815                         fflush(f);
  1917 		fflush(f);
  1816                     }
  1918 	    }
  1817 #endif
  1919 
  1818             _immediateInterrupt = 0;
  1920 	    _immediateInterrupt = 0;
  1819             if (cnt == 1) {
  1921 	    if (cnt == 1) {
  1820                 if (_INST(position) != nil) {
  1922 		if (_INST(position) != nil) {
  1821                     _INST(position) = _MKSMALLINT(_intVal(_INST(position)) + 1);
  1923 		    _INST(position) = _MKSMALLINT(_intVal(_INST(position)) + 1);
  1822                 }
  1924 		}
  1823                 RETURN ( self );
  1925 		RETURN ( self );
  1824             }
  1926 	    }
  1825             ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
  1927 	    _INST(lastErrorNumber) = _MKSMALLINT(errno);
  1826             return ( nil );
  1928 	}
  1827         }
  1929     }
  1828     }
  1930 %}.
  1829 %}
  1931     lastErrorNumber notNil ifTrue:[^ self writeError].
  1830 .
       
  1831     filePointer isNil ifTrue:[^ self errorNotOpen].
  1932     filePointer isNil ifTrue:[^ self errorNotOpen].
  1832     (mode == #readonly) ifTrue:[^ self errorReadOnly].
  1933     (mode == #readonly) ifTrue:[^ self errorReadOnly].
  1833     self errorBinary
  1934     self errorBinary
  1834 ! !
  1935 ! !
  1835 
  1936 
  1851     char *rslt;
  1952     char *rslt;
  1852     extern errno;
  1953     extern errno;
  1853     int fd, ch;
  1954     int fd, ch;
  1854     int _buffered;
  1955     int _buffered;
  1855 
  1956 
  1856     if ((_INST(filePointer) != nil) && (_INST(mode) != _writeonly)) {
  1957     _INST(lastErrorNumber) = nil;
  1857         if (_INST(binary) != true) {
  1958     if ((_INST(filePointer) != nil)
  1858             f = MKFD(_INST(filePointer));
  1959      && (_INST(mode) != @symbol(writeonly))) {
  1859             _immediateInterrupt = 1;
  1960 	if (_INST(binary) != true) {
  1860             buffer[0] = 0;
  1961 	    f = MKFD(_INST(filePointer));
  1861 
  1962 	    _immediateInterrupt = 1;
  1862             _buffered = (_INST(buffered) == true);
  1963 	    buffer[0] = 0;
  1863 
  1964 
  1864             /*
  1965 	    _buffered = (_INST(buffered) == true);
  1865              * mhmh - the following code looks ok to me,
  1966 
  1866              * but seems not to work for sockets
  1967 	    /*
  1867              */
  1968 	     * mhmh - the following code looks ok to me,
       
  1969 	     * but seems not to work for sockets
       
  1970 	     */
  1868 #ifdef DOES_NOT_WORK
  1971 #ifdef DOES_NOT_WORK
  1869             if (_INST(mode) == _readwrite)
  1972 	    if (_INST(mode) == _readwrite)
  1870                 fseek(f, 0L, 1); /* needed in stdio */
  1973 		fseek(f, 0L, 1); /* needed in stdio */
  1871             do {
  1974 	    do {
  1872                 rslt = fgets(buffer, sizeof(buffer), f);
  1975 		rslt = fgets(buffer, sizeof(buffer), f);
  1873             } while ((rslt == NULL) && (errno == EINTR));
  1976 	    } while ((rslt == NULL) && (errno == EINTR));
  1874 #else
  1977 #else
  1875             if (_buffered) {
  1978 	    if (_buffered) {
  1876                 if ((_INST(didWrite) != false) && (_INST(mode) == _readwrite)) {
  1979 		if ((_INST(didWrite) != false)
  1877                     _INST(didWrite) = false;
  1980 		 && (_INST(mode) == @symbol(readwrite))) {
  1878                     fseek(f, 0L, 1); /* needed in stdio */
  1981 		    _INST(didWrite) = false;
  1879                 }
  1982 		    fseek(f, 0L, 1); /* needed in stdio */
  1880             }
  1983 		}
  1881             rslt = buffer;
  1984 	    }
  1882             fd = fileno(f);
  1985 	    rslt = buffer;
  1883             for (;;) {
  1986 	    fd = fileno(f);
  1884                 if (_buffered) {
  1987 	    for (;;) {
  1885                     ch = getc(f);
  1988 		if (_buffered) {
  1886                     if (ch == EOF)
  1989 		    ch = getc(f);
  1887                         len = 0;
  1990 		    if (ch == EOF) {
  1888                     else {
  1991 			if (ferror(f)) {
  1889                         len = 1;
  1992 			    if (errno == EINTR) {
  1890                         *rslt = ch;
  1993 				clearerr(f);
  1891                     }
  1994 				continue;
  1892                 } else {
  1995 			    }
  1893                     do {
  1996 			    _INST(lastErrorNumber) = _MKSMALLINT(errno);
  1894                         len = read(fd, rslt, 1);
  1997 			}
  1895                     } while ((len < 0) && (errno == EINTR));
  1998 			len = 0;
  1896                 }
  1999 		    } else {
  1897                 if (len <= 0) {
  2000 			len = 1;
  1898                     if (rslt == buffer) {
  2001 			*rslt = ch;
  1899                         rslt = NULL;
  2002 		    }
  1900                     } else {
  2003 		} else {
  1901                         *rslt = '\0';
  2004 		    do {
  1902                     }
  2005 			len = read(fd, rslt, 1);
  1903                     break;
  2006 		    } while ((len < 0) && (errno == EINTR));
  1904                 }
  2007 		}
  1905                 rslt++;
  2008 		if (len <= 0) {
  1906                 if (*(rslt-1) == '\n') {
  2009 		    if (rslt == buffer) {
  1907                     *rslt = '\0';
  2010 			rslt = NULL;
  1908                     break;
  2011 		    } else {
  1909                 }
  2012 			*rslt = '\0';
  1910                 if (rslt == (buffer + sizeof(buffer) - 1)) {
  2013 		    }
  1911                     *rslt = '\0';
  2014 		    break;
  1912                     break;
  2015 		}
  1913                 }
  2016 		rslt++;
  1914             }
  2017 		if (*(rslt-1) == '\n') {
       
  2018 		    *rslt = '\0';
       
  2019 		    break;
       
  2020 		}
       
  2021 		if (rslt == (buffer + sizeof(buffer) - 1)) {
       
  2022 		    *rslt = '\0';
       
  2023 		    break;
       
  2024 		}
       
  2025 	    }
  1915 #endif
  2026 #endif
  1916             _immediateInterrupt = 0;
  2027 	    _immediateInterrupt = 0;
  1917             if (rslt != NULL) {
  2028 	    if (rslt != NULL) {
  1918                 len = strlen(buffer);
  2029 		len = strlen(buffer);
  1919                 if (_INST(position) != nil) {
  2030 		if (_INST(position) != nil) {
  1920                     _INST(position) = _MKSMALLINT(_intVal(_INST(position)) + len + 1);
  2031 		    _INST(position) = _MKSMALLINT(_intVal(_INST(position)) + len + 1);
  1921                 }
  2032 		}
  1922                 /* remove EOL character */
  2033 		/* remove EOL character */
  1923                 if ((len != 0) && (buffer[len-1] == '\n')) {
  2034 		if ((len != 0) && (buffer[len-1] == '\n')) {
  1924                     buffer[--len] = '\0';
  2035 		    buffer[--len] = '\0';
  1925                 }
  2036 		}
  1926                 if ((len != 0) && (buffer[len-1] == '\r')) {
  2037 		if ((len != 0) && (buffer[len-1] == '\r')) {
  1927                     buffer[--len] = '\0';
  2038 		    buffer[--len] = '\0';
  1928                 }
  2039 		}
  1929                 RETURN ( _MKSTRING(buffer COMMA_CON) );
  2040 		RETURN ( _MKSTRING(buffer COMMA_CON) );
  1930             }
  2041 	    }
  1931             _INST(hitEOF) = true;
  2042 	    if (ferror(f)) {
  1932             RETURN ( nil );
  2043 		_INST(lastErrorNumber) = _MKSMALLINT(errno);
  1933         }
  2044 	    } else {
  1934     }
  2045 		_INST(hitEOF) = true;
  1935 %}
  2046 		RETURN ( nil );
  1936 .
  2047 	    }
       
  2048 	}
       
  2049     }
       
  2050 %}.
       
  2051     lastErrorNumber notNil ifTrue:[^ self readError].
  1937     filePointer isNil ifTrue:[^ self errorNotOpen].
  2052     filePointer isNil ifTrue:[^ self errorNotOpen].
  1938     (mode == #writeonly) ifTrue:[^ self errorWriteOnly].
  2053     (mode == #writeonly) ifTrue:[^ self errorWriteOnly].
  1939     self errorBinary
  2054     self errorBinary
  1940 !
  2055 !
  1941 
  2056 
  1949     OBJ pos;
  2064     OBJ pos;
  1950     char *s;
  2065     char *s;
  1951     extern errno;
  2066     extern errno;
  1952     extern int _immediateInterrupt;
  2067     extern int _immediateInterrupt;
  1953 
  2068 
  1954     if ((_INST(filePointer) != nil) && (_INST(mode) != _readonly)) {
  2069     _INST(lastErrorNumber) = nil;
  1955         if (_INST(binary) != true) {
  2070     if ((_INST(filePointer) != nil) 
  1956             if (__isString(aString)) {
  2071      && (_INST(mode) != @symbol(readonly))) {
  1957                 f = MKFD(_INST(filePointer));
  2072 	if (_INST(binary) != true) {
  1958                 s = (char *) _stringVal(aString);
  2073 	    if (__isString(aString)) {
  1959                 len = _stringSize(aString);
  2074 		f = MKFD(_INST(filePointer));
  1960 
  2075 		s = (char *) _stringVal(aString);
  1961                 _immediateInterrupt = 1;
  2076 		len = _stringSize(aString);
       
  2077 
       
  2078 		_immediateInterrupt = 1;
  1962 #ifdef OLD
  2079 #ifdef OLD
  1963                 if (_INST(buffered) == false) {
  2080 		if (_INST(buffered) == false) {
  1964                     cnt = write(fileno(f), s, len);
  2081 		    cnt = write(fileno(f), s, len);
  1965                 } else 
  2082 		} else 
  1966 #endif
  2083 #endif
  1967                 { 
  2084 		{ 
  1968                     if ((_INST(didWrite) != true) && (_INST(mode) == _readwrite)) {
  2085 		    if ((_INST(didWrite) != true)
  1969                         _INST(didWrite) = true;
  2086 		     && (_INST(mode) == @symbol(readwrite))) {
  1970                         fseek(f, 0L, 1); /* needed in stdio */
  2087 			_INST(didWrite) = true;
  1971                     }
  2088 			fseek(f, 0L, 1); /* needed in stdio */
  1972                     cnt = fwrite(s, 1, len, f);
  2089 		    }
  1973                 }
  2090 		    cnt = fwrite(s, 1, len, f);
  1974                 if (cnt == len) {
  2091 		}
       
  2092 		if (cnt == len) {
  1975 #ifdef OLD
  2093 #ifdef OLD
  1976                     if (_INST(buffered) == false) {
  2094 		    if (_INST(buffered) == false) {
  1977                         cnt = write(fileno(f), "\n", 1);
  2095 			cnt = write(fileno(f), "\n", 1);
  1978                     } else 
  2096 		    } else 
  1979 #endif
  2097 #endif
  1980                     { 
  2098 		    { 
  1981                         cnt = fwrite("\n", 1, 1, f);
  2099 			cnt = fwrite("\n", 1, 1, f);
  1982                     }
  2100 		    }
  1983 #ifndef OLD
  2101 #ifndef OLD
  1984                     if (_INST(buffered) == false) {
  2102 		    if (_INST(buffered) == false) {
  1985                         fflush(f);
  2103 			fflush(f);
  1986                     }
  2104 		    }
  1987 #endif
  2105 #endif
  1988                     if (cnt == 1) {
  2106 		    if (cnt == 1) {
  1989                         pos = _INST(position);
  2107 			pos = _INST(position);
  1990                         if (pos != nil) {
  2108 			if (pos != nil) {
  1991                             _INST(position) = _MKSMALLINT(_intVal(pos)+len+1);
  2109 			    _INST(position) = _MKSMALLINT(_intVal(pos)+len+1);
  1992                         }
  2110 			}
  1993                         _immediateInterrupt = 0;
  2111 			_immediateInterrupt = 0;
  1994                         RETURN ( self );
  2112 			RETURN ( self );
  1995                     }
  2113 		    }
  1996                 }
  2114 		}
  1997                 _immediateInterrupt = 0;
  2115 		_immediateInterrupt = 0;
  1998                 ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
  2116 		_INST(lastErrorNumber) = _MKSMALLINT(errno);
  1999                 RETURN ( nil );
  2117 	    }
  2000             }
  2118 	}
  2001         }
  2119     }
  2002     }
  2120 %}.
  2003 %}
  2121     lastErrorNumber notNil ifTrue:[^ self writeError].
  2004 .
       
  2005     super nextPutAll:aString.
  2122     super nextPutAll:aString.
  2006     self cr.
  2123     self cr.
  2007 !
  2124 !
  2008 
  2125 
  2009 nextPutLinesFrom:aStream upToLineStartingWith:aStringOrNil
  2126 nextPutLinesFrom:aStream upToLineStartingWith:aStringOrNil
  2010     "read from aStream up to and including a line starting with aStringOrNil
  2127     "read from aStream up to and including a line starting with aStringOrNil
  2011      and append it to self. 
  2128      and append it to self. 
  2012      can be used to copy/create large files or copy from a pipe/socket.
  2129      Can be used to copy/create large files or copy from a pipe/socket.
  2013 
  2130 
  2014      If aStringOrNil is nil or not matched, copy preceeds to the end.
  2131      If aStringOrNil is nil or not matched, copy preceeds to the end.
  2015      (this allows for example to read a Socket and transfer the data quickly
  2132      (this allows for example to read a Socket and transfer the data quickly
  2016       into a file - without creating zillions of temporary strings)"
  2133       into a file - without creating zillions of temporary strings)"
  2017 
  2134 
  2018     |srcFilePointer|
  2135     |srcFilePointer readError|
  2019 
  2136 
  2020     (mode == #readonly) ifTrue:[^ self errorReadOnly].
  2137     (mode == #readonly) ifTrue:[^ self errorReadOnly].
  2021     filePointer isNil ifTrue:[^ self errorNotOpen].
  2138     filePointer isNil ifTrue:[^ self errorNotOpen].
  2022     srcFilePointer := aStream filePointer.
  2139     srcFilePointer := aStream filePointer.
  2023     srcFilePointer isNil ifTrue:[^ aStream errorNotOpen].
  2140     srcFilePointer isNil ifTrue:[^ aStream errorNotOpen].
  2028     char *matchString;
  2145     char *matchString;
  2029     int matchLen = 0;
  2146     int matchLen = 0;
  2030     char buffer[1024];
  2147     char buffer[1024];
  2031     extern int _immediateInterrupt;
  2148     extern int _immediateInterrupt;
  2032 
  2149 
  2033     if (_isSmallInteger(srcFilePointer) 
  2150     _INST(lastErrorNumber) = nil;
  2034 #ifdef OLD
  2151     if (_isSmallInteger(srcFilePointer)) {
  2035      && (_INST(buffered) == true)
  2152 	if ((aStringOrNil == nil) || __isString(aStringOrNil)) {
       
  2153 	    if (aStringOrNil != nil) {
       
  2154 		matchString = (char *) _stringVal(aStringOrNil);
       
  2155 		matchLen = _stringSize(aStringOrNil);
       
  2156 	    }
       
  2157 	    dst = MKFD(_INST(filePointer));
       
  2158 	    src = (FILE *)_intVal(srcFilePointer);
       
  2159 	    _immediateInterrupt = 1;
       
  2160 	    errno = 0;
       
  2161 
       
  2162 	    if ((_INST(didWrite) != true)
       
  2163 	     && (_INST(mode) == @symbol(readwrite))) {
       
  2164 		_INST(didWrite) = true;
       
  2165 		fseek(dst, 0L, 1); /* needed in stdio */
       
  2166 	    }
       
  2167 
       
  2168 	    for (;;) {
       
  2169 		if (fgets(buffer, sizeof(buffer), src) == NULL) {
       
  2170 		    if (ferror(src)) {
       
  2171 			readError = _MKSMALLINT(errno);
       
  2172 			goto err;
       
  2173 		    }
       
  2174 		    break;
       
  2175 		}
       
  2176 		if (fputs(buffer, dst) == EOF) {
       
  2177 		    if (ferror(dst)) {
       
  2178 			_INST(lastErrorNumber) = _MKSMALLINT(errno);
       
  2179 			goto err;
       
  2180 		    }
       
  2181 		    break;
       
  2182 		}
       
  2183 #ifndef OLD
       
  2184 		if (_INST(buffered) == false) {
       
  2185 		    fflush(dst);
       
  2186 		}
  2036 #endif
  2187 #endif
  2037     ) {
  2188 		if (matchLen) {
  2038         if ((aStringOrNil == nil) || __isString(aStringOrNil)) {
  2189 		    if (strncmp(matchString, buffer, matchLen) == 0) 
  2039             if (aStringOrNil != nil) {
  2190 			break;
  2040                 matchString = (char *) _stringVal(aStringOrNil);
  2191 		}
  2041                 matchLen = _stringSize(aStringOrNil);
  2192 	    }
  2042             }
  2193 	    _immediateInterrupt = 0;
  2043             dst = MKFD(_INST(filePointer));
  2194 	    _INST(position) = nil;
  2044             src = (FILE *)_intVal(srcFilePointer);
  2195 	    RETURN (self);
  2045             _immediateInterrupt = 1;
  2196 	}
  2046             for (;;) {
  2197     }
  2047                 if (fgets(buffer, sizeof(buffer), src) == NULL) break;
  2198 err: ;
  2048                 if (fputs(buffer, dst) == EOF) break;
  2199 %}.
  2049 #ifndef OLD
  2200     readError ifTrue:[
  2050                     if (_INST(buffered) == false) {
  2201 	aStream setLastErrorNumber:readError.
  2051                         fflush(dst);
  2202 	^ aStream readError
  2052                     }
  2203     ].
  2053 #endif
  2204     lastErrorNumber notNil ifTrue:[^ self writeError].
  2054                 if (matchLen) {
       
  2055                     if (strncmp(matchString, buffer, matchLen) == 0) 
       
  2056                         break;
       
  2057                 }
       
  2058             }
       
  2059             _immediateInterrupt = 0;
       
  2060             _INST(position) = nil;
       
  2061             RETURN ( self );
       
  2062         }
       
  2063     }
       
  2064 %}
       
  2065 .
       
  2066     buffered ifFalse:[^ self errorNotBuffered].
  2205     buffered ifFalse:[^ self errorNotBuffered].
       
  2206     "
       
  2207      argument error
       
  2208     "
  2067     ^ self primitiveFailed
  2209     ^ self primitiveFailed
  2068 !
  2210 !
  2069 
  2211 
  2070 peekForLineStartingWith:aString
  2212 peekForLineStartingWith:aString
  2071     "read ahead for next line starting with aString;
  2213     "read ahead for next line starting with aString;
  2072      return the line-string if found, nil otherwise.
  2214      return the line-string if found, or nil if EOF is encountered.
  2073      Do not advance position i.e. nextLine will reread this line"
  2215      If matched, not advance position behond that line
       
  2216      i.e. nextLine will read the matched line.
       
  2217      If not matched, reposition to original position for firther reading."
  2074 
  2218 
  2075     (mode == #writeonly) ifTrue:[^ self errorWriteOnly].
  2219     (mode == #writeonly) ifTrue:[^ self errorWriteOnly].
  2076     filePointer isNil ifTrue:[^ self errorNotOpen].
  2220     filePointer isNil ifTrue:[^ self errorNotOpen].
  2077     binary ifTrue:[^ self errorBinary].
  2221     binary ifTrue:[^ self errorBinary].
  2078 
  2222 
  2083     char *cp;
  2227     char *cp;
  2084     char *matchString;
  2228     char *matchString;
  2085     int  firstpos = -1, lastpos;
  2229     int  firstpos = -1, lastpos;
  2086     extern int _immediateInterrupt;
  2230     extern int _immediateInterrupt;
  2087 
  2231 
       
  2232     _INST(lastErrorNumber) = nil;
  2088     if (__isString(aString)) {
  2233     if (__isString(aString)) {
  2089         matchString = (char *) _stringVal(aString);
  2234 	matchString = (char *) _stringVal(aString);
  2090         l = _stringSize(aString);
  2235 	l = _stringSize(aString);
  2091 
  2236 
  2092         f = MKFD(_INST(filePointer));
  2237 	f = MKFD(_INST(filePointer));
  2093 
  2238 
  2094         if ((_INST(didWrite) != false) && (_INST(mode) == _readwrite)) {
  2239 	if ((_INST(didWrite) != false)
  2095             _INST(didWrite) = false;
  2240 	 && (_INST(mode) == @symbol(readwrite))) {
  2096             fseek(f, 0L, 1); /* needed in stdio */
  2241 	    _INST(didWrite) = false;
  2097         }
  2242 	    fseek(f, 0L, 1); /* needed in stdio */
  2098 
  2243 	}
  2099         for (;;) {
  2244 
  2100             lastpos = ftell(f);
  2245 	for (;;) {
  2101             if (firstpos == -1) firstpos = lastpos;
  2246 	    lastpos = ftell(f);
  2102 
  2247 	    if (firstpos == -1) firstpos = lastpos;
  2103             _immediateInterrupt = 1;
  2248 
  2104             do {
  2249 	    _immediateInterrupt = 1;
  2105                 cp = fgets(buffer, sizeof(buffer), f);
  2250 	    do {
  2106             } while ((cp == NULL) && (errno == EINTR));
  2251 		cp = fgets(buffer, sizeof(buffer), f);
  2107             _immediateInterrupt = 0;
  2252 	    } while ((cp == NULL) && (errno == EINTR));
  2108 
  2253 	    _immediateInterrupt = 0;
  2109             if (cp == NULL) {
  2254 
  2110                 fseek(f, firstpos, 0);
  2255 	    if (cp == NULL) {
  2111                 RETURN ( nil );
  2256 		if (ferror(f)) {
  2112             }
  2257 		    _INST(lastErrorNumber) = _MKSMALLINT(errno);
  2113             if (strncmp(cp, matchString, l) == 0) {
  2258 		    goto err;
  2114                 fseek(f, lastpos, 0);
  2259 		} else {
  2115                 break;
  2260 		    fseek(f, firstpos, 0);
  2116             }
  2261 		    RETURN (nil);
  2117         }
  2262 		}
  2118         /* remove EOL character */
  2263 	    }
  2119         cp = buffer;
  2264 	    if (strncmp(cp, matchString, l) == 0) {
  2120         while (*cp && (*cp != '\n')) cp++;
  2265 		fseek(f, lastpos, 0);
  2121         *cp = '\0';
  2266 		break;
  2122         RETURN ( _MKSTRING(buffer COMMA_CON) );
  2267 	    }
  2123     }
  2268 	}
  2124 %}
  2269 	/* remove EOL character */
  2125 .
  2270 	cp = buffer;
  2126     self argumentMustBeString
  2271 	while (*cp && (*cp != '\n')) cp++;
       
  2272 	*cp = '\0';
       
  2273 	RETURN ( _MKSTRING(buffer COMMA_CON) );
       
  2274     }
       
  2275 err: ;
       
  2276 %}.
       
  2277     lastErrorNumber notNil ifTrue:[^ self readError].
       
  2278     ^ self argumentMustBeString
  2127 !
  2279 !
  2128 
  2280 
  2129 peekForLineStartingWithAny:aCollectionOfStrings
  2281 peekForLineStartingWithAny:aCollectionOfStrings
  2130     "read ahead for next line starting with any of aCollectionOfStrings;
  2282     "read ahead for next line starting with any of aCollectionOfStrings;
  2131      return the index in aCollection if found, nil otherwise..
  2283      return the index in aCollection if found, nil otherwise..
  2138     filePointer isNil ifTrue:[^ self errorNotOpen].
  2290     filePointer isNil ifTrue:[^ self errorNotOpen].
  2139     binary ifTrue:[^ self errorBinary].
  2291     binary ifTrue:[^ self errorBinary].
  2140 
  2292 
  2141     startPos := self position.
  2293     startPos := self position.
  2142     [self atEnd] whileFalse:[
  2294     [self atEnd] whileFalse:[
  2143         linePos := self position.
  2295 	linePos := self position.
  2144         line := self nextLine.
  2296 	line := self nextLine.
  2145         index := 1.
  2297 	line notNil ifTrue:[
  2146         aCollectionOfStrings do:[:prefix |
  2298 	    index := 1.
  2147             (line startsWith:prefix) ifTrue:[
  2299 	    aCollectionOfStrings do:[:prefix |
  2148                 self position:linePos.
  2300 		(line startsWith:prefix) ifTrue:[
  2149                 ^ index
  2301 		    self position:linePos.
  2150             ].
  2302 		    ^ index
  2151             index := index + 1
  2303 		].
  2152         ]
  2304 		index := index + 1
       
  2305 	    ]
       
  2306 	]
  2153     ].
  2307     ].
  2154     self position:startPos.
  2308     self position:startPos.
  2155     ^ nil
  2309     ^ nil
  2156 ! !
  2310 ! !
  2157 
  2311 
  2167     OBJ _true = true;
  2321     OBJ _true = true;
  2168     int c;
  2322     int c;
  2169     extern int _immediateInterrupt;
  2323     extern int _immediateInterrupt;
  2170 
  2324 
  2171     if (_INST(hitEOF) == _true) {
  2325     if (_INST(hitEOF) == _true) {
  2172         RETURN (_true);
  2326 	RETURN (_true);
  2173     }
  2327     }
       
  2328     _INST(lastErrorNumber) = nil;
  2174     if ((t = _INST(filePointer)) != nil) {
  2329     if ((t = _INST(filePointer)) != nil) {
  2175         f = MKFD(t);
  2330 	f = MKFD(t);
  2176 #ifdef OLD
  2331 #ifdef OLD
  2177         RETURN ( feof(f) ? _true : false );
  2332 	RETURN ( feof(f) ? _true : false );
  2178 #else
  2333 #else
  2179         _immediateInterrupt = 1;
  2334 	if ((_INST(didWrite) != false)
  2180         c = getc(f);
  2335 	 && (_INST(mode) == @symbol(readwrite))) {
  2181         _immediateInterrupt = 0;
  2336 	    _INST(didWrite) = false;
  2182         if (c == EOF) {
  2337 	    fseek(f, 0L, 1); /* needed in stdio */
  2183             _INST(hitEOF) = _true;
  2338 	}
  2184             RETURN (_true);
  2339 
  2185         }
  2340 	_immediateInterrupt = 1;
  2186         ungetc(c, f);
  2341 	c = getc(f);
  2187         RETURN (false);
  2342 	_immediateInterrupt = 0;
       
  2343 	if (c != EOF) {
       
  2344 	    ungetc(c, f);
       
  2345 	    RETURN (false);
       
  2346 	}
       
  2347 	if (ferror(f)) {
       
  2348 	    _INST(lastErrorNumber) = _MKSMALLINT(errno);
       
  2349 	} else {
       
  2350 	    _INST(hitEOF) = _true;
       
  2351 	    RETURN (_true);
       
  2352 	}
  2188 #endif
  2353 #endif
  2189     }
  2354     }
  2190 %}
  2355 %}.
  2191 .
  2356     lastErrorNumber notNil ifTrue:[^ self readError].
  2192     self errorNotOpen
  2357     ^ self errorNotOpen
  2193 !
  2358 !
  2194 
  2359 
  2195 canReadWithoutBlocking
  2360 canReadWithoutBlocking
  2196     "return true, if any data is available for reading (i.e.
  2361     "return true, if any data is available for reading (i.e.
  2197      a read operation will not block the smalltalk process), false otherwise."
  2362      a read operation will not block the smalltalk process), false otherwise."
  2198 
  2363 
  2199     |fd|
  2364     |fd|
  2200 
  2365 
  2201     filePointer isNil ifTrue:[
  2366     filePointer isNil ifTrue:[^ self errorNotOpen].
  2202         ^ self errorNotOpen
  2367     mode == #writeonly ifTrue:[^ self errorWriteOnly].
  2203     ].
       
  2204     mode == #writeonly ifTrue:[
       
  2205         ^ self errorWriteOnly
       
  2206     ].
       
  2207 
  2368 
  2208     fd := self fileDescriptor.
  2369     fd := self fileDescriptor.
  2209     ^ OperatingSystem readCheck:fd
  2370     ^ OperatingSystem readCheck:fd
  2210 
  2371 
  2211     "
  2372     "
  2212      |pipe|
  2373      |pipe|
  2213 
  2374 
  2214      pipe := PipeStream readingFrom:'(sleep 10; echo hello)'.
  2375      pipe := PipeStream readingFrom:'(sleep 10; echo hello)'.
  2215      pipe canReadWithoutBlocking ifTrue:[
  2376      pipe canReadWithoutBlocking ifTrue:[
  2216          Transcript showCr:'data available'
  2377 	 Transcript showCr:'data available'
  2217      ] ifFalse:[
  2378      ] ifFalse:[
  2218          Transcript showCr:'no data available'
  2379 	 Transcript showCr:'no data available'
  2219      ].
  2380      ].
  2220      pipe close
  2381      pipe close
  2221     "
  2382     "
  2222 !
  2383 !
  2223 
  2384 
  2225     "return true, if data can be written into the stream 
  2386     "return true, if data can be written into the stream 
  2226      (i.e. a write operation will not block the smalltalk process)."
  2387      (i.e. a write operation will not block the smalltalk process)."
  2227 
  2388 
  2228     |fd|
  2389     |fd|
  2229 
  2390 
  2230     filePointer isNil ifTrue:[
  2391     filePointer isNil ifTrue:[^ self errorNotOpen].
  2231         ^ self errorNotOpen
  2392     mode == #readonly ifTrue:[^ self errorReadOnly].
  2232     ].
       
  2233     mode == #readonly ifTrue:[
       
  2234         ^ self errorReadOnly
       
  2235     ].
       
  2236 
  2393 
  2237     fd := self fileDescriptor.
  2394     fd := self fileDescriptor.
  2238     ^ OperatingSystem writeCheck:fd
  2395     ^ OperatingSystem writeCheck:fd
  2239 ! !
  2396 ! !
  2240 
  2397 
  2256      Return true if data is available, false if not (i.e. a timeout occured).
  2413      Return true if data is available, false if not (i.e. a timeout occured).
  2257      The other threads are not affected by the wait."
  2414      The other threads are not affected by the wait."
  2258 
  2415 
  2259     |fd inputSema hasData wasBlocked|
  2416     |fd inputSema hasData wasBlocked|
  2260 
  2417 
  2261     filePointer isNil ifTrue:[
  2418     filePointer isNil ifTrue:[^ self errorNotOpen].
  2262         ^ self errorNotOpen
  2419     mode == #writeonly ifTrue:[^ self errorWriteOnly].
  2263     ].
       
  2264     mode == #writeonly ifTrue:[
       
  2265         ^ self errorWriteOnly
       
  2266     ].
       
  2267 
  2420 
  2268     fd := self fileDescriptor.
  2421     fd := self fileDescriptor.
  2269     (OperatingSystem readCheck:fd) ifTrue:[^ true].
  2422     (OperatingSystem readCheck:fd) ifTrue:[^ true].
  2270 
  2423 
  2271     wasBlocked := OperatingSystem blockInterrupts.
  2424     wasBlocked := OperatingSystem blockInterrupts.
  2272     hasData := OperatingSystem readCheck:fd.
  2425     hasData := OperatingSystem readCheck:fd.
  2273     hasData ifFalse:[
  2426     hasData ifFalse:[
  2274         inputSema := Semaphore new.
  2427 	inputSema := Semaphore new.
  2275         timeout notNil ifTrue:[
  2428 	timeout notNil ifTrue:[
  2276             Processor signal:inputSema afterSeconds:timeout
  2429 	    Processor signal:inputSema afterSeconds:timeout
  2277         ].
  2430 	].
  2278         Processor signal:inputSema onInput:fd.
  2431 	Processor signal:inputSema onInput:fd.
  2279         Processor activeProcess state:#ioWait.
  2432 	Processor activeProcess state:#ioWait.
  2280         inputSema wait.
  2433 	inputSema wait.
  2281         Processor disableSemaphore:inputSema.
  2434 	Processor disableSemaphore:inputSema.
  2282         hasData := OperatingSystem readCheck:fd
  2435 	hasData := OperatingSystem readCheck:fd
  2283     ].
  2436     ].
  2284     wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
  2437     wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
  2285     ^ hasData
  2438     ^ hasData
  2286 !
  2439 !
  2287 
  2440 
  2302      The other threads are not affected by the wait."
  2455      The other threads are not affected by the wait."
  2303 
  2456 
  2304     |fd outputSema canWrite wasBlocked|
  2457     |fd outputSema canWrite wasBlocked|
  2305 
  2458 
  2306     filePointer isNil ifTrue:[
  2459     filePointer isNil ifTrue:[
  2307         ^ self errorNotOpen
  2460 	^ self errorNotOpen
  2308     ].
  2461     ].
  2309     mode == #readonly ifTrue:[
  2462     mode == #readonly ifTrue:[
  2310         ^ self errorReadOnly
  2463 	^ self errorReadOnly
  2311     ].
  2464     ].
  2312 
  2465 
  2313     fd := self fileDescriptor.
  2466     fd := self fileDescriptor.
  2314     (OperatingSystem writeCheck:fd) ifTrue:[^ true].
  2467     (OperatingSystem writeCheck:fd) ifTrue:[^ true].
  2315 
  2468 
  2316     wasBlocked := OperatingSystem blockInterrupts.
  2469     wasBlocked := OperatingSystem blockInterrupts.
  2317     canWrite := OperatingSystem writeCheck:fd.
  2470     canWrite := OperatingSystem writeCheck:fd.
  2318     canWrite ifFalse:[
  2471     canWrite ifFalse:[
  2319         outputSema := Semaphore new.
  2472 	outputSema := Semaphore new.
  2320         timeout notNil ifTrue:[
  2473 	timeout notNil ifTrue:[
  2321             Processor signal:outputSema afterSeconds:timeout
  2474 	    Processor signal:outputSema afterSeconds:timeout
  2322         ].
  2475 	].
  2323         Processor signal:outputSema onOutput:fd.
  2476 	Processor signal:outputSema onOutput:fd.
  2324         Processor activeProcess state:#ioWait.
  2477 	Processor activeProcess state:#ioWait.
  2325         outputSema wait.
  2478 	outputSema wait.
  2326         Processor disableSemaphore:outputSema.
  2479 	Processor disableSemaphore:outputSema.
  2327         canWrite := OperatingSystem writeCheck:fd
  2480 	canWrite := OperatingSystem writeCheck:fd
  2328     ].
  2481     ].
  2329     wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
  2482     wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
  2330     ^ canWrite
  2483     ^ canWrite
  2331 ! !
  2484 ! !
  2332      
  2485      
  2333 !ExternalStream methodsFor:'reimplemented for speed'!
  2486 !ExternalStream methodsFor:'reimplemented for speed'!
  2334 
  2487 
  2335 peekFor:anObject
  2488 peekFor:anObject
  2336     "return true and move past if next == something.
  2489     "return true and move past next element, if next == something.
  2337      Otherwise, stay and return false."
  2490      Otherwise, stay and return false. False is also returned
       
  2491      when EOF is encountered."
  2338 
  2492 
  2339 %{  /* NOCONTEXT */
  2493 %{  /* NOCONTEXT */
  2340 
  2494 
  2341     FILE *f;
  2495     FILE *f;
  2342     int c;
  2496     int c;
  2343     int peekValue;
  2497     int peekValue;
  2344     extern int _immediateInterrupt;
  2498     extern int _immediateInterrupt;
  2345 
  2499 
  2346     if (_INST(filePointer) != nil) {
  2500     _INST(lastErrorNumber) = nil;
  2347         if (_INST(binary) == true) {
  2501     if ((_INST(filePointer) != nil)
  2348             if (_isSmallInteger(anObject)) {
  2502      && (_INST(mode) != @symbol(writeonly))) {
  2349                 peekValue = _intVal(anObject) & 0xFF;
  2503 	if (_INST(binary) == true) {
  2350             } else {
  2504 	    if (_isSmallInteger(anObject)) {
  2351                 goto bad;
  2505 		peekValue = _intVal(anObject) & 0xFF;
  2352             }
  2506 	    } else {
  2353         } else {
  2507 		goto bad;
  2354             if (__isCharacter(anObject)) {
  2508 	    }
  2355                 peekValue = _intVal(_characterVal(anObject)) & 0xFF;
  2509 	} else {
  2356             } else {
  2510 	    if (__isCharacter(anObject)) {
  2357                 goto bad;
  2511 		peekValue = _intVal(_characterVal(anObject)) & 0xFF;
  2358             }
  2512 	    } else {
  2359         }
  2513 		goto bad;
  2360 
  2514 	    }
  2361         f = MKFD(_INST(filePointer));
  2515 	}
  2362         _immediateInterrupt = 1;
  2516 
  2363         c = getc(f);
  2517 	if ((_INST(didWrite) != false)
  2364         _immediateInterrupt = 0;
  2518 	 && (_INST(mode) == @symbol(readwrite))) {
  2365 
  2519 	    _INST(didWrite) = false;
  2366         if (c == peekValue) {
  2520 	    fseek(f, 0L, 1); /* needed in stdio */
  2367             OBJ pos;
  2521 	}
  2368 
  2522 
  2369             if ((pos = _INST(position)) != nil) {
  2523 	f = MKFD(_INST(filePointer));
  2370                 _INST(position) = _MKSMALLINT(_intVal(pos) + 1);
  2524 	_immediateInterrupt = 1;
  2371             }
  2525 	c = getc(f);
  2372             RETURN ( true );
  2526 	_immediateInterrupt = 0;
  2373         }
  2527 
  2374 
  2528 	if (c == peekValue) {
  2375         if (c == EOF) {
  2529 	    OBJ pos;
  2376             _INST(hitEOF) = true;
  2530 
  2377         } else {
  2531 	    if ((pos = _INST(position)) != nil) {
  2378             ungetc(c, f);
  2532 		_INST(position) = _MKSMALLINT(_intVal(pos) + 1);
  2379         }
  2533 	    }
  2380         RETURN ( false );
  2534 	    RETURN (true);
       
  2535 	}
       
  2536 
       
  2537 	if (c != EOF) {
       
  2538 	    ungetc(c, f);
       
  2539 	    RETURN (false);
       
  2540 	}
       
  2541 
       
  2542 	if (ferror(f)) {
       
  2543 	    _INST(lastErrorNumber) = _MKSMALLINT(errno);
       
  2544 	} else {
       
  2545 	    _INST(hitEOF) = true;
       
  2546 	    RETURN (false);
       
  2547 	}
  2381     }
  2548     }
  2382 bad: ;
  2549 bad: ;
  2383 %}
  2550 %}.
  2384 .
  2551     mode == #writeonly ifTrue:[^ self errorWriteOnly].
       
  2552     lastErrorNumber notNil iftrue:[^ self readError].
  2385     filePointer isNil ifTrue:[^ self errorNotOpen].
  2553     filePointer isNil ifTrue:[^ self errorNotOpen].
  2386     ^ super peekFor:anObject
  2554     ^ super peekFor:anObject
  2387 !
  2555 !
  2388 
  2556 
  2389 nextMatchFor:anObject
  2557 nextMatchFor:anObject
  2395 
  2563 
  2396     FILE *f;
  2564     FILE *f;
  2397     int peekValue, c;
  2565     int peekValue, c;
  2398     extern int _immediateInterrupt;
  2566     extern int _immediateInterrupt;
  2399 
  2567 
  2400     if ((_INST(binary) == true) && _isSmallInteger(anObject)) {
  2568     _INST(lastErrorNumber) = nil;
  2401         peekValue = _intVal(anObject) & 0xFF;
  2569     if ((_INST(filePointer) != nil)
  2402     } else {
  2570      && (_INST(mode) != @symbol(writeonly))) {
  2403         if ((_INST(binary) != true) && __isCharacter(anObject)) {
  2571 	if ((_INST(binary) == true) && _isSmallInteger(anObject)) {
  2404             peekValue = _intVal(_characterVal(anObject)) & 0xFF;
  2572 	    peekValue = _intVal(anObject) & 0xFF;
  2405         } else
  2573 	} else {
  2406             peekValue = -1;
  2574 	    if ((_INST(binary) != true) && __isCharacter(anObject)) {
  2407     }
  2575 		peekValue = _intVal(_characterVal(anObject)) & 0xFF;
  2408 
  2576 	    } else {
  2409     if (peekValue >= 0) {
  2577 		peekValue = -1;
  2410         if (_INST(filePointer) != nil) {
  2578 	    }   
  2411             if (_INST(mode) != _writeonly) {
  2579 	}
  2412                 f = MKFD(_INST(filePointer));
  2580 
  2413                 _immediateInterrupt = 1;
  2581 	if (peekValue >= 0) {
  2414                 _INST(position) = nil;
  2582 	    f = MKFD(_INST(filePointer));
  2415                 
  2583 	    _immediateInterrupt = 1;
  2416                 if ((_INST(didWrite) != false) && (_INST(mode) == _readwrite)) {
  2584 	    _INST(position) = nil;
  2417                     _INST(didWrite) = false;
  2585 
  2418                     fseek(f, 0L, 1); /* needed in stdio */
  2586 	    if ((_INST(didWrite) != false)
  2419                 }
  2587 	     && (_INST(mode) == @symbol(readwrite))) {
  2420 
  2588 		_INST(didWrite) = false;
  2421                 for (;;) {
  2589 		fseek(f, 0L, 1); /* needed in stdio */
  2422                     c = getc(f);
  2590 	    }
  2423                     if (c == EOF) {
  2591 
  2424                         _INST(hitEOF) = true;
  2592 	    for (;;) {
  2425                         _immediateInterrupt = 0;
  2593 		c = getc(f);
  2426                         RETURN (nil);
  2594 		if (c == EOF) {
  2427                     }
  2595 		    _immediateInterrupt = 0;
  2428                     if (c == peekValue) {
  2596 		    if (ferror(f)) {
  2429                         _immediateInterrupt = 0;
  2597 			_INST(lastErrorNumber) = _MKSMALLINT(errno);
  2430                         RETURN (anObject);
  2598 			break;
  2431                     }
  2599 		    }
  2432                 }
  2600 		    _INST(hitEOF) = true;
  2433                 _immediateInterrupt = 0;
  2601 		    RETURN (nil);
  2434             }
  2602 		}
  2435         }
  2603 		if (c == peekValue) {
  2436     }
  2604 		    _immediateInterrupt = 0;
  2437 %}
  2605 		    RETURN (anObject);
  2438 .
  2606 		}
       
  2607 	    }
       
  2608 	    _immediateInterrupt = 0;
       
  2609 	}
       
  2610     }
       
  2611 %}.
       
  2612     lastErrorNumber notNil iftrue:[^ self readError].
  2439     filePointer isNil ifTrue:[^ self errorNotOpen].
  2613     filePointer isNil ifTrue:[^ self errorNotOpen].
  2440     ^ super nextMatchFor:anObject
  2614     ^ super nextMatchFor:anObject
  2441 !
  2615 !
  2442 
  2616 
  2443 skipLine
  2617 skipLine
  2449 
  2623 
  2450     FILE *f;
  2624     FILE *f;
  2451     char buffer[1024];
  2625     char buffer[1024];
  2452     extern int _immediateInterrupt;
  2626     extern int _immediateInterrupt;
  2453 
  2627 
  2454     if ((_INST(filePointer) != nil) && (_INST(mode) != _writeonly)) {
  2628     _INST(lastErrorNumber) = nil;
  2455         if (_INST(binary) != true) {
  2629     if ((_INST(filePointer) != nil)
  2456             f = MKFD(_INST(filePointer));
  2630      && (_INST(mode) != @symbol(writeonly))) {
       
  2631 	if (_INST(binary) != true) {
       
  2632 	    f = MKFD(_INST(filePointer));
  2457             
  2633             
  2458             if ((_INST(didWrite) != false) && (_INST(mode) == _readwrite)) {
  2634 	    if ((_INST(didWrite) != false)
  2459                 _INST(didWrite) = false;
  2635 	     && (_INST(mode) == @symbol(readwrite))) {
  2460                 fseek(f, 0L, 1); /* needed in stdio */
  2636 		_INST(didWrite) = false;
  2461             }
  2637 		fseek(f, 0L, 1); /* needed in stdio */
  2462 
  2638 	    }
  2463             _immediateInterrupt = 1;
  2639 
  2464             if (fgets(buffer, sizeof(buffer), f) != NULL) {
  2640 	    _immediateInterrupt = 1;
  2465                 _immediateInterrupt = 0;
  2641 	    if (fgets(buffer, sizeof(buffer), f) != NULL) {
  2466                 RETURN ( self );
  2642 		_immediateInterrupt = 0;
  2467             }
  2643 		RETURN ( self );
  2468             _INST(hitEOF) = true;
  2644 	    }
  2469             _immediateInterrupt = 0;
  2645 	    _immediateInterrupt = 0;
  2470             RETURN ( nil );
  2646 	    if (ferror(f)) {
  2471         }
  2647 		_INST(lastErrorNumber) = _MKSMALLINT(errno);
  2472     }
  2648 	    } else {
  2473 %}
  2649 		_INST(hitEOF) = true;
  2474 .
  2650 		RETURN ( nil );
       
  2651 	    }
       
  2652 	}
       
  2653     }
       
  2654 %}.
       
  2655     lastErrorNumber notNil iftrue:[^ self readError].
  2475     filePointer isNil ifTrue:[^ self errorNotOpen].
  2656     filePointer isNil ifTrue:[^ self errorNotOpen].
  2476     binary ifTrue:[^ self errorBinary].
  2657     binary ifTrue:[^ self errorBinary].
  2477     self errorWriteOnly
  2658     ^ self errorWriteOnly
  2478 !
  2659 !
  2479 
  2660 
  2480 skipThroughAll:aString
  2661 skipThroughAll:aString
  2481     "search & skip for the sequence given by the argument, aCollection;
  2662     "search & skip for the sequence given by the argument, aCollection;
  2482      return nil if not found, self otherwise. If successfull, the next read 
  2663      return nil if not found, self otherwise. If successfull, the next read 
  2483      will return the character after the searchstring."
  2664      will return the character after the searchstring."
  2484 
  2665 
  2485     |buffer len first|
  2666     |buffer len first|
  2486 
  2667 
  2487     (aString isString and:[binary not]) ifTrue:[
  2668     (aString isString and:[binary not]) ifTrue:[
  2488         len := aString size.
  2669 	len := aString size.
  2489         first := aString at:1.
  2670 	first := aString at:1.
  2490         buffer := String new:len.
  2671 	buffer := String new:len.
  2491         buffer at:1 put:first.
  2672 	buffer at:1 put:first.
  2492         len := len - 1.
  2673 	len := len - 1.
  2493         [true] whileTrue:[
  2674 	[true] whileTrue:[
  2494             (self skipThrough:first) isNil ifTrue:[
  2675 	    (self skipThrough:first) isNil ifTrue:[
  2495                 ^ nil.
  2676 		^ nil.
  2496             ].
  2677 	    ].
  2497             (self nextBytes:len into:buffer startingAt:2) == len ifFalse:[
  2678 	    (self nextBytes:len into:buffer startingAt:2) == len ifFalse:[
  2498                 ^ nil
  2679 		^ nil
  2499             ].
  2680 	    ].
  2500             buffer = aString ifTrue:[
  2681 	    buffer = aString ifTrue:[
  2501                 "
  2682 		"
  2502                  position back, before string
  2683 		 position back, before string
  2503                 "
  2684 		"
  2504                 ^ self
  2685 		^ self
  2505             ].
  2686 	    ].
  2506         ].
  2687 	].
  2507         "NOT REACHED"
  2688 	"NOT REACHED"
  2508     ].
  2689     ].
  2509     ^ super skipThroughAll:aString
  2690     ^ super skipThroughAll:aString
  2510 
  2691 
  2511     "
  2692     "
  2512      |s|
  2693      |s|
  2523 
  2704 
  2524     |oldPos|
  2705     |oldPos|
  2525 
  2706 
  2526     oldPos := self position.
  2707     oldPos := self position.
  2527     (self skipThroughAll:aString) isNil ifTrue:[
  2708     (self skipThroughAll:aString) isNil ifTrue:[
  2528         "
  2709 	"
  2529          restore position
  2710 	 restore position
  2530         "
  2711 	"
  2531         self position:oldPos.
  2712 	self position:oldPos.
  2532         ^ nil
  2713 	^ nil
  2533     ].
  2714     ].
  2534     "
  2715     "
  2535      position before match-string
  2716      position before match-string
  2536     "
  2717     "
  2537     self position:(self position - aString size).
  2718     self position:(self position - aString size).
  2555 
  2736 
  2556     FILE *f;
  2737     FILE *f;
  2557     REGISTER int c, cSearch;
  2738     REGISTER int c, cSearch;
  2558     extern int _immediateInterrupt;
  2739     extern int _immediateInterrupt;
  2559 
  2740 
  2560     if ((_INST(filePointer) != nil) && (_INST(mode) != _writeonly)) {
  2741     _INST(lastErrorNumber) = nil;
  2561         if (_INST(binary) == true) {
  2742     if ((_INST(filePointer) != nil)
  2562             /* searched for object must be a smallInteger */
  2743      && (_INST(mode) != @symbol(writeonly))) {
  2563             if (! _isSmallInteger(aCharacter)) goto badArgument;
  2744 	if (_INST(binary) == true) {
  2564             cSearch = _intVal(aCharacter);
  2745 	    /* searched for object must be a smallInteger */
  2565         } else {
  2746 	    if (! _isSmallInteger(aCharacter)) goto badArgument;
  2566             /* searched for object must be a character */
  2747 	    cSearch = _intVal(aCharacter);
  2567             if (! __isCharacter(aCharacter)) goto badArgument;
  2748 	} else {
  2568             cSearch = _intVal(_characterVal(aCharacter));
  2749 	    /* searched for object must be a character */
  2569         }
  2750 	    if (! __isCharacter(aCharacter)) goto badArgument;
  2570         /* Q: should we just say: "not found" ? */
  2751 	    cSearch = _intVal(_characterVal(aCharacter));
  2571         if ((cSearch < 0) || (cSearch > 255)) goto badArgument;
  2752 	}
  2572 
  2753 	/* Q: should we just say: "not found" ? */
  2573         f = MKFD(_INST(filePointer));
  2754 	if ((cSearch < 0) || (cSearch > 255)) goto badArgument;
       
  2755 
       
  2756 	f = MKFD(_INST(filePointer));
  2574         
  2757         
  2575         if ((_INST(didWrite) != false) && (_INST(mode) == _readwrite)) {
  2758 	if ((_INST(didWrite) != false)
  2576             _INST(didWrite) = false;
  2759 	 && (_INST(mode) == @symbol(readwrite))) {
  2577             fseek(f, 0L, 1); /* needed in stdio */
  2760 	    _INST(didWrite) = false;
  2578         }
  2761 	    fseek(f, 0L, 1); /* needed in stdio */
  2579 
  2762 	}
  2580         _immediateInterrupt = 1;
  2763 
  2581         while (1) {
  2764 	_immediateInterrupt = 1;
  2582             if (feof(f)) {
  2765 	while (1) {
  2583                 _immediateInterrupt = 0;
  2766 #ifdef NOTNEEDED
  2584                 RETURN ( nil );
  2767 	    if (feof(f)) {
  2585             }
  2768 		_immediateInterrupt = 0;
  2586 
  2769 		RETURN ( nil );
  2587             c = getc(f);
  2770 	    }
  2588 
  2771 #endif
  2589             if (c < 0) {
  2772 	    c = getc(f);
  2590                 _immediateInterrupt = 0;
  2773 
  2591                 _INST(hitEOF) = true;
  2774 	    if (c == cSearch) {
  2592                 RETURN (nil);
  2775 		_immediateInterrupt = 0;
  2593             }
  2776 		RETURN (self);
  2594             if (c == cSearch) {
  2777 	    }
  2595                 _immediateInterrupt = 0;
  2778 	    if (c < 0) {
  2596                 RETURN (self);
  2779 		_immediateInterrupt = 0;
  2597             }
  2780 		if (ferror(f)) {
  2598         }
  2781 		    _INST(lastErrorNumber) = _MKSMALLINT(errno);
       
  2782 		    break;
       
  2783 		} else {
       
  2784 		    _INST(hitEOF) = true;
       
  2785 		    RETURN (nil);
       
  2786 		}
       
  2787 	    }
       
  2788 	}
  2599     }
  2789     }
  2600 badArgument: ;
  2790 badArgument: ;
  2601 %}
  2791 %}.
  2602 .
  2792     lastErrorNumber notNil iftrue:[^ self readError].
  2603     filePointer isNil ifTrue:[^ self errorNotOpen].
  2793     filePointer isNil ifTrue:[^ self errorNotOpen].
  2604     (mode == #writeonly) ifTrue:[^ self errorWriteOnly].
  2794     (mode == #writeonly) ifTrue:[^ self errorWriteOnly].
  2605     "
  2795     "
  2606      argument must be integer/character in binary mode, 
  2796      argument must be integer/character in binary mode, 
  2607      character in text mode
  2797      character in text mode
  2625 
  2815 
  2626     FILE *f;
  2816     FILE *f;
  2627     REGISTER int c;
  2817     REGISTER int c;
  2628     extern int _immediateInterrupt;
  2818     extern int _immediateInterrupt;
  2629 
  2819 
  2630     if ((_INST(filePointer) != nil) && (_INST(mode) != _writeonly)) {
  2820     _INST(lastErrorNumber) = nil;
  2631         if (_INST(binary) != true) {
  2821     if ((_INST(filePointer) != nil)
  2632             f = MKFD(_INST(filePointer));
  2822      && (_INST(mode) != @symbol(writeonly))) {
       
  2823 	if (_INST(binary) != true) {
       
  2824 	    f = MKFD(_INST(filePointer));
  2633             
  2825             
  2634             if ((_INST(didWrite) != false) && (_INST(mode) == _readwrite)) {
  2826 	    if ((_INST(didWrite) != false) && (_INST(mode) == _readwrite)) {
  2635                 _INST(didWrite) = false;
  2827 		_INST(didWrite) = false;
  2636                 fseek(f, 0L, 1); /* needed in stdio */
  2828 		fseek(f, 0L, 1); /* needed in stdio */
  2637             }
  2829 	    }
  2638 
  2830 
  2639             _immediateInterrupt = 1;
  2831 	    _immediateInterrupt = 1;
  2640             while (1) {
  2832 	    while (1) {
  2641                 if (feof(f)) {
  2833 		if (feof(f)) {
  2642                     _immediateInterrupt = 0;
  2834 		    _immediateInterrupt = 0;
  2643                     RETURN ( nil );
  2835 		    RETURN ( nil );
  2644                 }
  2836 		}
  2645 
  2837 
  2646                 c = getc(f);
  2838 		c = getc(f);
  2647 
  2839 
  2648                 switch (c) {
  2840 		switch (c) {
  2649                     case ' ':
  2841 		    case ' ':
  2650                     case '\t':
  2842 		    case '\t':
  2651                     case '\n':
  2843 		    case '\n':
  2652                     case '\r':
  2844 		    case '\r':
  2653                     case '\b':
  2845 		    case '\b':
  2654                     case '\014':
  2846 		    case '\014':
  2655                         break;
  2847 			break;
  2656 
  2848 
  2657                     default:
  2849 		    default:
  2658                         if (c < 0) {
  2850 			_immediateInterrupt = 0;
  2659                             _INST(hitEOF) = true;
  2851 			if (c < 0) {
  2660                             _immediateInterrupt = 0;
  2852 			    if (ferror(f)) {
  2661                             RETURN ( nil );
  2853 				_INST(lastErrorNumber) = _MKSMALLINT(errno);
  2662                         }
  2854 				goto err;
  2663                         ungetc(c, f);
  2855 			    }
  2664                         _immediateInterrupt = 0;
  2856 			    _INST(hitEOF) = true;
  2665                         RETURN ( _MKCHARACTER(c & 0xFF) );
  2857 			    RETURN ( nil );
  2666                 }
  2858 			}
  2667             }
  2859 			ungetc(c, f);
  2668         }
  2860 			RETURN ( _MKCHARACTER(c & 0xFF) );
  2669     }
  2861 		}
  2670 %}
  2862 	    }
  2671 .
  2863 	}
       
  2864     }
       
  2865 err: ;
       
  2866 %}.
       
  2867     lastErrorNumber notNil iftrue:[^ self readError].
  2672     filePointer isNil ifTrue:[^ self errorNotOpen].
  2868     filePointer isNil ifTrue:[^ self errorNotOpen].
  2673     (mode == #writeonly) ifTrue:[^ self errorWriteOnly].
  2869     (mode == #writeonly) ifTrue:[^ self errorWriteOnly].
  2674     ^ self errorBinary.
  2870     ^ self errorBinary.
  2675 !
  2871 !
  2676 
  2872 
  2684 
  2880 
  2685     FILE *f;
  2881     FILE *f;
  2686     int c;
  2882     int c;
  2687     extern int _immediateInterrupt;
  2883     extern int _immediateInterrupt;
  2688 
  2884 
  2689     if ((_INST(filePointer) != nil) && (_INST(mode) != _writeonly)) {
  2885     _INST(lastErrorNumber) = nil;
  2690         if (_INST(binary) != true) {
  2886     if ((_INST(filePointer) != nil)
  2691             f = MKFD(_INST(filePointer));
  2887      && (_INST(mode) != @symbol(writeonly))) {
  2692 
  2888 	if (_INST(binary) != true) {
  2693             if ((_INST(didWrite) != false) && (_INST(mode) == _readwrite)) {
  2889 	    f = MKFD(_INST(filePointer));
  2694                 _INST(didWrite) = false;
  2890 
  2695                 fseek(f, 0L, 1); /* needed in stdio */
  2891 	    if ((_INST(didWrite) != false)
  2696             }
  2892 	     && (_INST(mode) == @symbol(readwrite))) {
  2697 
  2893 		_INST(didWrite) = false;
  2698             _immediateInterrupt = 1;
  2894 		fseek(f, 0L, 1); /* needed in stdio */
  2699             while (1) {
  2895 	    }
       
  2896 
       
  2897 	    _immediateInterrupt = 1;
       
  2898 	    while (1) {
  2700                 
  2899                 
  2701                 if (feof(f)) {
  2900 		if (feof(f)) {
  2702                     _immediateInterrupt = 0;
  2901 		    _immediateInterrupt = 0;
  2703                     RETURN ( nil );
  2902 		    RETURN ( nil );
  2704                 }
  2903 		}
  2705 
  2904 
  2706                 c = getc(f);
  2905 		c = getc(f);
  2707 
  2906 
  2708                 switch (c) {
  2907 		switch (c) {
  2709                     case ' ':
  2908 		    case ' ':
  2710                     case '\t':
  2909 		    case '\t':
  2711                     case '\b':
  2910 		    case '\b':
  2712                         break;
  2911 			break;
  2713 
  2912 
  2714                     default:
  2913 		    default:
  2715                         if (c < 0) {
  2914 			_immediateInterrupt = 0;
  2716                             _INST(hitEOF) = true;
  2915 			if (c < 0) {
  2717                             _immediateInterrupt = 0;
  2916 			    if (ferror(f)) {
  2718                             RETURN ( nil );
  2917 				_INST(lastErrorNumber) = _MKSMALLINT(errno);
  2719                         }
  2918 				goto err;
  2720                         ungetc(c, f);
  2919 			    }
  2721                         _immediateInterrupt = 0;
  2920 			    _INST(hitEOF) = true;
  2722                         RETURN ( _MKCHARACTER(c & 0xFF) );
  2921 			    RETURN ( nil );
  2723                 }
  2922 			}
  2724             }
  2923 			ungetc(c, f);
  2725         }
  2924 			RETURN ( _MKCHARACTER(c & 0xFF) );
  2726     }
  2925 		}
  2727 %}
  2926 	    }
  2728 .
  2927 	}
       
  2928     }
       
  2929 err: ;
       
  2930 %}.
       
  2931     lastErrorNumber notNil iftrue:[^ self readError].
  2729     filePointer isNil ifTrue:[^ self errorNotOpen].
  2932     filePointer isNil ifTrue:[^ self errorNotOpen].
  2730     (mode == #writeonly) ifTrue:[^ self errorWriteOnly].
  2933     (mode == #writeonly) ifTrue:[^ self errorWriteOnly].
  2731     self errorBinary
  2934     ^ self errorBinary
       
  2935 !
       
  2936 
       
  2937 nextAlphaNumericWord
       
  2938     "read the next word (i.e. up to non letter-or-digit).
       
  2939      return a string containing those characters."
       
  2940 
       
  2941 %{  /* STACK: 2000 */
       
  2942     FILE *f;
       
  2943     int len;
       
  2944     char buffer[1024];
       
  2945     int ch;
       
  2946     int cnt = 0;
       
  2947     extern int _immediateInterrupt;
       
  2948 
       
  2949     if ((_INST(filePointer) != nil)
       
  2950      && (_INST(mode) != @symbol(writeonly))) {
       
  2951 	f = MKFD(_INST(filePointer));
       
  2952 
       
  2953 	_immediateInterrupt = 1;
       
  2954 
       
  2955 	if ((_INST(didWrite) != false)
       
  2956 	 && (_INST(mode) == @symbol(readwrite))) {
       
  2957 	    _INST(didWrite) = false;
       
  2958 	    fseek(f, 0L, 1); /* needed in stdio */
       
  2959 	}
       
  2960 
       
  2961 	for (;;) {
       
  2962 	    ch = getc(f);
       
  2963 	    if (ch < 0) {
       
  2964 		if (ferror(f)) {
       
  2965 		    _INST(lastErrorNumber) = _MKSMALLINT(errno);
       
  2966 		    goto err;
       
  2967 		}
       
  2968 		_INST(hitEOF) = true;
       
  2969 		break;
       
  2970 	    }
       
  2971 	    cnt++;
       
  2972 
       
  2973 	    if (ch >= ' ') break;
       
  2974 	    if ((ch != ' ') && (ch != '\t') && (ch != '\r')
       
  2975 	     && (ch != '\n') && (ch != 0x0b)) break;
       
  2976 	}
       
  2977 	ungetc(ch, f);
       
  2978 	cnt--;
       
  2979 
       
  2980 	len = 0;
       
  2981 	for (;;) {
       
  2982 	    ch = getc(f);
       
  2983 	    if (ch < 0) {
       
  2984 		if (ferror(f)) {
       
  2985 		    _INST(lastErrorNumber) = _MKSMALLINT(errno);
       
  2986 		    goto err;
       
  2987 		}
       
  2988 		_INST(hitEOF) = true;
       
  2989 		break;
       
  2990 	    }
       
  2991 
       
  2992 	    ch &= 0xFF;
       
  2993 	    if (! (((ch >= 'a') && (ch <= 'z')) ||
       
  2994 		   ((ch >= 'A') && (ch <= 'Z')) ||
       
  2995 		   ((ch >= '0') && (ch <= '9')))) {
       
  2996 		ungetc(ch, f);
       
  2997 		break;
       
  2998 	    }
       
  2999 	    cnt++;
       
  3000 	    buffer[len++] = ch;
       
  3001 	    if (len >= sizeof(buffer)-1) {
       
  3002 		/* emergency */
       
  3003 		break;
       
  3004 	    }
       
  3005 	}
       
  3006 	_immediateInterrupt = 0;
       
  3007 
       
  3008 	if (_INST(position) != nil) {
       
  3009 	    _INST(position) = _MKSMALLINT(_intVal(_INST(position)) + cnt);
       
  3010 	}
       
  3011 	buffer[len] = '\0';
       
  3012 	if (len != 0) {
       
  3013 	    RETURN ( _MKSTRING(buffer COMMA_CON) );
       
  3014 	}
       
  3015 	RETURN ( nil );
       
  3016     }
       
  3017 err: ;
       
  3018 %}.
       
  3019     lastErrorNumber notNil ifTrue:[^ self readError].
       
  3020     filePointer isNil ifTrue:[^ self errorNotOpen].
       
  3021     ^ self errorWriteOnly
  2732 !
  3022 !
  2733 
  3023 
  2734 nextChunk
  3024 nextChunk
  2735     "return the next chunk, i.e. all characters up to the next
  3025     "return the next chunk, i.e. all characters up to the next
  2736      non-doubled exclamation mark; undouble doubled exclamation marks.
  3026      non-doubled exclamation mark; undouble doubled exclamation marks.
  2737      - reimplemented for speed"
  3027      - reimplemented for speed"
  2738 
  3028 
  2739     |retVal|
  3029     |retVal|
  2740 
  3030 
  2741     filePointer isNil ifTrue:[
  3031     filePointer isNil ifTrue:[^ self errorNotOpen].
  2742         ^ self errorNotOpen
  3032     binary ifTrue:[^ self errorBinary].
  2743     ].
  3033     (mode == #writeonly) ifTrue:[^ self errorWriteOnly].
  2744     binary ifTrue:[
       
  2745         ^ self errorBinary
       
  2746     ].
       
  2747 
       
  2748 %{
  3034 %{
  2749     FILE *f;
  3035     FILE *f;
  2750     int done = 0;
  3036     int done = 0;
  2751     REGISTER int c;
  3037     REGISTER int c;
  2752     unsigned char peekC;
  3038     unsigned char peekC;
  2753     char *buffer, *newBuffer;
  3039     char *buffer = (char *)0, *newBuffer;
  2754     REGISTER int index;
  3040     REGISTER int index;
  2755     int currSize;
  3041     int currSize;
  2756     int inComment, inString, inPrimitive = 0;
  3042     int inComment, inString, inPrimitive = 0;
  2757     extern int _immediateInterrupt;
  3043     extern int _immediateInterrupt;
  2758 
  3044 
       
  3045     _INST(lastErrorNumber) = nil;
  2759     f = MKFD(_INST(filePointer));
  3046     f = MKFD(_INST(filePointer));
  2760     
  3047     
  2761     if ((_INST(didWrite) != false) && (_INST(mode) == _readwrite)) {
  3048     if ((_INST(didWrite) != false)
  2762         _INST(didWrite) = false;
  3049      && (_INST(mode) == @symbol(readwrite))) {
  2763         fseek(f, 0L, 1); /* needed in stdio */
  3050 	_INST(didWrite) = false;
       
  3051 	fseek(f, 0L, 1); /* needed in stdio */
       
  3052     }
       
  3053 
       
  3054     if (feof(f)) {
       
  3055 	_immediateInterrupt = 0;
       
  3056 	RETURN (nil);
  2764     }
  3057     }
  2765 
  3058 
  2766     /*
  3059     /*
  2767      * skip spaces
  3060      * skip spaces
  2768      */
  3061      */
  2769     _immediateInterrupt = 1;
  3062     _immediateInterrupt = 1;
  2770     while (! done) {
  3063     while (! done) {
  2771         if (feof(f)) {
  3064 
  2772             _immediateInterrupt = 0;
  3065 	do {
  2773             RETURN ( nil );
  3066 	    c = getc(f);
  2774         }
  3067 	} while ((c < 0) && (errno == EINTR));
  2775 
  3068 
  2776         do {
  3069 	switch (c) {
  2777             c = getc(f);
  3070 	    case ' ':
  2778         } while ((c < 0) && (errno == EINTR));
  3071 	    case '\t':
  2779 
  3072 	    case '\n':
  2780         switch (c) {
  3073 	    case '\r':
  2781             case ' ':
  3074 	    case '\b':
  2782             case '\t':
  3075 	    case '\014':
  2783             case '\n':
  3076 		break;
  2784             case '\r':
  3077 
  2785             case '\b':
  3078 	    case EOF:
  2786             case '\014':
  3079 		_immediateInterrupt = 0;
  2787                 break;
  3080 		if (ferror(f)) {
  2788 
  3081 		    _INST(lastErrorNumber) = _MKSMALLINT(errno);
  2789             case EOF:
  3082 		    goto err;
  2790                 _immediateInterrupt = 0;
  3083 		}
  2791                 _INST(hitEOF) = true;
  3084 		_INST(hitEOF) = true;
  2792                 RETURN ( nil );
  3085 		RETURN (nil);
  2793 
  3086 
  2794             default:
  3087 	    default:
  2795                 ungetc(c, f);
  3088 		ungetc(c, f);
  2796                 done = 1;
  3089 		done = 1;
  2797                 break;
  3090 		break;
  2798         }
  3091 	}
  2799     }
  3092     }
  2800 
  3093 
  2801     /*
  3094     /*
  2802      * read chunk into a buffer
  3095      * read chunk into a buffer
  2803      */
  3096      */
  2804     buffer = (char *)malloc(3000);
  3097     buffer = (char *)malloc(3000);
  2805     currSize = 3000;
  3098     currSize = 3000;
  2806     index = 0;
  3099     index = 0;
  2807     while (! feof(f)) {
  3100     while (! feof(f)) {
  2808         /* do we have to resize the buffer ? */
  3101 	/* do we have to resize the buffer ? */
  2809         if ((index+2) >= currSize) {
  3102 	if ((index+2) >= currSize) {
  2810             newBuffer = (char *)malloc(currSize * 2);
  3103 	    newBuffer = (char *)malloc(currSize * 2);
  2811             bcopy(buffer, newBuffer, index);
  3104 	    bcopy(buffer, newBuffer, index);
  2812             free(buffer);
  3105 	    free(buffer);
  2813             buffer = newBuffer;
  3106 	    buffer = newBuffer;
  2814             currSize = currSize * 2;
  3107 	    currSize = currSize * 2;
  2815         }
  3108 	}
  2816         do {
  3109 	do {
  2817             c = getc(f);
  3110 	    c = getc(f);
  2818         } while (c < 0 && (errno == EINTR));
  3111 	} while (c < 0 && (errno == EINTR));
  2819 
  3112 
  2820         if (c == '%') {
  3113 	if (c == '%') {
  2821             peekC = getc(f);
  3114 	    peekC = getc(f);
  2822             ungetc(peekC, f);
  3115 	    ungetc(peekC, f);
  2823             if (peekC == '{') {
  3116 	    if (peekC == '{') {
  2824                 inPrimitive++;
  3117 		inPrimitive++;
  2825             } else if (peekC == '}') {
  3118 	    } else if (peekC == '}') {
  2826                 inPrimitive--;
  3119 		inPrimitive--;
  2827             }
  3120 	    }
  2828         } else {
  3121 	} else {
  2829             if (! inPrimitive) {
  3122 	    if (! inPrimitive) {
  2830                 if (c == '!') {
  3123 		if (c == '!') {
  2831                     do {
  3124 		    do {
  2832                         c = getc(f);
  3125 			c = getc(f);
  2833                     } while (c < 0 && (errno == EINTR));
  3126 		    } while (c < 0 && (errno == EINTR));
  2834                     if (c != '!') {
  3127 		    if (c != '!') {
  2835                         ungetc(c, f);
  3128 			ungetc(c, f);
  2836                         break;
  3129 			break;
  2837                     }
  3130 		    }
  2838                 }
  3131 		}
  2839             }
  3132 	    }
  2840         }
  3133 	}
  2841         if (c == EOF) {
  3134 
  2842             _INST(hitEOF) = true;
  3135 	if (c < 0) {
  2843             break;
  3136 	    _immediateInterrupt = 0;
  2844         }
  3137 	    if (ferror(f)) {
  2845         buffer[index++] = c;
  3138 		_INST(lastErrorNumber) = _MKSMALLINT(errno);
       
  3139 		goto err;
       
  3140 	    }
       
  3141 	    _INST(hitEOF) = true;
       
  3142 	    break;
       
  3143 	}
       
  3144 	buffer[index++] = c;
  2846     }
  3145     }
  2847     _immediateInterrupt = 0;
  3146     _immediateInterrupt = 0;
  2848 
  3147 
  2849     buffer[index] = '\0';
  3148     buffer[index] = '\0';
  2850     /*
  3149     /*
  2851      * make it a string
  3150      * make it a string
  2852      */
  3151      */
  2853     retVal = _MKSTRING(buffer COMMA_CON);
  3152     retVal = _MKSTRING(buffer COMMA_CON);
  2854     free(buffer);
  3153 err:
  2855 %}
  3154     if (buffer)
  2856 .
  3155 	free(buffer);
       
  3156 %}.
       
  3157     lastErrorNumber notNil ifTrue:[^ self readError].
  2857     ^ retVal
  3158     ^ retVal
  2858 ! !
  3159 ! !