Daily bump.
[official-gcc.git] / libio / parsestream.cc
blobe430e602c8dcd6bbafdb4211dc1f2e4de5ecd5ef
1 /* This is part of libio/iostream, providing -*- C++ -*- input/output.
2 Copyright (C) 1993 Free Software Foundation
4 This file is part of the GNU IO Library. This library is free
5 software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 2, or (at your option)
8 any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this library; see the file COPYING. If not, write to the Free
17 Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 As a special exception, if you link this library with files
20 compiled with a GNU compiler to produce an executable, this does not cause
21 the resulting executable to be covered by the GNU General Public License.
22 This exception does not however invalidate any other reasons why
23 the executable file might be covered by the GNU General Public License.
25 Written by Per Bothner (bothner@cygnus.com). */
27 #ifdef __GNUG__
28 #pragma implementation
29 #endif
30 #include "libioP.h"
31 #include "parsestream.h"
32 #include <stdlib.h>
34 streambuf* parsebuf::setbuf(char*, int)
36 return NULL;
39 int parsebuf::tell_in_line()
41 return 0;
44 int parsebuf::pbackfail(int c)
46 if (c == EOF)
47 return 0;
48 if (seekoff(-1, ios::cur) == EOF)
49 return EOF;
50 return (unsigned char)c;
53 char* parsebuf::current_line() { return NULL; }
55 streampos parsebuf::seekoff(streamoff offset, _seek_dir dir, int)
57 // Make offset relative to line start.
58 switch (dir) {
59 case ios::beg:
60 offset -= pos_at_line_start;
61 break;
62 case ios::cur:
63 offset += tell_in_line();
64 break;
65 default:
66 return EOF;
68 if (offset < -1)
69 return EOF;
70 if (offset > _line_length + 1)
71 return EOF;
72 return seek_in_line(offset) + pos_at_line_start;
75 // string_parsebuf invariants:
76 // The reserve ares (base() .. ebuf()) is always the entire string.
77 // The get area (eback() .. egptr()) is the extended current line
78 // (i.e. with the '\n' at either end, if these exist).
80 string_parsebuf::string_parsebuf(char *buf, int len,
81 int delete_at_close /* = 0*/)
82 : parsebuf()
84 setb(buf, buf+len, delete_at_close);
85 register char *ptr = buf;
86 while (ptr < ebuf() && *ptr != '\n') ptr++;
87 _line_length = ptr - buf;
88 setg(buf, buf, ptr);
91 int string_parsebuf::underflow()
93 register char* ptr = egptr(); // Point to end of current_line
94 do {
95 int i = right() - ptr;
96 if (i <= 0)
97 return EOF;
98 ptr++; i--; // Skip '\n'.
99 char *line_start = ptr;
100 while (ptr < right() && *ptr == '\n') ptr++;
101 setg(line_start-1, line_start, ptr + (ptr < right()));
102 pos_at_line_start = line_start - left();
103 _line_length = ptr - line_start;
104 __line_number++;
105 } while (gptr() == ptr);
106 return *gptr();
109 char* string_parsebuf::current_line()
111 char *ptr = eback();
112 if (__line_number > 0)
113 ptr++; // Skip '\n' at end of previous line.
114 return ptr;
117 int string_parsebuf::tell_in_line()
119 int offset = gptr() - eback();
120 if (__line_number > 0)
121 offset--;
122 return offset;
125 int string_parsebuf::seek_in_line(int i)
127 int delta = i - tell_in_line();
128 gbump(delta); // FIXME: Needs error (bounds) checking!
129 return i;
132 static const char NewLine[1] = { '\n' };
134 general_parsebuf::general_parsebuf(streambuf *buf, int delete_arg_buf)
135 : parsebuf()
137 delete_buf = delete_arg_buf;
138 sbuf = buf;
139 int buf_size = 128;
140 char* buffer = (char*)malloc(buf_size);
141 setb(buffer, buffer+buf_size, 1);
142 // setg(buffer, buffer, buffer);
145 general_parsebuf::~general_parsebuf()
147 if (delete_buf)
148 delete sbuf;
151 int general_parsebuf::underflow()
153 register char *ptr = base();
154 int has_newline = eback() < gptr() && gptr()[-1] == '\n';
155 if (has_newline)
156 *ptr++ = '\n';
157 register streambuf *sb = sbuf;
158 register int ch;
159 for (;;) {
160 ch = sb->sbumpc();
161 if (ch == EOF)
162 break;
163 if (ptr == ebuf()) {
164 int old_size = ebuf() - base();
165 char *new_buffer = new char[old_size * 2];
166 memcpy(new_buffer, base(), old_size);
167 setb(new_buffer, new_buffer + 2 * old_size, 1);
168 ptr = new_buffer + old_size;
170 *ptr++ = ch;
171 if (ch == '\n')
172 break;
174 char *cur_pos = base() + has_newline;
175 pos_at_line_start += _line_length + 1;
176 _line_length = ptr - cur_pos;
177 if (ch != EOF || _line_length > 0)
178 __line_number++;
179 setg(base(), cur_pos, ptr);
180 return ptr == cur_pos ? EOF : cur_pos[0];
183 char* general_parsebuf::current_line()
185 char* ret = base();
186 if (__line_number > 1)
187 ret++; // Move past '\n' from end of previous line.
188 return ret;
191 int general_parsebuf::tell_in_line()
193 int off = gptr() - base();
194 if (__line_number > 1)
195 off--; // Subtract 1 for '\n' from end of previous line.
196 return off;
199 int general_parsebuf::seek_in_line(int i)
201 if (__line_number == 0)
202 (void)general_parsebuf::underflow();
203 if (__line_number > 1)
204 i++; // Add 1 for '\n' from end of previous line.
205 if (i < 0) i = 0;
206 int len = egptr() - eback();
207 if (i > len) i = len;
208 setg(base(), base() + i, egptr());
209 return i;
212 func_parsebuf::func_parsebuf(CharReader func, void *argm) : parsebuf()
214 read_func = func;
215 arg = argm;
216 buf_start = NULL;
217 buf_end = NULL;
218 setb((char*)NewLine, (char*)NewLine+1, 0);
219 setg((char*)NewLine, (char*)NewLine+1, (char*)NewLine+1);
220 backed_up_to_newline = 0;
223 int func_parsebuf::tell_in_line()
225 if (buf_start == NULL)
226 return 0;
227 if (egptr() != (char*)NewLine+1)
228 // Get buffer was line buffer.
229 return gptr() - buf_start;
230 if (backed_up_to_newline)
231 return -1; // Get buffer is '\n' preceding current line.
232 // Get buffer is '\n' following current line.
233 return (buf_end - buf_start) + (gptr() - (char*)NewLine);
236 char* func_parsebuf::current_line()
238 return buf_start;
241 int func_parsebuf::seek_in_line(int i)
243 if (i < 0) {
244 // Back up to preceding '\n'.
245 if (i < -1) i = -1;
246 backed_up_to_newline = 1;
247 setg((char*)NewLine, (char*)NewLine+(i+1), (char*)NewLine+1);
248 return i;
250 backed_up_to_newline = 0;
251 int line_length = buf_end-buf_start;
252 if (i <= line_length) {
253 setg(buf_start, buf_start+i, buf_end);
254 return i;
256 i -= line_length;
257 if (i > 0) i = 1;
258 setg((char*)NewLine, (char*)NewLine+i, (char*)NewLine+1);
259 return line_length + i;
262 int func_parsebuf::underflow()
264 retry:
265 if (gptr() < egptr())
266 return *gptr();
267 if (gptr() != (char*)NewLine+1) {
268 // Get buffer was line buffer. Move to following '\n'.
269 setg((char*)NewLine, (char*)NewLine, (char*)NewLine+1);
270 return *gptr();
272 if (backed_up_to_newline)
273 // Get buffer was '\n' preceding current line. Move to current line.
274 backed_up_to_newline = 0;
275 else {
276 // Get buffer was '\n' following current line. Read new line.
277 if (buf_start) free(buf_start);
278 char *str = (*read_func)(arg);
279 buf_start = str;
280 if (str == NULL)
281 return EOF;
282 // Initially, _line_length == -1, so pos_at_line_start becomes 0.
283 pos_at_line_start += _line_length + 1;
284 _line_length = strlen(str);
285 buf_end = str + _line_length;
286 __line_number++;
288 setg(buf_start, buf_start, buf_end);
289 goto retry;
292 #if 0
293 size_t parsebuf::line_length()
295 if (current_line_length == (size_t)(-1)) // Initial value;
296 (void)sgetc();
297 return current_line_length;
299 #endif
301 int parsebuf::seek_in_line(int i)
303 #if 1
304 abort();
305 return i; // Suppress warnings.
306 #else
307 if (i > 0) {
308 size_t len = line_length();
309 if ((unsigned)i > len) i = len;
311 else if (i < -1) i = -1;
312 int new_pos = seekoff(pos_at_line_start + i, ios::beg);
313 if (new_pos == EOF)
314 return tell_in_line();
315 else return new_pos - pos_at_line_start;
316 #endif