home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / progc / djlsr106.arj / PARSESTR.CC < prev    next >
C/C++ Source or Header  |  1992-03-30  |  8KB  |  307 lines

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