/* * dnsutl - utilities to make DNS easier to configure * Copyright (C) 1999, 2006, 2007 Peter Miller * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see * . * * functions to lexically analyze files containing lines which consist * of space separated fields */ #include #include #include #include #include #include #include #include static const char *fn; static FILE *fp; static int linum; static int incriment_line_number; static int non_printing_whine; map_token_ty map_token; char *map_value; static int error_count; void map_open(const char *filename) { if (filename) { fn = filename; fp = fopen(fn, "r"); if (!fp) nfatal("open \"%s\"", fn); } else { fn = "(stdin)"; fp = stdin; } linum = 1; } void map_close(void) { if (error_count) { fatal ( "%s: found %d fatal error%s", fn, error_count, (error_count == 1 ? "" : "s") ); } if (fp != stdin) fclose(fp); fn = 0; fp = 0; linum = 0; error_count = 0; incriment_line_number = 0; } static int map_getc(void) { int c; for (;;) { c = getc(fp); switch (c) { case EOF: if (ferror(fp)) nfatal("read \"%s\"", fn); break; case '\\': c = getc(fp); if (c == '\n') { ++incriment_line_number; continue; } if (c != EOF) ungetc(c, fp); c = '\\'; break; } return c; } } static void map_ungetc(int c) { if (c != EOF) ungetc(c, fp); } void map_lex(void) { int c; int bufpos; static int bufmax; static char *buffer; map_value = 0; if (incriment_line_number) { linum += incriment_line_number; incriment_line_number = 0; } for (;;) { c = map_getc(); switch (c) { case EOF: if (ferror(fp)) nfatal("read \"%s\"", fn); map_token = map_token_eof; return; case '\n': ++incriment_line_number; non_printing_whine = 0; map_token = map_token_eoln; return; case ' ': case '\t': break; default: bufpos = 0; non_printing_whine = 0; for (;;) { if (!isprint(c) && !non_printing_whine) map_error("line contains non printing character"); if (bufpos >= bufmax) { bufmax += 100; buffer = mem_change_size(buffer, bufmax); } buffer[bufpos++] = c; c = map_getc(); if (c == '\n' || c == ' ' || c == '\t' || c == EOF) { map_ungetc(c); break; } } if (bufpos >= bufmax) { bufmax += 100; buffer = mem_change_size(buffer, bufmax); } buffer[bufpos] = 0; map_value = buffer; map_token = map_token_string; return; case '#': /* * throw comments away */ for (;;) { c = map_getc(); if (c == '\n' || c == EOF) { map_ungetc(c); break; } } break; } } } void map_error(const char *s, ...) { va_list ap; char *msg; va_start(ap, s); msg = vmprintf(s, ap); va_end(ap); msg = mem_copy_string(msg); error("%s: %d: %s", fn, linum, msg); mem_free(msg); ++error_count; if (error_count >= 20) fatal("%s: too many fatal errors, aborting", fn); } void map_warning(const char *s, ...) { va_list ap; char *msg; va_start(ap, s); msg = vmprintf(s, ap); va_end(ap); msg = mem_copy_string(msg); error("%s: %d: warning: %s", fn, linum, msg); mem_free(msg); } int map_read(strlist_ty *slp) { strlist_zero(slp); for (;;) { map_lex(); switch (map_token) { case map_token_eof: return 0; case map_token_eoln: /* ignore blank lines */ break; case map_token_string: for (;;) { string_ty *s; s = str_from_c(map_value); strlist_append(slp, s); str_free(s); map_lex(); if (map_token != map_token_string) break; } if (map_token == map_token_eoln) return 1; if (map_token == map_token_eof) return 1; /* fall through... */ default: map_error("syntax error"); for (;;) { map_lex(); if (map_token == map_token_eoln) break; if (map_token == map_token_eof) break; } break; } } }