7c7baefda791cfdef4757a242a25641c7b87a4ec
[openwrt/openwrt.git] / scripts / config / zconf.l
1 %option nostdinit noyywrap never-interactive full ecs
2 %option 8bit nodefault perf-report perf-report
3 %option noinput
4 %x COMMAND HELP STRING PARAM
5 %{
6 /*
7 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
8 * Released under the terms of the GNU GPL v2.0.
9 */
10
11 #include <limits.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <unistd.h>
16 #include <glob.h>
17 #include <libgen.h>
18
19 #include "lkc.h"
20
21 #define START_STRSIZE 16
22
23 static struct {
24 struct file *file;
25 int lineno;
26 } current_pos;
27
28 static char *text;
29 static int text_size, text_asize;
30
31 struct buffer {
32 struct buffer *parent;
33 YY_BUFFER_STATE state;
34 };
35
36 struct buffer *current_buf;
37
38 static int last_ts, first_ts;
39
40 static void zconf_endhelp(void);
41 static void zconf_endfile(void);
42
43 static void new_string(void)
44 {
45 text = xmalloc(START_STRSIZE);
46 text_asize = START_STRSIZE;
47 text_size = 0;
48 *text = 0;
49 }
50
51 static void append_string(const char *str, int size)
52 {
53 int new_size = text_size + size + 1;
54 if (new_size > text_asize) {
55 new_size += START_STRSIZE - 1;
56 new_size &= -START_STRSIZE;
57 text = realloc(text, new_size);
58 text_asize = new_size;
59 }
60 memcpy(text + text_size, str, size);
61 text_size += size;
62 text[text_size] = 0;
63 }
64
65 static void alloc_string(const char *str, int size)
66 {
67 text = xmalloc(size + 1);
68 memcpy(text, str, size);
69 text[size] = 0;
70 }
71 %}
72
73 n [A-Za-z0-9_]
74
75 %%
76 int str = 0;
77 int ts, i;
78
79 [ \t]*#.*\n |
80 [ \t]*\n {
81 current_file->lineno++;
82 return T_EOL;
83 }
84 [ \t]*#.*
85
86
87 [ \t]+ {
88 BEGIN(COMMAND);
89 }
90
91 . {
92 unput(yytext[0]);
93 BEGIN(COMMAND);
94 }
95
96
97 <COMMAND>{
98 {n}+ {
99 const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
100 BEGIN(PARAM);
101 current_pos.file = current_file;
102 current_pos.lineno = current_file->lineno;
103 if (id && id->flags & TF_COMMAND) {
104 zconflval.id = id;
105 return id->token;
106 }
107 alloc_string(yytext, yyleng);
108 zconflval.string = text;
109 return T_WORD;
110 }
111 .
112 \n {
113 BEGIN(INITIAL);
114 current_file->lineno++;
115 return T_EOL;
116 }
117 }
118
119 <PARAM>{
120 "&&" return T_AND;
121 "||" return T_OR;
122 "(" return T_OPEN_PAREN;
123 ")" return T_CLOSE_PAREN;
124 "!" return T_NOT;
125 "=" return T_EQUAL;
126 "!=" return T_UNEQUAL;
127 \"|\' {
128 str = yytext[0];
129 new_string();
130 BEGIN(STRING);
131 }
132 \n BEGIN(INITIAL); current_file->lineno++; return T_EOL;
133 --- /* ignore */
134 ({n}|[-/.])+ {
135 const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
136 if (id && id->flags & TF_PARAM) {
137 zconflval.id = id;
138 return id->token;
139 }
140 alloc_string(yytext, yyleng);
141 zconflval.string = text;
142 return T_WORD;
143 }
144 #.* /* comment */
145 \\\n current_file->lineno++;
146 .
147 <<EOF>> {
148 BEGIN(INITIAL);
149 }
150 }
151
152 <STRING>{
153 [^'"\\\n]+/\n {
154 append_string(yytext, yyleng);
155 zconflval.string = text;
156 return T_WORD_QUOTE;
157 }
158 [^'"\\\n]+ {
159 append_string(yytext, yyleng);
160 }
161 \\.?/\n {
162 append_string(yytext + 1, yyleng - 1);
163 zconflval.string = text;
164 return T_WORD_QUOTE;
165 }
166 \\.? {
167 append_string(yytext + 1, yyleng - 1);
168 }
169 \'|\" {
170 if (str == yytext[0]) {
171 BEGIN(PARAM);
172 zconflval.string = text;
173 return T_WORD_QUOTE;
174 } else
175 append_string(yytext, 1);
176 }
177 \n {
178 printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
179 current_file->lineno++;
180 BEGIN(INITIAL);
181 return T_EOL;
182 }
183 <<EOF>> {
184 BEGIN(INITIAL);
185 }
186 }
187
188 <HELP>{
189 [ \t]+ {
190 ts = 0;
191 for (i = 0; i < yyleng; i++) {
192 if (yytext[i] == '\t')
193 ts = (ts & ~7) + 8;
194 else
195 ts++;
196 }
197 last_ts = ts;
198 if (first_ts) {
199 if (ts < first_ts) {
200 zconf_endhelp();
201 return T_HELPTEXT;
202 }
203 ts -= first_ts;
204 while (ts > 8) {
205 append_string(" ", 8);
206 ts -= 8;
207 }
208 append_string(" ", ts);
209 }
210 }
211 [ \t]*\n/[^ \t\n] {
212 current_file->lineno++;
213 zconf_endhelp();
214 return T_HELPTEXT;
215 }
216 [ \t]*\n {
217 current_file->lineno++;
218 append_string("\n", 1);
219 }
220 [^ \t\n].* {
221 while (yyleng) {
222 if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t'))
223 break;
224 yyleng--;
225 }
226 append_string(yytext, yyleng);
227 if (!first_ts)
228 first_ts = last_ts;
229 }
230 <<EOF>> {
231 zconf_endhelp();
232 return T_HELPTEXT;
233 }
234 }
235
236 <<EOF>> {
237 if (current_file) {
238 zconf_endfile();
239 return T_EOL;
240 }
241 fclose(yyin);
242 yyterminate();
243 }
244
245 %%
246 void zconf_starthelp(void)
247 {
248 new_string();
249 last_ts = first_ts = 0;
250 BEGIN(HELP);
251 }
252
253 static void zconf_endhelp(void)
254 {
255 zconflval.string = text;
256 BEGIN(INITIAL);
257 }
258
259
260 /*
261 * Try to open specified file with following names:
262 * ./name
263 * $(srctree)/name
264 * The latter is used when srctree is separate from objtree
265 * when compiling the kernel.
266 * Return NULL if file is not found.
267 */
268 FILE *zconf_fopen(const char *name)
269 {
270 char *env, fullname[PATH_MAX+1];
271 FILE *f;
272
273 f = fopen(name, "r");
274 if (!f && name != NULL && name[0] != '/') {
275 env = getenv(SRCTREE);
276 if (env) {
277 sprintf(fullname, "%s/%s", env, name);
278 f = fopen(fullname, "r");
279 }
280 }
281 return f;
282 }
283
284 void zconf_initscan(const char *name)
285 {
286 yyin = zconf_fopen(name);
287 if (!yyin) {
288 printf("can't find file %s\n", name);
289 exit(1);
290 }
291
292 current_buf = xmalloc(sizeof(*current_buf));
293 memset(current_buf, 0, sizeof(*current_buf));
294
295 current_file = file_lookup(name);
296 current_file->lineno = 1;
297 }
298
299 static void __zconf_nextfile(const char *name)
300 {
301 struct file *iter;
302 struct file *file = file_lookup(name);
303 struct buffer *buf = xmalloc(sizeof(*buf));
304 memset(buf, 0, sizeof(*buf));
305
306 current_buf->state = YY_CURRENT_BUFFER;
307 yyin = zconf_fopen(file->name);
308 if (!yyin) {
309 printf("%s:%d: can't open file \"%s\"\n",
310 zconf_curname(), zconf_lineno(), file->name);
311 exit(1);
312 }
313 yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
314 buf->parent = current_buf;
315 current_buf = buf;
316
317 for (iter = current_file->parent; iter; iter = iter->parent ) {
318 if (!strcmp(current_file->name,iter->name) ) {
319 printf("%s:%d: recursive inclusion detected. "
320 "Inclusion path:\n current file : '%s'\n",
321 zconf_curname(), zconf_lineno(),
322 zconf_curname());
323 iter = current_file->parent;
324 while (iter && \
325 strcmp(iter->name,current_file->name)) {
326 printf(" included from: '%s:%d'\n",
327 iter->name, iter->lineno-1);
328 iter = iter->parent;
329 }
330 if (iter)
331 printf(" included from: '%s:%d'\n",
332 iter->name, iter->lineno+1);
333 exit(1);
334 }
335 }
336 file->lineno = 1;
337 file->parent = current_file;
338 current_file = file;
339 }
340
341 void zconf_nextfile(const char *name)
342 {
343 glob_t gl;
344 int err;
345 int i;
346 char path[PATH_MAX], *p;
347
348 err = glob(name, GLOB_ERR | GLOB_MARK, NULL, &gl);
349
350 /* ignore wildcard patterns that return no result */
351 if (err == GLOB_NOMATCH && strchr(name, '*')) {
352 err = 0;
353 gl.gl_pathc = 0;
354 }
355
356 if (err == GLOB_NOMATCH) {
357 p = strdup(current_file->name);
358 if (p) {
359 snprintf(path, sizeof(path), "%s/%s", dirname(p), name);
360 err = glob(path, GLOB_ERR | GLOB_MARK, NULL, &gl);
361 free(p);
362 }
363 }
364
365 if (err) {
366 const char *reason = "unknown error";
367
368 switch (err) {
369 case GLOB_NOSPACE:
370 reason = "out of memory";
371 break;
372 case GLOB_ABORTED:
373 reason = "read error";
374 break;
375 case GLOB_NOMATCH:
376 reason = "No files found";
377 break;
378 default:
379 break;
380 }
381
382 printf("%s:%d: glob failed: %s \"%s\"\n", zconf_curname(), zconf_lineno(),
383 reason, name);
384
385 exit(1);
386 }
387
388 for (i = 0; i < gl.gl_pathc; i++)
389 __zconf_nextfile(gl.gl_pathv[i]);
390 }
391
392 static void zconf_endfile(void)
393 {
394 struct buffer *parent;
395
396 current_file = current_file->parent;
397
398 parent = current_buf->parent;
399 if (parent) {
400 fclose(yyin);
401 yy_delete_buffer(YY_CURRENT_BUFFER);
402 yy_switch_to_buffer(parent->state);
403 }
404 free(current_buf);
405 current_buf = parent;
406 }
407
408 int zconf_lineno(void)
409 {
410 return current_pos.lineno;
411 }
412
413 const char *zconf_curname(void)
414 {
415 return current_pos.file ? current_pos.file->name : "<none>";
416 }