ReadStream.st
changeset 1 a27a279701f8
child 2 6526dde5f3ac
equal deleted inserted replaced
0:aa2498ef6470 1:a27a279701f8
       
     1 "
       
     2  COPYRIGHT (c) 1988-93 by Claus Gittinger
       
     3               All Rights Reserved
       
     4 
       
     5  This software is furnished under a license and may be used
       
     6  only in accordance with the terms of that license and with the
       
     7  inclusion of the above copyright notice.   This software may not
       
     8  be provided or otherwise made available to, or used by, any
       
     9  other person.  No title to or ownership of the software is
       
    10  hereby transferred.
       
    11 "
       
    12 
       
    13 PositionableStream subclass:#ReadStream
       
    14        instanceVariableNames:''
       
    15        classVariableNames:''
       
    16        poolDictionaries:''
       
    17        category:'Streams'
       
    18 !
       
    19 
       
    20 ReadStream comment:'
       
    21 
       
    22 COPYRIGHT (c) 1988-93 by Claus Gittinger
       
    23               All Rights Reserved
       
    24 
       
    25 ReadStream defines protocol for reading streamwise over collections. Code here
       
    26 is specially tuned for streaming over strings.
       
    27 
       
    28 %W% %E%
       
    29 '!
       
    30 
       
    31 !ReadStream methodsFor:'access-reading'!
       
    32 
       
    33 peek
       
    34     "return the next element; do NOT advance read pointer.
       
    35      - reimplemented for speed on String-Streams"
       
    36 
       
    37 %{  /* NOCONTEXT */
       
    38 
       
    39     REGISTER int pos;
       
    40     unsigned ch;
       
    41 
       
    42     if (_isString(_INST(collection))
       
    43      && _isSmallInteger(_INST(position))
       
    44      && _isSmallInteger(_INST(readLimit))) {
       
    45 
       
    46         pos = _intVal(_INST(position));
       
    47         if (pos > _intVal(_INST(readLimit))) {
       
    48             RETURN ( nil );
       
    49         }
       
    50         if ((pos > 0)
       
    51          && (pos < _qSize(_INST(collection)) - OHDR_SIZE)) {
       
    52             ch = _stringVal(_INST(collection))[pos-1];
       
    53             RETURN ( _MKCHARACTER(ch) );
       
    54         }
       
    55     }
       
    56 %}
       
    57 .
       
    58     (position > readLimit) ifTrue:[^ nil].
       
    59     ^ collection at:position
       
    60 !
       
    61 
       
    62 next
       
    63     "return the next element; advance read pointer.
       
    64      - reimplemented for speed on String-Streams"
       
    65 
       
    66     |ret|
       
    67 
       
    68 %{  /* NOCONTEXT */
       
    69 
       
    70     REGISTER int pos;
       
    71     unsigned ch;
       
    72 
       
    73     if (_isString(_INST(collection))
       
    74      && _isSmallInteger(_INST(position))
       
    75      && _isSmallInteger(_INST(readLimit))) {
       
    76 
       
    77         pos = _intVal(_INST(position));
       
    78         if (pos > _intVal(_INST(readLimit))) {
       
    79             RETURN ( nil );
       
    80         }
       
    81         if ((pos > 0)
       
    82          && (pos < _qSize(_INST(collection)) - OHDR_SIZE)) {
       
    83             ch = _stringVal(_INST(collection))[pos-1];
       
    84             _INST(position) = _MKSMALLINT(pos + 1);
       
    85             RETURN ( _MKCHARACTER(ch) );
       
    86         }
       
    87     }
       
    88 %}
       
    89 .
       
    90     (position > readLimit) ifTrue:[^ nil].
       
    91     ret := collection at:position.
       
    92     position := position + 1.
       
    93     ^ ret
       
    94 !
       
    95 
       
    96 nextPeek
       
    97     "advance read pointer return the peek element.
       
    98      this is equivalent to (self next; peek).
       
    99      - reimplemented for speed on String-Streams"
       
   100 
       
   101 %{  /* NOCONTEXT */
       
   102 
       
   103     if (_isString(_INST(collection))
       
   104      && _isSmallInteger(_INST(position))
       
   105      && _isSmallInteger(_INST(readLimit))) {
       
   106         REGISTER int pos;
       
   107         unsigned ch;
       
   108 
       
   109         pos = _intVal(_INST(position));
       
   110         if (pos > _intVal(_INST(readLimit))) {
       
   111             RETURN ( nil );
       
   112         }
       
   113         if ((pos > 0)
       
   114          && (pos < _qSize(_INST(collection)) - OHDR_SIZE)) {
       
   115             _INST(position) = _MKSMALLINT(pos + 1);
       
   116             pos = pos + 1;
       
   117             if (pos < _qSize(_INST(collection)) - OHDR_SIZE) {
       
   118                 ch = _stringVal(_INST(collection))[pos-1];
       
   119                 RETURN ( _MKCHARACTER(ch) );
       
   120             }
       
   121             RETURN ( nil );
       
   122         }
       
   123     }
       
   124 %}
       
   125 .
       
   126     (position > readLimit) ifTrue:[^ nil].
       
   127     position := position + 1.
       
   128     (position > readLimit) ifTrue:[^ nil].
       
   129     ^ collection at:position
       
   130 !
       
   131 
       
   132 nextDecimalInteger
       
   133     "read the next integer in radix 10. dont skip whitespace.
       
   134      - reimplemented for speed on String-Streams"
       
   135 
       
   136     |value|
       
   137 %{
       
   138     int pos, limit, sz;
       
   139     register unsigned char *cp;
       
   140     register unsigned ch;
       
   141     int val = 0;
       
   142 
       
   143     if (_isString(_INST(collection))
       
   144      && _isSmallInteger(_INST(position))
       
   145      && _isSmallInteger(_INST(readLimit))) {
       
   146         pos = _intVal(_INST(position));
       
   147         limit = _intVal(_INST(readLimit));
       
   148         sz = _qSize(_INST(collection)) - OHDR_SIZE;
       
   149         if (sz < limit)
       
   150             limit = sz; 
       
   151         cp = _stringVal(_INST(collection)) + pos - 1;
       
   152 
       
   153         for (;;) {
       
   154             if (pos > limit) break;
       
   155             ch = *cp;
       
   156 
       
   157             if ((ch < '0') || (ch > '9')) break;
       
   158             val = val * 10 + (ch - '0');
       
   159             pos++;
       
   160             if (val > (_MAX_INT / 10)) goto oops;
       
   161             cp++;
       
   162         }
       
   163         _INST(position) = _MKSMALLINT(pos);
       
   164         return _MKSMALLINT(val);
       
   165     }
       
   166 oops:
       
   167     value = _MKSMALLINT(val);
       
   168 %}
       
   169 .
       
   170     [self peek notNil and:[self peek isDigitRadix:10]] whileTrue:[
       
   171         value = (value * 10) + self peek digitValue.
       
   172         self next
       
   173     ].
       
   174     ^ value
       
   175 !
       
   176 
       
   177 nextWord
       
   178     "read the next word (i.e. up to non letter-or-digit).
       
   179      return a string containing those characters.
       
   180      - reimplemented for speed on String-Streams"
       
   181 %{
       
   182     /* speedup, if collection is a string */
       
   183 
       
   184     int pos, limit, sz;
       
   185     int len;
       
   186     char buffer[1024];
       
   187     register unsigned char *cp;
       
   188     register unsigned ch;
       
   189 
       
   190     if (_isString(_INST(collection))
       
   191      && _isSmallInteger(_INST(position))
       
   192      && _isSmallInteger(_INST(readLimit))) {
       
   193         pos = _intVal(_INST(position));
       
   194         limit = _intVal(_INST(readLimit));
       
   195         sz = _qSize(_INST(collection)) - OHDR_SIZE;
       
   196         if (sz < limit)
       
   197             limit = sz; 
       
   198         cp = _stringVal(_INST(collection)) + pos - 1;
       
   199 
       
   200         for (;;) {
       
   201             if (pos > limit) break;
       
   202             ch = *cp;
       
   203 
       
   204             if (ch > ' ') break;
       
   205             if ((ch != ' ') && (ch != '\t') && (ch != '\r')
       
   206              && (ch != '\n') && (ch != 0x0b)) break;
       
   207             cp++;
       
   208             pos++;
       
   209         }
       
   210 
       
   211         len = 0;
       
   212         for (;;) {
       
   213             if (pos > limit) break;
       
   214             ch = *cp & 0xFF;
       
   215 
       
   216             if (! (((ch >= 'a') && (ch <= 'z')) ||
       
   217                    ((ch >= 'A') && (ch <= 'Z')) ||
       
   218                    ((ch >= '0') && (ch <= '9'))))
       
   219                 break;
       
   220             buffer[len++] = ch;
       
   221             if (len >= (sizeof(buffer)-1)) {
       
   222                 /* emergency */
       
   223                 break;
       
   224             }
       
   225             pos++;
       
   226             cp++;
       
   227         }
       
   228 
       
   229         _INST(position) = _MKSMALLINT(pos);
       
   230         buffer[len] = '\0';
       
   231         RETURN ( (len != 0) ? _MKSTRING(buffer COMMA_CON) : nil );
       
   232     }
       
   233 %}
       
   234 .
       
   235     ^ super nextWord
       
   236 !
       
   237 
       
   238 nextSymbol
       
   239     "read the next selector-symbol (i.e. up to non letter-or-digit).
       
   240      return a string containing those characters.
       
   241      - reimplemented for speed on String-Streams"
       
   242 %{
       
   243     int pos, limit, sz;
       
   244     int len;
       
   245     char buffer[1024];
       
   246     register unsigned char *cp;
       
   247     register unsigned ch;
       
   248 
       
   249     if (_isString(_INST(collection))
       
   250      && _isSmallInteger(_INST(position))
       
   251      && _isSmallInteger(_INST(readLimit))) {
       
   252         pos = _intVal(_INST(position));
       
   253         limit = _intVal(_INST(readLimit));
       
   254         sz = _qSize(_INST(collection)) - OHDR_SIZE;
       
   255         if (sz < limit)
       
   256             limit = sz; 
       
   257         cp = _stringVal(_INST(collection)) + pos - 1;
       
   258 
       
   259         len = 0;
       
   260         for (;;) {
       
   261             if (pos > limit) break;
       
   262             ch = *cp;
       
   263 
       
   264             if (! (((ch >= 'a') && (ch <= 'z')) ||
       
   265                    ((ch >= 'A') && (ch <= 'Z')) ||
       
   266                    ((ch >= '0') && (ch <= '9')) ||
       
   267                    (ch == ':')))
       
   268                 break;
       
   269             buffer[len++] = ch;
       
   270             if (len >= (sizeof(buffer)-1)) {
       
   271                 /* emergency */
       
   272                 break;
       
   273             }
       
   274             pos++;
       
   275             cp++;
       
   276         }
       
   277 
       
   278         _INST(position) = _MKSMALLINT(pos);
       
   279         buffer[len] = '\0';
       
   280         RETURN ( (len != 0) ? _MKSTRING(buffer COMMA_CON) : nil );
       
   281     }
       
   282 %}
       
   283 .
       
   284     ^ super nextSymbol
       
   285 !
       
   286 
       
   287 skipFor:anObject
       
   288     "skip all objects up-to and including anObject;
       
   289      return the element after anObject.
       
   290      - reimplemented for speed on String-Streams"
       
   291 
       
   292 %{  /* NOCONTEXT */
       
   293 
       
   294     if (_isString(_INST(collection))
       
   295      && _isCharacter(anObject)
       
   296      && _isSmallInteger(_INST(position))
       
   297      && _isSmallInteger(_INST(readLimit))) {
       
   298         REGISTER unsigned char *chars;
       
   299         REGISTER int pos, limit;
       
   300 	unsigned ch;
       
   301 
       
   302         pos = _intVal(_INST(position));
       
   303         if (pos <= 0) {
       
   304             RETURN ( nil );
       
   305         }
       
   306 
       
   307         limit = _intVal(_INST(readLimit));
       
   308         if (limit > (_qSize(_INST(collection)) - OHDR_SIZE))
       
   309             limit = _qSize(_INST(collection)) - OHDR_SIZE;
       
   310 
       
   311         chars = (unsigned char *)(_stringVal(_INST(collection)) + pos - 1);
       
   312         ch = _intVal(_characterVal(anObject)) & 0xFF;
       
   313         while (pos < limit) {
       
   314             if (*chars == ch) {
       
   315                 ch = *++chars;
       
   316                 pos++;
       
   317                 _INST(position) = _MKSMALLINT(pos);
       
   318                 RETURN ( _MKCHARACTER(ch) );
       
   319             }
       
   320             chars++;
       
   321             pos++;
       
   322         }
       
   323         _INST(position) = _MKSMALLINT(pos);
       
   324         RETURN ( nil );
       
   325     }
       
   326 %}
       
   327 .
       
   328     ^ super skipFor:anObject
       
   329 !
       
   330 
       
   331 
       
   332 skipSeparators
       
   333     "skip all whitespace; next will return next non-white-space element.
       
   334      - reimplemented for speed on String-Streams"
       
   335 
       
   336 %{  /* NOCONTEXT */
       
   337 
       
   338     if (_isString(_INST(collection))
       
   339      && _isSmallInteger(_INST(position))
       
   340      && _isSmallInteger(_INST(readLimit))) {
       
   341         REGISTER unsigned char *chars;
       
   342         REGISTER unsigned ch;
       
   343         REGISTER int pos;
       
   344         int limit;
       
   345 
       
   346         pos = _intVal(_INST(position));
       
   347         if (pos <= 0) {
       
   348             RETURN ( nil );
       
   349         }
       
   350 
       
   351         limit = _intVal(_INST(readLimit));
       
   352         if (limit > (_qSize(_INST(collection)) - OHDR_SIZE))
       
   353             limit = _qSize(_INST(collection)) - OHDR_SIZE;
       
   354 
       
   355         chars = (unsigned char *)(_stringVal(_INST(collection)) + pos - 1);
       
   356         while (pos <= limit) {
       
   357             ch = *chars++;
       
   358             if ((ch != ' ') && (ch != '\t') && (ch != '\r')
       
   359              && (ch != '\n') && (ch != 0x0B)) {
       
   360                 _INST(position) = _MKSMALLINT(pos);
       
   361                 RETURN ( _MKCHARACTER(ch) );
       
   362             }
       
   363             pos++;
       
   364         }
       
   365         _INST(position) = _MKSMALLINT(pos);
       
   366         RETURN ( nil );
       
   367     }
       
   368 %}
       
   369 .
       
   370     ^ super skipSeparators
       
   371 !
       
   372 
       
   373 skipToAll:aCollection
       
   374     "skip for the sequence given by the argument, aCollection;
       
   375      return nil if not found, self otherwise. On a successful match, next read
       
   376      will return elements of aCollection."
       
   377 
       
   378     |oldPos buffer l first idx|
       
   379 
       
   380     oldPos := self position.
       
   381     l := aCollection size.
       
   382     first := aCollection at:1.
       
   383     [self atEnd] whileFalse:[
       
   384         buffer := self next:l.
       
   385         buffer = aCollection ifTrue:[
       
   386             self position:(self position - l).
       
   387             ^ self
       
   388         ].
       
   389         idx := buffer indexOf:first startingAt:2.
       
   390         idx == 0 ifFalse:[
       
   391             self position:(self position - l + idx - 1)
       
   392         ]
       
   393     ].
       
   394     self position:oldPos.
       
   395     ^ nil
       
   396 
       
   397     "|s|
       
   398      s := ReadStream on:'12345678901234567890'.
       
   399      s skipToAll:'901'.
       
   400      s next:4"
       
   401 ! !
       
   402 
       
   403 !ReadStream methodsFor:'access-writing'!
       
   404 
       
   405 nextPut:anElement
       
   406     ^ self error:'ReadStreams cannot write'
       
   407 ! !