--- a/ExternalStream.st Thu May 12 04:07:15 1994 +0200
+++ b/ExternalStream.st Tue May 17 12:09:46 1994 +0200
@@ -22,7 +22,7 @@
COPYRIGHT (c) 1988 by Claus Gittinger
All Rights Reserved
-$Header: /cvs/stx/stx/libbasic/ExternalStream.st,v 1.15 1994-03-30 09:31:24 claus Exp $
+$Header: /cvs/stx/stx/libbasic/ExternalStream.st,v 1.16 1994-05-17 10:07:23 claus Exp $
written 88 by claus
'!
@@ -35,7 +35,6 @@
#ifdef hpux
# define fileno(f) ((f->__fileH << 8) | (f->__fileL))
#endif
-
%}
!ExternalStream class methodsFor:'documentation'!
@@ -45,6 +44,7 @@
ExternalStream defines protocol common to Streams which have a file-descriptor and
represent some file or communicationChannel of the underlying OperatingSystem.
ExternalStream is abstract; concrete classes are FileStream, PipeStream etc.
+
ExternalStreams can be in two modes: text (the default) and binary.
In text-mode, the elements read/written are characters;
while in binary-mode the basic elements are bytes which read/write as SmallIntegers
@@ -54,11 +54,14 @@
data is not written until either a cr is written (in text mode) or a synchronizeOutput
is sent (in both modes).
- The underlying OperatingSystem streams may either be close explicitely (sending a close)
+ The underlying OperatingSystem streams may either be closed explicitely (sending a close)
or just forgotten - in this case, the garbage collector will eventually collect the
- object AND a close be performed automatically (but you will NOT know when this happens).
- Closing is also suggested - since all streams understand it (it is defined as a noop in
- one of the superclasses).
+ object AND a close will be performed automatically (but you will NOT know when this
+ happens - so it is recommended, that you close your files when no longer needed).
+ Closing is also suggested since if smalltalk is finished (be it by purpose, or due to
+ some crash) the data will not be in the file, if unclosed.
+ All streams understand the close message, so it never hurts to use it (it is defined as
+ a noop in one of the superclasses).
Most of the methods found here redefine inherited methods for better performance,
since I/O from/to files should be fast.
@@ -66,6 +69,8 @@
Recovering a snapshot:
not all streams can be restored to the state they had before - see the implementation of
reOpen in subclasses for more information.
+ For streams sitting on some communication channel (i.e. Pipes and Sockets) you should
+ reestablish the stream upon image restart (make someone dependent on ObjectMemory).
"
! !
@@ -486,8 +491,8 @@
nextByte
"read the next byte and return it as an Integer; return nil on error.
- This is allowed in both text and binary modes, always returning a
- byte binary value."
+ This is allowed in both text and binary modes, always returning the
+ bytes binary value as an integer in 0..255."
%{ /* NOCONTEXT */
@@ -529,6 +534,17 @@
self errorWriteOnly
!
+nextBytesInto:anObject
+ "read bytes into an object; the number of bytes read is defined
+ by the objects size.
+ return the number of bytes written or nil on error.
+ The object must have non-pointer indexed instvars
+ (i.e. be a ByteArray, String, Float- or DoubleArray).
+ Use with care - non object oriented i/o"
+
+ ^ self nextBytes:(anObject size) into:anObject startingAt:1
+!
+
nextBytes:count into:anObject
"read the next count bytes into an object and return the number of
bytes read or nil on error. The object must have non-pointer indexed
@@ -576,7 +592,7 @@
nInstBytes = OHDR_SIZE + nInstVars * sizeof(OBJ);
objSize = _Size(anObject) - nInstBytes;
if ((offs >= 0) && (cnt >= 0) && (objSize >= (cnt + offs))) {
- cp = (char *)_InstPtr(anObject) + OHDR_SIZE + offs;
+ cp = (char *)_InstPtr(anObject) + nInstBytes + offs;
savInt = _immediateInterrupt;
_immediateInterrupt = 1;
do {
@@ -1038,9 +1054,20 @@
self primitiveFailed
!
+nextPutBytesFrom:anObject
+ "write bytes from an object; the number of bytes is defined by
+ the objects size.
+ Return the number of bytes written or nil on error.
+ The object must have non-pointer indexed instvars
+ (i.e. be a ByteArray, String, Float- or DoubleArray).
+ Use with care - non object oriented i/o"
+
+ ^ self nextPutBytes:(anObject size) from:anObject startingAt:1
+!
+
nextPutBytes:count from:anObject
"write count bytes from an object.
- return the number of bytes written or nil on error.
+ Return the number of bytes written or nil on error.
The object must have non-pointer indexed instvars
(i.e. be a ByteArray, String, Float- or DoubleArray).
Use with care - non object oriented i/o"
@@ -1089,7 +1116,7 @@
nInstBytes = OHDR_SIZE + nInstVars * sizeof(OBJ);
objSize = _Size(anObject) - nInstBytes;
if ( (offs >= 0) && (cnt >= 0) && (objSize >= (cnt + offs)) ) {
- cp = (char *)_InstPtr(anObject) + OHDR_SIZE + offs;
+ cp = (char *)_InstPtr(anObject) + nInstBytes + offs;
savInt = _immediateInterrupt;
_immediateInterrupt = 1;
#ifdef OLD
@@ -1127,33 +1154,6 @@
self primitiveFailed
!
-nextPutWord:aNumber
- "write the argument, aNumber as a signed short (two bytes);
- write msb-first for compatibility with other smalltalks.
- I dont know if it should be named nextPutWord: or nextWordPut:;
- one of them will vanish ..."
-
- ^ self nextShortPut:aNumber MSB:true
-!
-
-nextWordPut:aNumber
- "for compatibility - this will vanish"
-
- ^ self nextPutShort:aNumber MSB:true
-!
-
-nextShortPut:aNumber MSB:msbFlag
- "for compatibility - this will vanish"
-
- ^ self nextPutShort:aNumber MSB:msbFlag
-!
-
-nextLongPut:aNumber MSB:msbFlag
- "for compatibility - this will vanish"
-
- ^ self nextPutLong:aNumber MSB:msbFlag
-!
-
nextPutShort:aNumber MSB:msbFlag
"Write the argument, aNumber as a short (two bytes). If msbFlag is
true, data is written most-significant byte first; otherwise least
@@ -1284,12 +1284,12 @@
aNumber isInteger ifTrue:[
msbFlag ifTrue:[
"high word first"
- (self nextShortPut:(aNumber // 16r10000) MSB:true) idNil ifTrue:[^ nil].
- ^ self nextShortPut:(aNumber // 16r10000) MSB:true
+ (self nextShortPut:(aNumber // 16r10000) MSB:true) isNil ifTrue:[^ nil].
+ ^ self nextShortPut:(aNumber \\ 16r10000) MSB:true
].
"low word first"
- (self nextShortPut:(aNumber // 16r10000) MSB:false) isNil ifTrue:[^ nil].
- ^ self nextShortPut:(aNumber \\ 16r10000) MSB:false.
+ (self nextShortPut:(aNumber \\ 16r10000) MSB:false) isNil ifTrue:[^ nil].
+ ^ self nextShortPut:(aNumber // 16r10000) MSB:false.
].
self argumentMustBeInteger
! !
@@ -1525,6 +1525,16 @@
if (__isByteArray(aCollection)) {
cp = _ByteArrayInstPtr(aCollection)->ba_element;
len = _byteArraySize(aCollection);
+ } else {
+ if (__isBytes(aCollection)) {
+ int nInst;
+
+ cp = _ByteArrayInstPtr(aCollection)->ba_element;
+ len = _byteArraySize(aCollection);
+ nInst = _intVal(_ClassInstPtr(_qClass(aCollection))->c_ninstvars);
+ cp += nInst * sizeof(OBJ);
+ len -= nInst * sizeof(OBJ);
+ }
}
}
}
@@ -1592,6 +1602,16 @@
if (__isByteArray(aCollection)) {
cp = _ByteArrayInstPtr(aCollection)->ba_element;
len = _byteArraySize(aCollection);
+ } else {
+ if (__isBytes(aCollection)) {
+ int nInst;
+
+ cp = _ByteArrayInstPtr(aCollection)->ba_element;
+ len = _byteArraySize(aCollection);
+ nInst = _intVal(_ClassInstPtr(_qClass(aCollection))->c_ninstvars);
+ cp += nInst * sizeof(OBJ);
+ len -= nInst * sizeof(OBJ);
+ }
}
}
if (cp != NULL) {
@@ -2015,13 +2035,24 @@
%{ /* NOCONTEXT */
FILE *f;
+ OBJ t;
+ int c;
if (_INST(hitEOF) == true) {
RETURN (true);
}
- if (_INST(filePointer) != nil) {
- f = MKFD(_INST(filePointer));
+ if ((t = _INST(filePointer)) != nil) {
+ f = MKFD(t);
+#ifdef OLD
RETURN ( feof(f) ? true : false );
+#else
+ c = getc(f);
+ if (c == EOF) {
+ RETURN (true);
+ }
+ ungetc(c, f);
+ RETURN (false);
+#endif
}
%}
.
@@ -2201,34 +2232,137 @@
self errorWriteOnly
!
+skipThroughAll:aString
+ "search & skip for the sequence given by the argument, aCollection;
+ return nil if not found, self otherwise. If successfull, the next read
+ will return the character after the searchstring."
+
+ |buffer len first|
+
+ (aString isString and:[binary not]) ifTrue:[
+ len := aString size.
+ first := aString at:1.
+ buffer := String new:len.
+ buffer at:1 put:first.
+ len := len - 1.
+ [true] whileTrue:[
+ (self skipThrough:first) isNil ifTrue:[
+ ^ nil.
+ ].
+ (self nextBytes:len into:buffer startingAt:2) == len ifFalse:[
+ ^ nil
+ ].
+ buffer = aString ifTrue:[
+ "
+ position back, before string
+ "
+ ^ self
+ ].
+ ].
+ "NOT REACHED"
+ ].
+ ^ super skipThroughAll:aString
+
+ "
+ |s|
+ s := 'Makefile' asFilename readStream.
+ s skipThroughAll:'are'.
+ s next:10
+ "
+!
+
skipToAll:aString
"skip for the sequence given by the argument, aCollection;
return nil if not found, self otherwise. On a successful match, next read
will return characters of aString."
- |oldPos buffer l first idx|
+ |oldPos|
+
+ oldPos := self position.
+ (self skipThroughAll:aString) isNil ifTrue:[
+ "
+ restore position
+ "
+ self position:oldPos.
+ ^ nil
+ ].
+ "
+ position before match-string
+ "
+ self position:(self position - aString size).
+ ^ self
+
+ "
+ |s|
+ s := 'Makefile' asFilename readStream.
+ s skipToAll:'are'.
+ s next:10
+ "
+!
+
+skipThrough:aCharacter
+ "skip all characters up-to and including aCharacter. Return the receiver if
+ skip was successfull, otherwise (i.e. if not found) return nil.
+ The next read operation will return the character after aCharacter.
+ The argument, aCharacter must be character, or integer wehn in binary mode."
+
+%{ /* NOCONTEXT */
+
+ FILE *f;
+ REGISTER int c, cSearch;
+ extern int _immediateInterrupt;
+ int savInt;
- (aString isKindOf:String) ifTrue:[
- oldPos := self position.
- l := aString size.
- first := aString at:1.
- buffer := String new:l.
- [true] whileTrue:[
- (self nextBytes:l into:buffer) == l ifFalse:[
- self position:oldPos.
- ^ nil
- ].
- buffer = aString ifTrue:[
- self position:(self position - l).
- ^ self
- ].
- idx := buffer indexOf:first startingAt:2.
- idx == 0 ifFalse:[
- self position:(self position - l + idx - 1)
- ]
- ]
- ].
- ^ super skipFor:aString
+ if ((_INST(filePointer) != nil) && (_INST(mode) != _writeonly)) {
+ if (_INST(binary) == true) {
+ /* searched for object must be a smallInteger */
+ if (! _isSmallInteger(aCharacter)) goto badArgument;
+ cSearch = _intVal(aCharacter);
+ } else {
+ /* searched for object must be a character */
+ if (! __isCharacter(aCharacter)) goto badArgument;
+ cSearch = _intVal(_characterVal(aCharacter));
+ }
+ /* Q: should we just say: "not found" ? */
+ if ((cSearch < 0) || (cSearch > 255)) goto badArgument;
+
+ f = MKFD(_INST(filePointer));
+ if (_INST(mode) == _readwrite)
+ fseek(f, 0L, 1); /* needed in stdio */
+ while (1) {
+ if (feof(f)) {
+ RETURN ( nil );
+ }
+ savInt = _immediateInterrupt;
+ _immediateInterrupt = 1;
+ c = getc(f);
+ _immediateInterrupt = savInt;
+ if (c < 0) {
+ _INST(hitEOF) = true;
+ RETURN ( nil );
+ }
+ if (c == cSearch) {
+ RETURN (self);
+ }
+ }
+ }
+badArgument: ;
+%}
+.
+ filePointer isNil ifTrue:[^ self errorNotOpen].
+ (mode == #writeonly) ifTrue:[^ self errorWriteOnly].
+ "
+ argument must be integer/character in binary mode,
+ character in text mode
+ "
+ ^ self error:'invalid argument'.
+
+ "
+ |s|
+ s := 'Makefile' asFilename readStream.
+ s skipThrough:$=.
+ s next:10
+ "
!
skipSeparators