ReadStream.st
branchjv
changeset 18120 e3a375d5f6a8
parent 18112 0d7ac9096619
parent 17612 368b5e4da6c9
child 18192 32a7c53ef4d0
--- a/ReadStream.st	Tue Feb 04 21:09:59 2014 +0100
+++ b/ReadStream.st	Wed Apr 01 10:20:10 2015 +0100
@@ -1,3 +1,5 @@
+"{ Encoding: utf8 }"
+
 "
  COPYRIGHT (c) 1988 by Claus Gittinger
 	      All Rights Reserved
@@ -11,6 +13,8 @@
 "
 "{ Package: 'stx:libbasic' }"
 
+"{ NameSpace: Smalltalk }"
+
 PositionableStream subclass:#ReadStream
 	instanceVariableNames:''
 	classVariableNames:''
@@ -18,6 +22,22 @@
 	category:'Streams'
 !
 
+!ReadStream primitiveDefinitions!
+%{
+
+#include <stdio.h>
+#define _STDIO_H_INCLUDED_
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#ifdef __osx__
+// missing definition ?
+extern void *memchr( void *, int, size_t);
+#endif
+
+%}
+! !
+
 !ReadStream class methodsFor:'documentation'!
 
 copyright
@@ -55,6 +75,33 @@
     ^ super with:aCollection
 ! !
 
+!ReadStream methodsFor:'Compatibility-Squeak'!
+
+next: n into: aCollection startingAt: startIndex
+    "Read n objects into the given collection.
+    Return aCollection or a partial copy if less than
+    n elements have been read."
+
+    | max |
+
+    collection notNil ifTrue:[
+        max := (readLimit - position) min: n.
+        aCollection
+            replaceFrom: startIndex
+            to: startIndex+max-1
+            with: collection
+            startingAt: position+1.
+        position := position + max.
+        max = n
+            ifTrue:[^ aCollection]
+            ifFalse:[^ aCollection copyFrom: 1 to: startIndex+max-1].
+    ].
+
+    ^ super next:n into:aCollection startingAt:startIndex.
+
+
+    "Modified: / 12-09-2010 / 13:06:09 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
 
 !ReadStream methodsFor:'converting'!
 
@@ -88,13 +135,13 @@
      |t s|
 
      t := 'hello world' asText
