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 
new_string(void)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 
append_string(const char * str,int size)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 
alloc_string(const char * str,int size)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 
warn_ignored_character(char chr)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 	({n}|$)+	{
118 		/* this token includes at least one '$' */
119 		yylval.string = expand_token(yytext, yyleng);
120 		if (strlen(yylval.string))
121 			return T_VARIABLE;
122 		free(yylval.string);
123 	}
124 	"="	{ BEGIN(ASSIGN_VAL); yylval.flavor = VAR_RECURSIVE; return T_ASSIGN; }
125 	":="	{ BEGIN(ASSIGN_VAL); yylval.flavor = VAR_SIMPLE; return T_ASSIGN; }
126 	"+="	{ BEGIN(ASSIGN_VAL); yylval.flavor = VAR_APPEND; return T_ASSIGN; }
127 	[[:blank:]]+
128 	.	warn_ignored_character(*yytext);
129 	\n	{
130 		BEGIN(INITIAL);
131 		return T_EOL;
132 	}
133 }
134 
135 <ASSIGN_VAL>{
136 	[^[:blank:]\n]+.*	{
137 		alloc_string(yytext, yyleng);
138 		yylval.string = text;
139 		return T_ASSIGN_VAL;
140 	}
141 	\n	{ BEGIN(INITIAL); return T_EOL; }
142 	.
143 }
144 
145 <PARAM>{
146 	"&&"	return T_AND;
147 	"||"	return T_OR;
148 	"("	return T_OPEN_PAREN;
149 	")"	return T_CLOSE_PAREN;
150 	"!"	return T_NOT;
151 	"="	return T_EQUAL;
152 	"!="	return T_UNEQUAL;
153 	"<="	return T_LESS_EQUAL;
154 	">="	return T_GREATER_EQUAL;
155 	"<"	return T_LESS;
156 	">"	return T_GREATER;
157 	\"|\'	{
158 		str = yytext[0];
159 		new_string();
160 		BEGIN(STRING);
161 	}
162 	\n	BEGIN(INITIAL); return T_EOL;
163 	({n}|[/.])+	{
164 		const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
165 		if (id && id->flags & TF_PARAM) {
166 			yylval.id = id;
167 			return id->token;
168 		}
169 		alloc_string(yytext, yyleng);
170 		yylval.string = text;
171 		return T_WORD;
172 	}
173 	({n}|[/.$])+	{
174 		/* this token includes at least one '$' */
175 		yylval.string = expand_token(yytext, yyleng);
176 		if (strlen(yylval.string))
177 			return T_WORD;
178 		free(yylval.string);
179 	}
180 	#.*	/* comment */
181 	\\\n	;
182 	[[:blank:]]+
183 	.	warn_ignored_character(*yytext);
184 	<<EOF>> {
185 		BEGIN(INITIAL);
186 	}
187 }
188 
189 <STRING>{
190 	"$".*	append_expanded_string(yytext);
191 	[^$'"\\\n]+/\n	{
192 		append_string(yytext, yyleng);
193 		yylval.string = text;
194 		return T_WORD_QUOTE;
195 	}
196 	[^$'"\\\n]+	{
197 		append_string(yytext, yyleng);
198 	}
199 	\\.?/\n	{
200 		append_string(yytext + 1, yyleng - 1);
201 		yylval.string = text;
202 		return T_WORD_QUOTE;
203 	}
204 	\\.?	{
205 		append_string(yytext + 1, yyleng - 1);
206 	}
207 	\'|\"	{
208 		if (str == yytext[0]) {
209 			BEGIN(PARAM);
210 			yylval.string = text;
211 			return T_WORD_QUOTE;
212 		} else
213 			append_string(yytext, 1);
214 	}
215 	\n	{
216 		fprintf(stderr,
217 			"%s:%d:warning: multi-line strings not supported\n",
218 			zconf_curname(), zconf_lineno());
219 		BEGIN(INITIAL);
220 		return T_EOL;
221 	}
222 	<<EOF>>	{
223 		BEGIN(INITIAL);
224 	}
225 }
226 
227 <HELP>{
228 	[ \t]+	{
229 		ts = 0;
230 		for (i = 0; i < yyleng; i++) {
231 			if (yytext[i] == '\t')
232 				ts = (ts & ~7) + 8;
233 			else
234 				ts++;
235 		}
236 		last_ts = ts;
237 		if (first_ts) {
238 			if (ts < first_ts) {
239 				zconf_endhelp();
240 				return T_HELPTEXT;
241 			}
242 			ts -= first_ts;
243 			while (ts > 8) {
244 				append_string("        ", 8);
245 				ts -= 8;
246 			}
247 			append_string("        ", ts);
248 		}
249 	}
250 	[ \t]*\n/[^ \t\n] {
251 		zconf_endhelp();
252 		return T_HELPTEXT;
253 	}
254 	[ \t]*\n	{
255 		append_string("\n", 1);
256 	}
257 	[^ \t\n].* {
258 		while (yyleng) {
259 			if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t'))
260 				break;
261 			yyleng--;
262 		}
263 		append_string(yytext, yyleng);
264 		if (!first_ts)
265 			first_ts = last_ts;
266 	}
267 	<<EOF>>	{
268 		zconf_endhelp();
269 		return T_HELPTEXT;
270 	}
271 }
272 
273 <<EOF>>	{
274 	if (current_file) {
275 		zconf_endfile();
276 		return T_EOL;
277 	}
278 	fclose(yyin);
279 	yyterminate();
280 }
281 
282 %%
283 static char *expand_token(const char *in, size_t n)
284 {
285 	char *out;
286 	int c;
287 	char c2;
288 	const char *rest, *end;
289 
290 	new_string();
291 	append_string(in, n);
292 
293 	/* get the whole line because we do not know the end of token. */
294 	while ((c = input()) != EOF) {
295 		if (c == '\n') {
296 			unput(c);
297 			break;
298 		}
299 		c2 = c;
300 		append_string(&c2, 1);
301 	}
302 
303 	rest = text;
304 	out = expand_one_token(&rest);
305 
306 	/* push back unused characters to the input stream */
307 	end = rest + strlen(rest);
308 	while (end > rest)
309 		unput(*--end);
310 
311 	free(text);
312 
313 	return out;
314 }
315 
316 static void append_expanded_string(const char *str)
317 {
318 	const char *end;
319 	char *res;
320 
321 	str++;
322 
323 	res = expand_dollar(&str);
324 
325 	/* push back unused characters to the input stream */
326 	end = str + strlen(str);
327 	while (end > str)
328 		unput(*--end);
329 
330 	append_string(res, strlen(res));
331 
332 	free(res);
333 }
334 
335 void zconf_starthelp(void)
336 {
337 	new_string();
338 	last_ts = first_ts = 0;
339 	BEGIN(HELP);
340 }
341 
342 static void zconf_endhelp(void)
343 {
344 	yylval.string = text;
345 	BEGIN(INITIAL);
346 }
347 
348 
349 /*
350  * Try to open specified file with following names:
351  * ./name
352  * $(srctree)/name
353  * The latter is used when srctree is separate from objtree
354  * when compiling the kernel.
355  * Return NULL if file is not found.
356  */
357 FILE *zconf_fopen(const char *name)
358 {
359 	char *env, fullname[PATH_MAX+1];
360 	FILE *f;
361 
362 	f = fopen(name, "r");
363 	if (!f && name != NULL && name[0] != '/') {
364 		env = getenv(SRCTREE);
365 		if (env) {
366 			sprintf(fullname, "%s/%s", env, name);
367 			f = fopen(fullname, "r");
368 		}
369 	}
370 	return f;
371 }
372 
373 void zconf_initscan(const char *name)
374 {
375 	yyin = zconf_fopen(name);
376 	if (!yyin) {
377 		fprintf(stderr, "can't find file %s\n", name);
378 		exit(1);
379 	}
380 
381 	current_buf = xmalloc(sizeof(*current_buf));
382 	memset(current_buf, 0, sizeof(*current_buf));
383 
384 	current_file = file_lookup(name);
385 	yylineno = 1;
386 }
387 
388 void zconf_nextfile(const char *name)
389 {
390 	struct file *iter;
391 	struct file *file = file_lookup(name);
392 	struct buffer *buf = xmalloc(sizeof(*buf));
393 	memset(buf, 0, sizeof(*buf));
394 
395 	current_buf->state = YY_CURRENT_BUFFER;
396 	yyin = zconf_fopen(file->name);
397 	if (!yyin) {
398 		fprintf(stderr, "%s:%d: can't open file \"%s\"\n",
399 			zconf_curname(), zconf_lineno(), file->name);
400 		exit(1);
401 	}
402 	yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
403 	buf->parent = current_buf;
404 	current_buf = buf;
405 
406 	current_file->lineno = yylineno;
407 	file->parent = current_file;
408 
409 	for (iter = current_file; iter; iter = iter->parent) {
410 		if (!strcmp(iter->name, file->name)) {
411 			fprintf(stderr,
412 				"Recursive inclusion detected.\n"
413 				"Inclusion path:\n"
414 				"  current file : %s\n", file->name);
415 			iter = file;
416 			do {
417 				iter = iter->parent;
418 				fprintf(stderr, "  included from: %s:%d\n",
419 					iter->name, iter->lineno - 1);
420 			} while (strcmp(iter->name, file->name));
421 			exit(1);
422 		}
423 	}
424 
425 	yylineno = 1;
426 	current_file = file;
427 }
428 
429 static void zconf_endfile(void)
430 {
431 	struct buffer *parent;
432 
433 	current_file = current_file->parent;
434 	if (current_file)
435 		yylineno = current_file->lineno;
436 
437 	parent = current_buf->parent;
438 	if (parent) {
439 		fclose(yyin);
440 		yy_delete_buffer(YY_CURRENT_BUFFER);
441 		yy_switch_to_buffer(parent->state);
442 	}
443 	free(current_buf);
444 	current_buf = parent;
445 }
446 
447 int zconf_lineno(void)
448 {
449 	return current_pos.lineno;
450 }
451 
452 const char *zconf_curname(void)
453 {
454 	return current_pos.file ? current_pos.file->name : "<none>";
455 }
456