author | james |
Thu, 25 Oct 2001 08:04:22 +0200 | |
changeset 6102 | 7fdf73f3256b |
parent 5394 | f877659e09f7 |
child 7685 | 535a69a7cd69 |
permissions | -rw-r--r-- |
58 | 1 |
" |
2 |
COPYRIGHT (c) 1994 by Claus Gittinger |
|
379 | 3 |
All Rights Reserved |
58 | 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 |
||
5394 | 13 |
"{ Package: 'stx:libbasic' }" |
14 |
||
58 | 15 |
Stream subclass:#PeekableStream |
1295 | 16 |
instanceVariableNames:'' |
17 |
classVariableNames:'' |
|
18 |
poolDictionaries:'' |
|
19 |
category:'Streams' |
|
58 | 20 |
! |
21 |
||
88 | 22 |
!PeekableStream class methodsFor:'documentation'! |
23 |
||
24 |
copyright |
|
25 |
" |
|
26 |
COPYRIGHT (c) 1994 by Claus Gittinger |
|
379 | 27 |
All Rights Reserved |
58 | 28 |
|
88 | 29 |
This software is furnished under a license and may be used |
30 |
only in accordance with the terms of that license and with the |
|
31 |
inclusion of the above copyright notice. This software may not |
|
32 |
be provided or otherwise made available to, or used by, any |
|
33 |
other person. No title to or ownership of the software is |
|
34 |
hereby transferred. |
|
35 |
" |
|
36 |
! |
|
58 | 37 |
|
88 | 38 |
documentation |
39 |
" |
|
40 |
abstract superclass for all Stream which support read-ahead |
|
41 |
(i.e. peeking) of one element. |
|
42 |
Concrete subclasses must implement a peek method. |
|
1295 | 43 |
|
44 |
[author:] |
|
45 |
Claus Gittinger |
|
88 | 46 |
" |
47 |
! ! |
|
58 | 48 |
|
5394 | 49 |
!PeekableStream methodsFor:'chunk input/output'! |
50 |
||
51 |
nextChunk |
|
52 |
"return the next chunk, i.e. all characters up to the next |
|
53 |
exclamation mark. Within the chunk, exclamation marks have to be doubled, |
|
54 |
they are undoubled here. |
|
55 |
Except for primitive code, in which doubling is not needed (allowed). |
|
56 |
This exception was added to make it easier to edit primitive code with |
|
57 |
external editors. However, this means, that other Smalltalks cannot always |
|
58 |
read chunks containing primitive code |
|
59 |
- but that doesnt really matter, since C-primitives are an ST/X feature anyway." |
|
60 |
||
61 |
|theString sep newString done thisChar nextChar inPrimitive |
|
62 |
index "{ Class:SmallInteger }" |
|
63 |
currSize "{ Class:SmallInteger }" | |
|
64 |
||
65 |
sep := ChunkSeparator. |
|
66 |
theString := String new:500. |
|
67 |
currSize := 500. |
|
68 |
thisChar := self skipSeparators. |
|
69 |
thisChar := self next. |
|
70 |
index := 0. |
|
71 |
done := false. |
|
72 |
inPrimitive := false. |
|
73 |
||
74 |
[done] whileFalse:[ |
|
75 |
((index + 2) <= currSize) ifFalse:[ |
|
76 |
newString := String new:(currSize * 2). |
|
77 |
newString replaceFrom:1 to:currSize with:theString. |
|
78 |
currSize := currSize * 2. |
|
79 |
theString := newString |
|
80 |
]. |
|
81 |
thisChar isNil ifTrue:[ |
|
82 |
done := true |
|
83 |
] ifFalse:[ |
|
84 |
(thisChar == $% ) ifTrue:[ |
|
85 |
nextChar := self peek. |
|
86 |
(nextChar == ${ ) ifTrue:[ |
|
87 |
inPrimitive := true. |
|
88 |
index := index + 1. |
|
89 |
theString at:index put:thisChar. |
|
90 |
thisChar := self next |
|
91 |
] ifFalse:[ |
|
92 |
(nextChar == $} ) ifTrue:[ |
|
93 |
inPrimitive := false. |
|
94 |
index := index + 1. |
|
95 |
theString at:index put:thisChar. |
|
96 |
thisChar := self next |
|
97 |
] |
|
98 |
] |
|
99 |
] ifFalse:[ |
|
100 |
inPrimitive ifFalse:[ |
|
101 |
(thisChar == sep) ifTrue:[ |
|
102 |
(self peek == sep) ifFalse:[ |
|
103 |
done := true |
|
104 |
] ifTrue:[ |
|
105 |
self next |
|
106 |
] |
|
107 |
] |
|
108 |
] |
|
109 |
] |
|
110 |
]. |
|
111 |
done ifFalse:[ |
|
112 |
index := index + 1. |
|
113 |
theString at:index put:thisChar. |
|
114 |
thisChar := self next |
|
115 |
] |
|
116 |
]. |
|
117 |
(index == 0) ifTrue:[^ '']. |
|
118 |
^ theString copyTo:index |
|
119 |
! ! |
|
120 |
||
4404 | 121 |
!PeekableStream methodsFor:'positioning'! |
58 | 122 |
|
68 | 123 |
skipAny:skipCollection |
124 |
"skip all characters included in the argument-set. |
|
125 |
returns the next peeked element or nil, if the end-of-stream was reached." |
|
126 |
||
127 |
|nextOne| |
|
128 |
||
4432
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
129 |
nextOne := self peekOrNil. |
68 | 130 |
[nextOne notNil and:[skipCollection includes:nextOne]] whileTrue:[ |
4432
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
131 |
self next. |
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
132 |
nextOne := self peekOrNil |
68 | 133 |
]. |
134 |
^ nextOne |
|
135 |
||
136 |
" |
|
137 |
|s skipChars| |
|
138 |
||
139 |
s := ReadStream on:'some numbers1234with\in other99 stuff' withCRs. |
|
140 |
skipChars := 'abcdefghijklmnopqrstuvwxyz\ ' withCRs. |
|
141 |
s skipAny:skipChars. |
|
1422 | 142 |
Transcript showCR:(Integer readFrom:s). |
68 | 143 |
s skipAny:skipChars. |
1422 | 144 |
Transcript showCR:(Integer readFrom:s). |
68 | 145 |
" |
146 |
! |
|
147 |
||
611 | 148 |
skipSeparators |
149 |
"skip all whitespace; returns the next peeked element or |
|
150 |
nil, if the end-of-stream was reached. |
|
151 |
The streams elements should be characters. |
|
152 |
Notice: compare this method to skipSpaces" |
|
153 |
||
154 |
|nextOne| |
|
155 |
||
4432
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
156 |
nextOne := self peekOrNil. |
611 | 157 |
[nextOne notNil and:[nextOne isSeparator]] whileTrue:[ |
4432
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
158 |
self next. |
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
159 |
nextOne := self peekOrNil |
611 | 160 |
]. |
161 |
^ nextOne |
|
162 |
||
163 |
" |
|
164 |
|s| |
|
165 |
||
166 |
s := ReadStream on:'one two\three' withCRs. |
|
167 |
s skipSeparators. |
|
1422 | 168 |
Transcript showCR:(s nextWord). |
611 | 169 |
s skipSeparators. |
1422 | 170 |
Transcript showCR:(s nextWord). |
611 | 171 |
s skipSeparators. |
1422 | 172 |
Transcript showCR:(s next displayString). |
611 | 173 |
" |
174 |
! |
|
175 |
||
176 |
skipSeparatorsExceptCR |
|
177 |
"skip all whitespace except carriage return; returns the |
|
178 |
next peeked element or nil, if the end-of-stream was reached. |
|
179 |
The streams elements should be characters. |
|
180 |
Notice: compare this method to skipSpaces and skipSeparators" |
|
181 |
||
182 |
|nextOne| |
|
183 |
||
4432
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
184 |
nextOne := self peekOrNil. |
611 | 185 |
[nextOne notNil |
186 |
and:[nextOne isSeparator |
|
187 |
and:[nextOne ~~ Character cr]]] whileTrue:[ |
|
4432
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
188 |
self next. |
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
189 |
nextOne := self peekOrNil |
611 | 190 |
]. |
191 |
^ nextOne |
|
192 |
! |
|
193 |
||
68 | 194 |
skipSpaces |
195 |
"skip all spaces; returns the next peeked element or |
|
196 |
nil, if the end-of-stream was reached. |
|
197 |
The streams elements should be characters. |
|
198 |
Notice: this one skips only spaces (i.e. no cr, tabs etc) |
|
4432
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
199 |
usually, skipSeparators is what you want." |
68 | 200 |
|
201 |
|nextOne| |
|
202 |
||
4432
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
203 |
nextOne := self peekOrNil. |
68 | 204 |
[nextOne notNil and:[nextOne == Character space]] whileTrue:[ |
4432
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
205 |
self next. |
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
206 |
nextOne := self peekOrNil |
68 | 207 |
]. |
208 |
^ nextOne |
|
209 |
||
210 |
" |
|
211 |
|s| |
|
212 |
||
213 |
s := ReadStream on:'one two\three' withCRs. |
|
214 |
s skipSpaces. |
|
1422 | 215 |
Transcript showCR:(s nextWord). |
68 | 216 |
s skipSpaces. |
1422 | 217 |
Transcript showCR:(s nextWord). |
68 | 218 |
s skipSpaces. |
1422 | 219 |
Transcript showCR:(s next displayString). |
68 | 220 |
" |
4404 | 221 |
! ! |
222 |
||
223 |
!PeekableStream methodsFor:'reading'! |
|
224 |
||
225 |
nextDecimalInteger |
|
226 |
"read the next integer in radix 10. Does NOT skip initial whitespace. |
|
227 |
The streams elements should be characters. |
|
4432
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
228 |
Be careful - this method returns 0 if not posiioned on a digit intitially |
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
229 |
or if the end of the stream is encountered." |
4404 | 230 |
|
231 |
|nextOne value| |
|
232 |
||
4432
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
233 |
nextOne := self peekOrNil. |
4404 | 234 |
value := 0. |
235 |
[nextOne notNil and:[nextOne isDigitRadix:10]] whileTrue:[ |
|
236 |
value := (value * 10) + nextOne digitValue. |
|
4432
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
237 |
self next. |
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
238 |
nextOne := self peekOrNil |
4404 | 239 |
]. |
240 |
^ value |
|
241 |
||
242 |
" |
|
243 |
|s| |
|
244 |
||
245 |
s := '1234 5678' readStream. |
|
246 |
s nextDecimalInteger. |
|
247 |
" |
|
248 |
||
249 |
" |
|
250 |
|s| |
|
251 |
||
252 |
s := '1234 5678' readStream. |
|
253 |
s nextDecimalInteger. |
|
254 |
s skipSpaces. |
|
255 |
s nextDecimalInteger. |
|
256 |
" |
|
257 |
! |
|
258 |
||
259 |
nextDelimited:terminator |
|
260 |
"return the contents of the receiver, up to the next terminator character. |
|
261 |
Doubled terminators indicate an embedded terminator character. |
|
262 |
For example: 'this '' was a quote'. |
|
263 |
Start postioned before the initial terminator." |
|
264 |
||
265 |
| out ch | |
|
266 |
||
267 |
out := WriteStream on: (String new: 1000). |
|
268 |
self atEnd ifTrue: [^ '']. |
|
269 |
self next == terminator ifFalse: [self skip: -1]. "absorb initial terminator" |
|
270 |
[(ch := self next) == nil] whileFalse: [ |
|
271 |
(ch == terminator) ifTrue: [ |
|
272 |
self peek == terminator ifFalse: [ |
|
273 |
^ out contents "terminator is not doubled; we're done!!" |
|
274 |
]. |
|
275 |
self next. "skip doubled terminator" |
|
276 |
]. |
|
277 |
out nextPut: ch. |
|
278 |
]. |
|
279 |
^ out contents |
|
280 |
||
281 |
" |
|
282 |
('*foo bar baz* more foo' readStream nextDelimited:$*) |
|
283 |
('*foo bar **baz***' readStream nextDelimited:$*) |
|
284 |
" |
|
285 |
! |
|
286 |
||
287 |
nextPeek |
|
288 |
"advance to next element and return the peeked element" |
|
289 |
||
290 |
self next. |
|
291 |
^ self peek |
|
292 |
! |
|
293 |
||
294 |
peek |
|
295 |
"return the next element of the stream without advancing (i.e. |
|
296 |
the following send of next will return this element again.) |
|
297 |
- we do not know here how to do it, it must be redefined in subclass" |
|
298 |
||
299 |
^ self subclassResponsibility |
|
300 |
! |
|
301 |
||
302 |
peekFor:anObject |
|
303 |
"if the next-to-be-read object is equal to the argument, anObject, read it |
|
304 |
and return true. Otherwise, leave the receiver unaffected and return false." |
|
305 |
||
306 |
self peek = anObject ifTrue:[ |
|
307 |
self next. |
|
308 |
^ true |
|
309 |
]. |
|
310 |
^ false |
|
68 | 311 |
! |
312 |
||
2419 | 313 |
upToMatching:aBlock |
314 |
"Return the next elements up to but not including the next element |
|
315 |
for which aBlock returns true. |
|
316 |
The next read will return that matching element." |
|
317 |
||
318 |
|answerStream element| |
|
319 |
||
320 |
answerStream := WriteStream on:(self contentsSpecies new). |
|
321 |
[self atEnd] whileFalse: [ |
|
322 |
element := self peek. |
|
323 |
(aBlock value:element) ifTrue: [^ answerStream contents]. |
|
324 |
answerStream nextPut:element. |
|
325 |
self next. |
|
326 |
]. |
|
327 |
^ answerStream contents |
|
328 |
||
329 |
" |
|
330 |
'hello world' readStream upToMatching:[:c | c isSeparator]. |
|
331 |
" |
|
4404 | 332 |
" |
333 |
|s| |
|
334 |
||
335 |
s := 'hello world' readStream. |
|
336 |
s upToMatching:[:c | c isSeparator]. |
|
337 |
s upToEnd |
|
338 |
" |
|
2419 | 339 |
|
2421 | 340 |
"Modified: 26.2.1997 / 12:20:57 / cg" |
2419 | 341 |
! |
342 |
||
68 | 343 |
upToSeparator |
344 |
"Return the next elements up to but not including the next separator. |
|
4404 | 345 |
The next read will return the separator. |
346 |
If no separator is encountered, the contents up to the end is returned. |
|
347 |
The elements are supposed to understand #isSeparator |
|
348 |
(i.e. the receiver is supposed to be a character-stream)." |
|
68 | 349 |
|
4404 | 350 |
^ self upToMatching:[:ch | ch isSeparator] |
2060 | 351 |
|
352 |
" |
|
4404 | 353 |
'hello world' readStream upToSeparator |
354 |
'helloworld' readStream upToSeparator |
|
355 |
'helloworld' readStream upToSeparator |
|
356 |
'' readStream upToSeparator |
|
357 |
||
358 |
|s| |
|
359 |
s := 'hello world' readStream. |
|
360 |
s upToSeparator. |
|
361 |
s upToEnd |
|
2060 | 362 |
" |
363 |
||
364 |
"Modified: 4.1.1997 / 23:38:05 / cg" |
|
611 | 365 |
! ! |
58 | 366 |
|
701 | 367 |
!PeekableStream class methodsFor:'documentation'! |
368 |
||
369 |
version |
|
5394 | 370 |
^ '$Header: /cvs/stx/stx/libbasic/PeekableStream.st,v 1.21 2000-05-22 11:11:09 cg Exp $' |
701 | 371 |
! ! |