English Language flag
// Log In
// CVSweb
Project: FreeWRT
// Summary // Activity // Search // Tracker // Lists // News // SCM // Wiki

SCM Repository

ViewVC logotype

Contents of /branches/common-nfo/tools/nfotiser/parser.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3459 - (show annotations) (download)
Thu Aug 9 13:50:32 2007 UTC (6 years, 6 months ago) by tg
File MIME type: text/plain
File size: 9247 byte(s)
add some debugging – enough to find the endless loop

1 /* $FreeWRT: src/share/misc/licence.template,v 1.20 2006/12/11 21:04:56 tg Rel $ */
2
3 /*-
4 * Copyright (c) 2007
5 * Thorsten Glaser <tg@mirbsd.de>
6 *
7 * Provided that these terms and disclaimer and all copyright notices
8 * are retained or reproduced in an accompanying document, permission
9 * is granted to deal in this work without restriction, including un-
10 * limited rights to use, publicly perform, distribute, sell, modify,
11 * merge, give away, or sublicence.
12 *
13 * Advertising materials mentioning features or use of this work must
14 * display the following acknowledgement:
15 * This product includes material provided by Thorsten Glaser.
16 * This acknowledgement does not need to be reprinted if this work is
17 * linked into a bigger work whose licence does not allow such clause
18 * and the author of this work is given due credit in the bigger work
19 * or its accompanying documents, where such information is generally
20 * kept, provided that said credits are retained.
21 *
22 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
23 * the utmost extent permitted by applicable law, neither express nor
24 * implied; without malicious intent or gross negligence. In no event
25 * may a licensor, author or contributor be held liable for indirect,
26 * direct, other damage, loss, or other issues arising in any way out
27 * of dealing in the work, even if advised of the possibility of such
28 * damage or existence of a defect, except proven that it results out
29 * of said person's immediate fault when using the work as intended.
30 */
31
32 #include <sys/param.h>
33 #include <sys/mman.h>
34 #include <sys/stat.h>
35
36 #include <err.h>
37 #include <errno.h>
38 #include <stdint.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 //#include <unistd.h>
43
44 #include "nfotiser.h"
45
46 /*
47 * Parsing works as follows:
48 *
49 * - strip completely empty line
50 * - strip line beginning with hash mark
51 * - if line ends with backslash, get next line that is not
52 * + empty
53 * + beginning with a hash mark
54 * and look if it begins with a tab (if not: syntax error)
55 * if so, strip backslash + newline + tab and repeat
56 * - if line begins with a tab, strip it and append line to
57 * the last line, including the newline separator
58 * - match line with '([A-Za-z_][A-Za-z0-9_]*)\t(.*)$' and
59 * call \1 the key and \2 the value (else: syntax error)
60 * - uppercase the key
61 * - enter the key/value pair in the system
62 *
63 * The following is also part of parsing, but left to the caller:
64 * - replace ${foo} with the value of key "foo"
65 * - undouble all backslashes
66 *
67 * We enter the key into the system up to three-fold:
68 * - KWT_NORMAL => ([A-Za-z_][A-Za-z0-9_]*)
69 * + \1 = keyword (toupper'd)
70 * - KWT_MULTI => ([A-Za-z_][A-Za-z0-9_]*)_([A-Za-z0-9_]*)
71 * + \1 = keyword (toupper'd)
72 * + \2 = kw_multi (case preserving)
73 * - KWT_ITERATED => ([A-Za-z_][A-Za-z0-9_]*)_([0-9]*)
74 * + \1 = keyword (toupper'd)
75 * + \2 = kw_iter (unsigned integer value)
76 * - KWT_MULTITER => ([A-Za-z_][A-Za-z0-9_]*)_([0-9]*)_([A-Za-z0-9_]*)
77 * + \1 = keyword (toupper'd)
78 * + \2 = kw_iter (unsigned integer value)
79 * + \3 = kw_multi (case preserving)
80 *
81 * Cf. https://www.freewrt.org/trac/wiki/Documentation/Specs/Freewrt_info_files
82 * for more examples and a more human-readable version of this specification.
83 */
84
85 struct parser_result *
86 nfo_parse(int fd, const struct parser_keywords *kws)
87 {
88 struct parser_result *res;
89 struct parser_res *entry;
90 const struct parser_keywords *kwp;
91 char *cp, *t, *tp, *buf, *buf_base;
92 size_t len, n, lineno;
93 struct stat sb;
94 char *entry_multi;
95 unsigned entry_iter;
96
97 res = xmalloc(sizeof (struct parser_result));
98 CIRCLEQ_INIT(res);
99
100 if (fstat(fd, &sb))
101 err(255, "cannot stat");
102
103 /* slurp whole file into mapped memory */
104 len = sb.st_size;
105 D(2, "trying to mmap %zu bytes...", len);
106 if ((cp = mmap(NULL, len, PROT_READ, MAP_FILE, fd, 0)) == MAP_FAILED)
107 err(255, "cannot mmap %zu bytes", len);
108 D(2, "ok\n");
109 /* make a nice NUL-terminated copy (malloc'd) */
110 D(2, "copying %zu bytes...", len);
111 buf = buf_base = str_nsave(cp, len);
112 D(2, " munmap...");
113 if (munmap(cp, len))
114 err(255, "cannot munmap");
115 D(2, "ok\n");
116 /* don't need the file any more */
117
118 /* now we can operate on the NUL-terminated R/W string “buf” */
119 if (buf[len - 1] != '\n')
120 errx(1, "syntax error: file does not end with a newline!");
121
122 D(2, "entire string: «%s» (%zu)\n", buf, strlen(buf));
123 lineno = 1;
124
125 loop_newline:
126 /* completely new line buffer */
127 cp = NULL;
128
129 loop_getline:
130 /* get a line and add it to line buffer */
131 if (*buf == '\0') {
132 D(2, "D: [%4zu] read EOF\n", lineno);
133 goto loop_eof;
134 }
135 if (*buf == '\n') {
136 D(2, "D: [%4zu] read newline\n", lineno);
137 ++buf;
138 ++lineno;
139 goto loop_getline;
140 }
141 if (*buf == '#') {
142 D(2, "D: [%4zu] read comment ", lineno);
143 t = buf;
144 while (*t != '\n')
145 ++t;
146 *t++ = '\0';
147 D(2, "'%s'\n", buf);
148 buf = t;
149 ++lineno;
150 goto loop_getline;
151 }
152 if (*buf == '\t') {
153 D(2, "D: [%4zu] read trail line\n", lineno);
154 if (cp == NULL)
155 errx(1, "syntax error: expected lead line,"
156 " got trail line!");
157 t = ++buf;
158 goto loop_storeline;
159 } else {
160 D(2, "D: [%4zu] read head line (%02X)\n", lineno, *buf);
161 }
162 if (cp != NULL)
163 goto process_line;
164 if ((*buf >= 'A' && *buf <= 'Z') ||
165 (*buf >= 'a' && *buf <= 'z') || *buf == '_')
166 t = buf;
167 else
168 errx(1, "syntax error: line must begin with"
169 " a letter or underscore!");
170 loop_storeline:
171 while (*t != '\n')
172 ++t;
173 t = str_nsave(buf, t - buf + /* NL */ 1);
174 if (cp != NULL) {
175 if (*(tp = cp + strlen(cp) - 2) == '\\')
176 *tp = '\0';
177 }
178 tp = str_add(cp, t);
179 if (cp != NULL)
180 free(cp);
181 free(t);
182 cp = tp;
183 goto loop_getline;
184 process_line:
185 /* cp points to <line>[<nl><line>…][\]<nl> */
186 /* buf points to first byte of next line */
187 if (*(tp = cp + strlen(cp) - 2) == '\\')
188 errx(1, "syntax error: expected trail line,"
189 " got lead line!");
190 process_lastline:
191 /* cut off final newline */
192 *++tp = '\0';
193
194 /* parse the meat out of there */
195 if ((tp = strchr(cp, '\t')) == NULL)
196 errx(1, "syntax error: expected keyword +"
197 " tab + value!");
198 *tp++ = '\0';
199 /* cp points to keyword, tp points to value */
200 entry_multi = NULL;
201 entry_iter = 0;
202 for (kwp = kws; kwp->kwprefix != NULL; ++kwp) {
203 char *np;
204
205 /* exact match? */
206 if (!strcasecmp(cp, kwp->kwprefix))
207 /* yepp */ break;
208 /* prefix match allowed? */
209 if (kwp->kwtype == KWT_NORMAL)
210 /* nope */ continue;
211 /* prefix match? */
212 if (strncasecmp(cp, kwp->kwprefix, n = strlen(kwp->kwprefix)))
213 /* nope */ continue;
214 if (cp[n] != '_')
215 /* same */ continue;
216 /* okay, we got a prefix match, get args */
217 np = cp + n + 1;
218 if (kwp->kwtype == KWT_ITERATED ||
219 kwp->kwtype == KWT_MULTITER) {
220 char *zp = np;
221
222 if (zp[0] == '0' && (zp[1] == 'x' || zp[1] == 'X'))
223 zp += 2;
224 while (*zp >= '0' && *zp <= '9')
225 ++zp;
226 if (zp == np)
227 errx(1, "syntax error: iterator expected");
228 if (*zp != (char)(kwp->kwtype == KWT_ITERATED ?
229 '\0' : '_'))
230 errx(1, "syntax error: %s expected,"
231 " got 0x%02X", kwp->kwtype == KWT_ITERATED ?
232 "tab" : "underscore", *zp);
233 *zp++ = '\0';
234 entry_iter = (unsigned)strtoul(np, NULL, 0);
235 np = zp;
236 }
237 if (kwp->kwtype == KWT_MULTI ||
238 kwp->kwtype == KWT_MULTITER)
239 entry_multi = str_save(np);
240 /* values filled out */
241 break;
242 }
243 if (kwp->kwprefix == NULL)
244 errx(1, "unknown keyword '%s'", cp);
245 entry = xmalloc(sizeof (struct parser_res));
246 bzero(entry, sizeof (struct parser_res));
247 entry->keyword = kwp->kwnum;
248 entry->kw_multi = entry_multi;
249 entry->kw_iter = entry_iter;
250 entry->value = str_save(tp);
251 CIRCLEQ_INSERT_TAIL(res, entry, e);
252 free(cp);
253 goto loop_newline;
254 loop_eof:
255 if (cp != NULL) {
256 if (*(tp = cp + strlen(cp) - 2) == '\\')
257 errx(1, "syntax error: expected trail line,"
258 " read end of file!");
259 goto process_lastline;
260 }
261 free(buf_base);
262 return (res);
263 }
264
265 const struct parser_keywords *
266 parser_getkwbynum(parser_kwords num, const struct parser_keywords *kws)
267 {
268 const struct parser_keywords *kwp;
269
270 for (kwp = kws; kwp->kwprefix != NULL; ++kwp)
271 if (kwp->kwnum == num)
272 break;
273
274 return (kwp->kwprefix == NULL ? NULL : kwp);
275 }
276
277 void
278 parser_dump(struct parser_res *entry, const struct parser_keywords *kws)
279 {
280 const struct parser_keywords *kwp;
281
282 kwp = parser_getkwbynum(entry->keyword, kws);
283 printf("keyword %s (type %s)",
284 kwp == NULL ? "<unknown>" : kwp->kwprefix,
285 kwp == NULL ? "invalid" :
286 kwp->kwtype == KWT_NORMAL ? "normal" :
287 kwp->kwtype == KWT_MULTI ? "multi" :
288 kwp->kwtype == KWT_ITERATED ? "iterated" :
289 kwp->kwtype == KWT_MULTITER ? "multiter" : "unknown");
290 if (kwp) {
291 if (kwp->kwtype == KWT_ITERATED ||
292 kwp->kwtype == KWT_MULTITER)
293 printf(", iterator %u", entry->kw_iter);
294 if (kwp->kwtype == KWT_MULTI ||
295 kwp->kwtype == KWT_MULTITER)
296 printf(", multival '%s'", entry->kw_multi);
297 }
298 putchar('\n');
299 }
300
301 void
302 parser_free(struct parser_result *head)
303 {
304 struct parser_res *entry;
305
306 if (head == NULL)
307 return;
308
309 while (!CIRCLEQ_EMPTY(head)) {
310 entry = CIRCLEQ_FIRST(head);
311 CIRCLEQ_REMOVE(head, entry, e);
312 if (entry->kw_multi != NULL)
313 free(entry->kw_multi);
314 if (entry->value != NULL)
315 free(entry->value);
316 free(entry);
317 }
318
319 free(head);
320 }

root@freewrt.org:443
ViewVC Help
Powered by ViewVC 1.1.20