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 3455 - (show annotations) (download)
Thu Aug 9 13:10:50 2007 UTC (6 years, 6 months ago) by tg
File MIME type: text/plain
File size: 8384 byte(s)
finish the parser (hopefully), add a dumper

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 ch, *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 close(fd);
113
114 /* now we can operate on the NUL-terminated R/W string “buf” */
115 if (buf[len - 1] != '\n')
116 errx(1, "syntax error: file does not end with a newline!");
117
118 loop_newline:
119 /* completely new line buffer */
120 cp = NULL;
121
122 loop_getline:
123 /* get a line and add it to line buffer */
124 if (*buf == '\0')
125 goto loop_eof;
126 if (*buf == '\n') {
127 ++buf;
128 goto loop_getline;
129 }
130 if (*buf == '#') {
131 while (*buf != '\n')
132 ++buf;
133 goto loop_getline;
134 }
135 if (*buf == '\t') {
136 if (cp == NULL)
137 errx(1, "syntax error: expected lead line,"
138 " got trail line!");
139 t = ++buf;
140 goto loop_storeline;
141 }
142 if (cp != NULL)
143 goto process_line;
144 if ((*buf >= 'A' && *buf <= 'Z') ||
145 (*buf >= 'a' && *buf <= 'z') || *buf == '_')
146 t = buf;
147 else
148 errx(1, "syntax error: line must begin with"
149 " a letter or underscore!");
150 loop_storeline:
151 while (*t != '\n')
152 ++t;
153 t = str_nsave(buf, t - buf + /* NL */ 1);
154 loop_addline:
155 if (cp != NULL) {
156 if (*(tp = cp + strlen(cp) - 2) == '\\')
157 *tp = '\0';
158 }
159 tp = str_add(cp, t);
160 if (cp != NULL)
161 free(cp);
162 free(t);
163 cp = tp;
164 goto loop_getline;
165 process_line:
166 /* cp points to <line>[<nl><line>…][\]<nl> */
167 /* buf points to first byte of next line */
168 if (*(tp = cp + strlen(cp) - 2) == '\\')
169 errx(1, "syntax error: expected trail line,"
170 " got lead line!");
171 process_lastline:
172 /* cut off final newline */
173 *++tp = '\0';
174
175 /* parse the meat out of there */
176 if ((tp = strchr(cp, '\t')) == NULL)
177 errx(1, "syntax error: expected keyword +"
178 " tab + value!");
179 *tp++ = '\0';
180 /* cp points to keyword, tp points to value */
181 entry_multi = NULL;
182 entry_iter = 0;
183 for (kwp = kws; kwp->kwprefix != NULL; ++kwp) {
184 char *np;
185
186 /* exact match? */
187 if (!strcasecmp(cp, kwp->kwprefix))
188 /* yepp */ break;
189 /* prefix match allowed? */
190 if (kwp->kwtype == KWT_NORMAL)
191 /* nope */ continue;
192 /* prefix match? */
193 if (strncasecmp(cp, kwp->kwprefix, n = strlen(kwp->kwprefix)))
194 /* nope */ continue;
195 if (cp[n] != '_')
196 /* same */ continue;
197 /* okay, we got a prefix match, get args */
198 np = cp + n + 1;
199 if (kwp->kwtype == KWT_ITERATED ||
200 kwp->kwtype == KWT_MULTITER) {
201 char *zp = np;
202
203 if (zp[0] == '0' && (zp[1] == 'x' || zp[1] == 'X'))
204 zp += 2;
205 while (*zp >= '0' && *zp <= '9')
206 ++zp;
207 if (zp == np)
208 errx(1, "syntax error: iterator expected");
209 if (*zp != kwp->kwtype == KWT_ITERATED ? '\0' : '_')
210 errx(1, "syntax error: %s expected,"
211 " got 0x%02X", kwp->kwtype == KWT_ITERATED ?
212 "tab" : "underscore", *zp);
213 *zp++ = '\0';
214 entry_iter = (unsigned)strtoul(np, NULL, 0);
215 np = zp;
216 }
217 if (kwp->kwtype == KWT_MULTI ||
218 kwp->kwtype == KWT_MULTITER)
219 entry_multi = str_save(np);
220 /* values filled out */
221 break;
222 }
223 if (kwp->kwprefix == NULL)
224 errx(1, "unknown keyword '%s'", cp);
225 entry = xmalloc(sizeof (struct parser_res));
226 bzero(entry, sizeof (struct parser_res));
227 entry->keyword = kwp->kwnum;
228 entry->kw_multi = entry_multi;
229 entry->kw_iter = entry_iter;
230 entry->value = str_save(tp);
231 CIRCLEQ_INSERT_TAIL(res, entry, e);
232 free(cp);
233 goto loop_newline;
234 loop_eof:
235 if (cp != NULL) {
236 if (*(tp = cp + strlen(cp) - 2) == '\\')
237 errx(1, "syntax error: expected trail line,"
238 " read end of file!");
239 goto process_lastline;
240 }
241 free(buf_base);
242 return (res);
243 }
244
245 const struct parser_keywords *
246 parser_getkwbynum(parser_kwords num, const struct parser_keywords *kws)
247 {
248 const struct parser_keywords *kwp;
249
250 for (kwp = kws; kwp->kwprefix != NULL; ++kwp)
251 if (kwp->kwnum == num)
252 break;
253
254 return (kwp->kwprefix == NULL ? NULL : kwp);
255 }
256
257 void
258 nfo_parser_dump(struct parser_res *entry, const struct parser_keywords *kws)
259 {
260 const struct parser_keywords *kwp;
261
262 printf("keyword %s (type %s)",
263 (kwp = parser_getkwbynum(entry->keyword, kws)) == NULL ?
264 "<unknown>" : kwp->kwprefix,
265 kwp == NULL ? "invalid" :
266 kwp->kwtype == KWT_NORMAL ? "normal" :
267 kwp->kwtype == KWT_MULTI ? "multi" :
268 kwp->kwtype == KWT_ITERATED ? "iterated" :
269 kwp->kwtype == KWT_MULTITER ? "multiter" : "unknown");
270 if (kwp) {
271 if (kwp->kwtype == KWT_ITERATED ||
272 kwp->kwtype == KWT_MULTITER)
273 printf(", iterator %u", entry->kw_iter);
274 if (kwp->kwtype == KWT_MULTI ||
275 kwp->kwtype == KWT_MULTITER)
276 printf(", multival '%s'", entry->kw_multi);
277 }
278 putchar('\n');
279 }

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