Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | // This may look like C code, but it is really -*- C++ -*- |
2 | /* | |
3 | Copyright (C) 1989 Free Software Foundation | |
4 | written by Doug Lea (dl@rocky.oswego.edu) | |
5 | ||
6 | This file is part of GNU CC. | |
7 | ||
8 | GNU CC is distributed in the hope that it will be useful, | |
9 | but WITHOUT ANY WARRANTY. No author or distributor | |
10 | accepts responsibility to anyone for the consequences of using it | |
11 | or for whether it serves any particular purpose or works at all, | |
12 | unless he says so in writing. Refer to the GNU CC General Public | |
13 | License for full details. | |
14 | ||
15 | Everyone is granted permission to copy, modify and redistribute | |
16 | GNU CC, but only under the conditions described in the | |
17 | GNU CC General Public License. A copy of this license is | |
18 | supposed to have been given to you along with GNU CC so you | |
19 | can know your rights and responsibilities. It should be in a | |
20 | file named COPYING. Among other things, the copyright notice | |
21 | and this notice must be preserved on all copies. | |
22 | */ | |
23 | ||
24 | /* *** Version 1.2 -- nearly 100% AT&T 1.2 compatible *** */ | |
25 | ||
26 | #ifdef __GNUG__ | |
27 | #pragma implementation | |
28 | #endif | |
29 | #include <stream.h> | |
30 | #include <stdarg.h> | |
31 | #include <values.h> | |
32 | #include <ctype.h> | |
33 | #include <Obstack.h> | |
34 | ||
35 | ||
36 | istream::istream(streambuf* s, int sk, ostream* t) | |
37 | : bp(s), state(_good), skipws(sk), tied_to(t), ownbuf(0) {} | |
38 | ||
39 | istream::istream(int sz, char* buf, int sk, ostream* t) | |
40 | : state(_good), skipws(sk), tied_to(t), ownbuf(1) | |
41 | { | |
42 | bp = new streambuf; | |
43 | if (buf == 0) | |
44 | { | |
45 | bp->alloc = 1; | |
46 | buf = new char[sz]; | |
47 | } | |
48 | else | |
49 | bp->alloc = 0; | |
50 | ||
51 | bp->setbuf(buf, sz, sz); | |
52 | } | |
53 | ||
54 | istream::~istream() | |
55 | { | |
56 | if (ownbuf) delete bp; | |
57 | } | |
58 | ||
59 | istream::istream(const char* filename, io_mode m, access_mode a, int sk, ostream* t) | |
60 | : state(_good), skipws(sk), tied_to(t), ownbuf(1) | |
61 | { | |
62 | bp = new filebuf(filename, m, a); | |
63 | } | |
64 | ||
65 | istream::istream(const char* filename, const char* m, int sk, ostream* t) | |
66 | : state(_good), skipws(sk), tied_to(t), ownbuf(1) | |
67 | { | |
68 | bp = new filebuf(filename, m); | |
69 | } | |
70 | ||
71 | istream::istream(int filedesc, io_mode m, int sk, ostream* t) | |
72 | : state(_good), skipws(sk), tied_to(t), ownbuf(1) | |
73 | { | |
74 | bp = new filebuf(filedesc, m); | |
75 | } | |
76 | ||
77 | istream::istream(FILE* fileptr, int sk, ostream* t) | |
78 | : state(_good), skipws(sk), tied_to(t), ownbuf(1) | |
79 | { | |
80 | bp = new filebuf(fileptr); | |
81 | ||
82 | } | |
83 | ||
84 | istream::istream(int filedesc, int sk, ostream* t) | |
85 | : state(_good), skipws(sk), tied_to(t), ownbuf(1) | |
86 | { | |
87 | bp = new filebuf(filedesc); | |
88 | } | |
89 | ||
90 | istream::istream(int filedesc, char* buf, int buflen, int sk, ostream* t) | |
91 | : state(_good), skipws(sk), tied_to(t), ownbuf(1) | |
92 | { | |
93 | bp = new filebuf(filedesc, buf, buflen); | |
94 | } | |
95 | ||
96 | istream& istream::open(const char* filename, io_mode m, access_mode a) | |
97 | { | |
98 | return failif(bp->open(filename, m, a) == 0); | |
99 | } | |
100 | ||
101 | istream& istream::open(const char* filename, const char* m) | |
102 | { | |
103 | return failif(bp->open(filename, m) == 0); | |
104 | } | |
105 | ||
106 | istream& istream::open(int filedesc, io_mode m) | |
107 | { | |
108 | return failif(bp->open(filedesc, m) == 0); | |
109 | } | |
110 | ||
111 | istream& istream::open(FILE* fileptr) | |
112 | { | |
113 | return failif(bp->open(fileptr) == 0); | |
114 | } | |
115 | ||
116 | istream& istream::open(const char* filenam, open_mode m) | |
117 | { | |
118 | return failif(bp->open(filenam, m) == 0); | |
119 | } | |
120 | ||
121 | istream& istream::get(char& c) | |
122 | { | |
123 | if (good()) | |
124 | { | |
125 | if(tied_to != 0) tied_to->flush(); | |
126 | int ch = bp->sgetc(); | |
127 | if (ch == EOF) | |
128 | set(_eof); | |
129 | else | |
130 | { | |
131 | c = ch; | |
132 | bp->stossc(); | |
133 | } | |
134 | } | |
135 | return *this; | |
136 | } | |
137 | ||
138 | ||
139 | istream& istream::operator >> (whitespace&) | |
140 | { | |
141 | if (good()) | |
142 | { | |
143 | int ch; | |
144 | if(tied_to != 0) tied_to->flush(); | |
145 | while (((ch = bp->sgetc()) != EOF) && isspace(ch)) bp->stossc(); | |
146 | if (ch == EOF) set(_eof); | |
147 | } | |
148 | return *this; | |
149 | } | |
150 | ||
151 | ||
152 | istream& istream::operator >> (char& c) | |
153 | { | |
154 | if (skipws) (*this >> WS); | |
155 | return get(c); | |
156 | } | |
157 | ||
158 | istream& istream::get(char* s, int n, char terminator) | |
159 | { | |
160 | if (!readable()) | |
161 | { | |
162 | set(_fail); | |
163 | return *this; | |
164 | } | |
165 | ||
166 | char ch = 0; | |
167 | char* start = s; | |
168 | if (--n > 0 && get(ch)) | |
169 | { | |
170 | if (ch == terminator) | |
171 | unget(ch); | |
172 | else | |
173 | { | |
174 | *s++ = ch; --n; | |
175 | while (n-- > 0 && get(ch)) | |
176 | { | |
177 | if (ch == terminator) | |
178 | { | |
179 | unget(ch); | |
180 | break; | |
181 | } | |
182 | else | |
183 | *s++ = ch; | |
184 | } | |
185 | } | |
186 | } | |
187 | ||
188 | *s = 0; | |
189 | if (s != start) clear(); | |
190 | return *this; | |
191 | } | |
192 | ||
193 | ||
194 | istream& istream::operator >> (char* s) | |
195 | { | |
196 | if (!readable() || s == 0) | |
197 | { | |
198 | set(_fail); | |
199 | return *this; | |
200 | } | |
201 | ||
202 | if (skipws && !(*this >> WS)) return *this; | |
203 | ||
204 | char ch; | |
205 | char* start = s; | |
206 | if (get(ch)) | |
207 | { | |
208 | *s++ = ch; | |
209 | while (get(ch)) | |
210 | { | |
211 | if (isspace(ch)) | |
212 | { | |
213 | unget(ch); | |
214 | break; | |
215 | } | |
216 | else | |
217 | *s++ = ch; | |
218 | } | |
219 | } | |
220 | ||
221 | *s = 0; | |
222 | if (s != start) clear(); | |
223 | return *this; | |
224 | } | |
225 | ||
226 | ||
227 | istream& istream::getline(char* s, int n, char terminator) | |
228 | { | |
229 | if (!readable()) | |
230 | { | |
231 | set(_fail); | |
232 | return *this; | |
233 | } | |
234 | char* start = s; | |
235 | char ch; | |
236 | while (--n > 0 && get(ch) && ((*s++ = ch) != terminator)); | |
237 | ||
238 | *s = 0; | |
239 | if (s != start) clear(); | |
240 | return *this; | |
241 | } | |
242 | ||
243 | // from Doug Schmidt | |
244 | ||
245 | // This should probably be a page size.... | |
246 | #define CHUNK_SIZE 512 | |
247 | ||
248 | /* Reads an arbitrarily long input line terminated by a user-specified | |
249 | TERMINATOR. Super-nifty trick using recursion avoids unnecessary calls | |
250 | to NEW! */ | |
251 | ||
252 | char *istream::readline (int chunk_number, char terminator) | |
253 | { | |
254 | char buf[CHUNK_SIZE]; | |
255 | register char *bufptr = buf; | |
256 | register char *ptr; | |
257 | char ch; | |
258 | int continu; | |
259 | ||
260 | while ((continu = !!get(ch)) && ch != terminator) /* fill the current buffer */ | |
261 | { | |
262 | *bufptr++ = ch; | |
263 | if (bufptr - buf >= CHUNK_SIZE) /* prepend remainder to ptr buffer */ | |
264 | { | |
265 | if (ptr = readline (chunk_number + 1, terminator)) | |
266 | ||
267 | for (; bufptr != buf; *--ptr = *--bufptr); | |
268 | ||
269 | return ptr; | |
270 | } | |
271 | } | |
272 | if (!continu && bufptr == buf) | |
273 | return NULL; | |
274 | ||
275 | int size = (chunk_number * CHUNK_SIZE + bufptr - buf) + 1; | |
276 | ||
277 | if (ptr = new char[size]) | |
278 | { | |
279 | ||
280 | for (*(ptr += (size - 1)) = '\0'; bufptr != buf; *--ptr = *--bufptr) | |
281 | ; | |
282 | ||
283 | return ptr; | |
284 | } | |
285 | else | |
286 | return NULL; | |
287 | } | |
288 | ||
289 | /* Reads an arbitrarily long input line terminated by TERMINATOR. | |
290 | This routine allocates its own memory, so the user should | |
291 | only supply the address of a (char *). */ | |
292 | ||
293 | istream& istream::gets(char **s, char terminator) | |
294 | { | |
295 | return failif(!readable() || !(*s = readline (0, terminator))); | |
296 | } | |
297 | ||
298 | istream& istream::operator >> (long& y) | |
299 | { | |
300 | if (!readable()) | |
301 | { | |
302 | set(_bad); | |
303 | return *this; | |
304 | } | |
305 | ||
306 | int got_one = 0; | |
307 | char sgn = 0; | |
308 | char ch; | |
309 | y = 0; | |
310 | if (skipws) *this >> WS; | |
311 | if (!good()) | |
312 | { | |
313 | set(_bad); | |
314 | return *this; | |
315 | } | |
316 | while (get(ch)) | |
317 | { | |
318 | if (ch == '-') | |
319 | { | |
320 | if (sgn == 0 && got_one == 0) | |
321 | sgn = '-'; | |
322 | else | |
323 | break; | |
324 | } | |
325 | else if (ch >= '0' && ch <= '9') | |
326 | y = y * 10 + ((got_one = ch) - '0'); | |
327 | else | |
328 | break; | |
329 | } | |
330 | if (good()) | |
331 | unget(ch); | |
332 | if (!got_one) | |
333 | set(_bad); | |
334 | else | |
335 | clear(); | |
336 | ||
337 | if (sgn == '-') | |
338 | y = -y; | |
339 | ||
340 | return *this; | |
341 | } | |
342 | ||
343 | istream& istream::operator >> (unsigned long& y) | |
344 | { | |
345 | if (!readable()) | |
346 | { | |
347 | set(_bad); | |
348 | return *this; | |
349 | } | |
350 | ||
351 | int got_one = 0; | |
352 | char ch; | |
353 | y = 0; | |
354 | if (skipws) *this >> WS; | |
355 | if (!good()) | |
356 | while (get(ch)) | |
357 | { | |
358 | if (ch >= '0' && ch <= '9') | |
359 | y = y * 10 + ((got_one = ch) - '0'); | |
360 | else | |
361 | break; | |
362 | } | |
363 | if (good()) | |
364 | unget(ch); | |
365 | if (!got_one) | |
366 | set(_bad); | |
367 | else | |
368 | clear(); | |
369 | return *this; | |
370 | } | |
371 | ||
372 | ||
373 | /* for input to a double, we must trust atof (cannot even use | |
374 | the better strtod since it is not universally supported). So | |
375 | guaranteed legal chars are gathered up into an obstack. The | |
376 | only possible, undiagnosable error is that the input number | |
377 | might give a floating overflow or underflow inside atof. | |
378 | I know of no way to avoid this */ | |
379 | ||
380 | extern Obstack _libgxx_io_ob; | |
381 | ||
382 | istream& istream::operator >> (double & y) | |
383 | { | |
384 | if (!readable()) | |
385 | { | |
386 | set(_bad); | |
387 | return *this; | |
388 | } | |
389 | ||
390 | ||
391 | char seenint = 0; | |
392 | char seendec = 0; | |
393 | char seenexp = 0; | |
394 | char seensgn = 0; | |
395 | char seene = 0; | |
396 | char seenexpsgn = 0; | |
397 | char seendot = 0; | |
398 | char ch; | |
399 | ||
400 | if (skipws) *this >> WS; | |
401 | if (!good()) | |
402 | { | |
403 | set(_bad); | |
404 | return *this; | |
405 | } | |
406 | while (get(ch)) | |
407 | { | |
408 | if (ch == '-' || ch == '+') | |
409 | { | |
410 | if (seene && !seenexpsgn) | |
411 | _libgxx_io_ob.grow(seenexpsgn = ch); | |
412 | else if (!seensgn && !seenint) | |
413 | _libgxx_io_ob.grow(seensgn = ch); | |
414 | else | |
415 | break; | |
416 | } | |
417 | else if (ch == '.' && !seendot) | |
418 | { | |
419 | _libgxx_io_ob.grow(seendot = ch); | |
420 | } | |
421 | else if ((ch == 'e' || ch == 'E') && !seene) | |
422 | { | |
423 | _libgxx_io_ob.grow(seene = ch); | |
424 | } | |
425 | else if (ch >= '0' && ch <= '9') | |
426 | { | |
427 | _libgxx_io_ob.grow(ch); | |
428 | if (seene) seenexp = ch; | |
429 | else if (seendot) seendec = ch; | |
430 | else seenint = ch; | |
431 | } | |
432 | else | |
433 | break; | |
434 | } | |
435 | char* str = (char *) _libgxx_io_ob.finish(0); | |
436 | if (good()) | |
437 | unget(ch); | |
438 | if ((seenint || seendec) && (!seene || seenexp)) | |
439 | y = atof(str); | |
440 | else | |
441 | set(_bad); | |
442 | _libgxx_io_ob.free(str); | |
443 | return *this; | |
444 | } | |
445 | ||
446 | istream& istream::operator >> (int& y) | |
447 | { | |
448 | long l; (*this >> l); y = int(l); return *this; | |
449 | } | |
450 | ||
451 | istream& istream:: operator >> (unsigned int& y) | |
452 | { | |
453 | long l; (*this >> l); y = (unsigned int)(l); return *this; | |
454 | } | |
455 | ||
456 | istream& istream:: operator >> (short& y) | |
457 | { | |
458 | long l; (*this >> l); y = short(l); return *this; | |
459 | } | |
460 | ||
461 | istream& istream:: operator >> (unsigned short& y) | |
462 | { | |
463 | long l; (*this >> l); y = (unsigned short)(l); return *this; | |
464 | } | |
465 | ||
466 | istream& istream:: operator >> (float& y) | |
467 | { | |
468 | double d; (*this >> d); y = float(d); return *this; | |
469 | } | |
470 | ||
471 | const char* istream::name() | |
472 | { | |
473 | return bp->name(); | |
474 | } | |
475 | ||
476 | void istream::error() | |
477 | { | |
478 | bp->error(); | |
479 | } | |
480 | ||
481 | ostream* istream::tie(ostream* s) | |
482 | { | |
483 | ostream* was = tied_to; tied_to = s; return was; | |
484 | } | |
485 | ||
486 | void istream::_flush() | |
487 | { | |
488 | if(tied_to != 0) tied_to->flush(); | |
489 | } | |
490 | ||
491 | ||
492 | //-------------------------------------------------------------- | |
493 | ||
494 | extern ostream cout; | |
495 | ||
496 | #if 0 /* BSD 4.4 */ | |
497 | ||
498 | istream cin(stdin, 1, &cout); | |
499 | ||
500 | #else | |
501 | ||
502 | static char cinbuf[BUFSIZE]; | |
503 | istream cin (0, cinbuf, BUFSIZE, 1, &cout); | |
504 | ||
505 | #endif | |
506 | ||
507 | whitespace WS; |