author | ca |
Mon, 15 Mar 2004 11:14:27 +0100 | |
changeset 8192 | ade8d06d98eb |
parent 7685 | 535a69a7cd69 |
child 8443 | 7bc4348c059e |
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:[ |
|
8192 | 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 |
"/ thisChar == Character return ifTrue:[ |
|
114 |
"/ self peekOrNil == Character lf ifTrue:[ |
|
115 |
"/ thisChar := Character lf. |
|
116 |
"/ self next. |
|
117 |
"/ ] |
|
118 |
"/ ]. |
|
119 |
theString at:index put:thisChar. |
|
120 |
thisChar := self next. |
|
121 |
] |
|
5394 | 122 |
]. |
123 |
(index == 0) ifTrue:[^ '']. |
|
124 |
^ theString copyTo:index |
|
125 |
! ! |
|
126 |
||
4404 | 127 |
!PeekableStream methodsFor:'positioning'! |
58 | 128 |
|
68 | 129 |
skipAny:skipCollection |
130 |
"skip all characters included in the argument-set. |
|
131 |
returns the next peeked element or nil, if the end-of-stream was reached." |
|
132 |
||
133 |
|nextOne| |
|
134 |
||
4432
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
135 |
nextOne := self peekOrNil. |
68 | 136 |
[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
|
137 |
self next. |
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
138 |
nextOne := self peekOrNil |
68 | 139 |
]. |
140 |
^ nextOne |
|
141 |
||
142 |
" |
|
143 |
|s skipChars| |
|
144 |
||
145 |
s := ReadStream on:'some numbers1234with\in other99 stuff' withCRs. |
|
146 |
skipChars := 'abcdefghijklmnopqrstuvwxyz\ ' withCRs. |
|
147 |
s skipAny:skipChars. |
|
1422 | 148 |
Transcript showCR:(Integer readFrom:s). |
68 | 149 |
s skipAny:skipChars. |
1422 | 150 |
Transcript showCR:(Integer readFrom:s). |
68 | 151 |
" |
152 |
! |
|
153 |
||
611 | 154 |
skipSeparators |
155 |
"skip all whitespace; returns the next peeked element or |
|
156 |
nil, if the end-of-stream was reached. |
|
157 |
The streams elements should be characters. |
|
158 |
Notice: compare this method to skipSpaces" |
|
159 |
||
160 |
|nextOne| |
|
161 |
||
4432
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
162 |
nextOne := self peekOrNil. |
611 | 163 |
[nextOne notNil and:[nextOne isSeparator]] whileTrue:[ |
4432
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
164 |
self next. |
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
165 |
nextOne := self peekOrNil |
611 | 166 |
]. |
167 |
^ nextOne |
|
168 |
||
169 |
" |
|
170 |
|s| |
|
171 |
||
172 |
s := ReadStream on:'one two\three' withCRs. |
|
173 |
s skipSeparators. |
|
1422 | 174 |
Transcript showCR:(s nextWord). |
611 | 175 |
s skipSeparators. |
1422 | 176 |
Transcript showCR:(s nextWord). |
611 | 177 |
s skipSeparators. |
1422 | 178 |
Transcript showCR:(s next displayString). |
611 | 179 |
" |
180 |
! |
|
181 |
||
182 |
skipSeparatorsExceptCR |
|
183 |
"skip all whitespace except carriage return; returns the |
|
184 |
next peeked element or nil, if the end-of-stream was reached. |
|
185 |
The streams elements should be characters. |
|
186 |
Notice: compare this method to skipSpaces and skipSeparators" |
|
187 |
||
188 |
|nextOne| |
|
189 |
||
4432
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
190 |
nextOne := self peekOrNil. |
611 | 191 |
[nextOne notNil |
192 |
and:[nextOne isSeparator |
|
193 |
and:[nextOne ~~ Character cr]]] whileTrue:[ |
|
4432
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
194 |
self next. |
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
195 |
nextOne := self peekOrNil |
611 | 196 |
]. |
197 |
^ nextOne |
|
198 |
! |
|
199 |
||
68 | 200 |
skipSpaces |
201 |
"skip all spaces; returns the next peeked element or |
|
202 |
nil, if the end-of-stream was reached. |
|
203 |
The streams elements should be characters. |
|
204 |
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
|
205 |
usually, skipSeparators is what you want." |
68 | 206 |
|
207 |
|nextOne| |
|
208 |
||
4432
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
209 |
nextOne := self peekOrNil. |
68 | 210 |
[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
|
211 |
self next. |
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
212 |
nextOne := self peekOrNil |
68 | 213 |
]. |
214 |
^ nextOne |
|
215 |
||
216 |
" |
|
217 |
|s| |
|
218 |
||
219 |
s := ReadStream on:'one two\three' withCRs. |
|
220 |
s skipSpaces. |
|
1422 | 221 |
Transcript showCR:(s nextWord). |
68 | 222 |
s skipSpaces. |
1422 | 223 |
Transcript showCR:(s nextWord). |
68 | 224 |
s skipSpaces. |
1422 | 225 |
Transcript showCR:(s next displayString). |
68 | 226 |
" |
4404 | 227 |
! ! |
228 |
||
229 |
!PeekableStream methodsFor:'reading'! |
|
230 |
||
231 |
nextDecimalInteger |
|
232 |
"read the next integer in radix 10. Does NOT skip initial whitespace. |
|
233 |
The streams elements should be characters. |
|
4432
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
234 |
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
|
235 |
or if the end of the stream is encountered." |
4404 | 236 |
|
237 |
|nextOne value| |
|
238 |
||
4432
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
239 |
nextOne := self peekOrNil. |
4404 | 240 |
value := 0. |
241 |
[nextOne notNil and:[nextOne isDigitRadix:10]] whileTrue:[ |
|
242 |
value := (value * 10) + nextOne digitValue. |
|
4432
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
243 |
self next. |
5267a659f8d9
avoid raising pastEnd exceptions in skip-methods
Claus Gittinger <cg@exept.de>
parents:
4404
diff
changeset
|
244 |
nextOne := self peekOrNil |
4404 | 245 |
]. |
246 |
^ value |
|
247 |
||
248 |
" |
|
249 |
|s| |
|
250 |
||
251 |
s := '1234 5678' readStream. |
|
252 |
s nextDecimalInteger. |
|
253 |
" |
|
254 |
||
255 |
" |
|
256 |
|s| |
|
257 |
||
258 |
s := '1234 5678' readStream. |
|
259 |
s nextDecimalInteger. |
|
260 |
s skipSpaces. |
|
261 |
s nextDecimalInteger. |
|
262 |
" |
|
263 |
! |
|
264 |
||
265 |
nextDelimited:terminator |
|
266 |
"return the contents of the receiver, up to the next terminator character. |
|
267 |
Doubled terminators indicate an embedded terminator character. |
|
268 |
For example: 'this '' was a quote'. |
|
269 |
Start postioned before the initial terminator." |
|
270 |
||
271 |
| out ch | |
|
272 |
||
7685
535a69a7cd69
String new -> uninitializedNew: / basicNew:
Claus Gittinger <cg@exept.de>
parents:
5394
diff
changeset
|
273 |
out := WriteStream on: (String uninitializedNew: 1000). |
4404 | 274 |
self atEnd ifTrue: [^ '']. |
275 |
self next == terminator ifFalse: [self skip: -1]. "absorb initial terminator" |
|
276 |
[(ch := self next) == nil] whileFalse: [ |
|
277 |
(ch == terminator) ifTrue: [ |
|
278 |
self peek == terminator ifFalse: [ |
|
279 |
^ out contents "terminator is not doubled; we're done!!" |
|
280 |
]. |
|
281 |
self next. "skip doubled terminator" |
|
282 |
]. |
|
283 |
out nextPut: ch. |
|
284 |
]. |
|
285 |
^ out contents |
|
286 |
||
287 |
" |
|
288 |
('*foo bar baz* more foo' readStream nextDelimited:$*) |
|
289 |
('*foo bar **baz***' readStream nextDelimited:$*) |
|
290 |
" |
|
291 |
! |
|
292 |
||
293 |
nextPeek |
|
294 |
"advance to next element and return the peeked element" |
|
295 |
||
296 |
self next. |
|
297 |
^ self peek |
|
298 |
! |
|
299 |
||
300 |
peek |
|
301 |
"return the next element of the stream without advancing (i.e. |
|
302 |
the following send of next will return this element again.) |
|
303 |
- we do not know here how to do it, it must be redefined in subclass" |
|
304 |
||
305 |
^ self subclassResponsibility |
|
306 |
! |
|
307 |
||
308 |
peekFor:anObject |
|
309 |
"if the next-to-be-read object is equal to the argument, anObject, read it |
|
310 |
and return true. Otherwise, leave the receiver unaffected and return false." |
|
311 |
||
312 |
self peek = anObject ifTrue:[ |
|
313 |
self next. |
|
314 |
^ true |
|
315 |
]. |
|
316 |
^ false |
|
68 | 317 |
! |
318 |
||
2419 | 319 |
upToMatching:aBlock |
320 |
"Return the next elements up to but not including the next element |
|
321 |
for which aBlock returns true. |
|
322 |
The next read will return that matching element." |
|
323 |
||
324 |
|answerStream element| |
|
325 |
||
326 |
answerStream := WriteStream on:(self contentsSpecies new). |
|
327 |
[self atEnd] whileFalse: [ |
|
328 |
element := self peek. |
|
329 |
(aBlock value:element) ifTrue: [^ answerStream contents]. |
|
330 |
answerStream nextPut:element. |
|
331 |
self next. |
|
332 |
]. |
|
333 |
^ answerStream contents |
|
334 |
||
335 |
" |
|
336 |
'hello world' readStream upToMatching:[:c | c isSeparator]. |
|
337 |
" |
|
4404 | 338 |
" |
339 |
|s| |
|
340 |
||
341 |
s := 'hello world' readStream. |
|
342 |
s upToMatching:[:c | c isSeparator]. |
|
343 |
s upToEnd |
|
344 |
" |
|
2419 | 345 |
|
2421 | 346 |
"Modified: 26.2.1997 / 12:20:57 / cg" |
2419 | 347 |
! |
348 |
||
68 | 349 |
upToSeparator |
350 |
"Return the next elements up to but not including the next separator. |
|
4404 | 351 |
The next read will return the separator. |
352 |
If no separator is encountered, the contents up to the end is returned. |
|
353 |
The elements are supposed to understand #isSeparator |
|
354 |
(i.e. the receiver is supposed to be a character-stream)." |
|
68 | 355 |
|
4404 | 356 |
^ self upToMatching:[:ch | ch isSeparator] |
2060 | 357 |
|
358 |
" |
|
4404 | 359 |
'hello world' readStream upToSeparator |
360 |
'helloworld' readStream upToSeparator |
|
361 |
'helloworld' readStream upToSeparator |
|
362 |
'' readStream upToSeparator |
|
363 |
||
364 |
|s| |
|
365 |
s := 'hello world' readStream. |
|
366 |
s upToSeparator. |
|
367 |
s upToEnd |
|
2060 | 368 |
" |
369 |
||
370 |
"Modified: 4.1.1997 / 23:38:05 / cg" |
|
611 | 371 |
! ! |
58 | 372 |
|
701 | 373 |
!PeekableStream class methodsFor:'documentation'! |
374 |
||
375 |
version |
|
8192 | 376 |
^ '$Header: /cvs/stx/stx/libbasic/PeekableStream.st,v 1.23 2004-03-15 10:14:27 ca Exp $' |
701 | 377 |
! ! |