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
21static struct {
22	struct file *file;
23	int lineno;
24} current_pos;
25
26static char *text;
27static int text_size, text_asize;
28
29struct buffer {
30	struct buffer *parent;
31	YY_BUFFER_STATE state;
32};
33
34struct buffer *current_buf;
35
36static int last_ts, first_ts;
37
38static char *expand_token(const char *in, size_t n);
39static void append_expanded_string(const char *in);
40static void zconf_endhelp(void);
41static void zconf_endfile(void);
42
43static void new_string(void)
44{
45	text = xmalloc(START_STRSIZE);
46	text_asize = START_STRSIZE;
47	text_size = 0;
48	*text = 0;
49}
50
51static 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
65static 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
72static 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
80n	[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%%
283static 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
316static 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
335void zconf_starthelp(void)
336{
337	new_string();
338	last_ts = first_ts = 0;
339	BEGIN(HELP);
340}
341
342static 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 */
357FILE *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
373void 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
388void 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
429static 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
447int zconf_lineno(void)
448{
449	return current_pos.lineno;
450}
451
452const char *zconf_curname(void)
453{
454	return current_pos.file ? current_pos.file->name : "<none>";
455}
456