ReadStream.st
author Jan Vrany <jan.vrany@fit.cvut.cz>
Mon, 12 Jul 2010 17:20:36 +0100
branchjv
changeset 17780 b6e42c92eba0
parent 17772 6e0b3c06c364
child 17807 06cc6c49e291
permissions -rw-r--r--
Merged with /trunk

"
 COPYRIGHT (c) 1988 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.
"
"{ Package: 'stx:libbasic' }"

PositionableStream subclass:#ReadStream
	instanceVariableNames:''
	classVariableNames:''
	poolDictionaries:''
	category:'Streams'
!

!ReadStream class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 1988 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.
"
!

documentation
"
    ReadStream defines protocol for reading streamwise over collections. 

    [author:]
	Claus Gittinger

"
! !

!ReadStream class methodsFor:'blocked instance creation'!

with:aCollection
    "with on readStream makes no sense 
     - what do you want to read from the end of a collection?"
    <resource:#obsolete>

    self obsoleteMethodWarning:'WARNING: with: should not be used for ReadStreams - use #on:'.
    ^ super with:aCollection
! !

!ReadStream methodsFor:'converting'!

readStream
    "return a readStream from the receiver. Since this is already
     a readStream, return self."

    ^ self
!

readStreamOrNil
    "return a readStream from the receiver. Since this is already
     a readStream, return self.

     This method has been defined for protocol copmatibility with Filename"

    ^ self
! !

!ReadStream methodsFor:'emphasis'!

emphasis
    "return the emphasis of the current (i.e. next returned by #next)
     element. Streams on a string will return nil for all elements.
     Streams on collections which nothing at all about emphasises, 
     will report an error."

    ^ collection emphasisAt:(position - ZeroPosition + 1).

    "
     |t s|

     t := 'hello world' asText
                emphasizeFrom:1 to:5 with:#bold;
                emphasizeFrom:7 to:11 with:#italic.

     s := t readStream.
     [s atEnd] whileFalse:[
        Transcript show:(s emphasis); show:' '.
        Transcript show:''''; show:(s next); showCR:''''.
     ].
    "

    "Modified: 15.5.1996 / 17:30:33 / cg"
! !

!ReadStream methodsFor:'queries'!

copyFrom:beginning to:end
    ^ collection copyFrom:beginning to:end
!

isReadable
    "return true, if reading is supported by the recevier.
     Here, true is always returned."

    ^ true

    "Modified: 4.10.1997 / 17:59:21 / cg"
!

isWritable
    "return true, if writing is supported by the recevier.
     This has to be redefined in concrete subclasses."

    ^ false
!

size
    "return the number of elements in the streamed collection."

    ^ collection size

    "Created: 13.9.1996 / 18:14:35 / cg"
    "Modified: 4.10.1997 / 17:59:45 / cg"
! !

!ReadStream methodsFor:'reading'!

next
    "return the next element; advance read pointer.
     return nil, if there is no next element.
     - tuned for a bit more speed on String/ByteArray/Array-Streams"

    |ret|

%{  /* NOCONTEXT */

    REGISTER int pos;
    unsigned ch;
    OBJ coll, p, l;

    coll = __INST(collection);
    p = __INST(position);
    l = __INST(readLimit);

    if (__isNonNilObject(coll) && __bothSmallInteger(p, l)) {

        pos = __intVal(p);
        /* make 1-based */
        pos = pos + 1 - __intVal( @global(PositionableStream:ZeroPosition));
        if (pos > 0 && pos <= __intVal(l)) {
            OBJ cls, ret;

            cls = __qClass(coll);
            if (cls == @global(String)) {
                if (pos <= __stringSize(coll)) {
                    ch = __stringVal(coll)[pos-1];
                    ret = __MKCHARACTER(ch);
                    __INST(position) = __mkSmallInteger(__intVal(__INST(position)) + 1);
                    RETURN ( ret );
                }
            } else if (cls == @global(ByteArray)) {
                if (pos <= __byteArraySize(coll)) {
                    ch = __ByteArrayInstPtr(coll)->ba_element[pos-1];
                    ret = __mkSmallInteger(ch);
                    __INST(position) = __mkSmallInteger(__intVal(__INST(position)) + 1);
                    RETURN ( ret );
                }
            } else if (cls == @global(Unicode16String)) {
                if (pos <= __unicode16StringSize(coll)) {
                    ch = __Unicode16StringInstPtr(coll)->s_element[pos-1];
                    ret = __MKUCHARACTER(ch);
                    __INST(position) = __mkSmallInteger(__intVal(__INST(position)) + 1);
                    RETURN ( ret );
                }
            } else if (cls == @global(Array)) {
                if (pos <= __arraySize(coll)) {
                    ret = __ArrayInstPtr(coll)->a_element[pos-1];
                    __INST(position) = __mkSmallInteger(__intVal(__INST(position)) + 1);
                    RETURN ( ret );
                }
            }
        }
    }
%}.
    ((position + 1 - ZeroPosition) > readLimit) ifTrue:[^ self pastEndRead].
    ret := collection at:(position + 1 - ZeroPosition).
    position := position + 1.
    ^ ret
