eXept Software AG Logo

Smalltalk/X Webserver

Documentation of class 'PeekableStream':

Home

Documentation
www.exept.de
Everywhere
for:
[back]

Class: PeekableStream


Inheritance:

   Object
   |
   +--Stream
      |
      +--PeekableStream
         |
         +--ActorStream
         |
         +--CollectingReadStream
         |
         +--EncodedStream
         |
         +--FilteringStream
         |
         +--IteratorStream
         |
         +--JSONReader
         |
         +--MultiReadStream
         |
         +--PositionableStream
         |
         +--ZipArchive::AbstractZipStream

Package:
stx:libbasic
Category:
Streams
Version:
rev: 1.94 date: 2024/01/30 08:48:16
user: stefan
file: PeekableStream.st directory: libbasic
module: stx stc-classLibrary: libbasic

Description:


abstract superclass for all Stream which support read-ahead
(i.e. peeking) of one element.
Concrete subclasses must implement a peek method.

[caveat:]
    Basing capabilities like readability/writability/positionability/peekability on inheritance makes
    the class hierarchy ugly and leads to strange and hard to teach redefinitions (aka. NonPositionableStream
    below PositionableStream or ExternalReadStream under WriteStream)

copyright

COPYRIGHT (c) 1994 by Claus Gittinger All Rights Reserved This software is furnished under a license and may be used only in accordance with the terms of that license and with the inclusion of the above copyright notice. This software may not be provided or otherwise made available to, or used by, any other person. No title to or ownership of the software is hereby transferred.

Class protocol:

Signal constants
o  currentFileInDirectoryQuerySignal
return the querySignal, which can be used to ask for the current directory
during a fileIn (that is the directory where the filed-in file resides),
and in a fileBrowsers doIt.
Using this, allows for the loaded code or doIts to ask for the fileBrowsers
current directory, by asking this querySignal (which is nice sometimes).

o  currentSourceContainerQuery
return the querySignal, which can be used to ask for the current source container filename
during a fileIn
Using this, allows for the loaded code to remember the classes file name.

class initialization
o  initialize
setup the signal used to handle errors during fileIn

Usage example(s):

     self initialize

queries
o  currentFileInDirectory
during a fileIn (if a script), the script can ask for the current directory

o  currentSourceContainer
during a fileIn (if a script), the script can ask for the current filename

testing
o  isAbstract
Return if this class is an abstract class.
True is returned here for myself only; false for subclasses.
Abstract subclasses must redefine this again.


Instance protocol:

chunk input/output
o  nextChunk
return the next chunk, i.e. all characters up to the next
exclamation mark. Within the chunk, exclamation marks have to be doubled,
they are undoubled here.
Except for primitive code, in which doubling is not needed (allowed).
This exception was added to make it easier to edit primitive code with
external editors. However, this means, that other Smalltalks cannot always
read chunks containing primitive code
- but that doesn't really matter, since C-primitives are an ST/X feature anyway.

Usage example(s):

