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)
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). */
28 #pragma implementation
31 #include "parsestream.h"
35 streambuf
* parsebuf::setbuf(char*, int)
40 int parsebuf::tell_in_line()
45 int parsebuf::pbackfail(int c
)
49 if (seekoff(-1, ios::cur
) == EOF
)
51 return (unsigned char)c
;
54 char* parsebuf::current_line() { return NULL
; }
56 streampos
parsebuf::seekoff(streamoff offset
, _seek_dir dir
, int)
58 // Make offset relative to line start.
61 offset
-= pos_at_line_start
;
64 offset
+= tell_in_line();
71 if (offset
> _line_length
+ 1)
73 return seek_in_line(offset
) + pos_at_line_start
;
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).
81 string_parsebuf::string_parsebuf(char *buf
, int len
,
82 int delete_at_close
/* = 0*/)
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
;
92 int string_parsebuf::underflow()
94 register char* ptr
= egptr(); // Point to end of current_line
96 int i
= right() - ptr
;
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
;
106 } while (gptr() == ptr
);
110 char* string_parsebuf::current_line()
113 if (__line_number
> 0)
114 ptr
++; // Skip '\n' at end of previous line.
118 int string_parsebuf::tell_in_line()
120 int offset
= gptr() - eback();
121 if (__line_number
> 0)
126 int string_parsebuf::seek_in_line(int i
)
128 int delta
= i
- tell_in_line();
129 gbump(delta
); // FIXME: Needs error (bounds) checking!
133 static const char NewLine
[1] = { '\n' };
135 general_parsebuf::general_parsebuf(streambuf
*buf
, int delete_arg_buf
)
138 delete_buf
= delete_arg_buf
;
141 char* buffer
= (char*)malloc(buf_size
);
142 setb(buffer
, buffer
+buf_size
, 1);
143 // setg(buffer, buffer, buffer);
146 general_parsebuf::~general_parsebuf()
152 int general_parsebuf::underflow()
154 register char *ptr
= base();
155 int has_newline
= eback() < gptr() && gptr()[-1] == '\n';
158 register streambuf
*sb
= sbuf
;
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
;
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)
180 setg(base(), cur_pos
, ptr
);
181 return ptr
== cur_pos
? EOF
: cur_pos
[0];
184 char* general_parsebuf::current_line()
187 if (__line_number
> 1)
188 ret
++; // Move past '\n' from end of previous line.
192 int general_parsebuf::tell_in_line()
194 int off
= gptr() - base();
195 if (__line_number
> 1)
196 off
--; // Subtract 1 for '\n' from end of previous line.
200 int general_parsebuf::seek_in_line(int i
)
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.
207 int len
= egptr() - eback();
208 if (i
> len
) i
= len
;
209 setg(base(), base() + i
, egptr());
213 func_parsebuf::func_parsebuf(CharReader func
, void *argm
) : parsebuf()
219 setb((char*)NewLine
, (char*)NewLine
+1, 0);
220 setg((char*)NewLine
, (char*)NewLine
+1, (char*)NewLine
+1);
221 backed_up_to_newline
= 0;
224 int func_parsebuf::tell_in_line()
226 if (buf_start
== NULL
)
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
);
237 char* func_parsebuf::current_line()
242 int func_parsebuf::seek_in_line(int i
)
245 // Back up to preceding '\n'.
247 backed_up_to_newline
= 1;
248 setg((char*)NewLine
, (char*)NewLine
+(i
+1), (char*)NewLine
+1);
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
);
259 setg((char*)NewLine
, (char*)NewLine
+i
, (char*)NewLine
+1);
260 return line_length
+ i
;
263 int func_parsebuf::underflow()
266 if (gptr() < egptr())
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);
273 if (backed_up_to_newline
)
274 // Get buffer was '\n' preceding current line. Move to current line.
275 backed_up_to_newline
= 0;
277 // Get buffer was '\n' following current line. Read new line.
278 if (buf_start
) free(buf_start
);
279 char *str
= (*read_func
)(arg
);
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
;
289 setg(buf_start
, buf_start
, buf_end
);
294 size_t parsebuf::line_length()
296 if (current_line_length
== (size_t)(-1)) // Initial value;
298 return current_line_length
;
302 int parsebuf::seek_in_line(int i
)
306 return i
; // Suppress warnings.
309 size_t len
= line_length();
310 if ((unsigned)i
> len
) i
= len
;
312 else if (i
< -1) i
= -1;
313 int new_pos
= seekoff(pos_at_line_start
+ i
, ios::beg
);
315 return tell_in_line();
316 else return new_pos
- pos_at_line_start
;