%{ /* 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; }