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