/*
* dnsutl - utilities to make DNS easier to configure
* Copyright (C) 1999-2001, 2003, 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 <http://www.gnu.org/licenses/>.
*/
#include <ac/ctype.h>
#include <ac/stdarg.h>
#include <ac/stdio.h>
#include <ac/string.h>
#include <error.h>
#include <lex.h>
#include <mem.h>
#include <mprintf.h>
#include <str.h>
#include <gram.gen.h> /* must be after str.h */
static const char *fn;
static FILE *fp;
static int linum;
static int incriment_line_number;
static int non_printing_whine;
extern gram_STYPE gram_lval;
static int error_count;
static int word_on_line;
void
lex_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;
word_on_line = 0;
}
void
lex_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
lex_getc(void)
{
int c;
for (;;)
{
c = getc(fp);
switch (c)
{
case EOF:
if (ferror(fp))
nfatal("read \"%s\"", fn);
break;
#if 0
case '\\':
c = getc(fp);
if (c == '\n')
{
++incriment_line_number;
continue;
}
if (c != EOF)
ungetc(c, fp);
c = '\\';
break;
#endif
}
return c;
}
}
static void
lex_ungetc(int c)
{
if (c != EOF)
ungetc(c, fp);
}
static int
inner_lex(void)
{
int c;
int bufpos;
static int bufmax;
static char *buffer;
if (incriment_line_number)
{
linum += incriment_line_number;
incriment_line_number = 0;
}
for (;;)
{
c = lex_getc();
switch (c)
{
case EOF:
if (ferror(fp))
nfatal("read \"%s\"", fn);
return 0;
case '\n':
++incriment_line_number;
non_printing_whine = 0;
return EOLN;
case ' ':
case '\t':
break;
default:
bufpos = 0;
non_printing_whine = 0;
for (;;)
{
if (!isprint(c) && !non_printing_whine)
gram_error("line contains non printing character");
if (bufpos >= bufmax)
{
bufmax = bufmax * 2 + 16;
buffer = mem_change_size(buffer, bufmax);
}
buffer[bufpos++] = c;
c = lex_getc();
if (c == '\n' || c == ' ' || c == '\t'
|| c == EOF || c == ';')
{
lex_ungetc(c);
break;
}
}
gram_lval.lv_string = str_n_from_c(buffer, bufpos);
return STRING;
case ';':
/*
* throw comments away
*/
for (;;)
{
c = lex_getc();
if (c == '\n' || c == EOF)
{
lex_ungetc(c);
break;
}
}
break;
}
}
}
typedef struct table_ty table_ty;
struct table_ty
{
const char *name;
int token;
};
static table_ty table[] =
{
{ "cache", CACHE, },
{ "directory", DIRECTORY, },
{ "domain", DOMAIN, },
{ "forwarders", FORWARDERS, },
{ "options", OPTIONS, },
{ "primary", PRIMARY, },
{ "secondary", SECONDARY, },
};
static int
reserved(string_ty *s)
{
table_ty *tp;
/* This is slow. I'll speed it up if it's ever a problem. */
for (tp = table; tp < ENDOF(table); ++tp)
{
if (0 == strcmp(s->str_text, tp->name))
return tp->token;
}
return STRING;
}
int
gram_lex(void)
{
int n = inner_lex();
if (word_on_line == 0 && n == STRING)
{
n = reserved(gram_lval.lv_string);
if (n != STRING)
str_free(gram_lval.lv_string);
}
if (n == EOLN)
word_on_line = 0;
else
++word_on_line;
return n;
}
void
gram_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
lex_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);
}
syntax highlighted by Code2HTML, v. 0.9.1