nis-util  1.0.D108
lib/input.cc
Go to the documentation of this file.
00001 //
00002 // nis-util - NIS Administration Utilities
00003 // Copyright (C) 2012 Peter Miller
00004 //
00005 // This program is free software; you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation; either version 2 of the License, or (at
00008 // your option) any later version.
00009 //
00010 // This program is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License along
00016 // with this program. If not, see <http://www.gnu.org/licenses/>.
00017 //
00018 
00019 #include <lib/ac/string.h>
00020 
00021 #include <lib/input.h>
00022 #include <lib/rcstring/accumulator.h>
00023 
00024 
00025 #define BUFSIZE ((size_t)1u << 14)
00026 
00027 
00028 input::~input()
00029 {
00030     delete [] buf;
00031     buf = 0;
00032     buf_allocated = 0;
00033     pos = 0;
00034     avail = 0;
00035     relative_line_number = 0;
00036 }
00037 
00038 
00039 input::input() :
00040     buf(0),
00041     buf_allocated(0),
00042     pos(0),
00043     avail(0),
00044     relative_line_number(0),
00045     buf_locn(__FILE__, __LINE__)
00046 {
00047 }
00048 
00049 
00050 int
00051 input::underflow(void)
00052 {
00053     if (pos >= avail)
00054     {
00055         refill();
00056         if (avail == 0)
00057             return input::eof;
00058     }
00059     unsigned char c = buf[pos++];
00060     if (c == '\n')
00061         ++relative_line_number;
00062     return c;
00063 }
00064 
00065 
00066 void
00067 input::unget(int c)
00068 {
00069     if (c == input::eof)
00070         return;
00071     if (c == '\n')
00072         --relative_line_number;
00073     if (pos <= 0)
00074     {
00075         size_t nbytes = avail - pos;
00076 
00077         // reallocate the buffer data, but larger
00078         size_t new_buf_alloc = (buf_allocated ? 2 * buf_allocated : BUFSIZE);
00079         unsigned char *new_buf = new unsigned char [new_buf_alloc];
00080         size_t new_pos = new_buf_alloc - nbytes;
00081         assert(new_pos > 0);
00082 
00083         // moving the existing data to the top end
00084         memcpy(new_buf + new_pos, buf + pos, nbytes);
00085 
00086         delete [] buf;
00087         buf = new_buf;
00088         buf_allocated = new_buf_alloc;
00089         pos = new_pos;
00090         avail = new_buf_alloc;
00091     }
00092 
00093     --pos;
00094     buf[pos] = c;
00095 }
00096 
00097 
00098 void
00099 input::refill(void)
00100 {
00101     if (!buf)
00102     {
00103         buf_allocated = BUFSIZE;
00104         buf = new unsigned char [buf_allocated];
00105     }
00106     pos = 0;
00107     avail = read_inner(buf_locn, buf, buf_allocated);
00108     relative_line_number = 0;
00109 }
00110 
00111 
00112 source_location
00113 input::get_source_location(void)
00114 {
00115     if (!buf)
00116         refill();
00117     return (buf_locn + relative_line_number);
00118 }
00119 
00120 
00121 int
00122 input::count_newlines(const void *data, size_t data_size)
00123 {
00124     const char *cp = (const char *)data;
00125     const char *end = cp + data_size;
00126     int result = 0;
00127     while (cp < end)
00128     {
00129         // use memchr, it's probably been optimized
00130         const char *nl = (const char *)memchr(cp, '\n', end - cp);
00131         if (!nl)
00132             break;
00133         cp = nl + 1;
00134     }
00135     return result;
00136 }
00137 
00138 
00139 bool
00140 input::read_one_line(source_location &line_locn, rcstring &line)
00141 {
00142     line_locn = get_source_location();
00143     rcstring_accumulator acc;
00144     for (;;)
00145     {
00146         int c = get();
00147         if (c == input::eof)
00148         {
00149             if (acc.empty())
00150                 return false;
00151             line = acc.mkstr();
00152             return true;
00153         }
00154         if (c == '\n')
00155         {
00156             line = acc.mkstr();
00157             return true;
00158         }
00159         acc.push_back((unsigned char)c);
00160     }
00161 }
00162 
00163 
00164 // vim: set ts=8 sw=4 et :