1%option backup nostdinit noyywrap never-interactive full ecs
2%option 8bit backup nodefault perf-report perf-report
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#define LKC_DIRECT_LINK
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 void zconf_endhelp(void);
39static void zconf_endfile(void);
40
41void new_string(void)
42{
43	text = malloc(START_STRSIZE);
44	text_asize = START_STRSIZE;
45	text_size = 0;
46	*text = 0;
47}
48
49void append_string(const char *str, int size)
50{
51	int new_size = text_size + size + 1;
52	if (new_size > text_asize) {
53		new_size += START_STRSIZE - 1;
54		new_size &= -START_STRSIZE;
55		text = realloc(text, new_size);
56		text_asize = new_size;
57	}
58	memcpy(text + text_size, str, size);
59	text_size += size;
60	text[text_size] = 0;
61}
62
63void alloc_string(const char *str, int size)
64{
65	text = malloc(size + 1);
66	memcpy(text, str, size);
67	text[size] = 0;
68}
69%}
70
71ws	[ \n\t]
72n	[A-Za-z0-9_]
73
74%%
75	int str = 0;
76	int ts, i;
77
78[ \t]*#.*\n	|
79[ \t]*\n	{
80	current_file->lineno++;
81	return T_EOL;
82}
83[ \t]*#.*
84
85
86[ \t]+	{
87	BEGIN(COMMAND);
88}
89
90.	{
91	unput(yytext[0]);
92	BEGIN(COMMAND);
93}
94
95
96<COMMAND>{
97	{n}+	{
98		struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
99		BEGIN(PARAM);
100		current_pos.file = current_file;
101		current_pos.lineno = current_file->lineno;
102		if (id && id->flags & TF_COMMAND) {
103			zconflval.id = id;
104			return id->token;
105		}
106		alloc_string(yytext, yyleng);
107		zconflval.string = text;
108		return T_WORD;
109	}
110	.
111	\n	{
112		BEGIN(INITIAL);
113		current_file->lineno++;
114		return T_EOL;
115	}
116}
117
118<PARAM>{
119	"&&"	return T_AND;
120	"||"	return T_OR;
121	"("	return T_OPEN_PAREN;
122	")"	return T_CLOSE_PAREN;
123	"!"	return T_NOT;
124	"="	return T_EQUAL;
125	"!="	return T_UNEQUAL;
126	\"|\'	{
127		str = yytext[0];
128		new_string();
129		BEGIN(STRING);
130	}
131	\n	BEGIN(INITIAL); current_file->lineno++; return T_EOL;
132	---	/* ignore */
133	({n}|[-/.])+	{
134		struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
135		if (id && id->flags & TF_PARAM) {
136			zconflval.id = id;
137			return id->token;
138		}
139		alloc_string(yytext, yyleng);
140		zconflval.string = text;
141		return T_WORD;
142	}
143	#.*	/* comment */
144	\\\n	current_file->lineno++;
145	.
146	<<EOF>> {
147		BEGIN(INITIAL);
148	}
149}
150
151<STRING>{
152	[^'"\\\n]+/\n	{
153		append_string(yytext, yyleng);
154		zconflval.string = text;
155		return T_WORD_QUOTE;
156	}
157	[^'"\\\n]+	{
158		append_string(yytext, yyleng);
159	}
160	\\.?/\n	{
161		append_string(yytext + 1, yyleng - 1);
162		zconflval.string = text;
163		return T_WORD_QUOTE;
164	}
165	\\.?	{
166		append_string(yytext + 1, yyleng - 1);
167	}
168	\'|\"	{
169		if (str == yytext[0]) {
170			BEGIN(PARAM);
171			zconflval.string = text;
172			return T_WORD_QUOTE;
173		} else
174			append_string(yytext, 1);
175	}
176	\n	{
177		printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
178		current_file->lineno++;
179		BEGIN(INITIAL);
180		return T_EOL;
181	}
182	<<EOF>>	{
183		BEGIN(INITIAL);
184	}
185}
186
187<HELP>{
188	[ \t]+	{
189		ts = 0;
190		for (i = 0; i < yyleng; i++) {
191			if (yytext[i] == '\t')
192				ts = (ts & ~7) + 8;
193			else
194				ts++;
195		}
196		last_ts = ts;
197		if (first_ts) {
198			if (ts < first_ts) {
199				zconf_endhelp();
200				return T_HELPTEXT;
201			}
202			ts -= first_ts;
203			while (ts > 8) {
204				append_string("        ", 8);
205				ts -= 8;
206			}
207			append_string("        ", ts);
208		}
209	}
210	[ \t]*\n/[^ \t\n] {
211		current_file->lineno++;
212		zconf_endhelp();
213		return T_HELPTEXT;
214	}
215	[ \t]*\n	{
216		current_file->lineno++;
217		append_string("\n", 1);
218	}
219	[^ \t\n].* {
220		append_string(yytext, yyleng);
221		if (!first_ts)
222			first_ts = last_ts;
223	}
224	<<EOF>>	{
225		zconf_endhelp();
226		return T_HELPTEXT;
227	}
228}
229
230<<EOF>>	{
231	if (current_file) {
232		zconf_endfile();
233		return T_EOL;
234	}
235	fclose(yyin);
236	yyterminate();
237}
238
239%%
240void zconf_starthelp(void)
241{
242	new_string();
243	last_ts = first_ts = 0;
244	BEGIN(HELP);
245}
246
247static void zconf_endhelp(void)
248{
249	zconflval.string = text;
250	BEGIN(INITIAL);
251}
252
253
254/*
255 * Try to open specified file with following names:
256 * ./name
257 * $(srctree)/name
258 * The latter is used when srctree is separate from objtree
259 * when compiling the kernel.
260 * Return NULL if file is not found.
261 */
262FILE *zconf_fopen(const char *name)
263{
264	char *env, fullname[PATH_MAX+1];
265	FILE *f;
266
267	f = fopen(name, "r");
268	if (!f && name != NULL && name[0] != '/') {
269		env = getenv(SRCTREE);
270		if (env) {
271			sprintf(fullname, "%s/%s", env, name);
272			f = fopen(fullname, "r");
273		}
274	}
275	return f;
276}
277
278void zconf_initscan(const char *name)
279{
280	yyin = zconf_fopen(name);
281	if (!yyin) {
282		printf("can't find file %s\n", name);
283		exit(1);
284	}
285
286	current_buf = malloc(sizeof(*current_buf));
287	memset(current_buf, 0, sizeof(*current_buf));
288
289	current_file = file_lookup(name);
290	current_file->lineno = 1;
291	current_file->flags = FILE_BUSY;
292}
293
294void zconf_nextfile(const char *name)
295{
296	struct file *file = file_lookup(name);
297	struct buffer *buf = malloc(sizeof(*buf));
298	memset(buf, 0, sizeof(*buf));
299
300	current_buf->state = YY_CURRENT_BUFFER;
301	yyin = zconf_fopen(name);
302	if (!yyin) {
303		printf("%s:%d: can't open file \"%s\"\n", zconf_curname(), zconf_lineno(), name);
304		exit(1);
305	}
306	yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
307	buf->parent = current_buf;
308	current_buf = buf;
309
310	if (file->flags & FILE_BUSY) {
311		printf("recursive scan (%s)?\n", name);
312		exit(1);
313	}
314	if (file->flags & FILE_SCANNED) {
315		printf("file %s already scanned?\n", name);
316		exit(1);
317	}
318	file->flags |= FILE_BUSY;
319	file->lineno = 1;
320	file->parent = current_file;
321	current_file = file;
322}
323
324static void zconf_endfile(void)
325{
326	struct buffer *parent;
327
328	current_file->flags |= FILE_SCANNED;
329	current_file->flags &= ~FILE_BUSY;
330	current_file = current_file->parent;
331
332	parent = current_buf->parent;
333	if (parent) {
334		fclose(yyin);
335		yy_delete_buffer(YY_CURRENT_BUFFER);
336		yy_switch_to_buffer(parent->state);
337	}
338	free(current_buf);
339	current_buf = parent;
340}
341
342int zconf_lineno(void)
343{
344	return current_pos.lineno;
345}
346
347char *zconf_curname(void)
348{
349	return current_pos.file ? current_pos.file->name : "<none>";
350}
351