match primitive only at beginning of line 
         (ExternalStream>>#nextChunk did this, although stc allows primitive to start anywhere)

Usage example(s):

now map CR LF to LF (ExternalStream>>#nextChunk did this)

Usage example(s):

map all CR in a CR only file to NL (ExternalStream>>#nextChunk did this)

fileIn
o  fileIn
file in from the receiver, i.e. read chunks and evaluate them.
Return the value of the last chunk.

o  fileInToPackage: package
file in from the receiver, i.e. read chunks and evaluate them.
Return the value of the last chunk.
Code will be installed into the given package.

positioning
o  skipAny: skipCollection
skip all elements included in the argument-collection.
Returns the next peeked element or nil, if the end-of-stream was reached.

Usage example(s):

     |s skipChars|

     s := ReadStream on:'some numbers1234with\in other99 stuff' withCRs.
     skipChars := 'abcdefghijklmnopqrstuvwxyz\ ' withCRs.
     s skipAny:skipChars.
     Transcript showCR:(Integer readFrom:s).
     s skipAny:skipChars.
     Transcript showCR:(Integer readFrom:s).

o  skipSeparators
skip all whitespace;
return the next peeked element or nil, if the end-of-stream was reached.
The stream's elements should be characters.
Notice: compare this method to skipSpaces

Usage example(s):

     |s|

     s := ReadStream on:'one      two\three' withCRs.
     s skipSeparators.
     Transcript showCR:(s nextAlphaNumericWord).
     s skipSeparators.
     Transcript showCR:(s nextAlphaNumericWord).
     s skipSeparators.
     Transcript showCR:(s next displayString).

o  skipSeparatorsExceptCR
skip all whitespace except carriage return; returns the
next peeked element or nil, if the end-of-stream was reached.
The stream's elements should be characters.
Notice: compare this method to skipSpaces and skipSeparators

o  skipSpaces
skip all spaces; returns the next peeked element or
nil, if the end-of-stream was reached.
The stream's elements should be characters.
Notice: this one skips only spaces (i.e. no cr, tabs etc)
usually, skipSeparators is what you want.

Usage example(s):

     |s|

     s := ReadStream on:'one      two\three' withCRs.
     s skipSpaces.
     Transcript showCR:(s nextWord).
     s skipSpaces.
     Transcript showCR:(s nextWord).
     s skipSpaces.
     Transcript showCR:(s next displayString).

private fileIn
o  basicFileInNotifying: someone passChunk: passChunk
central method to file in from the receiver, i.e. read chunks and evaluate them -
return the value of the last chunk.
Someone (which is usually some codeView) is notified of errors.

o  fileInNextChunkNotifying: someone
read next chunk, evaluate it and return the result;
someone (which is usually some codeView) is notified of errors.
Filein is done as follows:
read a chunk
if it started with an excla, evaluate it, and let the resulting object
fileIn more chunks.
This is a nice trick, since the methodsFor: expression evaluates to
a ClassCategoryReader which reads and compiles chunks for its class.
However, other than methodsFor expressions are possible - you can
(in theory) create readers for any syntax.

o  fileInNextChunkNotifying: someone passChunk: passChunk
read next chunk, evaluate it and return the result;
someone (which is usually some codeView) is notified of errors.
Filein is done as follows:
read a chunk
if it started with an excla, evaluate it, and let the resulting object
fileIn more chunks.
This is a nice trick, since the methodsFor: expression evaluates to
a ClassCategoryReader which reads and compiles chunks for its class.
However, other than methodsFor expressions are possible - you can
(in theory) create readers for any syntax.

o  fileInNextChunkNotifying: someone passChunk: passChunk silent: beSilent
read next chunk, evaluate it and return the result;
someone (which is usually some codeView) is notified of errors.
Filein is done as follows:
read a chunk
if it started with an excla, evaluate it, and let the resulting object
fileIn more chunks.
This is a nice trick, since the methodsFor: expression evaluates to
a ClassCategoryReader which reads and compiles chunks for its class.
However, other than methodsFor expressions are possible - you can
(in theory) create readers for any syntax.
The beSilent argument controls output to the transcript, if it's true or
false. If it's nil, output is controlled by the Smalltalk>>silenLoading setting.

o  fileInNotifying: notifiedLoader passChunk: passChunk
central method to file in from the receiver, i.e. read chunks and evaluate them -
return the value of the last chunk.
Someone (which is usually some codeView) is notified of errors.

o  fileInNotifying: notifiedLoader passChunk: passChunk inDirectory: aDirectory
central method to file in from the receiver, i.e. read chunks and evaluate them -
return the value of the last chunk.
Someone (which is usually some codeView) is notified of errors.
Add aDirectory to the search path for classes, while performing the fileIn.

o  fileInXMLNotifying: someone passChunk: passChunk
filein an XML source file (format as in campSmalltalk DTD)

reading
o  contents
return a collection of the elements up-to the end.
Return an empty collection, if the stream is already at the end.

o  nextPeek
advance to next element and return the peeked element.
this is equivalent to (self next; peek).

o  nextPeekOrNil
advance to next element and return the peeked element

o  nextUpTo: anObject
read a collection of all objects up-to anObject and return these
elements, but excluding anObject.
The next read operation will return anObject.
If anObject is not encountered, all elements up to the end are read
and returned, and the stream is positioned at the end.
Compare this with #upTo: which positions behind anObject

Usage example(s):

     |s|
     s := ReadStream on:#(1 2 3 4 5 6 7 8).
     Transcript showCR:(s nextUpTo:4).  
     Transcript showCR:s next

     |s|
     s := ReadStream on:#(1 2 3 4 5 6 7 8).
     Transcript showCR:(s upTo:4).  
     Transcript showCR:s next

     |s|
     s := ReadStream on:#(1 2 3 4 5 6 7 8).
     Transcript showCR:(s nextUpTo:9).  
     Transcript showCR:s next

     |s|
     s := ReadStream on:#(1 2 3 4 5 6 7 8).
     Transcript showCR:(s upTo:9).  
     Transcript showCR:s next

o  peek
return the next element of the stream without advancing (i.e.
the following send of next will return this element again.)
- we do not know here how to do it, it must be redefined in subclass

** This method must be redefined in concrete classes (subclassResponsibility) **

o  peekFor: anObject
if the next-to-be-read object is equal to the argument, anObject, read it
and return true. Otherwise, leave the receiver unaffected and return false.

Usage example(s):

      #() readStream peekFor:nil
      #() readStream signalAtEnd:true; peekFor:nil
      #(nil) readStream peekFor:nil
      'abc' readStream next; peekFor:$b.
      'abc' readStream next; peekFor:$c.

o  peekOrNil
like #peek, this returns the next readAhead element, if available.
However, unlike #peek, this does not raise an atEnd-query signal - even
if handled. Instead, nil is returned immediately.

o  skipThroughAnyForWhich: checkBlock
read & skip all objects up-to and including
the elements for which checkBlock returns true.
(i.e. skip until checkBlock returns false on an element)
If no such element is encountered, all elements up to the end
are skipped.

Usage example(s):

     |s|
     s := ReadStream on:#(1 2 3 4 5 6 7 8).
     s skipThroughAnyForWhich:[:e| e <= 4].  
     Transcript showCR:s next

     |s|
     s := ReadStream on:'hello world, this is some text'.
     s skipThroughAnyForWhich:[:ch | ch isSeparator not].
     s skipThroughAnyForWhich:[:ch | ch isSeparator].
     s skipThroughAnyForWhich:[:ch | ch isSeparator not].  
     s skipThroughAnyForWhich:[:ch | ch isSeparator].
     Transcript showCR:s upToEnd.

o  skipUntil: aBlock
skip all elements for which aBlock returns false.
Return true if more elements can be read, false if eof has been reached.

Usage example(s):

     #(1 2 3 4 5 6 7 8 9 10) readStream
        skipUntil:[:el | el >= 5];
        next

o  skipWhile: aBlock
skip all elements for which aBlock returns true.
Return true if more elements can be read,
false if eof has been reached.

Usage example(s):

     #(1 2 3 4 5 6 7 8 9 10) readStream
        skipWhile:[:el | el <= 5];
        next

o  throughAnyAtMost: limit forWhich: checkBlock
read & return a collection of all objects up-to and including
the element for which checkBlock returns true,
but stop when limit elements have been read.
(i.e. read until checkBlock returns false on an element or limit is reached)
If no such element is encountered, all elements up to the end, but not more than limit
are read and returned.

o  throughAnyForWhich: checkBlock
read & return a collection of all objects up-to and including
the element for which checkBlock returns true.
(i.e. read until checkBlock returns false on an element)
If no such element is encountered, all elements up to the end are read
and returned.

Usage example(s):

     |s|
     s := ReadStream on:#(1 2 3 4 5 6 7 8).
     Transcript showCR:(s throughAnyForWhich:[:e| e <= 4]).  
     Transcript showCR:s next

     |s|
     s := ReadStream on:'hello world, this is some text'.
     Transcript showCR:(s throughAnyForWhich:[:ch | ch isSeparator not]).  
     Transcript showCR:(s throughAnyForWhich:[:ch | ch isSeparator not]).  
     Transcript showCR:s upToEnd.

o  upToAny: aCollectionOfObjects
read a collection of all objects up to an element that is contained in
aCollectionOfObjects and return these elements, but excluding the matching one.
The next read operation will return the element AFTER anObject.
If no such element is encountered, all elements up to the end are read
and returned.
Compare this with #throughAll: which also reads up to some object
and also positions behind it, but DOES include it in the returned
value.

Usage example(s):

     |s|
     s := ReadStream on:'hello world'.
     Transcript showCR:(s upToAny:(Array with:Character space)).
     Transcript showCR:(s upToEnd)

     'Makefile' asFilename readStream upToAny:($A to:$Z)

o  upToBeforeAny: aCollectionOfObjects
read a collection of all objects up to an element that is contained in
aCollectionOfObjects and return these elements, but excluding the matching one.
The next read operation will return the matching element.
If no such element is encountered, all elements up to the end are read
and returned.
This returns the exact same as upToAny: would, but leaves the stream's position so that
the next read returns the matching delimiter instead of skipping it.
Caveat: this is the one which should have been called upTo: in the first place;
however, it seems now too late for a change.

Usage example(s):

     |s|
     s := ReadStream on:'hello world'.
     Transcript showCR:(s upToBeforeAny:(Array with:Character space)).
     Transcript showCR:(s upToEnd)

     'Make.proto' asFilename readStream upToBeforeAny:($A to:$Z)

o  upToElementForWhich: aBlock
read elements until aBlock returns true for an element.
Return the collected elements excluding that element.
Leave the stream positioned for the next read to return that element.
If no element matches, all elements up to the end are returned.
Notice the slight difference to upTo:, which positions AFTER the matched element,
whereas this leaves the stream positioned before the matched element.
(which - although being somewaht inconsistent -
kind of makes sense, because with upTo:, you know what the next character
is, whereas with this method, you might want to take a look at it)

Usage example(s):

     #(1 2 3 4 5 6 7 8 9 10) readStream
        upToElementForWhich:[:el | el > 5]

Usage example(s):

     |s part1 part2|
     s := 'abc$def' readStream.
     part1 := s upToElementForWhich:[:el | el isLetter not]. 
     part2 := s upToEnd.    

o  upToMatching: aBlock
marked as obsolete by exept MBP at 21-Jul-2021

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  upToSeparator
Return the next elements up to but not including the next separator.
The next read will return the separator.
If no separator is encountered, the contents up to the end is returned.
The elements are supposed to understand #isSeparator
(i.e. the receiver is supposed to be a character-stream).

Usage example(s):

     'hello world' readStream upToSeparator
     'helloworld' readStream upToSeparator
     'helloworld' readStream upToSeparator
     '' readStream upToSeparator

     |s s1 s2|
     s := 'hello world' readStream.
     s1 := s upToSeparator.
     s2 := s upToSeparator.
     {s1 . s2} inspect.

     |s|
     s := 'hello world' readStream.
     s upToSeparator.
     s upToEnd

reading-numbers
o  nextDecimalInteger
read the next integer in radix 10.
Does NOT skip initial whitespace.
Does NOT care for an initial sign.
The stream's elements should be characters.

Be careful - this method returns 0 if not positioned on a digit initially
or if the end of the stream is encountered.

Usage example(s):

     |s|

     s := '1234 5678' readStream.
     s nextDecimalInteger.

Usage example(s):

     |s|

     s := '1234 5678' readStream.
     s nextDecimalInteger.
     s skipSpaces.
     s nextDecimalInteger.

reading-strings
o  nextAlphaNumericWord
read the next word (i.e. up to non letter-or-digit).
Return a string containing those characters.
Any leading non-alphaNumeric chars are skipped.

National letters or digits in unicode are not treated as letters.

Usage example(s):

     |s|

     s := 'hello world 1234 foo1 foo2' asUnicodeString readStream.
     [s atEnd] whileFalse:[
        Transcript showCR:(s nextAlphaNumericWord).
     ].

Usage example(s):

     |s|

     s := 'hello +++ #world привiт ###123###abc### 1234 foo1 foo2++++' asUnicodeString readStream.
     [s atEnd] whileFalse:[
        Transcript showCR:(s nextAlphaNumericWord).
     ].

o  nextDelimited: terminator
return the contents of the receiver, up to the next terminator element.
Doubled terminators indicate an embedded terminator element.
For example: 'this '' was a quote'.
Start positioned before the initial terminator.

Usage example(s):

     ('*foo bar baz* more foo' readStream nextDelimited:$*) 
     ('*foo bar **baz***' readStream nextDelimited:$*)   

o  nextMatching: matchBlock1 thenMatching: matchBlock2
read the next word. The first character must match matchBlock1,
remaining characters must match matchBlock2.
Return a string containing those characters.
Useful to read identifiers, where the first char is from a different
set than the remaining (letter vs. letterOrDigit)

Usage example(s):

     |s|

     s := 'hello_world_1234 foo1 foo2' readStream.
     s nextMatching:[:c | c isLetter] 
       thenMatching:[:c | c isLetterOrDigit or:[c == $_]].

o  nextSymbol
read the next selector-symbol (i.e. up to non letter-or-digit).
Return a string containing those characters.
Any leading non-alphaNumeric chars are skipped.

Usage example(s):

     |s|

     s := 'hello: world 1234 foo1 foo2:' readStream.
     [s atEnd] whileFalse:[
        Transcript showCR:(s nextSymbol).
     ].

o  scanf: formatString
Read a collection of objects from the receiver according to
formatString, which is assumed to be a conversion control string as
specified in the Unix C-language manual page for scanf(3).
For copyright information, see goodies/String-printf_scanf.chg

Usage example(s):

     |s|

     s := 'hello 1234 world 456.678 abcde' readStream.
     s scanf:'%s %d %s %qf %c%c%c%c'.       
     s := 'hello 1234 world 456.678 abcde' readStream.
     s scanf:'%s %d %s %f %c%c%c' 

Usage example(s):

     |s|

     s := '123hello 1234 world 456.678' readStream.
     s scanf:'123%s %d %s %qf'       

Usage example(s):

     |s|

     s := '123hello 1234 world 456.678' readStream.
     s scanf:'xxx%s %d %s %qf'          

testing
o  isUnicodeEncoded
return true, if the streamed collection is any string (8-, 16- or 32-bit),
which definitly is not using UTF-x or JIS or any other encoding.
I.e. 'self next' always returns a unicode character.
Note: the answer of false does not mean that it is not unicode,
but it does mean that we don't know for sure.

o  isUnicodeEncoded: aBoolean
set to true, if the streamed collection is any string (8-, 16- or 32-bit),
which definitly is not using UTF-x or JIS or any other encoding.
I.e. 'self next' always returns a unicode character.
Note: the answer of false does not mean that it is not unicode,
but it does mean that we don't know for sure.



ST/X 7.7.0.0; WebServer 1.702 at 20f6060372b9.unknown:8081; Tue, 10 Dec 2024 09:55:22 GMT