nis-util
1.0.D108
|
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 :