scripts/config: sync with linux upstream
[oweals/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 }