OSDN Git Service

Revert last patch
[pf3gnuchains/gcc-fork.git] / libio / parsestream.cc
1 /* This is part of libio/iostream, providing -*- C++ -*- input/output.
2 Copyright (C) 1993 Free Software Foundation
3
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.
9
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.
14
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.
18
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.
24
25 Written by Per Bothner (bothner@cygnus.com). */
26
27 #ifdef __GNUG__
28 #pragma implementation
29 #endif
30 #include "libioP.h"
31 #include "parsestream.h"
32 #include <stdlib.h>
33 #include <string.h>
34
35 streambuf* parsebuf::setbuf(char*, int)
36 {
37     return NULL;
38 }
39
40 int parsebuf::tell_in_line()
41 {
42     return 0;
43 }
44
45 int parsebuf::pbackfail(int c)
46 {
47     if (c == EOF)
48         return 0;
49     if (seekoff(-1, ios::cur) == EOF)
50         return EOF;
51     return (unsigned char)c;
52 }
53
54 char* parsebuf::current_line() { return NULL; }
55
56 streampos parsebuf::seekoff(streamoff offset, _seek_dir dir, int)
57 {
58     // Make offset relative to line start.
59     switch (dir) {
60       case ios::beg:
61         offset -= pos_at_line_start;
62         break;
63       case ios::cur:
64         offset += tell_in_line();
65         break;
66       default:
67         return EOF;
68     }
69     if (offset < -1)
70         return EOF;
71     if (offset > _line_length + 1)
72         return EOF;
73     return seek_in_line(offset) + pos_at_line_start;
74 }
75
76 // string_parsebuf invariants:
77 // The reserve ares (base() .. ebuf()) is always the entire string.
78 // The get area (eback() .. egptr()) is the extended current line
79 // (i.e. with the '\n' at either end, if these exist).
80
81 string_parsebuf::string_parsebuf(char *buf, int len,
82                                  int delete_at_close /* = 0*/)
83 : parsebuf()
84 {
85     setb(buf, buf+len, delete_at_close);
86     register char *ptr = buf;
87     while (ptr < ebuf() && *ptr != '\n') ptr++;
88     _line_length = ptr - buf;
89     setg(buf, buf, ptr);
90 }
91
92 int string_parsebuf::underflow()
93 {
94     register char* ptr = egptr(); // Point to end of current_line
95     do {
96         int i = right() - ptr;
97         if (i <= 0)
98             return EOF;
99         ptr++; i--; // Skip '\n'.
100         char *line_start = ptr;
101         while (ptr < right() && *ptr == '\n') ptr++;
102         setg(line_start-1, line_start, ptr + (ptr < right()));
103         pos_at_line_start = line_start - left();
104         _line_length = ptr - line_start;
105         __line_number++;
106     } while (gptr() == ptr);
107     return *gptr();
108 }
109
110 char* string_parsebuf::current_line()
111 {
112     char *ptr = eback();
113     if (__line_number > 0)
114         ptr++; // Skip '\n' at end of previous line.
115     return ptr;
116 }
117
118 int string_parsebuf::tell_in_line()
119 {
120     int offset = gptr() - eback();
121     if (__line_number > 0)
122         offset--;
123     return offset;
124 }
125
126 int string_parsebuf::seek_in_line(int i)
127 {
128     int delta = i - tell_in_line();
129     gbump(delta); // FIXME: Needs error (bounds) checking!
130     return i;
131 }
132
133 static const char NewLine[1] = { '\n' };
134
135 general_parsebuf::general_parsebuf(streambuf *buf, int delete_arg_buf)
136  : parsebuf()
137 {
138     delete_buf = delete_arg_buf;
139     sbuf = buf;
140     int buf_size = 128;
141     char* buffer = (char*)malloc(buf_size);
142     setb(buffer, buffer+buf_size, 1);
143 //    setg(buffer, buffer, buffer);
144 }
145
146 general_parsebuf::~general_parsebuf()
147 {
148     if (delete_buf)
149         delete sbuf;
150 }
151
152 int general_parsebuf::underflow()
153 {
154     register char *ptr = base();
155     int has_newline = eback() < gptr() && gptr()[-1] == '\n';
156     if (has_newline)
157         *ptr++ = '\n';
158     register streambuf *sb = sbuf;
159     register int ch;
160     for (;;) {
161         ch = sb->sbumpc();
162         if (ch == EOF)
163             break;
164         if (ptr == ebuf()) {
165             int old_size = ebuf() - base();
166             char *new_buffer = new char[old_size * 2];
167             memcpy(new_buffer, base(), old_size);
168             setb(new_buffer, new_buffer + 2 * old_size, 1);
169             ptr = new_buffer + old_size;
170         }
171         *ptr++ = ch;
172         if (ch == '\n')
173             break;
174     }
175     char *cur_pos = base() + has_newline;
176     pos_at_line_start += _line_length + 1;
177     _line_length = ptr - cur_pos;
178     if (ch != EOF || _line_length > 0)
179         __line_number++;
180     setg(base(), cur_pos, ptr);
181     return ptr == cur_pos ? EOF : cur_pos[0];
182 }
183
184 char* general_parsebuf::current_line()
185 {
186     char* ret = base();
187     if (__line_number > 1)
188         ret++; // Move past '\n' from end of previous line.
189     return ret;
190 }
191
192 int general_parsebuf::tell_in_line()
193 {
194     int off = gptr() - base();
195     if (__line_number > 1)
196         off--; // Subtract 1 for '\n' from end of previous line.
197     return off;
198 }
199
200 int general_parsebuf::seek_in_line(int i)
201 {
202     if (__line_number == 0)
203         (void)general_parsebuf::underflow();
204     if (__line_number > 1)
205         i++; // Add 1 for '\n' from end of previous line.
206     if (i < 0) i = 0;
207     int len = egptr() - eback();
208     if (i > len) i = len;
209     setg(base(), base() + i, egptr());
210     return i;
211 }
212
213 func_parsebuf::func_parsebuf(CharReader func, void *argm) : parsebuf()
214 {
215     read_func = func;
216     arg = argm;
217     buf_start = NULL;
218     buf_end = NULL;
219     setb((char*)NewLine, (char*)NewLine+1, 0);
220     setg((char*)NewLine, (char*)NewLine+1, (char*)NewLine+1);
221     backed_up_to_newline = 0;
222 }
223
224 int func_parsebuf::tell_in_line()
225 {
226     if (buf_start == NULL)
227         return 0;
228     if (egptr() != (char*)NewLine+1)
229         // Get buffer was line buffer.
230         return gptr() - buf_start;
231     if (backed_up_to_newline)
232         return -1;  // Get buffer is '\n' preceding current line.
233     // Get buffer is '\n' following current line.
234     return (buf_end - buf_start) + (gptr() - (char*)NewLine);
235 }
236
237 char* func_parsebuf::current_line()
238 {
239     return buf_start;
240 }
241
242 int func_parsebuf::seek_in_line(int i)
243 {
244     if (i < 0) {
245         // Back up to preceding '\n'.
246         if (i < -1) i = -1;
247         backed_up_to_newline = 1;
248         setg((char*)NewLine, (char*)NewLine+(i+1), (char*)NewLine+1);
249         return i;
250     }
251     backed_up_to_newline = 0;
252     int line_length = buf_end-buf_start;
253     if (i <= line_length) {
254         setg(buf_start, buf_start+i, buf_end);
255         return i;
256     }
257     i -= line_length;
258     if (i > 0) i = 1;
259     setg((char*)NewLine, (char*)NewLine+i, (char*)NewLine+1);
260     return line_length + i;
261 }
262
263 int func_parsebuf::underflow()
264 {
265   retry:
266     if (gptr() < egptr())
267         return *gptr();
268     if (gptr() != (char*)NewLine+1) {
269         // Get buffer was line buffer.  Move to following '\n'.
270         setg((char*)NewLine, (char*)NewLine, (char*)NewLine+1);
271         return *gptr();
272     }
273     if (backed_up_to_newline)
274         // Get buffer was '\n' preceding current line. Move to current line.
275         backed_up_to_newline = 0;
276     else {
277         // Get buffer was '\n' following current line. Read new line.
278         if (buf_start) free(buf_start);
279         char *str = (*read_func)(arg);
280         buf_start = str;
281         if (str == NULL)
282             return EOF;
283         // Initially, _line_length == -1, so pos_at_line_start becomes 0.
284         pos_at_line_start += _line_length + 1;
285         _line_length = strlen(str);
286         buf_end = str + _line_length;
287         __line_number++;
288     }
289     setg(buf_start, buf_start, buf_end);
290     goto retry;
291 }
292
293 #if 0
294 size_t parsebuf::line_length()
295 {
296     if (current_line_length == (size_t)(-1)) // Initial value;
297         (void)sgetc();
298     return current_line_length;
299 }
300 #endif
301
302 int parsebuf::seek_in_line(int i)
303 {
304 #if 1
305     abort();
306     return i; // Suppress warnings.
307 #else
308     if (i > 0) {
309         size_t len = line_length();
310         if ((unsigned)i > len) i = len;
311     }
312     else if (i < -1) i = -1;
313     int new_pos = seekoff(pos_at_line_start + i, ios::beg);
314     if (new_pos == EOF)
315         return tell_in_line();
316     else return new_pos - pos_at_line_start;
317 #endif
318 }