|
|
1.1 root 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 GNU CC; see the file COPYING. If not, write to
17: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, 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 ([email protected]). */
26:
27: #ifdef __GNUG__
28: #pragma implementation
29: #endif
30: #include "libioP.h"
31: #include "parsestream.h"
32: extern "C" {
33: #include <stdlib.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 = ALLOC_BUF(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 0; // Suppress warning.
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.