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"
34 streambuf
* parsebuf::setbuf(char*, int)
39 int parsebuf::tell_in_line()
44 int parsebuf::pbackfail(int c
)
48 if (seekoff(-1, ios::cur
) == 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.
60 offset
-= pos_at_line_start
;
63 offset
+= tell_in_line();
70 if (offset
> _line_length
+ 1)
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*/)
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
;
91 int string_parsebuf::underflow()
93 register char* ptr
= egptr(); // Point to end of current_line
95 int i
= right() - ptr
;
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
;
105 } while (gptr() == ptr
);
109 char* string_parsebuf::current_line()
112 if (__line_number
> 0)
113 ptr
++; // Skip '\n' at end of previous line.
117 int string_parsebuf::tell_in_line()
119 int offset
= gptr() - eback();
120 if (__line_number
> 0)
125 int string_parsebuf::seek_in_line(int i
)
127 int delta
= i
- tell_in_line();
128 gbump(delta
); // FIXME: Needs error (bounds) checking!
132 static const char NewLine
[1] = { '\n' };
134 general_parsebuf::general_parsebuf(streambuf
*buf
, int delete_arg_buf
)
137 delete_buf
= delete_arg_buf
;
140 char* buffer
= (char*)malloc(buf_size
);
141 setb(buffer
, buffer
+buf_size
, 1);
142 // setg(buffer, buffer, buffer);
145 general_parsebuf::~general_parsebuf()
151 int general_parsebuf::underflow()
153 register char *ptr
= base();
154 int has_newline
= eback() < gptr() && gptr()[-1] == '\n';
157 register streambuf
*sb
= sbuf
;
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
;
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)
179 setg(base(), cur_pos
, ptr
);
180 return ptr
== cur_pos
? EOF
: cur_pos
[0];
183 char* general_parsebuf::current_line()
186 if (__line_number
> 1)
187 ret
++; // Move past '\n' from end of previous line.
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.
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.
206 int len
= egptr() - eback();
207 if (i
> len
) i
= len
;
208 setg(base(), base() + i
, egptr());
212 func_parsebuf::func_parsebuf(CharReader func
, void *argm
) : parsebuf()
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
)
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()
241 int func_parsebuf::seek_in_line(int i
)
244 // Back up to preceding '\n'.
246 backed_up_to_newline
= 1;
247 setg((char*)NewLine
, (char*)NewLine
+(i
+1), (char*)NewLine
+1);
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
);
258 setg((char*)NewLine
, (char*)NewLine
+i
, (char*)NewLine
+1);
259 return line_length
+ i
;
262 int func_parsebuf::underflow()
265 if (gptr() < egptr())
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);
272 if (backed_up_to_newline
)
273 // Get buffer was '\n' preceding current line. Move to current line.
274 backed_up_to_newline
= 0;
276 // Get buffer was '\n' following current line. Read new line.
277 if (buf_start
) free(buf_start
);
278 char *str
= (*read_func
)(arg
);
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
;
288 setg(buf_start
, buf_start
, buf_end
);
293 size_t parsebuf::line_length()
295 if (current_line_length
== (size_t)(-1)) // Initial value;
297 return current_line_length
;
301 int parsebuf::seek_in_line(int i
)
305 return i
; // Suppress warnings.
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
);
314 return tell_in_line();
315 else return new_pos
- pos_at_line_start
;