ReadStream.st
changeset 1 a27a279701f8
child 2 6526dde5f3ac
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ReadStream.st	Fri Jul 16 11:39:45 1993 +0200
@@ -0,0 +1,407 @@
+"
+ COPYRIGHT (c) 1988-93 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.
+"
+
+PositionableStream subclass:#ReadStream
+       instanceVariableNames:''
+       classVariableNames:''
+       poolDictionaries:''
+       category:'Streams'
+!
+
+ReadStream comment:'
+
+COPYRIGHT (c) 1988-93 by Claus Gittinger
+              All Rights Reserved
+
+ReadStream defines protocol for reading streamwise over collections. Code here
+is specially tuned for streaming over strings.
+
+%W% %E%
+'!
+
+!ReadStream methodsFor:'access-reading'!
+
+peek
+    "return the next element; do NOT advance read pointer.
+     - reimplemented for speed on String-Streams"
+
+%{  /* NOCONTEXT */
+
+    REGISTER int pos;
+    unsigned ch;
+
+    if (_isString(_INST(collection))
+     && _isSmallInteger(_INST(position))
+     && _isSmallInteger(_INST(readLimit))) {
+
+        pos = _intVal(_INST(position));
+        if (pos > _intVal(_INST(readLimit))) {
+            RETURN ( nil );
+        }
+        if ((pos > 0)
+         && (pos < _qSize(_INST(collection)) - OHDR_SIZE)) {
+            ch = _stringVal(_INST(collection))[pos-1];
+            RETURN ( _MKCHARACTER(ch) );
+        }
+    }
+%}
+.
+    (position > readLimit) ifTrue:[^ nil].
+    ^ collection at:position
+!
+
+next
+    "return the next element; advance read pointer.
+     - reimplemented for speed on String-Streams"
+
+    |ret|
+
+%{  /* NOCONTEXT */
+
+    REGISTER int pos;
+    unsigned ch;
+
+    if (_isString(_INST(collection))
+     && _isSmallInteger(_INST(position))
+     && _isSmallInteger(_INST(readLimit))) {
+
+        pos = _intVal(_INST(position));
+        if (pos > _intVal(_INST(readLimit))) {
+            RETURN ( nil );
+        }
+        if ((pos > 0)
+         && (pos < _qSize(_INST(collection)) - OHDR_SIZE)) {
+            ch = _stringVal(_INST(collection))[pos-1];
+            _INST(position) = _MKSMALLINT(pos + 1);
+            RETURN ( _MKCHARACTER(ch) );
+        }
+    }
+%}
+.
+    (position > readLimit) ifTrue:[^ nil].
+    ret := collection at:position.
+    position := position + 1.
+    ^ ret
+!
+
+nextPeek
+    "advance read pointer return the peek element.
+     this is equivalent to (self next; peek).
+     - reimplemented for speed on String-Streams"
+
+%{  /* NOCONTEXT */
+
+    if (_isString(_INST(collection))
+     && _isSmallInteger(_INST(position))
+     && _isSmallInteger(_INST(readLimit))) {
+        REGISTER int pos;
+        unsigned ch;
+
+        pos = _intVal(_INST(position));
+        if (pos > _intVal(_INST(readLimit))) {
+            RETURN ( nil );
+        }
+        if ((pos > 0)
+         && (pos < _qSize(_INST(collection)) - OHDR_SIZE)) {
+            _INST(position) = _MKSMALLINT(pos + 1);
+            pos = pos + 1;
+            if (pos < _qSize(_INST(collection)) - OHDR_SIZE) {
+                ch = _stringVal(_INST(collection))[pos-1];
+                RETURN ( _MKCHARACTER(ch) );
+            }
+            RETURN ( nil );
+        }
+    }
+%}
+.
+    (position > readLimit) ifTrue:[^ nil].
+    position := position + 1.
+    (position > readLimit) ifTrue:[^ nil].
+    ^ collection at:position
+!
+
+nextDecimalInteger
+    "read the next integer in radix 10. dont skip whitespace.
+     - reimplemented for speed on String-Streams"
+
+    |value|
+%{
+    int pos, limit, sz;
+    register unsigned char *cp;
+    register unsigned ch;
+    int val = 0;
+
+    if (_isString(_INST(collection))
+     && _isSmallInteger(_INST(position))
+     && _isSmallInteger(_INST(readLimit))) {
+        pos = _intVal(_INST(position));
+        limit = _intVal(_INST(readLimit));
+        sz = _qSize(_INST(collection)) - OHDR_SIZE;
+        if (sz < limit)
+            limit = sz; 
+        cp = _stringVal(_INST(collection)) + 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++;
+        }
+        _INST(position) = _MKSMALLINT(pos);
+        return _MKSMALLINT(val);
+    }
+oops:
+    value = _MKSMALLINT(val);
+%}
+.
+    [self peek notNil and:[self peek isDigitRadix:10]] whileTrue:[
+        value = (value * 10) + self peek digitValue.
+        self next
+    ].
+    ^ value
+!
+
+nextWord
+    "read the next word (i.e. up to non letter-or-digit).
+     return a string containing those characters.
+     - reimplemented for speed on String-Streams"
+%{
+    /* speedup, if collection is a string */
+
+    int pos, limit, sz;
+    int len;
+    char buffer[1024];
+    register unsigned char *cp;
+    register unsigned ch;
+
+    if (_isString(_INST(collection))
+     && _isSmallInteger(_INST(position))
+     && _isSmallInteger(_INST(readLimit))) {
+        pos = _intVal(_INST(position));
+        limit = _intVal(_INST(readLimit));
+        sz = _qSize(_INST(collection)) - OHDR_SIZE;
+        if (sz < limit)
+            limit = sz; 
+        cp = _stringVal(_INST(collection)) + pos - 1;
+
+        for (;;) {
+            if (pos > limit) break;
+            ch = *cp;
+
+            if (ch > ' ') break;
+            if ((ch != ' ') && (ch != '\t') && (ch != '\r')
+             && (ch != '\n') && (ch != 0x0b)) 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++;
+        }
+
+        _INST(position) = _MKSMALLINT(pos);
+        buffer[len] = '\0';
+        RETURN ( (len != 0) ? _MKSTRING(buffer COMMA_CON) : nil );
+    }
+%}
+.
+    ^ super nextWord
+!
+
+nextSymbol
+    "read the next selector-symbol (i.e. up to non letter-or-digit).
+     return a string containing those characters.
+     - reimplemented for speed on String-Streams"
+%{
+    int pos, limit, sz;
+    int len;
+    char buffer[1024];
+    register unsigned char *cp;
+    register unsigned ch;
+
+    if (_isString(_INST(collection))
+     && _isSmallInteger(_INST(position))
+     && _isSmallInteger(_INST(readLimit))) {
+        pos = _intVal(_INST(position));
+        limit = _intVal(_INST(readLimit));
+        sz = _qSize(_INST(collection)) - OHDR_SIZE;
+        if (sz < limit)
+            limit = sz; 
+        cp = _stringVal(_INST(collection)) + pos - 1;
+
+        len = 0;
+        for (;;) {
+            if (pos > limit) break;
+            ch = *cp;
+
+            if (! (((ch >= 'a') && (ch <= 'z')) ||
+                   ((ch >= 'A') && (ch <= 'Z')) ||
+                   ((ch >= '0') && (ch <= '9')) ||
+                   (ch == ':')))
+                break;
+            buffer[len++] = ch;
+            if (len >= (sizeof(buffer)-1)) {
+                /* emergency */
+                break;
+            }
+            pos++;
+            cp++;
+        }
+
+        _INST(position) = _MKSMALLINT(pos);
+        buffer[len] = '\0';
+        RETURN ( (len != 0) ? _MKSTRING(buffer COMMA_CON) : nil );
+    }
+%}
+.
+    ^ super nextSymbol
+!
+
+skipFor:anObject
+    "skip all objects up-to and including anObject;
+     return the element after anObject.
+     - reimplemented for speed on String-Streams"
+
+%{  /* NOCONTEXT */
+
+    if (_isString(_INST(collection))
+     && _isCharacter(anObject)
+     && _isSmallInteger(_INST(position))
+     && _isSmallInteger(_INST(readLimit))) {
+        REGISTER unsigned char *chars;
+        REGISTER int pos, limit;
+	unsigned ch;
+
+        pos = _intVal(_INST(position));
+        if (pos <= 0) {
+            RETURN ( nil );
+        }
+
+        limit = _intVal(_INST(readLimit));
+        if (limit > (_qSize(_INST(collection)) - OHDR_SIZE))
+            limit = _qSize(_INST(collection)) - OHDR_SIZE;
+
+        chars = (unsigned char *)(_stringVal(_INST(collection)) + pos - 1);
+        ch = _intVal(_characterVal(anObject)) & 0xFF;
+        while (pos < limit) {
+            if (*chars == ch) {
+                ch = *++chars;
+                pos++;
+                _INST(position) = _MKSMALLINT(pos);
+                RETURN ( _MKCHARACTER(ch) );
+            }
+            chars++;
+            pos++;
+        }
+        _INST(position) = _MKSMALLINT(pos);
+        RETURN ( nil );
+    }
+%}
+.
+    ^ super skipFor:anObject
+!
+
+
+skipSeparators
+    "skip all whitespace; next will return next non-white-space element.
+     - reimplemented for speed on String-Streams"
+
+%{  /* NOCONTEXT */
+
+    if (_isString(_INST(collection))
+     && _isSmallInteger(_INST(position))
+     && _isSmallInteger(_INST(readLimit))) {
+        REGISTER unsigned char *chars;
+        REGISTER unsigned ch;
+        REGISTER int pos;
+        int limit;
+
+        pos = _intVal(_INST(position));
+        if (pos <= 0) {
+            RETURN ( nil );
+        }
+
+        limit = _intVal(_INST(readLimit));
+        if (limit > (_qSize(_INST(collection)) - OHDR_SIZE))
+            limit = _qSize(_INST(collection)) - OHDR_SIZE;
+
+        chars = (unsigned char *)(_stringVal(_INST(collection)) + pos - 1);
+        while (pos <= limit) {
+            ch = *chars++;
+            if ((ch != ' ') && (ch != '\t') && (ch != '\r')
+             && (ch != '\n') && (ch != 0x0B)) {
+                _INST(position) = _MKSMALLINT(pos);
+                RETURN ( _MKCHARACTER(ch) );
+            }
+            pos++;
+        }
+        _INST(position) = _MKSMALLINT(pos);
+        RETURN ( nil );
+    }
+%}
+.
+    ^ super skipSeparators
+!
+
+skipToAll:aCollection
+    "skip for the sequence given by the argument, aCollection;
+     return nil if not found, self otherwise. On a successful match, next read
+     will return elements of aCollection."
+
+    |oldPos buffer l first idx|
+
+    oldPos := self position.
+    l := aCollection size.
+    first := aCollection at:1.
+    [self atEnd] whileFalse:[
+        buffer := self next:l.
+        buffer = aCollection ifTrue:[
+            self position:(self position - l).
+            ^ self
+        ].
+        idx := buffer indexOf:first startingAt:2.
+        idx == 0 ifFalse:[
+            self position:(self position - l + idx - 1)
+        ]
+    ].
+    self position:oldPos.
+    ^ nil
+
+    "|s|
+     s := ReadStream on:'12345678901234567890'.
+     s skipToAll:'901'.
+     s next:4"
+! !
+
+!ReadStream methodsFor:'access-writing'!
+
+nextPut:anElement
+    ^ self error:'ReadStreams cannot write'
+! !