• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 	        current_file->name, yylineno, 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 		yylval.string = text;
225 		return T_WORD_QUOTE;
226 	}
227 }
228 
229 <HELP>{
230 	[ \t]+	{
231 		ts = 0;
232 		for (i = 0; i < yyleng; i++) {
233 			if (yytext[i] == '\t')
234 				ts = (ts & ~7) + 8;
235 			else
236 				ts++;
237 		}
238 		last_ts = ts;
239 		if (first_ts) {
240 			if (ts < first_ts) {
241 				zconf_endhelp();
242 				return T_HELPTEXT;
243 			}
244 			ts -= first_ts;
245 			while (ts > 8) {
246 				append_string("        ", 8);
247 				ts -= 8;
248 			}
249 			append_string("        ", ts);
250 		}
251 	}
252 	[ \t]*\n/[^ \t\n] {
253 		zconf_endhelp();
254 		return T_HELPTEXT;
255 	}
256 	[ \t]*\n	{
257 		append_string("\n", 1);
258 	}
259 	[^ \t\n].* {
260 		while (yyleng) {
261 			if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t'))
262 				break;
263 			yyleng--;
264 		}
265 		append_string(yytext, yyleng);
266 		if (!first_ts)
267 			first_ts = last_ts;
268 	}
269 	<<EOF>>	{
270 		zconf_endhelp();
271 		return T_HELPTEXT;
272 	}
273 }
274 
275 <<EOF>>	{
276 	if (current_file) {
277 		zconf_endfile();
278 		return T_EOL;
279 	}
280 	fclose(yyin);
281 	yyterminate();
282 }
283 
284 %%
285 static char *expand_token(const char *in, size_t n)
286 {
287 	char *out;
288 	int c;
289 	char c2;
290 	const char *rest, *end;
291 
292 	new_string();
293 	append_string(in, n);
294 
295 	/* get the whole line because we do not know the end of token. */
296 	while ((c = input()) != EOF) {
297 		if (c == '\n') {
298 			unput(c);
299 			break;
300 		}
301 		c2 = c;
302 		append_string(&c2, 1);
303 	}
304 
305 	rest = text;
306 	out = expand_one_token(&rest);
307 
308 	/* push back unused characters to the input stream */
309 	end = rest + strlen(rest);
310 	while (end > rest)
311 		unput(*--end);
312 
313 	free(text);
314 
315 	return out;
316 }
317 
318 static void append_expanded_string(const char *str)
319 {
320 	const char *end;
321 	char *res;
322 
323 	str++;
324 
325 	res = expand_dollar(&str);
326 
327 	/* push back unused characters to the input stream */
328 	end = str + strlen(str);
329 	while (end > str)
330 		unput(*--end);
331 
332 	append_string(res, strlen(res));
333 
334 	free(res);
335 }
336 
337 void zconf_starthelp(void)
338 {
339 	new_string();
340 	last_ts = first_ts = 0;
341 	BEGIN(HELP);
342 }
343 
344 static void zconf_endhelp(void)
345 {
346 	yylval.string = text;
347 	BEGIN(INITIAL);
348 }
349 
350 
351 /*
352  * Try to open specified file with following names:
353  * ./name
354  * $(srctree)/name
355  * The latter is used when srctree is separate from objtree
356  * when compiling the kernel.
357  * Return NULL if file is not found.
358  */
359 FILE *zconf_fopen(const char *name)
360 {
361 	char *env, fullname[PATH_MAX+1];
362 	FILE *f;
363 
364 	f = fopen(name, "r");
365 	if (!f && name != NULL && name[0] != '/') {
366 		env = getenv(SRCTREE);
367 		if (env) {
368 			sprintf(fullname, "%s/%s", env, name);
369 			f = fopen(fullname, "r");
370 		}
371 	}
372 	return f;
373 }
374 
375 void zconf_initscan(const char *name)
376 {
377 	yyin = zconf_fopen(name);
378 	if (!yyin) {
379 		fprintf(stderr, "can't find file %s\n", name);
380 		exit(1);
381 	}
382 
383 	current_buf = xmalloc(sizeof(*current_buf));
384 	memset(current_buf, 0, sizeof(*current_buf));
385 
386 	current_file = file_lookup(name);
387 	yylineno = 1;
388 }
389 
390 void zconf_nextfile(const char *name)
391 {
392 	struct file *iter;
393 	struct file *file = file_lookup(name);
394 	struct buffer *buf = xmalloc(sizeof(*buf));
395 	memset(buf, 0, sizeof(*buf));
396 
397 	current_buf->state = YY_CURRENT_BUFFER;
398 	yyin = zconf_fopen(file->name);
399 	if (!yyin) {
400 		fprintf(stderr, "%s:%d: can't open file \"%s\"\n",
401 			zconf_curname(), zconf_lineno(), file->name);
402 		exit(1);
403 	}
404 	yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
405 	buf->parent = current_buf;
406 	current_buf = buf;
407 
408 	current_file->lineno = yylineno;
409 	file->parent = current_file;
410 
411 	for (iter = current_file; iter; iter = iter->parent) {
412 		if (!strcmp(iter->name, file->name)) {
413 			fprintf(stderr,
414 				"Recursive inclusion detected.\n"
415 				"Inclusion path:\n"
416 				"  current file : %s\n", file->name);
417 			iter = file;
418 			do {
419 				iter = iter->parent;
420 				fprintf(stderr, "  included from: %s:%d\n",
421 					iter->name, iter->lineno - 1);
422 			} while (strcmp(iter->name, file->name));
423 			exit(1);
424 		}
425 	}
426 
427 	yylineno = 1;
428 	current_file = file;
429 }
430 
431 static void zconf_endfile(void)
432 {
433 	struct buffer *parent;
434 
435 	current_file = current_file->parent;
436 	if (current_file)
437 		yylineno = current_file->lineno;
438 
439 	parent = current_buf->parent;
440 	if (parent) {
441 		fclose(yyin);
442 		yy_delete_buffer(YY_CURRENT_BUFFER);
443 		yy_switch_to_buffer(parent->state);
444 	}
445 	free(current_buf);
446 	current_buf = parent;
447 }
448 
449 int zconf_lineno(void)
450 {
451 	return current_pos.lineno;
452 }
453 
454 const char *zconf_curname(void)
455 {
456 	return current_pos.file ? current_pos.file->name : "<none>";
457 }
458