tparse.y - repo - list/download/sync packs with remote repositories
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
---
tparse.y (8106B)
---
1 /*
2 * Copyright (c) 2006 Bob Beck <beck@openbsd.org>
3 * Copyright (c) 2002-2006 Henning Brauer <henning@openbsd.org>
4 * Copyright (c) 2001 Markus Friedl. All rights reserved.
5 * Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
6 * Copyright (c) 2001 Theo de Raadt. All rights reserved.
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
21 %{
22 #include <errno.h>
23 #include <ctype.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "repo.h"
30
31 static TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
32 static struct file {
33 TAILQ_ENTRY(file) entry;
34 FILE *stream;
35 char *name;
36 int lineno;
37 int errors;
38 } *file, *topfile;
39
40 static struct file *pushfile(const char *);
41 static int popfile(void);
42 static int yyparse(void);
43 static int yylex(void);
44 static int yyerror(const char *, ...);
45 static int kwcmp(const void *, const void *);
46 static int lookup(char *);
47 static int lgetc(int);
48 static int lungetc(int);
49 static int findeol(void);
50
51 static struct repos *repos = NULL;
52 static char *local = NULL;
53 static int *insecure = NULL;
54
55 typedef struct {
56 union {
57 int number;
58 char *string;
59 } v;
60 int lineno;
61 } YYSTYPE;
62 %}
63
64 %token REPO LOCAL INSECURE ERROR
65 %token <v.string> STRING
66 %token <v.number> NUMBER
67 %%
68
69 grammar : /* empty */
70 | grammar '\n'
71 | grammar main '\n'
72 | grammar error '\n' {
73 file->errors++;
74 }
75 ;
76
77 main : REPO STRING {
78 addrepo(repos, $2);
79 }
80 | LOCAL STRING {
81 strncpy(local, $2, PATH_MAX);
82 }
83 | INSECURE NUMBER {
84 *insecure = $2;
85 }
86 ;
87 %%
88
89 struct keywords {
90 const char *name;
91 int val;
92 };
93
94 static int
95 yyerror(const char *fmt, ...)
96 {
97 char buf[512];
98 va_list ap;
99
100 file->errors++;
101 va_start(ap, fmt);
102 if (vsnprintf(buf, sizeof(buf), fmt, ap) < 0)
103 perror("vsnprintf");
104 va_end(ap);
105 fprintf(stderr, "%s:%d: %s\n", file->name, yylval.lineno, buf);
106 return 0;
107 }
108
109 static int
110 kwcmp(const void *k, const void *e)
111 {
112 return strcmp(k, ((const struct keywords *)e)->name);
113 }
114
115 static int
116 lookup(char *s)
117 {
118 /* this has to be sorted always */
119 static const struct keywords keywords[] = {
120 { "local", LOCAL },
121 { "repo", REPO },
122 { "insecure", INSECURE }
123 };
124 const struct keywords *p;
125
126 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
127 sizeof(keywords[0]), kwcmp);
128
129 if (p)
130 return p->val;
131 else
132 return STRING;
133 }
134
135 #define MAXPUSHBACK 128
136
137 static unsigned char *parsebuf;
138 static int parseindex;
139 static unsigned char pushback_buffer[MAXPUSHBACK];
140 static int pushback_index = 0;
141
142 static int
143 lgetc(int quotec)
144 {
145 int c, next;
146
147 if (parsebuf) {
148 /* Read character from the parsebuffer instead of input. */
149 if (parseindex >= 0) {
150 c = parsebuf[parseindex++];
151 if (c != '\0')
152 return c;
153 parsebuf = NULL;
154 } else
155 parseindex++;
156 }
157
158 if (pushback_index)
159 return pushback_buffer[--pushback_index];
160
161 if (quotec) {
162 if ((c = getc(file->stream)) == EOF) {
163 yyerror("reached end of file while parsing "
164 "quoted string");
165 if (file == topfile || popfile() == EOF)
166 return EOF;
167 return quotec;
168 }
169 return c;
170 }
171
172 while ((c = getc(file->stream)) == '\\') {
173 next = getc(file->stream);
174 if (next != '\n') {
175 c = next;
176 break;
177 }
178 yylval.lineno = file->lineno;
179 file->lineno++;
180 }
181
182 while (c == EOF) {
183 if (file == topfile || popfile() == EOF)
184 return EOF;
185 c = getc(file->stream);
186 }
187 return c;
188 }
189
190 static int
191 lungetc(int c)
192 {
193 if (c == EOF)
194 return EOF;
195 if (parsebuf) {
196 parseindex--;
197 if (parseindex >= 0)
198 return c;
199 }
200 if (pushback_index < MAXPUSHBACK-1)
201 return pushback_buffer[pushback_index++] = c;
202 else
203 return EOF;
204 }
205
206 static int
207 findeol(void)
208 {
209 int c;
210
211 parsebuf = NULL;
212 pushback_index = 0;
213
214 /* skip to either EOF or the first real EOL */
215 while (1) {
216 c = lgetc(0);
217 if (c == '\n') {
218 file->lineno++;
219 break;
220 }
221 if (c == EOF)
222 break;
223 }
224 return ERROR;
225 }
226
227 static int
228 yylex(void)
229 {
230 unsigned char buf[8096];
231 unsigned char *p;
232 int quotec, next, c;
233 int token;
234
235 p = buf;
236 while ((c = lgetc(0)) == ' ' || c == '\t')
237 ; /* nothing */
238
239 yylval.lineno = file->lineno;
240 if (c == '#')
241 while ((c = lgetc(0)) != '\n' && c != EOF)
242 ; /* nothing */
243
244 switch (c) {
245 case '\'':
246 case '"':
247 quotec = c;
248 while (1) {
249 if ((c = lgetc(quotec)) == EOF)
250 return 0;
251 if (c == '\n') {
252 file->lineno++;
253 continue;
254 } else if (c == '\\') {
255 if ((next = lgetc(quotec)) == EOF)
256 return 0;
257 if (next == quotec || c == ' ' || c == '\t')
258 c = next;
259 else if (next == '\n')
260 continue;
261 else
262 lungetc(next);
263 } else if (c == quotec) {
264 *p = '\0';
265 break;
266 } else if (c == '\0') {
267 yyerror("syntax error");
268 return findeol();
269 }
270 if (p + 1 >= buf + sizeof(buf) - 1) {
271 yyerror("string too long");
272 return findeol();
273 }
274 *p++ = c;
275 }
276 yylval.v.string = strdup((char *)buf);
277 if (!yylval.v.string)
278 perror("strdup");
279 return STRING;
280 }
281
282 #define allowed_to_end_number(x) \
283 (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
284
285 if (c == '-' || isdigit(c)) {
286 do {
287 *p++ = c;
288 if ((unsigned)(p-buf) >= sizeof(buf)) {
289 yyerror("string too long");
290 return findeol();
291 }
292 } while ((c = lgetc(0)) != EOF && isdigit(c));
293 lungetc(c);
294 if (p == buf + 1 && buf[0] == '-')
295 goto nodigits;
296 if (c == EOF || allowed_to_end_number(c)) {
297
298 *p = '\0';
299 yylval.v.number = strtoll((char *)buf, NULL, 10);
300 if (errno == ERANGE) {
301 yyerror("\"%s\" invalid number: %s",
302 buf, strerror(errno));
303 return findeol();
304 }
305 return NUMBER;
306 } else {
307 nodigits:
308 while (p > buf + 1)
309 lungetc(*--p);
310 c = *--p;
311 if (c == '-')
312 return c;
313 }
314 }
315
316 #define allowed_in_string(x) \
317 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
318 x != '{' && x != '}' && x != '<' && x != '>' && \
319 x != '!' && x != '=' && x != '/' && x != '#' && \
320 x != ','))
321
322 if (isalnum(c) || c == ':' || c == '_' || c == '*') {
323 do {
324 *p++ = c;
325 if ((unsigned)(p-buf) >= sizeof(buf)) {
326 yyerror("string too long");
327 return findeol();
328 }
329 } while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
330 lungetc(c);
331 *p = '\0';
332 if ((token = lookup((char *)buf)) == STRING)
333 if (!(yylval.v.string = strdup((char *)buf)))
334 perror("strdup");
335 return token;
336 }
337 if (c == '\n') {
338 yylval.lineno = file->lineno;
339 file->lineno++;
340 }
341 if (c == EOF)
342 return 0;
343 return c;
344 }
345
346 static struct file *
347 pushfile(const char *name)
348 {
349 struct file *nfile;
350
351 if (!(nfile = calloc(1, sizeof(struct file))))
352 return NULL;
353 if (!(nfile->name = strdup(name))) {
354 free(nfile);
355 return NULL;
356 }
357 if (!(nfile->stream = fopen(nfile->name, "r"))) {
358 free(nfile->name);
359 free(nfile);
360 return NULL;
361 }
362 nfile->lineno = 1;
363 TAILQ_INSERT_TAIL(&files, nfile, entry);
364 return nfile;
365 }
366
367 static int
368 popfile(void)
369 {
370 struct file *prev;
371
372 if ((prev = TAILQ_PREV(file, files, entry)))
373 prev->errors += file->errors;
374 TAILQ_REMOVE(&files, file, entry);
375 fclose(file->stream);
376 free(file->name);
377 free(file);
378 file = prev;
379 return file ? 0 : EOF;
380 }
381
382 int
383 parseconf(struct repos *rlist, char *localrepo, int *untrust, const char *filename)
384 {
385 int errors = 0;
386
387 if (!(file = pushfile(filename))) {
388 fprintf(stderr, "failed to open %s\n", filename);
389 return -1;
390 }
391 topfile = file;
392
393 repos = rlist;
394 local = localrepo;
395 insecure = untrust;
396
397 yyparse();
398 errors = file->errors;
399 popfile();
400
401 if (errors != 0)
402 return -1;
403
404 return errors != 0 ? -1 : 0;
405 }