aboutsummaryrefslogtreecommitdiff
path: root/libio/parsestream.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libio/parsestream.cc')
-rw-r--r--libio/parsestream.cc317
1 files changed, 317 insertions, 0 deletions
diff --git a/libio/parsestream.cc b/libio/parsestream.cc
new file mode 100644
index 00000000000..320afd06d9b
--- /dev/null
+++ b/libio/parsestream.cc
@@ -0,0 +1,317 @@
+/* This is part of libio/iostream, providing -*- C++ -*- input/output.
+Copyright (C) 1993 Free Software Foundation
+
+This file is part of the GNU IO Library. This library is free
+software; you can redistribute it and/or modify it under the
+terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this library; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+As a special exception, if you link this library with files
+compiled with a GNU compiler to produce an executable, this does not cause
+the resulting executable to be covered by the GNU General Public License.
+This exception does not however invalidate any other reasons why
+the executable file might be covered by the GNU General Public License.
+
+Written by Per Bothner (bothner@cygnus.com). */
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+#include "libioP.h"
+#include "parsestream.h"
+#include <stdlib.h>
+
+streambuf* parsebuf::setbuf(char*, int)
+{
+ return NULL;
+}
+
+int parsebuf::tell_in_line()
+{
+ return 0;
+}
+
+int parsebuf::pbackfail(int c)
+{
+ if (c == EOF)
+ return 0;
+ if (seekoff(-1, ios::cur) == EOF)
+ return EOF;
+ return (unsigned char)c;
+}
+
+char* parsebuf::current_line() { return NULL; }
+
+streampos parsebuf::seekoff(streamoff offset, _seek_dir dir, int)
+{
+ // Make offset relative to line start.
+ switch (dir) {
+ case ios::beg:
+ offset -= pos_at_line_start;
+ break;
+ case ios::cur:
+ offset += tell_in_line();
+ break;
+ default:
+ return EOF;
+ }
+ if (offset < -1)
+ return EOF;
+ if (offset > _line_length + 1)
+ return EOF;
+ return seek_in_line(offset) + pos_at_line_start;
+}
+
+// string_parsebuf invariants:
+// The reserve ares (base() .. ebuf()) is always the entire string.
+// The get area (eback() .. egptr()) is the extended current line
+// (i.e. with the '\n' at either end, if these exist).
+
+string_parsebuf::string_parsebuf(char *buf, int len,
+ int delete_at_close /* = 0*/)
+: parsebuf()
+{
+ setb(buf, buf+len, delete_at_close);
+ register char *ptr = buf;
+ while (ptr < ebuf() && *ptr != '\n') ptr++;
+ _line_length = ptr - buf;
+ setg(buf, buf, ptr);
+}
+
+int string_parsebuf::underflow()
+{
+ register char* ptr = egptr(); // Point to end of current_line
+ do {
+ int i = right() - ptr;
+ if (i <= 0)
+ return EOF;
+ ptr++; i--; // Skip '\n'.
+ char *line_start = ptr;
+ while (ptr < right() && *ptr == '\n') ptr++;
+ setg(line_start-1, line_start, ptr + (ptr < right()));
+ pos_at_line_start = line_start - left();
+ _line_length = ptr - line_start;
+ __line_number++;
+ } while (gptr() == ptr);
+ return *gptr();
+}
+
+char* string_parsebuf::current_line()
+{
+ char *ptr = eback();
+ if (__line_number > 0)
+ ptr++; // Skip '\n' at end of previous line.
+ return ptr;
+}
+
+int string_parsebuf::tell_in_line()
+{
+ int offset = gptr() - eback();
+ if (__line_number > 0)
+ offset--;
+ return offset;
+}
+
+int string_parsebuf::seek_in_line(int i)
+{
+ int delta = i - tell_in_line();
+ gbump(delta); // FIXME: Needs error (bounds) checking!
+ return i;
+}
+
+static const char NewLine[1] = { '\n' };
+
+general_parsebuf::general_parsebuf(streambuf *buf, int delete_arg_buf)
+ : parsebuf()
+{
+ delete_buf = delete_arg_buf;
+ sbuf = buf;
+ int buf_size = 128;
+ char* buffer = ALLOC_BUF(buf_size);
+ setb(buffer, buffer+buf_size, 1);
+// setg(buffer, buffer, buffer);
+}
+
+general_parsebuf::~general_parsebuf()
+{
+ if (delete_buf)
+ delete sbuf;
+}
+
+int general_parsebuf::underflow()
+{
+ register char *ptr = base();
+ int has_newline = eback() < gptr() && gptr()[-1] == '\n';
+ if (has_newline)
+ *ptr++ = '\n';
+ register streambuf *sb = sbuf;
+ register int ch;
+ for (;;) {
+ ch = sb->sbumpc();
+ if (ch == EOF)
+ break;
+ if (ptr == ebuf()) {
+ int old_size = ebuf() - base();
+ char *new_buffer = new char[old_size * 2];
+ memcpy(new_buffer, base(), old_size);
+ setb(new_buffer, new_buffer + 2 * old_size, 1);
+ ptr = new_buffer + old_size;
+ }
+ *ptr++ = ch;
+ if (ch == '\n')
+ break;
+ }
+ char *cur_pos = base() + has_newline;
+ pos_at_line_start += _line_length + 1;
+ _line_length = ptr - cur_pos;
+ if (ch != EOF || _line_length > 0)
+ __line_number++;
+ setg(base(), cur_pos, ptr);
+ return ptr == cur_pos ? EOF : cur_pos[0];
+}
+
+char* general_parsebuf::current_line()
+{
+ char* ret = base();
+ if (__line_number > 1)
+ ret++; // Move past '\n' from end of previous line.
+ return ret;
+}
+
+int general_parsebuf::tell_in_line()
+{
+ int off = gptr() - base();
+ if (__line_number > 1)
+ off--; // Subtract 1 for '\n' from end of previous line.
+ return off;
+}
+
+int general_parsebuf::seek_in_line(int i)
+{
+ if (__line_number == 0)
+ (void)general_parsebuf::underflow();
+ if (__line_number > 1)
+ i++; // Add 1 for '\n' from end of previous line.
+ if (i < 0) i = 0;
+ int len = egptr() - eback();
+ if (i > len) i = len;
+ setg(base(), base() + i, egptr());
+ return i;
+}
+
+func_parsebuf::func_parsebuf(CharReader func, void *argm) : parsebuf()
+{
+ read_func = func;
+ arg = argm;
+ buf_start = NULL;
+ buf_end = NULL;
+ setb((char*)NewLine, (char*)NewLine+1, 0);
+ setg((char*)NewLine, (char*)NewLine+1, (char*)NewLine+1);
+ backed_up_to_newline = 0;
+}
+
+int func_parsebuf::tell_in_line()
+{
+ if (buf_start == NULL)
+ return 0;
+ if (egptr() != (char*)NewLine+1)
+ // Get buffer was line buffer.
+ return gptr() - buf_start;
+ if (backed_up_to_newline)
+ return -1; // Get buffer is '\n' preceding current line.
+ // Get buffer is '\n' following current line.
+ return (buf_end - buf_start) + (gptr() - (char*)NewLine);
+}
+
+char* func_parsebuf::current_line()
+{
+ return buf_start;
+}
+
+int func_parsebuf::seek_in_line(int i)
+{
+ if (i < 0) {
+ // Back up to preceding '\n'.
+ if (i < -1) i = -1;
+ backed_up_to_newline = 1;
+ setg((char*)NewLine, (char*)NewLine+(i+1), (char*)NewLine+1);
+ return i;
+ }
+ backed_up_to_newline = 0;
+ int line_length = buf_end-buf_start;
+ if (i <= line_length) {
+ setg(buf_start, buf_start+i, buf_end);
+ return i;
+ }
+ i -= line_length;
+ if (i > 0) i = 1;
+ setg((char*)NewLine, (char*)NewLine+i, (char*)NewLine+1);
+ return line_length + i;
+}
+
+int func_parsebuf::underflow()
+{
+ retry:
+ if (gptr() < egptr())
+ return *gptr();
+ if (gptr() != (char*)NewLine+1) {
+ // Get buffer was line buffer. Move to following '\n'.
+ setg((char*)NewLine, (char*)NewLine, (char*)NewLine+1);
+ return *gptr();
+ }
+ if (backed_up_to_newline)
+ // Get buffer was '\n' preceding current line. Move to current line.
+ backed_up_to_newline = 0;
+ else {
+ // Get buffer was '\n' following current line. Read new line.
+ if (buf_start) free(buf_start);
+ char *str = (*read_func)(arg);
+ buf_start = str;
+ if (str == NULL)
+ return EOF;
+ // Initially, _line_length == -1, so pos_at_line_start becomes 0.
+ pos_at_line_start += _line_length + 1;
+ _line_length = strlen(str);
+ buf_end = str + _line_length;
+ __line_number++;
+ }
+ setg(buf_start, buf_start, buf_end);
+ goto retry;
+}
+
+#if 0
+size_t parsebuf::line_length()
+{
+ if (current_line_length == (size_t)(-1)) // Initial value;
+ (void)sgetc();
+ return current_line_length;
+}
+#endif
+
+int parsebuf::seek_in_line(int i)
+{
+#if 1
+ abort();
+ return i; // Suppress warnings.
+#else
+ if (i > 0) {
+ size_t len = line_length();
+ if ((unsigned)i > len) i = len;
+ }
+ else if (i < -1) i = -1;
+ int new_pos = seekoff(pos_at_line_start + i, ios::beg);
+ if (new_pos == EOF)
+ return tell_in_line();
+ else return new_pos - pos_at_line_start;
+#endif
+}