1 /* Path-style configuration file parser for Grecs.
2 Copyright (C) 2011-2016 Sergey Poznyakoff
3
4 Grecs is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 3 of the License, or (at your
7 option) any later version.
8
9 Grecs is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with Grecs. If not, see <http://www.gnu.org/licenses/>. */
16
17 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20 #include <stdlib.h>
21 #include <string.h>
22 #include <ctype.h>
23 #include <errno.h>
24 #include <grecs.h>
25
26 static int
next_char(FILE * infile)27 next_char(FILE *infile)
28 {
29 int c = fgetc(infile);
30 if (c == '\n')
31 grecs_locus_point_advance_line(grecs_current_locus_point);
32 else {
33 grecs_current_locus_point.col++;
34 if (c == '\\') {
35 int nc = fgetc(infile);
36 if (nc == '\n') {
37 grecs_locus_point_advance_line(grecs_current_locus_point);
38 c = fgetc(infile);
39 grecs_current_locus_point.col++;
40 } else
41 ungetc(nc, infile);
42 }
43 }
44 return c;
45 }
46
47 struct grecs_node *
grecs_path_parser(const char * name,int traceflags)48 grecs_path_parser(const char *name, int traceflags)
49 {
50 struct grecs_node *root, *subtree = NULL, *node;
51 FILE *infile;
52 struct grecs_txtacc *acc = NULL;
53 char *kw, *val;
54 grecs_locus_t kwloc, valloc, rootloc;
55 int inquote;
56 int lookahead;
57 int err = 0;
58 unsigned prev_col;
59
60 infile = fopen(name, "r");
61 if (!infile) {
62 grecs_error(NULL, errno, _("cannot open `%s'"), name);
63 return NULL;
64 }
65 grecs_current_locus_point.file = grecs_install_text(name);
66 grecs_current_locus_point.line = 1;
67 grecs_current_locus_point.col = 0;
68 rootloc.beg = grecs_current_locus_point;
69 rootloc.beg.col++;
70
71 acc = grecs_txtacc_create();
72
73 while ((lookahead = next_char(infile)) > 0) {
74 while (1) {
75 while (lookahead == ' ' || lookahead == '\t')
76 lookahead = next_char(infile);
77
78 if (lookahead == '#') {
79 while ((lookahead = next_char(infile)) &&
80 lookahead != '\n')
81 ;
82 continue;
83 }
84 break;
85 }
86
87 if (lookahead <= 0)
88 break;
89
90 kwloc.beg = grecs_current_locus_point;
91
92 inquote = 0;
93 for (; lookahead > 0 && lookahead != ':';
94 lookahead = next_char(infile)) {
95 if (inquote) {
96 if (inquote == '"' && lookahead == '\\') {
97 lookahead = next_char(infile);
98 if (lookahead <= 0)
99 break;
100 } else if (lookahead == inquote)
101 inquote = 0;
102 } else if (lookahead == '\'' || lookahead == '"')
103 inquote = lookahead;
104 grecs_txtacc_grow_char(acc, lookahead);
105 }
106
107 if (lookahead <= 0) {
108 grecs_error(&kwloc, 0, _("unexpected end of file"));
109 err = 1;
110 break;
111 }
112
113 grecs_txtacc_grow_char(acc, 0);
114 kw = grecs_txtacc_finish(acc, 0);
115
116 kwloc.end = grecs_current_locus_point;
117 kwloc.end.col--;
118
119 while ((lookahead = next_char(infile)) > 0 &&
120 (lookahead == ' ' || lookahead == '\t'));
121
122 if (lookahead <= 0) {
123 grecs_error(&kwloc, 0, _("unexpected end of file"));
124 err = 1;
125 break;
126 }
127
128 valloc.beg = grecs_current_locus_point;
129 do {
130 grecs_txtacc_grow_char(acc, lookahead);
131 prev_col = grecs_current_locus_point.col;
132 } while ((lookahead = next_char(infile)) > 0 &&
133 lookahead != '\n');
134 valloc.end = grecs_current_locus_point;
135 valloc.end.line--;
136 valloc.end.col = prev_col;
137
138 grecs_txtacc_grow_char(acc, 0);
139 val = grecs_txtacc_finish(acc, 0);
140
141 node = grecs_node_from_path_locus(kw, val, &kwloc, &valloc);
142 if (!node) {
143 grecs_error(&kwloc, 0, _("parse error"));
144 err = 1;
145 break;
146 }
147 node->locus.end = valloc.end;
148 node->idloc = kwloc;
149
150 if (!subtree)
151 subtree = node;
152 else
153 grecs_node_bind(subtree, node, 0);
154 grecs_txtacc_free_string(acc, kw);
155 grecs_txtacc_free_string(acc, val);
156 }
157
158 fclose(infile);
159 grecs_txtacc_free(acc);
160
161 if (err) {
162 grecs_tree_free(subtree);
163 root = NULL;
164 } else {
165 rootloc.end = grecs_current_locus_point;
166 root = grecs_node_create(grecs_node_root, &rootloc);
167 root->v.texttab = grecs_text_table();
168 grecs_node_bind(root, subtree, 1);
169 grecs_tree_reduce(root, NULL, 0);
170 }
171
172 return root;
173 }
174
175