/* Path-style configuration file parser for Grecs.
Copyright (C) 2011 Sergey Poznyakoff
Grecs 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.
Grecs 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 Grecs. If not, see . */
#ifdef HAVE_CONFIG_H
# include
#endif
#include
#include
#include
#include
#include
static int
next_char(FILE *infile)
{
int c = fgetc(infile);
if (c == '\n')
grecs_locus_point_advance_line(grecs_current_locus_point);
else {
grecs_current_locus_point.col++;
if (c == '\\') {
int nc = fgetc(infile);
if (nc == '\n') {
grecs_locus_point_advance_line(grecs_current_locus_point);
c = fgetc(infile);
grecs_current_locus_point.col++;
} else
ungetc(nc, infile);
}
}
return c;
}
struct grecs_node *
grecs_path_parser(const char *name, int traceflags)
{
struct grecs_node *root, *subtree = NULL, *node;
FILE *infile;
struct grecs_txtacc *acc = NULL;
char *kw, *val;
grecs_locus_t kwloc, valloc, rootloc;
int inquote;
int lookahead;
int err = 0;
unsigned prev_col;
infile = fopen(name, "r");
if (!infile) {
grecs_error(NULL, errno, _("cannot open `%s'"), name);
return NULL;
}
grecs_current_locus_point.file = grecs_install_text(name);
grecs_current_locus_point.line = 1;
grecs_current_locus_point.col = 0;
rootloc.beg = grecs_current_locus_point;
rootloc.beg.col++;
acc = grecs_txtacc_create();
while ((lookahead = next_char(infile)) > 0) {
while (1) {
while (lookahead == ' ' || lookahead == '\t')
lookahead = next_char(infile);
if (lookahead == '#') {
while ((lookahead = next_char(infile)) &&
lookahead != '\n')
;
continue;
}
break;
}
if (lookahead <= 0)
break;
kwloc.beg = grecs_current_locus_point;
inquote = 0;
for (; lookahead > 0 && lookahead != ':';
lookahead = next_char(infile)) {
if (inquote) {
if (inquote == '"' && lookahead == '\\') {
lookahead = next_char(infile);
if (lookahead <= 0)
break;
} else if (lookahead == inquote)
inquote = 0;
} else if (lookahead == '\'' || lookahead == '"')
inquote = lookahead;
grecs_txtacc_grow_char(acc, lookahead);
}
if (lookahead <= 0) {
grecs_error(&kwloc, 0, _("unexpected end of file"));
err = 1;
break;
}
grecs_txtacc_grow_char(acc, 0);
kw = grecs_txtacc_finish(acc, 0);
kwloc.end = grecs_current_locus_point;
kwloc.end.col--;
while ((lookahead = next_char(infile)) > 0 &&
(lookahead == ' ' || lookahead == '\t'));
if (lookahead <= 0) {
grecs_error(&kwloc, 0, _("unexpected end of file"));
err = 1;
break;
}
valloc.beg = grecs_current_locus_point;
do {
grecs_txtacc_grow_char(acc, lookahead);
prev_col = grecs_current_locus_point.col;
} while ((lookahead = next_char(infile)) > 0 &&
lookahead != '\n');
valloc.end = grecs_current_locus_point;
valloc.end.line--;
valloc.end.col = prev_col;
grecs_txtacc_grow_char(acc, 0);
val = grecs_txtacc_finish(acc, 0);
node = grecs_node_from_path_locus(kw, val, &kwloc, &valloc);
if (!node) {
grecs_error(&kwloc, 0, _("parse error"));
err = 1;
break;
}
node->locus.end = valloc.end;
node->idloc = kwloc;
if (!subtree)
subtree = node;
else
grecs_node_bind(subtree, node, 0);
grecs_txtacc_free_string(acc, kw);
grecs_txtacc_free_string(acc, val);
}
fclose(infile);
grecs_txtacc_free(acc);
if (err) {
grecs_tree_free(subtree);
root = NULL;
} else {
rootloc.end = grecs_current_locus_point;
root = grecs_node_create(grecs_node_root, &rootloc);
root->v.texttab = grecs_text_table();
grecs_node_bind(root, subtree, 1);
grecs_tree_reduce(root, NULL, 0);
}
return root;
}