%{
/* cfg_parser.y -- general-purpose configuration file parser
Copyright (C) 2007-2012, 2014-2018 Free Software Foundation, Inc.
GNU Mailutils 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.
GNU Mailutils 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 GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <netdb.h>
#include <mailutils/argcv.h>
#include <mailutils/wordsplit.h>
#include <mailutils/nls.h>
#include <mailutils/cfg.h>
#include <mailutils/alloc.h>
#include <mailutils/errno.h>
#include <mailutils/error.h>
#include <mailutils/list.h>
#include <mailutils/iterator.h>
#include <mailutils/debug.h>
#include <mailutils/util.h>
#include <mailutils/cctype.h>
#include <mailutils/stream.h>
#include <mailutils/stdstream.h>
#include <mailutils/cidr.h>
#include <mailutils/yyloc.h>
int mu_cfg_parser_verbose;
static mu_list_t /* of mu_cfg_node_t */ parse_node_list;
size_t mu_cfg_error_count;
static int _mu_cfg_errcnt;
int yylex ();
void _mu_line_begin (void);
void _mu_line_add (char *text, size_t len);
char *_mu_line_finish (void);
static int
yyerror (char *s)
{
mu_error ("%s", s);
mu_cfg_error_count++;
return 0;
}
static mu_config_value_t *
config_value_dup (mu_config_value_t *src)
{
if (!src)
return NULL;
else
{
/* FIXME: Use mu_opool_alloc */
mu_config_value_t *val = mu_alloc (sizeof (*val));
*val = *src;
return val;
}
}
static int
_node_set_parent (void *item, void *data)
{
struct mu_cfg_node *node = item;
node->parent = data;
return 0;
}
static mu_cfg_node_t *
mu_cfg_alloc_node (enum mu_cfg_node_type type, struct mu_locus_range *loc,
const char *tag, mu_config_value_t *label,
mu_list_t nodelist)
{
char *p;
mu_cfg_node_t *np;
size_t size = sizeof *np + strlen (tag) + 1;
np = mu_alloc (size);
np->type = type;
mu_locus_range_init (&np->locus);
mu_locus_range_copy (&np->locus, loc);
p = (char*) (np + 1);
np->tag = p;
strcpy (p, tag);
np->label = label;
np->nodes = nodelist;
np->parent = NULL;
return np;
}
void
mu_cfg_free_node (mu_cfg_node_t *node)
{
free (node->label);
free (node);
}
#define node_type_str(t) (((t) == mu_cfg_node_statement) ? "stmt" : "param")
static void
debug_print_node (mu_cfg_node_t *node)
{
if (mu_debug_level_p (MU_DEBCAT_CONFIG, MU_DEBUG_TRACE0))
{
if (node->type == mu_cfg_node_undefined)
{
/* Stay on the safe side */
mu_error (_("unknown statement type!"));
mu_cfg_error_count++;
}
else
{
/* FIXME: How to print label? */
mu_error ("statement: %s, id: %s",
node_type_str (node->type),
node->tag ? node->tag : "(null)");
}
}
}
static void
free_node_item (void *item)
{
mu_cfg_node_t *node = item;
switch (node->type)
{
case mu_cfg_node_statement:
mu_list_destroy (&node->nodes);
break;
case mu_cfg_node_undefined: /* hmm... */
case mu_cfg_node_param:
break;
}
mu_cfg_free_node (node);
}
int
mu_cfg_create_node_list (mu_list_t *plist)
{
int rc;
mu_list_t list;
rc = mu_list_create (&list);
if (rc)
return rc;
mu_list_set_destroy_item (list, free_node_item);
*plist = list;
return 0;
}
%}
%locations
%expect 1
%union {
mu_cfg_node_t node;
mu_cfg_node_t *pnode;
mu_list_t /* of mu_cfg_node_t */ nodelist;
char *string;
mu_config_value_t value, *pvalue;
mu_list_t list;
}
%token <string> MU_TOK_IDENT MU_TOK_STRING MU_TOK_QSTRING MU_TOK_MSTRING
%type <string> string slist
%type <list> slist0
%type <value> value
%type <pvalue> tag vallist
%type <list> values list vlist
%type <string> ident
%type <nodelist> stmtlist
%type <pnode> stmt simple block
%%
input : stmtlist
{
parse_node_list = $1;
}
;
stmtlist: stmt
{
mu_cfg_create_node_list (&$$);
mu_list_append ($$, $1);
}
| stmtlist stmt
{
mu_list_append ($1, $2);
$$ = $1;
debug_print_node ($2);
}
;
stmt : simple
| block
;
simple : ident vallist ';'
{
struct mu_locus_range lr;
lr.beg = @1.beg;
lr.end = @3.end;
$$ = mu_cfg_alloc_node (mu_cfg_node_param, &lr, $1, $2, NULL);
}
;
block : ident tag '{' '}' opt_sc
{
struct mu_locus_range lr;
lr.beg = @1.beg;
lr.end = @5.end;
$$ = mu_cfg_alloc_node (mu_cfg_node_statement, &lr, $1, $2, NULL);
}
| ident tag '{' stmtlist '}' opt_sc
{
struct
|