nis-util
1.0.D108
|
00001 // 00002 // nis-util - NIS Administration Utilities 00003 // Copyright (C) 2001, 2008, 2009, 2011, 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 00016 // along with this program. If not, see <http://www.gnu.org/licenses/>. 00017 // 00018 00019 #include <lib/ac/ctype.h> 00020 #include <lib/ac/stdarg.h> 00021 #include <libexplain/fclose.h> 00022 #include <libexplain/fopen.h> 00023 #include <libexplain/getc.h> 00024 #include <libexplain/output.h> 00025 #include <libexplain/realloc.h> 00026 00027 #include <lib/colon.h> 00028 #include <lib/configuration.h> 00029 #include <lib/input/file.h> 00030 #include <lib/input/remove_hash_comments.h> 00031 #include <lib/rcstring/accumulator.h> 00032 00033 00034 colon::~colon() 00035 { 00036 close(); 00037 } 00038 00039 00040 colon::colon(const rcstring &a_filename): 00041 filename(a_filename), 00042 non_printing_whine(0), 00043 token(token_eof), 00044 error_count(0), 00045 discard_comments_flag(false), 00046 discard_blank_lines_flag(false), 00047 explained_sequence_errors(false) 00048 { 00049 } 00050 00051 00052 void 00053 colon::open(void) 00054 { 00055 if (ip) 00056 return; 00057 ip = input_file::create(filename); 00058 if (discard_comments_flag) 00059 ip = input_remove_hash_comments::create(ip); 00060 error_count = 0; 00061 } 00062 00063 00064 void 00065 colon::close(void) 00066 { 00067 if (error_count) 00068 { 00069 explain_output_error_and_die 00070 ( 00071 "%s: found %d fatal error%s", 00072 filename.c_str(), 00073 error_count, 00074 (error_count == 1 ? "" : "s") 00075 ); 00076 } 00077 ip.reset(); 00078 error_count = 0; 00079 } 00080 00081 00082 source_location 00083 colon::get_source_location(void) 00084 const 00085 { 00086 if (!ip) 00087 return source_location("file has been closed", 666); 00088 return ip->get_source_location(); 00089 } 00090 00091 00092 void 00093 colon::lex(void) 00094 { 00095 rcstring_accumulator acc; 00096 for (;;) 00097 { 00098 token_locn = get_source_location(); 00099 int c = ip->get(); 00100 switch (c) 00101 { 00102 case input::eof: 00103 token = token_eof; 00104 return; 00105 00106 case '\n': 00107 non_printing_whine = 0; 00108 token = token_eoln; 00109 return; 00110 00111 case ':': 00112 token = token_colon; 00113 return; 00114 00115 default: 00116 for (;;) 00117 { 00118 if 00119 ( 00120 #ifdef AMERICAN_ASCII_ONLY 00121 !isprint(c) && !isspace(c) 00122 #else 00123 !c 00124 #endif 00125 && 00126 !non_printing_whine 00127 ) 00128 { 00129 error(token_locn, "line contains non printing character"); 00130 } 00131 acc.push_back((unsigned char)c); 00132 00133 c = ip->get(); 00134 if (c == input::eof) 00135 break; 00136 if (c == '\n' || c == ':') 00137 { 00138 ip->unget(c); 00139 break; 00140 } 00141 } 00142 token_value = acc.mkstr(); 00143 token = token_string; 00144 return; 00145 } 00146 } 00147 } 00148 00149 00150 void 00151 colon::error(const source_location &locn, const char *fmt, ...) 00152 { 00153 va_list ap; 00154 va_start(ap, fmt); 00155 verror(locn, fmt, ap); 00156 va_end(ap); 00157 } 00158 00159 00160 void 00161 colon::verror(const source_location &locn, const char *fmt, va_list ap) 00162 { 00163 rcstring msg = rcstring::vformat(fmt, ap); 00164 explain_output_error("%s: %s", locn.get_both().c_str(), msg.c_str()); 00165 if (!msg.ends_with("...")) 00166 { 00167 ++error_count; 00168 if (error_count >= 50) 00169 { 00170 explain_output_error_and_die 00171 ( 00172 "%s: too many fatal errors, aborting", 00173 filename.c_str() 00174 ); 00175 } 00176 } 00177 } 00178 00179 00180 void 00181 colon::pedantic_error(const source_location &locn, const char *fmt, ...) 00182 { 00183 va_list ap; 00184 va_start(ap, fmt); 00185 vpedantic_error(locn, fmt, ap); 00186 va_end(ap); 00187 } 00188 00189 00190 void 00191 colon::vpedantic_error(const source_location &locn, const char *fmt, va_list ap) 00192 { 00193 if (cfg.get_bool(SECTION_GLOBAL, "pedantic")) 00194 verror(locn, fmt, ap); 00195 else 00196 vwarning(locn, fmt, ap); 00197 } 00198 00199 00200 void 00201 colon::warning(const source_location &locn, const char *fmt, ...) 00202 { 00203 va_list ap; 00204 va_start(ap, fmt); 00205 vwarning(locn, fmt, ap); 00206 va_end(ap); 00207 } 00208 00209 00210 void 00211 colon::vwarning(const source_location &locn, const char *fmt, va_list ap) 00212 { 00213 // For maximum portability, always "use up" the arguments, even if 00214 // we don't issue the warning. 00215 rcstring msg = rcstring::vformat(fmt, ap); 00216 00217 if (cfg.get_bool(SECTION_GLOBAL, ITEM_WARNING)) 00218 { 00219 explain_output_error 00220 ( 00221 "%s: warning: %s", 00222 locn.get_both().c_str(), 00223 msg.c_str() 00224 ); 00225 } 00226 } 00227 00228 00229 bool 00230 colon::read_one_line(source_location &line_locn, line_t &line) 00231 { 00232 // 00233 // open the file if it isn't open already 00234 // 00235 open(); 00236 00237 // 00238 // Make sure the output is empty. 00239 // 00240 line.clear(); 00241 00242 // 00243 // Keep chewing tokens until we've read a whole line. 00244 // 00245 token = token_eoln; 00246 for (;;) 00247 { 00248 token_ty prev = token; 00249 lex(); 00250 switch (token) 00251 { 00252 case token_eof: 00253 if (prev == token_colon) 00254 line.push_back(rcstring("")); 00255 if (line.size() > 0) 00256 { 00257 error(token_locn, "last line needs newline"); 00258 return true; 00259 } 00260 return false; 00261 00262 case token_eoln: 00263 if (prev == token_colon) 00264 { 00265 if (line.empty()) 00266 line_locn = token_locn; 00267 line.push_back(rcstring()); 00268 } 00269 if (line.empty() && discard_blank_lines_flag) 00270 continue; 00271 return true; 00272 00273 case token_colon: 00274 if (prev != token_string) 00275 { 00276 if (line.empty()) 00277 line_locn = token_locn; 00278 line.push_back(rcstring()); 00279 } 00280 break; 00281 00282 case token_string: 00283 if (line.empty()) 00284 line_locn = token_locn; 00285 line.push_back(token_value); 00286 break; 00287 00288 default: 00289 error(token_locn, "malformed line"); 00290 for (;;) 00291 { 00292 lex(); 00293 if (token == token_eof) 00294 return false; 00295 if (token == token_eoln) 00296 break; 00297 } 00298 break; 00299 } 00300 } 00301 } 00302 00303 00304 void 00305 colon::discard_blank_lines(void) 00306 { 00307 discard_blank_lines_flag = true; 00308 } 00309 00310 00311 void 00312 colon::discard_comments(void) 00313 { 00314 discard_comments_flag = true; 00315 } 00316 00317 00318 void 00319 colon::explain_sequence_errors(void) 00320 { 00321 if (explained_sequence_errors) 00322 return; 00323 explained_sequence_errors = true; 00324 explain_output_error 00325 ( 00326 "by keeping the file sorted, common typographical errors show " 00327 "up as ordering errors" 00328 ); 00329 } 00330 00331 00332 // vim: set ts=8 sw=4 et :