!

next:count
    "return the next count elements of the stream as aCollection,
     which depends on the streams type - (see #contentsSpecies)."

    |answer|

    self contentsSpecies = collection class ifTrue:[
        ((position + count - ZeroPosition) > readLimit) ifFalse:[
            answer := collection copyFrom:position+1 to:position+count.
            position := position+count.
            ^ answer
        ].
    ].
    ^ super next:count

    "
     #[1 2 3 4 5 6 7 8 9] readStream
        next;      
        next:5;    
        next.
    "
!

nextAlphaNumericWord
    "read the next word (i.e. up to non letter-or-digit).
     return a string containing those characters.
     Skips any non-alphanumeric chars first.
     - tuned for speed on String-Streams for faster scanning"
%{
    /* speedup, if collection is a string */

    int pos, limit, sz;
    int len;
    char buffer[256];
    REGISTER unsigned char *cp;
    REGISTER unsigned ch;
    OBJ coll, p, l;

    coll = __INST(collection);
    p = __INST(position);
    l = __INST(readLimit);
    
    if (__isStringLike(coll) && __bothSmallInteger(p, l)) {

        pos = __intVal(p);
        /* make 1-based */
        pos = pos + 1 - __intVal( @global(PositionableStream:ZeroPosition));

        limit = __intVal(l);
        sz = __qSize(coll) - OHDR_SIZE;
        if (sz < limit)
            limit = sz; 
        cp = __stringVal(coll) + pos - 1;

        for (;;) {
            if (pos > limit) break;
            ch = *cp;

            if (((ch >= 'a') && (ch <= 'z')) ||
                ((ch >= 'A') && (ch <= 'Z')) ||
                ((ch >= '0') && (ch <= '9')))
                break;
            cp++;
            pos++;
        }

        len = 0;
        for (;;) {
            if (pos > limit) break;
            ch = *cp & 0xFF;

            if (! (((ch >= 'a') && (ch <= 'z')) ||
                   ((ch >= 'A') && (ch <= 'Z')) ||
                   ((ch >= '0') && (ch <= '9'))))
                break;
            buffer[len++] = ch;
            if (len >= (sizeof(buffer)-1)) {
                /* emergency */
                break;
            }
            pos++;
            cp++;
        }

        /* make ZeroPosition-based */
        pos = pos - 1 + __intVal( @global(PositionableStream:ZeroPosition));
        __INST(position) = __mkSmallInteger(pos);
        buffer[len] = '\0';
        RETURN ( (len != 0) ? __MKSTRING_L(buffer, len) : nil );
    }
%}
.
    ^ super nextAlphaNumericWord
!

nextByte
    "return the next element; advance read pointer.
     return nil, if there is no next element.
     - tuned for a bit more speed on String/ByteArray/Array-Streams"

    |ret|

%{  /* NOCONTEXT */

    REGISTER int pos;
    unsigned ch;
    OBJ coll, p, l;

    coll = __INST(collection);
    p = __INST(position);
    l = __INST(readLimit);

    if (__isNonNilObject(coll) && __bothSmallInteger(p, l)) {

        pos = __intVal(p);
        /* make 1-based */
        pos = pos + 1 - __intVal( @global(PositionableStream:ZeroPosition));
        if (pos > 0 && pos <= __intVal(l)) {
            OBJ cls, ret;

            cls = __qClass(coll);
            if (cls == @global(String)) {
                if (pos <= __stringSize(coll)) {
                    ch = __stringVal(coll)[pos-1];
                    ret = __mkSmallInteger(ch);
                    __INST(position) = __mkSmallInteger(__intVal(__INST(position)) + 1);
                    RETURN ( ret );
                }
            } else if (cls == @global(ByteArray)) {
                if (pos <= __byteArraySize(coll)) {
                    ch = __ByteArrayInstPtr(coll)->ba_element[pos-1];
                    ret = __mkSmallInteger(ch);
                    __INST(position) = __mkSmallInteger(__intVal(__INST(position)) + 1);
                    RETURN ( ret );
                }
            } else if (cls == @global(Array)) {
                if (pos <= __arraySize(coll)) {
                    ret = __ArrayInstPtr(coll)->a_element[pos-1];
                    __INST(position) = __mkSmallInteger(__intVal(__INST(position)) + 1);
                    RETURN ( ret );
                }
            }
        }
    }
%}.
    ((position + 1 - ZeroPosition) > readLimit) ifTrue:[^ self pastEndRead].
    ret := collection at:(position + 1 -ZeroPosition).
    position := position + 1.
    ^ ret asInteger
!

nextBytes:numBytes into:aCollection startingAt:initialIndex
    "return the next numBytes from the stream. If the end is
     reached before, only that many bytes are copyied into the
     collection.
     Returns the number of bytes that have been actually read.
     The receiver must support reading of binary bytes.

     Notice: this method is provided here for protocol completeness
             with externalStreams - it is normally not used with other
             streams."

    ((initialIndex + numBytes - 1) <= aCollection size 
        and:[(position + numBytes) <= readLimit 
        and:[collection isByteCollection 
        and:[aCollection isByteCollection
    ]]]) ifTrue:[
        "do it the fast way"
        aCollection 
            replaceBytesFrom:initialIndex to:(initialIndex + numBytes - 1) 
            with:collection startingAt:position+1.
        position := position + numBytes.
        ^ numBytes
    ].
    "do it the hard way"
    ^ super nextBytes:numBytes into:aCollection startingAt:initialIndex

    "
     |s n buffer|

     buffer := ByteArray new:10.

     s := ReadStream on:#[1 2 3 4 5 6 7 8 9].
     s next:3.
     n := s nextBytes:9 into:buffer startingAt:1.
     Transcript showCR:('n = %1; buffer = <%2>' bindWith:n with:buffer)
    "
!

nextDecimalInteger
    "read the next integer in radix 10. dont skip whitespace.
     - tuned for speed on String-Streams for faster scanning"

    |value nextOne|
%{
    int pos, limit, sz;
    REGISTER unsigned char *cp;
    REGISTER unsigned ch;
    INT val = 0;
    OBJ coll, p, l;

    coll = __INST(collection);
    p = __INST(position);
    l = __INST(readLimit);
    
    if (__isStringLike(coll) && __bothSmallInteger(p, l)) {

        pos = __intVal(p);
        /* make 1-based */
        pos = pos + 1 - __intVal( @global(PositionableStream:ZeroPosition));
        limit = __intVal(l);
        sz = __qSize(coll) - OHDR_SIZE;
        if (sz < limit)
            limit = sz; 
        cp = __stringVal(coll) + pos - 1;

        for (;;) {
            if (pos > limit) break;
            ch = *cp;

            if ((ch < '0') || (ch > '9')) break;
            val = val * 10 + (ch - '0');
            pos++;
            if (val > (_MAX_INT / 10)) goto oops;
            cp++;
        }
        /* make ZeroPosition-based */
        pos = pos - 1 + __intVal( @global(PositionableStream:ZeroPosition));
        __INST(position) = __mkSmallInteger(pos);
        RETURN (__mkSmallInteger(val));
    }
oops:
    value = __mkSmallInteger(val);
%}
.
    "fall-back for non-string streams - we have to continue where
     above primitive left off, in case of a large integer ...
     (instead of doing a super nextDecimalInteger)"

    nextOne := self peek.
    [nextOne notNil and:[nextOne isDigitRadix:10]] whileTrue:[
        value := (value * 10) + nextOne digitValue.
        nextOne := self nextPeek
    ].
    ^ value
!

nextOrNil
    "return the next element; advance read pointer.
     return nil, if there is no next element.
     - tuned for a bit more speed on String/ByteArray/Array-Streams"

    |ret|

%{  /* NOCONTEXT */

    REGISTER int pos;
    unsigned ch;
    OBJ coll, p, l;

    coll = __INST(collection);
    p = __INST(position);
    l = __INST(readLimit);

    if (__isNonNilObject(coll) && __bothSmallInteger(p, l)) {
        pos = __intVal(p);
        /* make 1-based */
        pos = pos + 1 - __intVal( @global(PositionableStream:ZeroPosition));
        if (pos > 0) {
            OBJ cls, ret;

            if (pos > __intVal(l)) {
                RETURN(nil);
            }

            cls = __qClass(coll);
            if (cls == @global(String)) {
                if (pos <= __stringSize(coll)) {
                    ch = __stringVal(coll)[pos-1];
                    ret = __MKCHARACTER(ch);
                    __INST(position) = __mkSmallInteger(__intVal(__INST(position)) + 1);
                    RETURN ( ret );
                }
            } else if (cls == @global(ByteArray)) {
                if (pos <= __byteArraySize(coll)) {
                    ch = __ByteArrayInstPtr(coll)->ba_element[pos-1];
                    ret = __mkSmallInteger(ch);
                    __INST(position) = __mkSmallInteger(__intVal(__INST(position)) + 1);
                    RETURN ( ret );
                }
            } else if (cls == @global(Unicode16String)) {
                if (pos <= __unicode16StringSize(coll)) {
                    ch = __Unicode16StringInstPtr(coll)->s_element[pos-1];
                    ret = __MKUCHARACTER(ch);
                    __INST(position) = __mkSmallInteger(__intVal(__INST(position)) + 1);
                    RETURN ( ret );
                }
            } else if (cls == @global(Array)) {
                if (pos <= __arraySize(coll)) {
                    ret = __ArrayInstPtr(coll)->a_element[pos-1];
                    __INST(position) = __mkSmallInteger(__intVal(__INST(position)) + 1);
                    RETURN ( ret );
                }
            }
        }
    }
%}.
    ret := collection at:(position + 1 - ZeroPosition).
    position := position + 1.
    ^ ret
!

nextPeek
    "advance read pointer return the peek element.
     this is equivalent to (self next; peek).
     - tuned for speed on String-Streams for faster scanning"

%{  /* NOCONTEXT */
    OBJ coll, l, p;

    coll = __INST(collection);
    p = __INST(position);
    l = __INST(readLimit);

    if (__isStringLike(coll) && __bothSmallInteger(p, l)) {
        REGISTER int pos;
        unsigned ch;

        pos = __intVal(p);
        /* make 1-based */
        pos = pos + 1 - __intVal( @global(PositionableStream:ZeroPosition));
        if ((pos > 0) && (pos < __intVal(l)) && (pos < __stringSize(coll))) {
            pos = pos + 1;
            ch = __stringVal(coll)[pos-1];
            /* make ZeroPosition-based */
            pos = pos - 1 + __intVal( @global(PositionableStream:ZeroPosition));
            __INST(position) = __mkSmallInteger(pos);
            RETURN ( __MKCHARACTER(ch) );
        }
    }
%}.
    ((position + 1 - ZeroPosition) > readLimit) ifTrue:[^ self pastEndRead].
    position := position + 1.
    ((position + 1 - ZeroPosition) > readLimit) ifTrue:[^ self pastEndRead].
    ^ collection at:(position + 1 - ZeroPosition)
!

peek
    "return the next element; do NOT advance read pointer.
     return nil, if there is no next element.
     - tuned for a bit more speed on String/ByteArray/Array-Streams"

%{  /* NOCONTEXT */

    REGISTER int pos;
    unsigned ch;
    OBJ coll;
    OBJ cls, p, l;

    coll = __INST(collection);
    p = __INST(position);
    l = __INST(readLimit);

    if (__isNonNilObject(coll) && __bothSmallInteger(p, l)) {

        pos = __intVal(p);
        /* make 1-based */
        pos = pos + 1 - __intVal( @global(PositionableStream:ZeroPosition));
        if (pos <= __intVal(l) && pos > 0) {
            cls = __qClass(coll);
            if (cls == @global(String)) {
                if (pos <= __stringSize(coll)) {
                    ch = __stringVal(coll)[pos-1];
                    RETURN ( __MKCHARACTER(ch) );
                }
            } else if (cls == @global(ByteArray)) {
                if (pos <= __byteArraySize(coll)) {
                    ch = __ByteArrayInstPtr(coll)->ba_element[pos-1];
                    RETURN ( __mkSmallInteger(ch) );
                }
            } else if (cls == @global(Array)) {
                if (pos <= __arraySize(coll)) {
                    RETURN ( __ArrayInstPtr(coll)->a_element[pos-1]);
                }
            }
        }
    }
%}.
    ((position + 1 - ZeroPosition) > readLimit) ifTrue:[^ self pastEndRead].
    ^ collection at:(position + 1 - ZeroPosition)
!

peekOrNil
    "return the next element; do NOT advance read pointer.
     return nil, if there is no next element.
     This is much like #peek -
     However, unlike #peek, this does not raise an atEnd-query signal - even
     if handled. Instead, nil is returned immediately."

%{  /* NOCONTEXT */

    REGISTER int pos;
    unsigned ch;
    OBJ coll;
    OBJ cls, p, l;

    coll = __INST(collection);
    p = __INST(position);
    l = __INST(readLimit);

    if (__isNonNilObject(coll) && __bothSmallInteger(p, l)) {

	pos = __intVal(p);
	/* make 1-based */
	pos = pos + 1 - __intVal( @global(PositionableStream:ZeroPosition));
	if (pos <= __intVal(l) && pos > 0) {
	    cls = __qClass(coll);
	    if (cls == @global(String)) {
		if (pos <= __stringSize(coll)) {
		    ch = __stringVal(coll)[pos-1];
		    RETURN ( __MKCHARACTER(ch) );
		}
		RETURN ( nil );
	    } else if (cls == @global(ByteArray)) {
		if (pos <= __byteArraySize(coll)) {
		    ch = __ByteArrayInstPtr(coll)->ba_element[pos-1];
		    RETURN ( __mkSmallInteger(ch) );
		}
		RETURN ( nil );
	    } else if (cls == @global(Array)) {
		if (pos <= __arraySize(coll)) {
		    RETURN ( __ArrayInstPtr(coll)->a_element[pos-1]);
		}
		RETURN ( nil );
	    }
	}
    }
%}.
    ((position + 1 - ZeroPosition) > readLimit) ifTrue:[^ nil].
    ^ collection at:(position + 1 - ZeroPosition)
!

skipSeparators
    "skip all whitespace; next will return next non-white-space element.
     Return the peeked character or nil, if the end-of-stream was reached.
     - reimplemented for speed on String-Streams for faster scanning"

%{  /* NOCONTEXT */
    OBJ coll, p, l;

    coll = __INST(collection);
    p = __INST(position);
    l = __INST(readLimit);

    if (__isStringLike(coll) && __bothSmallInteger(p, l)) {
        REGISTER unsigned char *chars;
        REGISTER unsigned ch;
        REGISTER int pos;
        int limit;
        int sz;

        pos = __intVal(p);
        /* make 1-based */
        pos = pos + 1 - __intVal( @global(PositionableStream:ZeroPosition));
        if (pos <= 0) {
            RETURN ( nil );
        }

        limit = __intVal(l);
        sz = __qSize(coll) - OHDR_SIZE;
        if (limit > sz) {
            limit = sz;
        }

        chars = (unsigned char *)(__stringVal(coll) + pos - 1);
        while (pos <= limit) {
            pos++;
            ch = *chars++;
            if ((ch > 0x20)
             || ((ch != ' ')
                 && (ch != '\t')
                 && (ch != '\r')
                 && (ch != '\n')
                 && (ch != '\f')
                 && (ch != 0x0B))) {
                /* make ZeroPosition-based */
                pos = pos - 1 + __intVal( @global(PositionableStream:ZeroPosition));
                __INST(position) = __mkSmallInteger(pos-1);
                RETURN ( __MKCHARACTER(ch) );
            }
        }
        /* make ZeroPosition-based */
        pos = pos - 1 + __intVal( @global(PositionableStream:ZeroPosition));
        __INST(position) = __mkSmallInteger(pos);
        RETURN ( nil );
    }
%}.
    ^ super skipSeparators

    "
     |s|

     s := '     hello     world    ' readStream.
     s skipSeparators.
     s next.
    "
!

skipSeparatorsExceptCR
    "skip all whitespace except newlines;
     next will return next non-white-space element.
     - reimplemented for speed on String-Streams for faster scanning"

%{  /* NOCONTEXT */

    OBJ coll, p, l;

    coll = __INST(collection);
    p = __INST(position);
    l = __INST(readLimit);

    if (__isStringLike(coll) && __bothSmallInteger(p, l)) {
        REGISTER unsigned char *chars;
        REGISTER unsigned ch;
        REGISTER int pos;
        int limit;

        pos = __intVal(p);
        /* make 1-based */
        pos = pos + 1 - __intVal( @global(PositionableStream:ZeroPosition));
        if (pos <= 0) {
            RETURN ( nil );
        }

        limit = __intVal(l);
        if (limit > (__qSize(coll) - OHDR_SIZE))
            limit = __qSize(coll) - OHDR_SIZE;

        chars = (unsigned char *)(__stringVal(coll) + pos - 1);
        while (pos <= limit) {
            ch = *chars++;
            if (((int)ch > 0x20)
             || (
                 (ch != ' ') 
                 && (ch != '\t')
                 && (ch != '\f')
                 && (ch != '\b')
                 && (ch != 0x0B))) {
                /* make ZeroPosition-based */
                pos = pos - 1 + __intVal( @global(PositionableStream:ZeroPosition));
                __INST(position) = __mkSmallInteger(pos);
                RETURN ( __MKCHARACTER(ch) );
            }
            pos++;
        }
        /* make ZeroPosition-based */
        pos = pos - 1 + __intVal( @global(PositionableStream:ZeroPosition));
        __INST(position) = __mkSmallInteger(pos);
        RETURN ( nil );
    }
%}
.
    ^ super skipSeparatorsExceptCR
!

skipThrough:anObject
    "skip all objects up-to and including anObject.
     Return the receiver if skip was successful, 
     otherwise (i.e. if not found) return nil and leave the stream positioned at the end.
     On success, the next read operation will return the element after anObject.
     - reimplemented for speed on String-Streams for faster scanning"

%{  /* NOCONTEXT */
    OBJ coll, p, l;

    coll = __INST(collection);
    p = __INST(position);
    l = __INST(readLimit);

    if (__isStringLike(coll)
     && __isCharacter(anObject)
     && __bothSmallInteger(p, l)) {
        REGISTER unsigned char *chars;
        REGISTER int pos, limit;
        unsigned ch;
        int sz;

        pos = __intVal(p);
        /* make 1-based */
        pos = pos + 1 - __intVal( @global(PositionableStream:ZeroPosition));
        if (pos <= 0) {
            RETURN ( nil );
        }

        limit = __intVal(l);
        sz = __stringSize(coll);
        if (limit > sz) limit = sz;

        chars = (unsigned char *)(__stringVal(coll) + pos - 1);
        ch = __intVal(_characterVal(anObject)) & 0xFF;
        while (pos < limit) {
            if (*chars == ch) {
                ch = *++chars;
                pos++;
                /* make ZeroPosition-based */
                pos = pos - 1 + __intVal( @global(PositionableStream:ZeroPosition));
                __INST(position) = __mkSmallInteger(pos);
                RETURN ( self );
            }
            chars++;
            pos++;
        }
        /* make ZeroPosition-based */
        pos = pos - 1 + __intVal( @global(PositionableStream:ZeroPosition));
        __INST(position) = __mkSmallInteger(pos+1);
        RETURN ( nil );
    }
%}.
    ^ super skipThrough:anObject
! !

!ReadStream methodsFor:'writing'!

nextPut:anElement
    "catch write access to readstreams - report an error"

    self shouldNotImplement
! !

!ReadStream class methodsFor:'documentation'!

version
    ^ '$Id: ReadStream.st 10544 2010-07-12 16:20:36Z vranyj1 $'
!

version_CVS
    ^ 'Header: /cvs/stx/stx/libbasic/ReadStream.st,v 1.64 2009/11/05 16:25:23 stefan Exp '
!

version_SVN
    ^ '$Id: ReadStream.st 10544 2010-07-12 16:20:36Z vranyj1 $'
! !