-                emphasizeFrom:1 to:5 with:#bold;
-                emphasizeFrom:7 to:11 with:#italic.
+		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:''''.
+	Transcript show:(s emphasis); show:' '.
+	Transcript show:''''; show:(s next); showCR:''''.
      ].
     "
 
@@ -104,7 +151,7 @@
 !ReadStream methodsFor:'queries'!
 
 collectionSize
-    "return the overall number of elements in the streamed collection   
+    "return the overall number of elements in the streamed collection
      (both already read and to be read)."
 
     ^ collection size
@@ -161,7 +208,7 @@
 
 %{  /* NOCONTEXT */
 
-    REGISTER int pos;
+    REGISTER INT pos;
     unsigned ch;
     OBJ coll, p, l;
 
@@ -171,47 +218,45 @@
 
     if (__isNonNilObject(coll) && __bothSmallInteger(p, l)) {
 
-        pos = __intVal(p);
-        /* make 1-based */
-        pos = pos + 1;
-        if (pos > 0 && pos <= __intVal(l)) {
-            OBJ cls, ret;
+	pos = __intVal(p);
+	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 );
-                }
-            }
-        }
+	    cls = __qClass(coll);
+	    if (cls == @global(String)) {
+		if (pos < __stringSize(coll)) {
+		    ch = __stringVal(coll)[pos];
+		    ret = __MKCHARACTER(ch);
+		    __INST(position) = __mkSmallInteger(pos+1);
+		    RETURN ( ret );
+		}
+	    } else if (cls == @global(ByteArray)) {
+		if (pos < __byteArraySize(coll)) {
+		    ch = __ByteArrayInstPtr(coll)->ba_element[pos];
+		    ret = __mkSmallInteger(ch);
+		    __INST(position) = __mkSmallInteger(pos+1);
+		    RETURN ( ret );
+		}
+	    } else if (cls == @global(Unicode16String)) {
+		if (pos < __unicode16StringSize(coll)) {
+		    ch = __Unicode16StringInstPtr(coll)->s_element[pos];
+		    ret = __MKUCHARACTER(ch);
+		    __INST(position) = __mkSmallInteger(pos+1);
+		    RETURN ( ret );
+		}
+	    } else if (cls == @global(Array)) {
+		if (pos < __arraySize(coll)) {
+		    ret = __ArrayInstPtr(coll)->a_element[pos];
+		    __INST(position) = __mkSmallInteger(pos+1);
+		    RETURN ( ret );
+		}
+	    }
+	}
     }
 %}.
     (position >= readLimit) ifTrue:[^ self pastEndRead].
-    ret := collection at:(position + 1).
     position := position + 1.
+    ret := collection at:position.
     ^ ret
 !
 
@@ -221,20 +266,20 @@
 
     |answer|
 
-    self contentsSpecies = collection class ifTrue:[
-        ((position + count) > readLimit) ifFalse:[
-            answer := collection copyFrom:position+1 to:position+count.
-            position := position+count.
-            ^ answer
-        ].
+    self contentsSpecies == collection class ifTrue:[
+	((position + count) > 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.
+	next;
+	next:5;
+	next.
     "
 !
 
@@ -246,9 +291,11 @@
 %{
     /* speedup, if collection is a string */
 
-    int pos, limit, sz;
-    int len;
-    char buffer[256];
+    INT pos, limit, sz;
+    INT len;
+    char quickBuffer[256];
+    char *buffer = quickBuffer;
+    int bufferSize = sizeof(quickBuffer);
     REGISTER unsigned char *cp;
     REGISTER unsigned ch;
     OBJ coll, p, l;
@@ -258,10 +305,11 @@
     l = __INST(readLimit);
 
     if (__isStringLike(coll) && __bothSmallInteger(p, l)) {
+	OBJ retVal;
 
 	pos = __intVal(p);
 	/* make 1-based */
-	pos = pos + 1 - __intVal( @global(PositionableStream:ZeroPosition));
+	pos = pos + 1;
 
 	limit = __intVal(l);
 	sz = __qSize(coll) - OHDR_SIZE;
@@ -269,6 +317,7 @@
 	    limit = sz;
 	cp = __stringVal(coll) + pos - 1;
 
+	/* skip over non-alphanumeric characters */
 	for (;;) {
 	    if (pos > limit) break;
 	    ch = *cp;
@@ -281,6 +330,7 @@
 	    pos++;
 	}
 
+	/* collect non-alphanumeric characters */
 	len = 0;
 	for (;;) {
 	    if (pos > limit) break;
@@ -291,19 +341,32 @@
 		   ((ch >= '0') && (ch <= '9'))))
 		break;
 	    buffer[len++] = ch;
-	    if (len >= (sizeof(buffer)-1)) {
-		/* emergency */
-		break;
+	    if (len >= (bufferSize-1)) {
+		int newBufferSize = bufferSize * 2;
+
+		if (buffer == quickBuffer) {
+		    buffer = (char *)malloc(newBufferSize);
+		    memcpy(buffer, quickBuffer, bufferSize);
+		} else {
+		    buffer = (char *)realloc(buffer, newBufferSize);
+		}
+		bufferSize = newBufferSize;
 	    }
 	    pos++;
 	    cp++;
 	}
 
-	/* make ZeroPosition-based */
-	pos = pos - 1 + __intVal( @global(PositionableStream:ZeroPosition));
+	pos = pos - 1;
 	__INST(position) = __mkSmallInteger(pos);
 	buffer[len] = '\0';
-	RETURN ( (len != 0) ? __MKSTRING_L(buffer, len) : nil );
+	if (len == 0) {
+	    RETURN (nil);
+	}
+	retVal = __MKSTRING_L(buffer, len);
+	if (buffer != quickBuffer) {
+	    free((void *)buffer);
+	}
+	RETURN ( retVal );
     }
 %}
 .
@@ -318,7 +381,7 @@
 
 %{  /* NOCONTEXT */
 
-    REGISTER int pos;
+    REGISTER INT pos;
     unsigned ch;
     OBJ coll, p, l;
 
@@ -328,95 +391,61 @@
 
     if (__isNonNilObject(coll) && __bothSmallInteger(p, l)) {
 
-        pos = __intVal(p);
-        /* make 1-based */
-        pos = pos + 1;
-        if (pos > 0 && pos <= __intVal(l)) {
-            OBJ cls, ret;
+	pos = __intVal(p);
+	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];
-                    if (!__isSmallInteger(ret) || __intVal(ret) > 255) goto out;
-                    __INST(position) = __mkSmallInteger(__intVal(__INST(position)) + 1);
-                    RETURN ( ret );
-                }
-            }
-        }
+	    cls = __qClass(coll);
+	    if (cls == @global(String)) {
+		if (pos < __stringSize(coll)) {
+		    ch = __stringVal(coll)[pos];
+		    ret = __mkSmallInteger(ch);
+		    __INST(position) = __mkSmallInteger(pos+1);
+		    RETURN ( ret );
+		}
+	    } else if (cls == @global(ByteArray)) {
+		if (pos < __byteArraySize(coll)) {
+		    ch = __ByteArrayInstPtr(coll)->ba_element[pos];
+		    ret = __mkSmallInteger(ch);
+		    __INST(position) = __mkSmallInteger(pos+1);
+		    RETURN ( ret );
+		}
+	    } else if (cls == @global(Array)) {
+		if (pos < __arraySize(coll)) {
+		    ret = __ArrayInstPtr(coll)->a_element[pos];
+		    if (!__isSmallInteger(ret) || __intVal(ret) > 255) goto out;
+		    __INST(position) = __mkSmallInteger(pos+1);
+		    RETURN ( ret );
+		}
+	    }
+	}
     }
 out:;
 %}.
     (position >= readLimit) ifTrue:[^ self pastEndRead].
     ret := (collection at:(position + 1)) asInteger.
     ret > 255 ifTrue:[
-        ret := ConversionError 
-            raiseRequestWith:self
-            errorString:' - #nextByte trying to read a non-byte'.
+	ret := ConversionError
+	    raiseRequestWith:self
+	    errorString:' - #nextByte trying to read a non-byte'.
     ].
     position := position + 1.
     ^ ret
 !
 
-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."
+nextDecimalInteger
+    "read the next integer in radix 10.
+     Does NOT skip initial whitespace.
+     The streams elements should be characters.
 
-    ((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
+     Be careful - this method returns 0 if not positioned on a digit intitially
+     or if the end of the stream is encountered.
 
-    "
-     |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"
+     Tuned for speed on String-Streams for faster scanning"
 
     |value nextOne|
 %{
-    int pos, limit, sz;
+    INT pos, limit, sz;
     REGISTER unsigned char *cp;
     REGISTER unsigned ch;
     INT val = 0;
@@ -430,7 +459,7 @@
 
 	pos = __intVal(p);
 	/* make 1-based */
-	pos = pos + 1 - __intVal( @global(PositionableStream:ZeroPosition));
+	pos++;
 	limit = __intVal(l);
 	sz = __qSize(coll) - OHDR_SIZE;
 	if (sz < limit)
@@ -447,8 +476,7 @@
 	    if (val > (_MAX_INT / 10)) goto oops;
 	    cp++;
 	}
-	/* make ZeroPosition-based */
-	pos = pos - 1 + __intVal( @global(PositionableStream:ZeroPosition));
+	pos--;
 	__INST(position) = __mkSmallInteger(pos);
 	RETURN (__mkSmallInteger(val));
     }
@@ -477,7 +505,7 @@
 
 %{  /* NOCONTEXT */
 
-    REGISTER int pos;
+    REGISTER INT pos;
     unsigned ch;
     OBJ coll, p, l;
 
@@ -486,50 +514,48 @@
     l = __INST(readLimit);
 
     if (__isNonNilObject(coll) && __bothSmallInteger(p, l)) {
-        pos = __intVal(p);
-        /* make 1-based */
-        pos = pos + 1;
-        if (pos > 0) {
-            OBJ cls, ret;
+	pos = __intVal(p);
+	if (pos >= 0) {
+	    OBJ cls, ret;
 
-            if (pos > __intVal(l)) {
-                RETURN(nil);
-            }
+	    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 );
-                }
-            }
-        }
+	    cls = __qClass(coll);
+	    if (cls == @global(String)) {
+		if (pos < __stringSize(coll)) {
+		    ch = __stringVal(coll)[pos];
+		    ret = __MKCHARACTER(ch);
+		    __INST(position) = __mkSmallInteger(pos + 1);
+		    RETURN ( ret );
+		}
+	    } else if (cls == @global(ByteArray)) {
+		if (pos < __byteArraySize(coll)) {
+		    ch = __ByteArrayInstPtr(coll)->ba_element[pos];
+		    ret = __mkSmallInteger(ch);
+		    __INST(position) = __mkSmallInteger(pos + 1);
+		    RETURN ( ret );
+		}
+	    } else if (cls == @global(Unicode16String)) {
+		if (pos < __unicode16StringSize(coll)) {
+		    ch = __Unicode16StringInstPtr(coll)->s_element[pos];
+		    ret = __MKUCHARACTER(ch);
+		    __INST(position) = __mkSmallInteger(pos + 1);
+		    RETURN ( ret );
+		}
+	    } else if (cls == @global(Array)) {
+		if (pos < __arraySize(coll)) {
+		    ret = __ArrayInstPtr(coll)->a_element[pos];
+		    __INST(position) = __mkSmallInteger(pos + 1);
+		    RETURN ( ret );
+		}
+	    }
+	}
     }
 %}.
-    ret := collection at:(position + 1).
     position := position + 1.
+    ret := collection at:position.
     ^ ret
 !
 
@@ -546,20 +572,16 @@
     l = __INST(readLimit);
 
     if (__isStringLike(coll) && __bothSmallInteger(p, l)) {
-        REGISTER int pos;
-        unsigned ch;
+	REGISTER INT pos;
+	unsigned ch;
 
-        pos = __intVal(p);
-        /* make 1-based */
-        pos = pos + 1;
-        if ((pos > 0) && (pos < __intVal(l)) && (pos < __stringSize(coll))) {
-            pos = pos + 1;
-            ch = __stringVal(coll)[pos-1];
-            /* make ZeroPosition-based */
-            pos = pos - 1;
-            __INST(position) = __mkSmallInteger(pos);
-            RETURN ( __MKCHARACTER(ch) );
-        }
+	pos = __intVal(p);
+	pos++;
+	if ((pos > 0) && (pos < __intVal(l)) && (pos < __stringSize(coll))) {
+	    ch = __stringVal(coll)[pos];
+	    __INST(position) = __mkSmallInteger(pos);
+	    RETURN ( __MKCHARACTER(ch) );
+	}
     }
 %}.
     (position >= readLimit) ifTrue:[^ self pastEndRead].
@@ -575,7 +597,7 @@
 
 %{  /* NOCONTEXT */
 
-    REGISTER int pos;
+    REGISTER INT pos;
     unsigned ch;
     OBJ coll;
     OBJ cls, p, l;
@@ -586,27 +608,25 @@
 
     if (__isNonNilObject(coll) && __bothSmallInteger(p, l)) {
 
-        pos = __intVal(p);
-        /* make 1-based */
-        pos = pos + 1;
-        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]);
-                }
-            }
-        }
+	pos = __intVal(p);
+	if ((pos < __intVal(l)) && (pos >= 0)) {
+	    cls = __qClass(coll);
+	    if (cls == @global(String)) {
+		if (pos < __stringSize(coll)) {
+		    ch = __stringVal(coll)[pos];
+		    RETURN ( __MKCHARACTER(ch) );
+		}
+	    } else if (cls == @global(ByteArray)) {
+		if (pos < __byteArraySize(coll)) {
+		    ch = __ByteArrayInstPtr(coll)->ba_element[pos];
+		    RETURN ( __mkSmallInteger(ch) );
+		}
+	    } else if (cls == @global(Array)) {
+		if (pos < __arraySize(coll)) {
+		    RETURN ( __ArrayInstPtr(coll)->a_element[pos]);
+		}
+	    }
+	}
     }
 %}.
     (position >= readLimit) ifTrue:[^ self pastEndRead].
@@ -622,7 +642,7 @@
 
 %{  /* NOCONTEXT */
 
-    REGISTER int pos;
+    REGISTER INT pos;
     unsigned ch;
     OBJ coll;
     OBJ cls, p, l;
@@ -633,30 +653,28 @@
 
     if (__isNonNilObject(coll) && __bothSmallInteger(p, l)) {
 
-        pos = __intVal(p);
-        /* make 1-based */
-        pos = pos + 1;
-        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 );
-            }
-        }
+	pos = __intVal(p);
+	if ((pos < __intVal(l)) && (pos >= 0)) {
+	    cls = __qClass(coll);
+	    if (cls == @global(String)) {
+		if (pos < __stringSize(coll)) {
+		    ch = __stringVal(coll)[pos];
+		    RETURN ( __MKCHARACTER(ch) );
+		}
+		RETURN ( nil );
+	    } else if (cls == @global(ByteArray)) {
+		if (pos < __byteArraySize(coll)) {
+		    ch = __ByteArrayInstPtr(coll)->ba_element[pos];
+		    RETURN ( __mkSmallInteger(ch) );
+		}
+		RETURN ( nil );
+	    } else if (cls == @global(Array)) {
+		if (pos < __arraySize(coll)) {
+		    RETURN ( __ArrayInstPtr(coll)->a_element[pos]);
+		}
+		RETURN ( nil );
+	    }
+	}
     }
 %}.
     (position >= readLimit) ifTrue:[^ nil].
@@ -678,13 +696,13 @@
     if (__isStringLike(coll) && __bothSmallInteger(p, l)) {
 	REGISTER unsigned char *chars;
 	REGISTER unsigned ch;
-	REGISTER int pos;
-	int limit;
-	int sz;
+	REGISTER INT pos;
+	INT limit;
+	INT sz;
 
 	pos = __intVal(p);
 	/* make 1-based */
-	pos = pos + 1 - __intVal( @global(PositionableStream:ZeroPosition));
+	pos++;
 	if (pos <= 0) {
 	    RETURN ( nil );
 	}
@@ -697,7 +715,6 @@
 
 	chars = (unsigned char *)(__stringVal(coll) + pos - 1);
 	while (pos <= limit) {
-	    pos++;
 	    ch = *chars++;
 	    if ((ch > 0x20)
 	     || ((ch != ' ')
@@ -706,14 +723,12 @@
 		 && (ch != '\n')
 		 && (ch != '\f')
 		 && (ch != 0x0B))) {
-		/* make ZeroPosition-based */
-		pos = pos - 1 + __intVal( @global(PositionableStream:ZeroPosition));
 		__INST(position) = __mkSmallInteger(pos-1);
 		RETURN ( __MKCHARACTER(ch) );
 	    }
+	    pos++;
 	}
-	/* make ZeroPosition-based */
-	pos = pos - 1 + __intVal( @global(PositionableStream:ZeroPosition));
+	pos--;
 	__INST(position) = __mkSmallInteger(pos);
 	RETURN ( nil );
     }
@@ -745,19 +760,21 @@
     if (__isStringLike(coll) && __bothSmallInteger(p, l)) {
 	REGISTER unsigned char *chars;
 	REGISTER unsigned ch;
-	REGISTER int pos;
-	int limit;
+	REGISTER INT pos;
+	INT limit;
+	INT sz;
 
 	pos = __intVal(p);
 	/* make 1-based */
-	pos = pos + 1 - __intVal( @global(PositionableStream:ZeroPosition));
+	pos = pos + 1;
 	if (pos <= 0) {
 	    RETURN ( nil );
 	}
 
 	limit = __intVal(l);
-	if (limit > (__qSize(coll) - OHDR_SIZE))
-	    limit = __qSize(coll) - OHDR_SIZE;
+	sz = __qSize(coll) - OHDR_SIZE;
+	if (limit > sz)
+	    limit = sz;
 
 	chars = (unsigned char *)(__stringVal(coll) + pos - 1);
 	while (pos <= limit) {
@@ -769,15 +786,13 @@
 		 && (ch != '\f')
 		 && (ch != '\b')
 		 && (ch != 0x0B))) {
-		/* make ZeroPosition-based */
-		pos = pos - 1 + __intVal( @global(PositionableStream:ZeroPosition));
+		pos--;
 		__INST(position) = __mkSmallInteger(pos);
 		RETURN ( __MKCHARACTER(ch) );
 	    }
 	    pos++;
 	}
-	/* make ZeroPosition-based */
-	pos = pos - 1 + __intVal( @global(PositionableStream:ZeroPosition));
+	pos--;
 	__INST(position) = __mkSmallInteger(pos);
 	RETURN ( nil );
     }
@@ -804,42 +819,87 @@
      && __isCharacter(anObject)
      && __bothSmallInteger(p, l)) {
 	REGISTER unsigned char *chars;
-	REGISTER int pos, limit;
+	REGISTER INT pos, limit;
 	unsigned ch;
-	int sz;
+	INT sz;
+
+	ch = __intVal(__characterVal(anObject));
+	if (ch <= 0xFF) {
+	    pos = __intVal(p);
+	    pos = pos + 1;
+	    if (pos <= 0) {
+		RETURN ( nil );
+	    }
 
-	pos = __intVal(p);
-	/* make 1-based */
-	pos = pos + 1 - __intVal( @global(PositionableStream:ZeroPosition));
-	if (pos <= 0) {
+	    limit = __intVal(l);
+	    sz = __stringSize(coll);
+	    if (limit > sz) limit = sz;
+
+	    chars = (unsigned char *)(__stringVal(coll) + pos - 1);
+	    while (pos < limit) {
+		if (*chars == ch) {
+		    ch = *++chars;
+		    __INST(position) = __mkSmallInteger(pos);
+		    RETURN ( self );
+		}
+		chars++;
+		pos++;
+	    }
+	    __INST(position) = __mkSmallInteger(pos);
 	    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
+!
+
+upTo:anObject
+%{
+    OBJ _collection = __INST(collection);
+
+    if (__isString(_collection)
+     && __isCharacter(anObject)) {
+	unsigned int ch = __intVal(__characterVal(anObject));
+
+	if (ch <= 0xFF) {
+	    int _startPos = __intVal(__INST(position));
+	    int _endIndex;
+	    char *startPtr = __stringVal(_collection) + _startPos;
+	    char *foundPtr;
+	    OBJ rslt;
+	    int nMax;
+
+	    _endIndex = __stringSize(_collection);
+	    if (__isInteger(__INST(readLimit))) {
+		int _readLimit = __intVal(__INST(readLimit));
+
+		if (_readLimit < _endIndex) _endIndex = _readLimit;
+	    }
+
+	    nMax = _endIndex-_startPos;
+	    foundPtr = (char *)memchr( startPtr, ch, (long)nMax);
+	    if (foundPtr == 0) {
+		// not found
+		rslt = __MKEMPTYSTRING(nMax);
+		// refetch - may GC
+		_collection = __INST(collection);
+		memcpy((void *)__stringVal(rslt), (void *)(__stringVal(_collection) + _startPos), (size_t)nMax);
+		__INST(position) = __mkSmallInteger(_endIndex);
+	    } else {
+		// found at foundPtr
+		int n = foundPtr-startPtr;
+
+		rslt = __MKEMPTYSTRING(n);
+		// refetch - may GC
+		_collection = __INST(collection);
+		memcpy((void *)__stringVal(rslt), (void *)(__stringVal(_collection) + _startPos), (size_t)n);
+		__INST(position) = __mkSmallInteger(_startPos + n + 1);
+	    }
+	    RETURN (rslt);
+	}
+    }
+%}.
+    ^ super upTo:anObject
 ! !
 
 !ReadStream methodsFor:'writing'!
@@ -853,10 +913,10 @@
 !ReadStream class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic/ReadStream.st,v 1.73 2013-12-02 19:06:35 stefan Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/ReadStream.st,v 1.81 2015-03-12 19:25:11 stefan Exp $'
 !
 
 version_CVS
-    ^ '$Header: /cvs/stx/stx/libbasic/ReadStream.st,v 1.73 2013-12-02 19:06:35 stefan Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/ReadStream.st,v 1.81 2015-03-12 19:25:11 stefan Exp $'
 ! !