%{
/* This file is part of tagr.
Copyright (C) 2000, 2005, 2009 Max Bouglacoff, Sergey Poznyakoff
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, 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 . */
#ifdef HAVE_CONFIG_H
# include
#endif
#include
#include
#include
#include
#include
#include
#include
#include
static pp_tab_t *ident_tab;
static char *tmp_file_name;
static FILE *tmp_file;
#define maxprec(a,b) ((a)>(b)?(a):(b))
static void out_char (int c);
static void out_value (pp_value_t *val);
static void deduce_format (pp_value_t *res,
const pp_value_t *a, const pp_value_t *b);
%}
%union {
int character;
double number;
pp_value_t value;
};
%token CHAR
%token NUMBER
%token IDENT
%token OBRACE CBRACE
%left '+' '-'
%left '*' '/'
%left UMINUS
%type eval value expr
%%
input: list
;
list : item
| list item
;
item : CHAR
{
out_char ($1);
}
| eval
{
out_value (&$1);
}
;
eval : IDENT
| obrace expr cbrace
{
$$ = $2;
}
| obrace error cbrace
{
init_value (&$$, unspecified_value, NULL);
}
;
obrace: OBRACE
{
begin_eval ();
}
;
cbrace: CBRACE
{
end_eval ();
}
;
expr : value
| '(' expr ')'
{
$$ = $2;
}
| expr '+' expr
{
if ($1.type == unspecified_value
|| $3.type == unspecified_value)
init_value (&$$, unspecified_value, NULL);
else if ($1.type != $3.type)
{
yyerror (_("type mismatch in addition"));
init_value (&$$, unspecified_value, NULL);
}
else
{
$$.type = $1.type;
deduce_format (&$$, &$1, &$3);
switch ($1.type)
{
case numeric_value:
$$.v.number = $1.v.number + $3.v.number;
break;
case string_value:
$$.v.string = xmalloc (strlen ($1.v.string)
+ strlen ($3.v.string) + 1);
strcpy ($$.v.string, $1.v.string);
strcat ($$.v.string, $3.v.string);
break;
default:
abort (); /* Should not happen */
}
}
}
| expr '-' expr
{
if ($1.type == unspecified_value
|| $3.type == unspecified_value)
init_value (&$$, unspecified_value, NULL);
else if ($1.type != $3.type)
{
yyerror (_("type mismatch in subtraction"));
init_value (&$$, unspecified_value, NULL);
}
else if ($1.type == string_value)
{
yyerror (_("subtraction not defined for strings"));
init_value (&$$, unspecified_value, NULL);
}
else
{
$$.type = $1.type;
deduce_format (&$$, &$1, &$3);
$$.v.number = $1.v.number - $3.v.number;
}
}
| expr '*' expr
{
if ($1.type == unspecified_value
|| $3.type == unspecified_value)
init_value (&$$, unspecified_value, NULL);
else if ($1.type != $3.type)
{
yyerror (_("type mismatch in multiplication"));
init_value (&$$, unspecified_value, NULL);
}
else if ($1.type == string_value)
{
yyerror (_("multiplication not defined for strings"));
init_value (&$$, unspecified_value, NULL);
}
else
{
$$.type = $1.type;
deduce_format (&$$, &$1, &$3);
$$.v.number = $1.v.number * $3.v.number;
}
}
| expr '/' expr
{
if ($1.type == unspecified_value
|| $3.type == unspecified_value)
init_value (&$$, unspecified_value, NULL);
else if ($1.type != $3.type)
{
yyerror (_("type mismatch in division"));
init_value (&$$, unspecified_value, NULL);
}
else if ($1.type == string_value)
{
yyerror (_("division not defined for strings"));
init_value (&$$, unspecified_value, NULL);
}
else if (fabs ($3.v.number) < 1.0e-5)
{
yyerror (_("division by zero"));
init_value (&$$, unspecified_value, NULL);
}
else
{
$$.type = $1.type;
deduce_format (&$$, &$1, &$3);
$$.v.number = $1.v.number / $3.v.number;
}
}
| '-' expr %prec UMINUS
{
if ($2.type == unspecified_value)
init_value (&$$, unspecified_value, NULL);
else if ($2.type == string_value)
{
yyerror (_("unary minus not defined for strings"));
init_value (&$$, unspecified_value, NULL);
}
else
{
$$ = $2;
$$.v.number = - $2.v.number;
}
}
| '+' expr %prec UMINUS
{
if ($2.type == unspecified_value)
init_value (&$$, unspecified_value, NULL);
else if ($2.type == string_value)
{
yyerror (_("unary plus not defined for strings"));
init_value (&$$, unspecified_value, NULL);
}
else
{
$$ = $2;
}
}
;
value : IDENT
| NUMBER
{
union value v;
v.number = $1;
init_value (&$$, numeric_value, &v);
}
;
%%
int
yyerror (char *s)
{
logmsg (L_ERR, "%s:%d: %s", html_input_file, html_input_line, s);
return 0;
}
int
create_html (pp_tab_t *tab, char *file, char *dest)
{
int rc;
if (html_open (file))
return 1;
tmp_file_name = mkfilename (NULL, dest, ".tmp");
tmp_file = fopen (tmp_file_name, "w");
if (!tmp_file)
{
logmsg (L_ERR, _("cannot open output file `%s': %s"),
file, strerror (errno));
html_close ();
return 1;
}
ident_tab = tab;
rc = yyparse ();
fclose (tmp_file);
if (rc == 0)
{
if (unlink (dest) && errno != ENOENT)
{
logmsg (L_ERR, _("cannot unlink file `%s': %s"),
dest, strerror (errno));
rc = 1;
}
if (rename (tmp_file_name, dest))
{
logmsg (L_ERR, _("cannot rename `%s' to `%s': %s"),
tmp_file_name, dest,
strerror (errno));
rc = 1;
}
}
free (tmp_file_name);
return rc;
}
static void
out_char (int c)
{
fputc (c, tmp_file);
}
static void
deduce_format (pp_value_t *res, const pp_value_t *a, const pp_value_t *b)
{
res->prec = maxprec (a->prec, b->prec);
if (!a->format && b->format)
{
res->fmt = b->fmt;
res->format = b->format;
}
else
{
res->fmt = a->fmt;
res->format = a->format;
}
}
void
format_unspecified (FILE *fp, union value v, const char *fmt, int prec)
{
fprintf (fp, "#UNSPECIFIED");
}
void
format_numeric (FILE *fp, union value v, const char *fmt, int prec)
{
if (prec >= 0)
fprintf (fp, "%.*f", prec, v.number);
else
fprintf (fp, "%f", v.number);
}
void
format_string (FILE *fp, union value v, const char *fmt, int prec)
{
if (fmt)
fprintf (fp, fmt, v.string);
else if (prec > 0)
fprintf (fp, "%.*s", prec, v.string);
else
fprintf (fp, "%s", v.string);
}
static value_format_fn default_format[] = {
format_unspecified,
format_numeric,
format_string
};
static void
out_value (pp_value_t *val)
{
value_format_fn format =
val->format ? val->format : default_format[val->type];
format (tmp_file, val->v, val->fmt, val->prec);
}
int
find_value (char *name, pp_value_t *val)
{
pp_tab_t *p;
for (p = ident_tab; p; p = p->next)
if (strcmp (p->name, name) == 0)
{
*val = p->value;
return 0;
}
return 1;
}
static void
free_value (pp_value_t *val)
{
if (val->type == string_value)
free (val->v.string);
}
void
init_value (pp_value_t *p, value_type type, union value *v)
{
memset (p, 0, sizeof (*p));
p->type = type;
p->prec = -1;
switch (p->type)
{
case unspecified_value:
break;
case numeric_value:
p->v.number = v->number;
break;
case string_value:
p->v.string = xstrdup (v->string);
}
}
static pp_value_t *
add_value (pp_tab_t **ptab, const char *name,
value_type type, union value *v)
{
pp_tab_t *p;
for (p = *ptab; p; p = p->next)
if (strcmp (p->name, name) == 0)
break;
if (p)
free_value (&p->value);
else
{
p = xmalloc (sizeof (*p));
p->next = *ptab;
p->name = xstrdup (name);
*ptab = p;
}
init_value (&p->value, type, v);
return &p->value;
}
pp_value_t *
add_numeric_value (pp_tab_t **ptab, const char *name, double number)
{
union value v;
v.number = number;
return add_value (ptab, name, numeric_value, &v);
}
pp_value_t *
add_string_value (pp_tab_t **ptab, const char *name, const char *string)
{
union value v;
v.string = xstrdup (string);
return add_value (ptab, name, string_value, &v);
}
void
free_tab (pp_tab_t **ptab)
{
pp_tab_t *p = *ptab;
while (p)
{
pp_tab_t *next = p->next;
free (p->name);
if (p->value.type == string_value)
free(p->value.v.string);
free (p);
p = next;
}
*ptab = NULL;
}
int
read_symtab (pp_tab_t **tab, const char *name)
{
FILE *fp;
char *buf = NULL;
size_t size = 0;
unsigned line = 0;
int status = 0;
fp = fopen (name, "r");
if (!fp)
return -1;
while (getline (&buf, &size, fp) > 0)
{
char *p, *var, *value;
int cmd;
size_t len = strlen (buf);
line++;
if (buf[len-1] == '\n')
buf[len-1] = 0;
if (buf[0] == '#' || buf[0] == 0)
continue;
p = buf;
cmd = *p++;
if (*p != ' ' || !(isascii (*++p) && isalpha (*p)))
{
logmsg (L_ERR, _("%s:%u: invalid input: %s"),
name, line, buf);
status = 1;
break;
}
var = p;
p = strchr (var, ' ');
if (!p)
{
logmsg (L_ERR, _("%s:%u: invalid input: %s"),
name, line, buf);
status = 1;
break;
}
*p++ = 0;
value = p;
switch (cmd)
{
case 's':
add_string_value (tab, var, value);
break;
case 'n':
{
char *p;
double num = strtod (value, &p);
if (*p)
{
logmsg (L_ERR, _("%s:%u: invalid numeric value: %s"),
name, line, value);
status = 1;
}
else
add_numeric_value (tab, var, num);
}
break;
default:
logmsg (L_NOTICE, _("%s:%u: ignoring unknown command %#03o"),
name, line, cmd);
}
}
free (buf);
fclose (fp);
return status;
}
int
write_symtab (pp_tab_t *tab, const char *name)
{
FILE *fp;
fp = fopen (name, "w");
if (!fp)
return -1;
for (; tab; tab = tab->next)
{
switch (tab->value.type)
{
case numeric_value:
fprintf (fp, "n %s %g\n", tab->name, tab->value.v.number);
break;
case string_value:
fprintf (fp, "s %s %s\n", tab->name, tab->value.v.string);
break;
case unspecified_value:
break;
}
}
fclose (fp);
return 0;
}
int
check_template ()
{
int rc;
pp_tab_t *tab = NULL;
add_string_value (&tab, "PROGRAM", PACKAGE_NAME);
add_string_value (&tab, "VERSION", PACKAGE_VERSION);
add_string_value (&tab, "ROUTERNAME", "routername");
add_string_value (&tab, "ROUTERIP", "routerip");
add_string_value (&tab, "NOW", "NOW");
add_numeric_value (&tab, "SPEED", 4096);
add_numeric_value (&tab, "MAXIN", 0);
add_numeric_value (&tab, "AVGIN", 1);
add_numeric_value (&tab, "CURIN", 2);
add_numeric_value (&tab, "MAXOUT", 3);
add_numeric_value (&tab, "AVGOUT", 4);
add_numeric_value (&tab, "CUROUT", 5);
add_numeric_value (&tab, "HMAXIN", 10);
add_numeric_value (&tab, "HAVGIN", 11);
add_numeric_value (&tab, "HCURIN", 12);
add_numeric_value (&tab, "HMAXOUT", 13);
add_numeric_value (&tab, "HAVGOUT", 14);
add_numeric_value (&tab, "HCUROUT", 15);
add_numeric_value (&tab, "TMAXIN", 20);
add_numeric_value (&tab, "TAVGIN", 21);
add_numeric_value (&tab, "TCURIN", 22);
add_numeric_value (&tab, "TMAXOUT", 23);
add_numeric_value (&tab, "TAVGOUT", 24);
add_numeric_value (&tab, "TCUROUT", 25);
add_numeric_value (&tab, "DMAXIN", 30);
add_numeric_value (&tab, "DAVGIN", 31);
add_numeric_value (&tab, "DCURIN", 32);
add_numeric_value (&tab, "DMAXOUT", 33);
add_numeric_value (&tab, "DAVGOUT", 34);
add_numeric_value (&tab, "DCUROUT", 35);
rc = create_html (tab, html_template, "test.html");
free_tab (&tab);
return rc;
}