d0f5b132a9b39802680a3f07343d0c36bf83e4ee
[carl9170fw.git] / config / zconf.l
1 %option nostdinit noyywrap never-interactive full ecs
2 %option 8bit nodefault yylineno
3 %x COMMAND HELP STRING PARAM ASSIGN_VAL
4 %{
5 /*
6  * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
7  * Released under the terms of the GNU GPL v2.0.
8  */
9
10 #include <assert.h>
11 #include <limits.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <unistd.h>
16
17 #include "lkc.h"
18
19 #define START_STRSIZE   16
20
21 static struct {
22         struct file *file;
23         int lineno;
24 } current_pos;
25
26 static char *text;
27 static int text_size, text_asize;
28
29 struct buffer {
30         struct buffer *parent;
31         YY_BUFFER_STATE state;
32 };
33
34 struct buffer *current_buf;
35
36 static int last_ts, first_ts;
37
38 static char *expand_token(const char *in, size_t n);
39 static void append_expanded_string(const char *in);
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 = xrealloc(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 static void warn_ignored_character(char chr)
73 {
74         fprintf(stderr,
75                 "%s:%d:warning: ignoring unsupported character '%c'\n",
76                 zconf_curname(), zconf_lineno(), chr);
77 }
78 %}
79
80 n       [A-Za-z0-9_-]
81
82 %%
83         int str = 0;
84         int ts, i;
85
86 [ \t]*#.*\n     |
87 [ \t]*\n        {
88         return T_EOL;
89 }
90 [ \t]*#.*
91
92
93 [ \t]+  {
94         BEGIN(COMMAND);
95 }
96
97 .       {
98         unput(yytext[0]);
99         BEGIN(COMMAND);
100 }
101
102
103 <COMMAND>{
104         {n}+    {
105                 const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
106                 current_pos.file = current_file;
107                 current_pos.lineno = yylineno;
108                 if (id && id->flags & TF_COMMAND) {
109                         BEGIN(PARAM);
110                         yylval.id = id;
111                         return id->token;
112                 }
113                 alloc_string(yytext, yyleng);
114                 yylval.string = text;
115                 return T_VARIABLE;
116         }
117         "="     { BEGIN(ASSIGN_VAL); yylval.flavor = VAR_RECURSIVE; return T_ASSIGN; }
118         ":="    { BEGIN(ASSIGN_VAL); yylval.flavor = VAR_SIMPLE; return T_ASSIGN; }
119         [[:blank:]]+
120         .       warn_ignored_character(*yytext);
121         \n      {
122                 BEGIN(INITIAL);
123                 return T_EOL;
124         }
125 }
126
127 <ASSIGN_VAL>{
128         [^[:blank:]\n]+.*       {
129                 alloc_string(yytext, yyleng);
130                 yylval.string = text;
131                 return T_ASSIGN_VAL;
132         }
133         \n      { BEGIN(INITIAL); return T_EOL; }
134         .
135 }
136
137 <PARAM>{
138         "&&"    return T_AND;
139         "||"    return T_OR;
140         "("     return T_OPEN_PAREN;
141         ")"     return T_CLOSE_PAREN;
142         "!"     return T_NOT;
143         "="     return T_EQUAL;
144         "!="    return T_UNEQUAL;
145         "<="    return T_LESS_EQUAL;
146         ">="    return T_GREATER_EQUAL;
147         "<"     return T_LESS;
148         ">"     return T_GREATER;
149         \"|\'   {
150                 str = yytext[0];
151                 new_string();
152                 BEGIN(STRING);
153         }
154         \n      BEGIN(INITIAL); return T_EOL;
155         ({n}|[/.])+     {
156                 const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
157                 if (id && id->flags & TF_PARAM) {
158                         yylval.id = id;
159                         return id->token;
160                 }
161                 alloc_string(yytext, yyleng);
162                 yylval.string = text;
163                 return T_WORD;
164         }
165         ({n}|[/.$])+    {
166                 /* this token includes at least one '$' */
167                 yylval.string = expand_token(yytext, yyleng);
168                 if (strlen(yylval.string))
169                         return T_WORD;
170                 free(yylval.string);
171         }
172         #.*     /* comment */
173         \\\n    ;
174         [[:blank:]]+
175         .       warn_ignored_character(*yytext);
176         <<EOF>> {
177                 BEGIN(INITIAL);
178         }
179 }
180
181 <STRING>{
182         "$".*   append_expanded_string(yytext);
183         [^$'"\\\n]+/\n  {
184                 append_string(yytext, yyleng);
185                 yylval.string = text;
186                 return T_WORD_QUOTE;
187         }
188         [^$'"\\\n]+     {
189                 append_string(yytext, yyleng);
190         }
191         \\.?/\n {
192                 append_string(yytext + 1, yyleng - 1);
193                 yylval.string = text;
194                 return T_WORD_QUOTE;
195         }
196         \\.?    {
197                 append_string(yytext + 1, yyleng - 1);
198         }
199         \'|\"   {
200                 if (str == yytext[0]) {
201                         BEGIN(PARAM);
202                         yylval.string = text;
203                         return T_WORD_QUOTE;
204                 } else
205                         append_string(yytext, 1);
206         }
207         \n      {
208                 fprintf(stderr,
209                         "%s:%d:warning: multi-line strings not supported\n",
210                         zconf_curname(), zconf_lineno());
211                 BEGIN(INITIAL);
212                 return T_EOL;
213         }
214         <<EOF>> {
215                 BEGIN(INITIAL);
216         }
217 }
218
219 <HELP>{
220         [ \t]+  {
221                 ts = 0;
222                 for (i = 0; i < yyleng; i++) {
223                         if (yytext[i] == '\t')
224                                 ts = (ts & ~7) + 8;
225                         else
226                                 ts++;
227                 }
228                 last_ts = ts;
229                 if (first_ts) {
230                         if (ts < first_ts) {
231                                 zconf_endhelp();
232                                 return T_HELPTEXT;
233                         }
234                         ts -= first_ts;
235                         while (ts > 8) {
236                                 append_string("        ", 8);
237                                 ts -= 8;
238                         }
239                         append_string("        ", ts);
240                 }
241         }
242         [ \t]*\n/[^ \t\n] {
243                 zconf_endhelp();
244                 return T_HELPTEXT;
245         }
246         [ \t]*\n        {
247                 append_string("\n", 1);
248         }
249         [^ \t\n].* {
250                 while (yyleng) {
251                         if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t'))
252                                 break;
253                         yyleng--;
254                 }
255                 append_string(yytext, yyleng);
256                 if (!first_ts)
257                         first_ts = last_ts;
258         }
259         <<EOF>> {
260                 zconf_endhelp();
261                 return T_HELPTEXT;
262         }
263 }
264
265 <<EOF>> {
266         if (current_file) {
267                 zconf_endfile();
268                 return T_EOL;
269         }
270         fclose(yyin);
271         yyterminate();
272 }
273
274 %%
275 static char *expand_token(const char *in, size_t n)
276 {
277         char *out;
278         int c;
279         char c2;
280         const char *rest, *end;
281
282         new_string();
283         append_string(in, n);
284
285         /* get the whole line because we do not know the end of token. */
286         while ((c = input()) != EOF) {
287                 if (c == '\n') {
288                         unput(c);
289                         break;
290                 }
291                 c2 = c;
292                 append_string(&c2, 1);
293         }
294
295         rest = text;
296         out = expand_one_token(&rest);
297
298         /* push back unused characters to the input stream */
299         end = rest + strlen(rest);
300         while (end > rest)
301                 unput(*--end);
302
303         free(text);
304
305         return out;
306 }
307
308 static void append_expanded_string(const char *str)
309 {
310         const char *end;
311         char *res;
312
313         str++;
314
315         res = expand_dollar(&str);
316
317         /* push back unused characters to the input stream */
318         end = str + strlen(str);
319         while (end > str)
320                 unput(*--end);
321
322         append_string(res, strlen(res));
323
324         free(res);
325 }
326
327 void zconf_starthelp(void)
328 {
329         new_string();
330         last_ts = first_ts = 0;
331         BEGIN(HELP);
332 }
333
334 static void zconf_endhelp(void)
335 {
336         yylval.string = text;
337         BEGIN(INITIAL);
338 }
339
340
341 /*
342  * Try to open specified file with following names:
343  * ./name
344  * $(srctree)/name
345  * The latter is used when srctree is separate from objtree
346  * when compiling the firmware.
347  * Return NULL if file is not found.
348  */
349 FILE *zconf_fopen(const char *name)
350 {
351         char *env, fullname[PATH_MAX+1];
352         FILE *f;
353
354         f = fopen(name, "r");
355         if (!f && name != NULL && name[0] != '/') {
356                 env = getenv(SRCTREE);
357                 if (env) {
358                         sprintf(fullname, "%s/%s", env, name);
359                         f = fopen(fullname, "r");
360                 }
361         }
362         return f;
363 }
364
365 void zconf_initscan(const char *name)
366 {
367         yyin = zconf_fopen(name);
368         if (!yyin) {
369                 fprintf(stderr, "can't find file %s\n", name);
370                 exit(1);
371         }
372
373         current_buf = xmalloc(sizeof(*current_buf));
374         memset(current_buf, 0, sizeof(*current_buf));
375
376         current_file = file_lookup(name);
377         yylineno = 1;
378 }
379
380 void zconf_nextfile(const char *name)
381 {
382         struct file *iter;
383         struct file *file = file_lookup(name);
384         struct buffer *buf = xmalloc(sizeof(*buf));
385         memset(buf, 0, sizeof(*buf));
386
387         current_buf->state = YY_CURRENT_BUFFER;
388         yyin = zconf_fopen(file->name);
389         if (!yyin) {
390                 fprintf(stderr, "%s:%d: can't open file \"%s\"\n",
391                         zconf_curname(), zconf_lineno(), file->name);
392                 exit(1);
393         }
394         yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
395         buf->parent = current_buf;
396         current_buf = buf;
397
398         current_file->lineno = yylineno;
399         file->parent = current_file;
400
401         for (iter = current_file; iter; iter = iter->parent) {
402                 if (!strcmp(iter->name, file->name)) {
403                         fprintf(stderr,
404                                 "Recursive inclusion detected.\n"
405                                 "Inclusion path:\n"
406                                 "  current file : %s\n", file->name);
407                         iter = file;
408                         do {
409                                 iter = iter->parent;
410                                 fprintf(stderr, "  included from: %s:%d\n",
411                                         iter->name, iter->lineno - 1);
412                         } while (strcmp(iter->name, file->name));
413                         exit(1);
414                 }
415         }
416
417         yylineno = 1;
418         current_file = file;
419 }
420
421 static void zconf_endfile(void)
422 {
423         struct buffer *parent;
424
425         current_file = current_file->parent;
426         if (current_file)
427                 yylineno = current_file->lineno;
428
429         parent = current_buf->parent;
430         if (parent) {
431                 fclose(yyin);
432                 yy_delete_buffer(YY_CURRENT_BUFFER);
433                 yy_switch_to_buffer(parent->state);
434         }
435         free(current_buf);
436         current_buf = parent;
437 }
438
439 int zconf_lineno(void)
440 {
441         return current_pos.lineno;
442 }
443
444 const char *zconf_curname(void)
445 {
446         return current_pos.file ? current_pos.file->name : "<none>";
447 }