1 %option nostdinit noyywrap never-interactive full ecs
2 %option 8bit 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 
17 #include "lkc.h"
18 #include "expand_env.h"
19 
20 #define START_STRSIZE	16
21 
22 static struct {
23 	struct file *file;
24 	int lineno;
25 } current_pos;
26 
27 static char *text;
28 static int text_size, text_asize;
29 
30 struct buffer {
31 	struct buffer *parent;
32 	YY_BUFFER_STATE state;
33 };
34 
35 struct buffer *current_buf;
36 
37 static int last_ts, first_ts;
38 
39 static void zconf_endhelp(void);
40 static void zconf_endfile(void);
41 
new_string(void)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 
append_string(const char * str,int size)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 = realloc(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 
alloc_string(const char * str,int size)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 
warn_ignored_character(char chr)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 	current_file->lineno++;
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 		BEGIN(PARAM);
107 		current_pos.file = current_file;
108 		current_pos.lineno = current_file->lineno;
109 		if (id && id->flags & TF_COMMAND) {
110 			zconflval.id = id;
111 			return id->token;
112 		}
113 		alloc_string(yytext, yyleng);
114 		zconflval.string = text;
115 		return T_WORD;
116 	}
117 	[^\r\n]  warn_ignored_character(*yytext);
118 	\r?\n	{
119 		BEGIN(INITIAL);
120 		current_file->lineno++;
121 		return T_EOL;
122 	}
123 }
124 
125 <PARAM>{
126 	"&&"	return T_AND;
127 	"||"	return T_OR;
128 	"("	return T_OPEN_PAREN;
129 	")"	return T_CLOSE_PAREN;
130 	"!"	return T_NOT;
131 	"="	return T_EQUAL;
132 	"!="	return T_UNEQUAL;
133 	"<="	return T_LESS_EQUAL;
134 	">="	return T_GREATER_EQUAL;
135 	"<"	return T_LESS;
136 	">"	return T_GREATER;
137 	\"|\'	{
138 		str = yytext[0];
139 		new_string();
140 		BEGIN(STRING);
141 	}
142 	\r?\n	BEGIN(INITIAL); current_file->lineno++; return T_EOL;
143 	({n}|[/.])+	{
144 		const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
145 		if (id && id->flags & TF_PARAM) {
146 			zconflval.id = id;
147 			return id->token;
148 		}
149 		alloc_string(yytext, yyleng);
150 		zconflval.string = text;
151 		return T_WORD;
152 	}
153 	#.*	/* comment */
154 	\\\r?\n	current_file->lineno++;
155 	[[:blank:]]+
156 	.	warn_ignored_character(*yytext);
157 	<<EOF>> {
158 		BEGIN(INITIAL);
159 	}
160 }
161 
162 <STRING>{
163 	[^'"\\\n]+/\n	{
164 		append_string(yytext, yyleng);
165 		zconflval.string = text;
166 		return T_WORD_QUOTE;
167 	}
168 	[^'"\\\n]+	{
169 		append_string(yytext, yyleng);
170 	}
171 	\\.?/\n	{
172 		append_string(yytext + 1, yyleng - 1);
173 		zconflval.string = text;
174 		return T_WORD_QUOTE;
175 	}
176 	\\.?	{
177 		append_string(yytext + 1, yyleng - 1);
178 	}
179 	\'|\"	{
180 		if (str == yytext[0]) {
181 			BEGIN(PARAM);
182 			zconflval.string = text;
183 			return T_WORD_QUOTE;
184 		} else
185 			append_string(yytext, 1);
186 	}
187 	\r?\n	{
188 		printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
189 		current_file->lineno++;
190 		BEGIN(INITIAL);
191 		return T_EOL;
192 	}
193 	<<EOF>>	{
194 		BEGIN(INITIAL);
195 	}
196 }
197 
198 <HELP>{
199 	[ \t]+	{
200 		ts = 0;
201 		for (i = 0; i < yyleng; i++) {
202 			if (yytext[i] == '\t')
203 				ts = (ts & ~7) + 8;
204 			else
205 				ts++;
206 		}
207 		last_ts = ts;
208 		if (first_ts) {
209 			if (ts < first_ts) {
210 				zconf_endhelp();
211 				return T_HELPTEXT;
212 			}
213 			ts -= first_ts;
214 			while (ts > 8) {
215 				append_string("        ", 8);
216 				ts -= 8;
217 			}
218 			append_string("        ", ts);
219 		}
220 	}
221 	[ \t]*\r?\n/[^ \t\r\n] {
222 		current_file->lineno++;
223 		zconf_endhelp();
224 		return T_HELPTEXT;
225 	}
226 	[ \t]*\r?\n	{
227 		current_file->lineno++;
228 		append_string("\n", 1);
229 	}
230 	[^ \t\r?\n].* {
231 		while (yyleng) {
232 			if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t'))
233 				break;
234 			yyleng--;
235 		}
236 		append_string(yytext, yyleng);
237 		if (!first_ts)
238 			first_ts = last_ts;
239 	}
240 	<<EOF>>	{
241 		zconf_endhelp();
242 		return T_HELPTEXT;
243 	}
244 }
245 
246 <<EOF>>	{
247 	if (current_file) {
248 		zconf_endfile();
249 		return T_EOL;
250 	}
251 	fclose(yyin);
252 	yyterminate();
253 }
254 
255 %%
256 void zconf_starthelp(void)
257 {
258 	new_string();
259 	last_ts = first_ts = 0;
260 	BEGIN(HELP);
261 }
262 
263 static void zconf_endhelp(void)
264 {
265 	zconflval.string = text;
266 	BEGIN(INITIAL);
267 }
268 
269 
270 /*
271  * Try to open specified file with following names:
272  * ./name
273  * $(srctree)/name
274  * The latter is used when srctree is separate from objtree
275  * when compiling the kernel.
276  * Return NULL if file is not found.
277  */
278 FILE *zconf_fopen(const char *name)
279 {
280 	char *env, fullname[PATH_MAX+1];
281 	FILE *f;
282 
283 	f = fopen(name, "r");
284 
285 	if (!f && name != NULL && name[0] != '/') {
286 		env = getenv(SRCTREE);
287 		if (env) {
288 			sprintf(fullname, "%s/%s", env, name);
289 			f = fopen(fullname, "r");
290 		}
291 	}
292 	return f;
293 }
294 
295 void zconf_initscan(const char *name)
296 {
297 	yyin = zconf_fopen(name);
298 	if (!yyin) {
299 		printf("can't find file %s\n", name);
300 		exit(1);
301 	}
302 
303 	current_buf = xmalloc(sizeof(*current_buf));
304 	memset(current_buf, 0, sizeof(*current_buf));
305 
306 	current_file = file_lookup(name, false);
307 	current_file->lineno = 1;
308 }
309 
310 void zconf_nextfile(const char *name, bool relative)
311 {
312 	struct file *iter;
313 	struct file *file = file_lookup(name, relative);
314 	struct buffer *buf = xmalloc(sizeof(*buf));
315 	memset(buf, 0, sizeof(*buf));
316 
317 	current_buf->state = YY_CURRENT_BUFFER;
318 	yyin = zconf_fopen(file->name);
319 	if (!yyin) {
320 		printf("%s:%d: can't open file \"%s\"\n",
321 		    zconf_curname(), zconf_lineno(), file->name);
322 		exit(1);
323 	}
324 	yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
325 	buf->parent = current_buf;
326 	current_buf = buf;
327 
328 	for (iter = current_file->parent; iter; iter = iter->parent ) {
329 		if (!strcmp(current_file->name,iter->name) ) {
330 			printf("%s:%d: recursive inclusion detected. "
331 			       "Inclusion path:\n  current file : '%s'\n",
332 			       zconf_curname(), zconf_lineno(),
333 			       zconf_curname());
334 			iter = current_file->parent;
335 			while (iter && \
336 			       strcmp(iter->name,current_file->name)) {
337 				printf("  included from: '%s:%d'\n",
338 				       iter->name, iter->lineno-1);
339 				iter = iter->parent;
340 			}
341 			if (iter)
342 				printf("  included from: '%s:%d'\n",
343 				       iter->name, iter->lineno+1);
344 			exit(1);
345 		}
346 	}
347 	file->lineno = 1;
348 	file->parent = current_file;
349 	current_file = file;
350 }
351 
352 void zconf_nextfiles(const char *expression, bool relative)
353 {
354 	/* Expand environment variables in 'expression' */
355 	char* str = expand_environment(expression, zconf_curname(), zconf_lineno());
356 
357 	/* zconf_nextfile() processes files in LIFO order, so to keep the
358 	   files in the order provided we need to process the list backwards
359 	*/
360 	if (str != NULL && strlen(str)) {
361 		char* pos = str + strlen(str); // start at null terminator
362 
363 		while (pos != str) {
364 			pos--;
365 			if(*pos == ' ') {
366 				*pos = '\0'; // split buffer into multiple c-strings
367 				if (strlen(pos + 1)) {
368 					zconf_nextfile(pos + 1, relative);
369 				}
370 			}
371 		}
372 
373 		if (strlen(str)) { // re-check as first character may have been a space
374 			zconf_nextfile(str, relative);
375 		}
376 	}
377 
378 	free_expanded(str);
379 }
380 
381 static void zconf_endfile(void)
382 {
383 	struct buffer *parent;
384 
385 	current_file = current_file->parent;
386 
387 	parent = current_buf->parent;
388 	if (parent) {
389 		fclose(yyin);
390 		yy_delete_buffer(YY_CURRENT_BUFFER);
391 		yy_switch_to_buffer(parent->state);
392 	}
393 	free(current_buf);
394 	current_buf = parent;
395 }
396 
397 int zconf_lineno(void)
398 {
399 	return current_pos.lineno;
400 }
401 
402 const char *zconf_curname(void)
403 {
404 	return current_pos.file ? current_pos.file->name : "<none>";
405 }
406