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 3457 - (show annotations) (download)
Thu Aug 9 13:40:07 2007 UTC (6 years, 6 months ago) by tg
File MIME type: text/plain
File size: 8710 byte(s)
hook parser and dumper into main loop, seems to loop and hog all mem tho, a case for the debugger...
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;
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 if ((cp = mmap(NULL, (len = sb.st_size), PROT_READ, MAP_FILE, fd, 0))
105 == MAP_FAILED)
106 err(255, "cannot mmap %zu bytes", len);
107 /* make a nice NUL-terminated copy (malloc'd) */
108 buf = buf_base = str_nsave(cp, len);
109 if (munmap(cp, len))
110 err(255, "cannot munmap");
111 /* don't need the file any more */
112
113 /* now we can operate on the NUL-terminated R/W string “buf” */
114 if (buf[len - 1] != '\n')
115 errx(1, "syntax error: file does not end with a newline!");
116
117 loop_newline:
118 /* completely new line buffer */
119 cp = NULL;
120
121 loop_getline:
122 /* get a line and add it to line buffer */
123 if (*buf == '\0')
124 goto loop_eof;
125 if (*buf == '\n') {
126 ++buf;
127 goto loop_getline;
128 }
129 if (*buf == '#') {
130 while (*buf != '\n')
131 ++buf;
132 goto loop_getline;
133 }
134 if (*buf == '\t') {
135 if (cp == NULL)
136 errx(1, "syntax error: expected lead line,"
137 " got trail line!");
138 t = ++buf;
139 goto loop_storeline;
140 }
141 if (cp != NULL)
142 goto process_line;
143 if ((*buf >= 'A' && *buf <= 'Z') ||
144 (*buf >= 'a' && *buf <= 'z') || *buf == '_')
145 t = buf;
146 else
147 errx(1, "syntax error: line must begin with"
148 " a letter or underscore!");
149 loop_storeline:
150 while (*t != '\n')
151 ++t;
152 t = str_nsave(buf, t - buf + /* NL */ 1);
153 if (cp != NULL) {
154 if (*(tp = cp + strlen(cp) - 2) == '\\')
155 *tp = '\0';
156 }
157 tp = str_add(cp, t);
158 if (cp != NULL)
159 free(cp);
160 free(t);
161 cp = tp;
162 goto loop_getline;
163 process_line:
164 /* cp points to <line>[<nl><line>…][\]<nl> */
165 /* buf points to first byte of next line */
166 if (*(tp = cp + strlen(cp) - 2) == '\\')
167 errx(1, "syntax error: expected trail line,"
168 " got lead line!");
169 process_lastline:
170 /* cut off final newline */
171 *++tp = '\0';
172
173 /* parse the meat out of there */
174 if ((tp = strchr(cp, '\t')) == NULL)
175 errx(1, "syntax error: expected keyword +"
176 " tab + value!");
177 *tp++ = '\0';
178 /* cp points to keyword, tp points to value */
179 entry_multi = NULL;
180 entry_iter = 0;
181 for (kwp = kws; kwp->kwprefix != NULL; ++kwp) {
182 char *np;
183
184 /* exact match? */
185 if (!strcasecmp(cp, kwp->kwprefix))
186 /* yepp */ break;
187 /* prefix match allowed? */
188 if (kwp->kwtype == KWT_NORMAL)
189 /* nope */ continue;
190 /* prefix match? */
191 if (strncasecmp(cp, kwp->kwprefix, n = strlen(kwp->kwprefix)))
192 /* nope */ continue;
193 if (cp[n] != '_')
194 /* same */ continue;
195 /* okay, we got a prefix match, get args */
196 np = cp + n + 1;
197 if (kwp->kwtype == KWT_ITERATED ||
198 kwp->kwtype == KWT_MULTITER) {
199 char *zp = np;
200
201 if (zp[0] == '0' && (zp[1] == 'x' || zp[1] == 'X'))
202 zp += 2;
203 while (*zp >= '0' && *zp <= '9')
204 ++zp;
205 if (zp == np)
206 errx(1, "syntax error: iterator expected");
207 if (*zp != (char)(kwp->kwtype == KWT_ITERATED ?
208 '\0' : '_'))
209 errx(1, "syntax error: %s expected,"
210 " got 0x%02X", kwp->kwtype == KWT_ITERATED ?
211 "tab" : "underscore", *zp);
212 *zp++ = '\0';
213 entry_iter = (unsigned)strtoul(np, NULL, 0);
214 np = zp;
215 }
216 if (kwp->kwtype == KWT_MULTI ||
217 kwp->kwtype == KWT_MULTITER)
218 entry_multi = str_save(np);
219 /* values filled out */
220 break;
221 }
222 if (kwp->kwprefix == NULL)
223 errx(1, "unknown keyword '%s'", cp);
224 entry = xmalloc(sizeof (struct parser_res));
225 bzero(entry, sizeof (struct parser_res));
226 entry->keyword = kwp->kwnum;
227 entry->kw_multi = entry_multi;
228 entry->kw_iter = entry_iter;
229 entry->value = str_save(tp);
230 CIRCLEQ_INSERT_TAIL(res, entry, e);
231 free(cp);
232 goto loop_newline;
233 loop_eof:
234 if (cp != NULL) {
235 if (*(tp = cp + strlen(cp) - 2) == '\\')
236 errx(1, "syntax error: expected trail line,"
237 " read end of file!");
238 goto process_lastline;
239 }
240 free(buf_base);
241 return (res);
242 }
243
244 const struct parser_keywords *
245 parser_getkwbynum(parser_kwords num, const struct parser_keywords *kws)
246 {
247 const struct parser_keywords *kwp;
248
249 for (kwp = kws; kwp->kwprefix != NULL; ++kwp)
250 if (kwp->kwnum == num)
251 break;
252
253 return (kwp->kwprefix == NULL ? NULL : kwp);
254 }
255
256 void
257 parser_dump(struct parser_res *entry, const struct parser_keywords *kws)
258 {
259 const struct parser_keywords *kwp;
260
261 kwp = parser_getkwbynum(entry->keyword, kws);
262 printf("keyword %s (type %s)",
263 kwp == NULL ? "<unknown>" : kwp->kwprefix,
264 kwp == NULL ? "invalid" :
265 kwp->kwtype == KWT_NORMAL ? "normal" :
266 kwp->kwtype == KWT_MULTI ? "multi" :
267 kwp->kwtype == KWT_ITERATED ? "iterated" :
268 kwp->kwtype == KWT_MULTITER ? "multiter" : "unknown");
269 if (kwp) {
270 if (kwp->kwtype == KWT_ITERATED ||
271 kwp->kwtype == KWT_MULTITER)
272 printf(", iterator %u", entry->kw_iter);
273 if (kwp->kwtype == KWT_MULTI ||
274 kwp->kwtype == KWT_MULTITER)
275 printf(", multival '%s'", entry->kw_multi);
276 }
277 putchar('\n');
278 }
279
280 void
281 parser_free(struct parser_result *head)
282 {
283 struct parser_res *entry;
284
285 if (head == NULL)
286 return;
287
288 while (!CIRCLEQ_EMPTY(head)) {
289 entry = CIRCLEQ_FIRST(head);
290 CIRCLEQ_REMOVE(head, entry, e);
291 if (entry->kw_multi != NULL)
292 free(entry->kw_multi);
293 if (entry->value != NULL)
294 free(entry->value);
295 free(entry);
296 }
297
298 free(head);
299 }

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