xref: /openbmc/linux/scripts/kconfig/preprocess.c (revision 97fb5e8d)
1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // Copyright (C) 2018 Masahiro Yamada <yamada.masahiro@socionext.com>
4 
5 #include <ctype.h>
6 #include <stdarg.h>
7 #include <stdbool.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 
12 #include "list.h"
13 #include "lkc.h"
14 
15 #define ARRAY_SIZE(arr)		(sizeof(arr) / sizeof((arr)[0]))
16 
17 static char *expand_string_with_args(const char *in, int argc, char *argv[]);
18 
19 static void __attribute__((noreturn)) pperror(const char *format, ...)
20 {
21 	va_list ap;
22 
23 	fprintf(stderr, "%s:%d: ", current_file->name, yylineno);
24 	va_start(ap, format);
25 	vfprintf(stderr, format, ap);
26 	va_end(ap);
27 	fprintf(stderr, "\n");
28 
29 	exit(1);
30 }
31 
32 /*
33  * Environment variables
34  */
35 static LIST_HEAD(env_list);
36 
37 struct env {
38 	char *name;
39 	char *value;
40 	struct list_head node;
41 };
42 
43 static void env_add(const char *name, const char *value)
44 {
45 	struct env *e;
46 
47 	e = xmalloc(sizeof(*e));
48 	e->name = xstrdup(name);
49 	e->value = xstrdup(value);
50 
51 	list_add_tail(&e->node, &env_list);
52 }
53 
54 static void env_del(struct env *e)
55 {
56 	list_del(&e->node);
57 	free(e->name);
58 	free(e->value);
59 	free(e);
60 }
61 
62 /* The returned pointer must be freed when done */
63 static char *env_expand(const char *name)
64 {
65 	struct env *e;
66 	const char *value;
67 
68 	if (!*name)
69 		return NULL;
70 
71 	list_for_each_entry(e, &env_list, node) {
72 		if (!strcmp(name, e->name))
73 			return xstrdup(e->value);
74 	}
75 
76 	value = getenv(name);
77 	if (!value)
78 		return NULL;
79 
80 	/*
81 	 * We need to remember all referenced environment variables.
82 	 * They will be written out to include/config/auto.conf.cmd
83 	 */
84 	env_add(name, value);
85 
86 	return xstrdup(value);
87 }
88 
89 void env_write_dep(FILE *f, const char *autoconfig_name)
90 {
91 	struct env *e, *tmp;
92 
93 	list_for_each_entry_safe(e, tmp, &env_list, node) {
94 		fprintf(f, "ifneq \"$(%s)\" \"%s\"\n", e->name, e->value);
95 		fprintf(f, "%s: FORCE\n", autoconfig_name);
96 		fprintf(f, "endif\n");
97 		env_del(e);
98 	}
99 }
100 
101 /*
102  * Built-in functions
103  */
104 struct function {
105 	const char *name;
106 	unsigned int min_args;
107 	unsigned int max_args;
108 	char *(*func)(int argc, char *argv[]);
109 };
110 
111 static char *do_error_if(int argc, char *argv[])
112 {
113 	if (!strcmp(argv[0], "y"))
114 		pperror("%s", argv[1]);
115 
116 	return NULL;
117 }
118 
119 static char *do_filename(int argc, char *argv[])
120 {
121 	return xstrdup(current_file->name);
122 }
123 
124 static char *do_info(int argc, char *argv[])
125 {
126 	printf("%s\n", argv[0]);
127 
128 	return xstrdup("");
129 }
130 
131 static char *do_lineno(int argc, char *argv[])
132 {
133 	char buf[16];
134 
135 	sprintf(buf, "%d", yylineno);
136 
137 	return xstrdup(buf);
138 }
139 
140 static char *do_shell(int argc, char *argv[])
141 {
142 	FILE *p;
143 	char buf[256];
144 	char *cmd;
145 	size_t nread;
146 	int i;
147 
148 	cmd = argv[0];
149 
150 	p = popen(cmd, "r");
151 	if (!p) {
152 		perror(cmd);
153 		exit(1);
154 	}
155 
156 	nread = fread(buf, 1, sizeof(buf), p);
157 	if (nread == sizeof(buf))
158 		nread--;
159 
160 	/* remove trailing new lines */
161 	while (nread > 0 && buf[nread - 1] == '\n')
162 		nread--;
163 
164 	buf[nread] = 0;
165 
166 	/* replace a new line with a space */
167 	for (i = 0; i < nread; i++) {
168 		if (buf[i] == '\n')
169 			buf[i] = ' ';
170 	}
171 
172 	if (pclose(p) == -1) {
173 		perror(cmd);
174 		exit(1);
175 	}
176 
177 	return xstrdup(buf);
178 }
179 
180 static char *do_warning_if(int argc, char *argv[])
181 {
182 	if (!strcmp(argv[0], "y"))
183 		fprintf(stderr, "%s:%d: %s\n",
184 			current_file->name, yylineno, argv[1]);
185 
186 	return xstrdup("");
187 }
188 
189 static const struct function function_table[] = {
190 	/* Name		MIN	MAX	Function */
191 	{ "error-if",	2,	2,	do_error_if },
192 	{ "filename",	0,	0,	do_filename },
193 	{ "info",	1,	1,	do_info },
194 	{ "lineno",	0,	0,	do_lineno },
195 	{ "shell",	1,	1,	do_shell },
196 	{ "warning-if",	2,	2,	do_warning_if },
197 };
198 
199 #define FUNCTION_MAX_ARGS		16
200 
201 static char *function_expand(const char *name, int argc, char *argv[])
202 {
203 	const struct function *f;
204 	int i;
205 
206 	for (i = 0; i < ARRAY_SIZE(function_table); i++) {
207 		f = &function_table[i];
208 		if (strcmp(f->name, name))
209 			continue;
210 
211 		if (argc < f->min_args)
212 			pperror("too few function arguments passed to '%s'",
213 				name);
214 
215 		if (argc > f->max_args)
216 			pperror("too many function arguments passed to '%s'",
217 				name);
218 
219 		return f->func(argc, argv);
220 	}
221 
222 	return NULL;
223 }
224 
225 /*
226  * Variables (and user-defined functions)
227  */
228 static LIST_HEAD(variable_list);
229 
230 struct variable {
231 	char *name;
232 	char *value;
233 	enum variable_flavor flavor;
234 	int exp_count;
235 	struct list_head node;
236 };
237 
238 static struct variable *variable_lookup(const char *name)
239 {
240 	struct variable *v;
241 
242 	list_for_each_entry(v, &variable_list, node) {
243 		if (!strcmp(name, v->name))
244 			return v;
245 	}
246 
247 	return NULL;
248 }
249 
250 static char *variable_expand(const char *name, int argc, char *argv[])
251 {
252 	struct variable *v;
253 	char *res;
254 
255 	v = variable_lookup(name);
256 	if (!v)
257 		return NULL;
258 
259 	if (argc == 0 && v->exp_count)
260 		pperror("Recursive variable '%s' references itself (eventually)",
261 			name);
262 
263 	if (v->exp_count > 1000)
264 		pperror("Too deep recursive expansion");
265 
266 	v->exp_count++;
267 
268 	if (v->flavor == VAR_RECURSIVE)
269 		res = expand_string_with_args(v->value, argc, argv);
270 	else
271 		res = xstrdup(v->value);
272 
273 	v->exp_count--;
274 
275 	return res;
276 }
277 
278 void variable_add(const char *name, const char *value,
279 		  enum variable_flavor flavor)
280 {
281 	struct variable *v;
282 	char *new_value;
283 	bool append = false;
284 
285 	v = variable_lookup(name);
286 	if (v) {
287 		/* For defined variables, += inherits the existing flavor */
288 		if (flavor == VAR_APPEND) {
289 			flavor = v->flavor;
290 			append = true;
291 		} else {
292 			free(v->value);
293 		}
294 	} else {
295 		/* For undefined variables, += assumes the recursive flavor */
296 		if (flavor == VAR_APPEND)
297 			flavor = VAR_RECURSIVE;
298 
299 		v = xmalloc(sizeof(*v));
300 		v->name = xstrdup(name);
301 		v->exp_count = 0;
302 		list_add_tail(&v->node, &variable_list);
303 	}
304 
305 	v->flavor = flavor;
306 
307 	if (flavor == VAR_SIMPLE)
308 		new_value = expand_string(value);
309 	else
310 		new_value = xstrdup(value);
311 
312 	if (append) {
313 		v->value = xrealloc(v->value,
314 				    strlen(v->value) + strlen(new_value) + 2);
315 		strcat(v->value, " ");
316 		strcat(v->value, new_value);
317 		free(new_value);
318 	} else {
319 		v->value = new_value;
320 	}
321 }
322 
323 static void variable_del(struct variable *v)
324 {
325 	list_del(&v->node);
326 	free(v->name);
327 	free(v->value);
328 	free(v);
329 }
330 
331 void variable_all_del(void)
332 {
333 	struct variable *v, *tmp;
334 
335 	list_for_each_entry_safe(v, tmp, &variable_list, node)
336 		variable_del(v);
337 }
338 
339 /*
340  * Evaluate a clause with arguments.  argc/argv are arguments from the upper
341  * function call.
342  *
343  * Returned string must be freed when done
344  */
345 static char *eval_clause(const char *str, size_t len, int argc, char *argv[])
346 {
347 	char *tmp, *name, *res, *endptr, *prev, *p;
348 	int new_argc = 0;
349 	char *new_argv[FUNCTION_MAX_ARGS];
350 	int nest = 0;
351 	int i;
352 	unsigned long n;
353 
354 	tmp = xstrndup(str, len);
355 
356 	/*
357 	 * If variable name is '1', '2', etc.  It is generally an argument
358 	 * from a user-function call (i.e. local-scope variable).  If not
359 	 * available, then look-up global-scope variables.
360 	 */
361 	n = strtoul(tmp, &endptr, 10);
362 	if (!*endptr && n > 0 && n <= argc) {
363 		res = xstrdup(argv[n - 1]);
364 		goto free_tmp;
365 	}
366 
367 	prev = p = tmp;
368 
369 	/*
370 	 * Split into tokens
371 	 * The function name and arguments are separated by a comma.
372 	 * For example, if the function call is like this:
373 	 *   $(foo,$(x),$(y))
374 	 *
375 	 * The input string for this helper should be:
376 	 *   foo,$(x),$(y)
377 	 *
378 	 * and split into:
379 	 *   new_argv[0] = 'foo'
380 	 *   new_argv[1] = '$(x)'
381 	 *   new_argv[2] = '$(y)'
382 	 */
383 	while (*p) {
384 		if (nest == 0 && *p == ',') {
385 			*p = 0;
386 			if (new_argc >= FUNCTION_MAX_ARGS)
387 				pperror("too many function arguments");
388 			new_argv[new_argc++] = prev;
389 			prev = p + 1;
390 		} else if (*p == '(') {
391 			nest++;
392 		} else if (*p == ')') {
393 			nest--;
394 		}
395 
396 		p++;
397 	}
398 	new_argv[new_argc++] = prev;
399 
400 	/*
401 	 * Shift arguments
402 	 * new_argv[0] represents a function name or a variable name.  Put it
403 	 * into 'name', then shift the rest of the arguments.  This simplifies
404 	 * 'const' handling.
405 	 */
406 	name = expand_string_with_args(new_argv[0], argc, argv);
407 	new_argc--;
408 	for (i = 0; i < new_argc; i++)
409 		new_argv[i] = expand_string_with_args(new_argv[i + 1],
410 						      argc, argv);
411 
412 	/* Search for variables */
413 	res = variable_expand(name, new_argc, new_argv);
414 	if (res)
415 		goto free;
416 
417 	/* Look for built-in functions */
418 	res = function_expand(name, new_argc, new_argv);
419 	if (res)
420 		goto free;
421 
422 	/* Last, try environment variable */
423 	if (new_argc == 0) {
424 		res = env_expand(name);
425 		if (res)
426 			goto free;
427 	}
428 
429 	res = xstrdup("");
430 free:
431 	for (i = 0; i < new_argc; i++)
432 		free(new_argv[i]);
433 	free(name);
434 free_tmp:
435 	free(tmp);
436 
437 	return res;
438 }
439 
440 /*
441  * Expand a string that follows '$'
442  *
443  * For example, if the input string is
444  *     ($(FOO)$($(BAR)))$(BAZ)
445  * this helper evaluates
446  *     $($(FOO)$($(BAR)))
447  * and returns a new string containing the expansion (note that the string is
448  * recursively expanded), also advancing 'str' to point to the next character
449  * after the corresponding closing parenthesis, in this case, *str will be
450  *     $(BAR)
451  */
452 static char *expand_dollar_with_args(const char **str, int argc, char *argv[])
453 {
454 	const char *p = *str;
455 	const char *q;
456 	int nest = 0;
457 
458 	/*
459 	 * In Kconfig, variable/function references always start with "$(".
460 	 * Neither single-letter variables as in $A nor curly braces as in ${CC}
461 	 * are supported.  '$' not followed by '(' loses its special meaning.
462 	 */
463 	if (*p != '(') {
464 		*str = p;
465 		return xstrdup("$");
466 	}
467 
468 	p++;
469 	q = p;
470 	while (*q) {
471 		if (*q == '(') {
472 			nest++;
473 		} else if (*q == ')') {
474 			if (nest-- == 0)
475 				break;
476 		}
477 		q++;
478 	}
479 
480 	if (!*q)
481 		pperror("unterminated reference to '%s': missing ')'", p);
482 
483 	/* Advance 'str' to after the expanded initial portion of the string */
484 	*str = q + 1;
485 
486 	return eval_clause(p, q - p, argc, argv);
487 }
488 
489 char *expand_dollar(const char **str)
490 {
491 	return expand_dollar_with_args(str, 0, NULL);
492 }
493 
494 static char *__expand_string(const char **str, bool (*is_end)(char c),
495 			     int argc, char *argv[])
496 {
497 	const char *in, *p;
498 	char *expansion, *out;
499 	size_t in_len, out_len;
500 
501 	out = xmalloc(1);
502 	*out = 0;
503 	out_len = 1;
504 
505 	p = in = *str;
506 
507 	while (1) {
508 		if (*p == '$') {
509 			in_len = p - in;
510 			p++;
511 			expansion = expand_dollar_with_args(&p, argc, argv);
512 			out_len += in_len + strlen(expansion);
513 			out = xrealloc(out, out_len);
514 			strncat(out, in, in_len);
515 			strcat(out, expansion);
516 			free(expansion);
517 			in = p;
518 			continue;
519 		}
520 
521 		if (is_end(*p))
522 			break;
523 
524 		p++;
525 	}
526 
527 	in_len = p - in;
528 	out_len += in_len;
529 	out = xrealloc(out, out_len);
530 	strncat(out, in, in_len);
531 
532 	/* Advance 'str' to the end character */
533 	*str = p;
534 
535 	return out;
536 }
537 
538 static bool is_end_of_str(char c)
539 {
540 	return !c;
541 }
542 
543 /*
544  * Expand variables and functions in the given string.  Undefined variables
545  * expand to an empty string.
546  * The returned string must be freed when done.
547  */
548 static char *expand_string_with_args(const char *in, int argc, char *argv[])
549 {
550 	return __expand_string(&in, is_end_of_str, argc, argv);
551 }
552 
553 char *expand_string(const char *in)
554 {
555 	return expand_string_with_args(in, 0, NULL);
556 }
557 
558 static bool is_end_of_token(char c)
559 {
560 	return !(isalnum(c) || c == '_' || c == '-');
561 }
562 
563 /*
564  * Expand variables in a token.  The parsing stops when a token separater
565  * (in most cases, it is a whitespace) is encountered.  'str' is updated to
566  * point to the next character.
567  *
568  * The returned string must be freed when done.
569  */
570 char *expand_one_token(const char **str)
571 {
572 	return __expand_string(str, is_end_of_token, 0, NULL);
573 }
574