xref: /linux-6.15/scripts/kconfig/preprocess.c (revision a9d83d74)
1104daea1SMasahiro Yamada // SPDX-License-Identifier: GPL-2.0
2104daea1SMasahiro Yamada //
3104daea1SMasahiro Yamada // Copyright (C) 2018 Masahiro Yamada <[email protected]>
4104daea1SMasahiro Yamada 
5558e78e3SMasahiro Yamada #include <ctype.h>
6104daea1SMasahiro Yamada #include <stdarg.h>
7104daea1SMasahiro Yamada #include <stdbool.h>
8104daea1SMasahiro Yamada #include <stdio.h>
9104daea1SMasahiro Yamada #include <stdlib.h>
10104daea1SMasahiro Yamada #include <string.h>
11104daea1SMasahiro Yamada 
12fbaf242cSMasahiro Yamada #include <array_size.h>
13fbaf242cSMasahiro Yamada #include <list.h>
14*a9d83d74SMasahiro Yamada #include <xalloc.h>
154ff7ceaeSMasahiro Yamada #include "internal.h"
16558e78e3SMasahiro Yamada #include "lkc.h"
17d3d16228SMasahiro Yamada #include "preprocess.h"
18104daea1SMasahiro Yamada 
19e298f3b4SMasahiro Yamada static char *expand_string_with_args(const char *in, int argc, char *argv[]);
205533397dSMasahiro Yamada static char *expand_string(const char *in);
21e298f3b4SMasahiro Yamada 
pperror(const char * format,...)22104daea1SMasahiro Yamada static void __attribute__((noreturn)) pperror(const char *format, ...)
23104daea1SMasahiro Yamada {
24104daea1SMasahiro Yamada 	va_list ap;
25104daea1SMasahiro Yamada 
264ff7ceaeSMasahiro Yamada 	fprintf(stderr, "%s:%d: ", cur_filename, yylineno);
27104daea1SMasahiro Yamada 	va_start(ap, format);
28104daea1SMasahiro Yamada 	vfprintf(stderr, format, ap);
29104daea1SMasahiro Yamada 	va_end(ap);
30104daea1SMasahiro Yamada 	fprintf(stderr, "\n");
31104daea1SMasahiro Yamada 
32104daea1SMasahiro Yamada 	exit(1);
33104daea1SMasahiro Yamada }
34104daea1SMasahiro Yamada 
35104daea1SMasahiro Yamada /*
36104daea1SMasahiro Yamada  * Environment variables
37104daea1SMasahiro Yamada  */
38104daea1SMasahiro Yamada static LIST_HEAD(env_list);
39104daea1SMasahiro Yamada 
40104daea1SMasahiro Yamada struct env {
41104daea1SMasahiro Yamada 	char *name;
42104daea1SMasahiro Yamada 	char *value;
43104daea1SMasahiro Yamada 	struct list_head node;
44104daea1SMasahiro Yamada };
45104daea1SMasahiro Yamada 
env_add(const char * name,const char * value)46104daea1SMasahiro Yamada static void env_add(const char *name, const char *value)
47104daea1SMasahiro Yamada {
48104daea1SMasahiro Yamada 	struct env *e;
49104daea1SMasahiro Yamada 
50104daea1SMasahiro Yamada 	e = xmalloc(sizeof(*e));
51104daea1SMasahiro Yamada 	e->name = xstrdup(name);
52104daea1SMasahiro Yamada 	e->value = xstrdup(value);
53104daea1SMasahiro Yamada 
54104daea1SMasahiro Yamada 	list_add_tail(&e->node, &env_list);
55104daea1SMasahiro Yamada }
56104daea1SMasahiro Yamada 
env_del(struct env * e)57104daea1SMasahiro Yamada static void env_del(struct env *e)
58104daea1SMasahiro Yamada {
59104daea1SMasahiro Yamada 	list_del(&e->node);
60104daea1SMasahiro Yamada 	free(e->name);
61104daea1SMasahiro Yamada 	free(e->value);
62104daea1SMasahiro Yamada 	free(e);
63104daea1SMasahiro Yamada }
64104daea1SMasahiro Yamada 
65104daea1SMasahiro Yamada /* The returned pointer must be freed when done */
env_expand(const char * name)66104daea1SMasahiro Yamada static char *env_expand(const char *name)
67104daea1SMasahiro Yamada {
68104daea1SMasahiro Yamada 	struct env *e;
69104daea1SMasahiro Yamada 	const char *value;
70104daea1SMasahiro Yamada 
71104daea1SMasahiro Yamada 	if (!*name)
72104daea1SMasahiro Yamada 		return NULL;
73104daea1SMasahiro Yamada 
74104daea1SMasahiro Yamada 	list_for_each_entry(e, &env_list, node) {
75104daea1SMasahiro Yamada 		if (!strcmp(name, e->name))
76104daea1SMasahiro Yamada 			return xstrdup(e->value);
77104daea1SMasahiro Yamada 	}
78104daea1SMasahiro Yamada 
79104daea1SMasahiro Yamada 	value = getenv(name);
80104daea1SMasahiro Yamada 	if (!value)
81104daea1SMasahiro Yamada 		return NULL;
82104daea1SMasahiro Yamada 
83104daea1SMasahiro Yamada 	/*
84104daea1SMasahiro Yamada 	 * We need to remember all referenced environment variables.
85104daea1SMasahiro Yamada 	 * They will be written out to include/config/auto.conf.cmd
86104daea1SMasahiro Yamada 	 */
87104daea1SMasahiro Yamada 	env_add(name, value);
88104daea1SMasahiro Yamada 
89104daea1SMasahiro Yamada 	return xstrdup(value);
90104daea1SMasahiro Yamada }
91104daea1SMasahiro Yamada 
env_write_dep(struct gstr * s)9256e634b0SMasahiro Yamada void env_write_dep(struct gstr *s)
93104daea1SMasahiro Yamada {
94104daea1SMasahiro Yamada 	struct env *e, *tmp;
95104daea1SMasahiro Yamada 
96104daea1SMasahiro Yamada 	list_for_each_entry_safe(e, tmp, &env_list, node) {
9756e634b0SMasahiro Yamada 		str_printf(s,
9856e634b0SMasahiro Yamada 			   "\n"
9956e634b0SMasahiro Yamada 			   "ifneq \"$(%s)\" \"%s\"\n"
10056e634b0SMasahiro Yamada 			   "$(autoconfig): FORCE\n"
10156e634b0SMasahiro Yamada 			   "endif\n",
10256e634b0SMasahiro Yamada 			   e->name, e->value);
103104daea1SMasahiro Yamada 		env_del(e);
104104daea1SMasahiro Yamada 	}
105104daea1SMasahiro Yamada }
106104daea1SMasahiro Yamada 
107e298f3b4SMasahiro Yamada /*
108e298f3b4SMasahiro Yamada  * Built-in functions
109e298f3b4SMasahiro Yamada  */
110e298f3b4SMasahiro Yamada struct function {
111e298f3b4SMasahiro Yamada 	const char *name;
112e298f3b4SMasahiro Yamada 	unsigned int min_args;
113e298f3b4SMasahiro Yamada 	unsigned int max_args;
114e298f3b4SMasahiro Yamada 	char *(*func)(int argc, char *argv[]);
115e298f3b4SMasahiro Yamada };
116e298f3b4SMasahiro Yamada 
do_error_if(int argc,char * argv[])1171d6272e6SMasahiro Yamada static char *do_error_if(int argc, char *argv[])
1181d6272e6SMasahiro Yamada {
1191d6272e6SMasahiro Yamada 	if (!strcmp(argv[0], "y"))
1201d6272e6SMasahiro Yamada 		pperror("%s", argv[1]);
1211d6272e6SMasahiro Yamada 
122135b4957SMasahiro Yamada 	return xstrdup("");
1231d6272e6SMasahiro Yamada }
1241d6272e6SMasahiro Yamada 
do_filename(int argc,char * argv[])125a702a617SMasahiro Yamada static char *do_filename(int argc, char *argv[])
126a702a617SMasahiro Yamada {
1274ff7ceaeSMasahiro Yamada 	return xstrdup(cur_filename);
128a702a617SMasahiro Yamada }
129a702a617SMasahiro Yamada 
do_info(int argc,char * argv[])1301d6272e6SMasahiro Yamada static char *do_info(int argc, char *argv[])
1311d6272e6SMasahiro Yamada {
1321d6272e6SMasahiro Yamada 	printf("%s\n", argv[0]);
1331d6272e6SMasahiro Yamada 
1341d6272e6SMasahiro Yamada 	return xstrdup("");
1351d6272e6SMasahiro Yamada }
1361d6272e6SMasahiro Yamada 
do_lineno(int argc,char * argv[])137a702a617SMasahiro Yamada static char *do_lineno(int argc, char *argv[])
138a702a617SMasahiro Yamada {
139a702a617SMasahiro Yamada 	char buf[16];
140a702a617SMasahiro Yamada 
141a702a617SMasahiro Yamada 	sprintf(buf, "%d", yylineno);
142a702a617SMasahiro Yamada 
143a702a617SMasahiro Yamada 	return xstrdup(buf);
144a702a617SMasahiro Yamada }
145a702a617SMasahiro Yamada 
do_shell(int argc,char * argv[])1462fd5b09cSMasahiro Yamada static char *do_shell(int argc, char *argv[])
1472fd5b09cSMasahiro Yamada {
1482fd5b09cSMasahiro Yamada 	FILE *p;
1498a4c5b2aSBrenda Streiff 	char buf[4096];
1502fd5b09cSMasahiro Yamada 	char *cmd;
1512fd5b09cSMasahiro Yamada 	size_t nread;
1522fd5b09cSMasahiro Yamada 	int i;
1532fd5b09cSMasahiro Yamada 
1542fd5b09cSMasahiro Yamada 	cmd = argv[0];
1552fd5b09cSMasahiro Yamada 
1562fd5b09cSMasahiro Yamada 	p = popen(cmd, "r");
1572fd5b09cSMasahiro Yamada 	if (!p) {
1582fd5b09cSMasahiro Yamada 		perror(cmd);
1592fd5b09cSMasahiro Yamada 		exit(1);
1602fd5b09cSMasahiro Yamada 	}
1612fd5b09cSMasahiro Yamada 
1622fd5b09cSMasahiro Yamada 	nread = fread(buf, 1, sizeof(buf), p);
1632fd5b09cSMasahiro Yamada 	if (nread == sizeof(buf))
1642fd5b09cSMasahiro Yamada 		nread--;
1652fd5b09cSMasahiro Yamada 
1662fd5b09cSMasahiro Yamada 	/* remove trailing new lines */
16773d1c580SJerry James 	while (nread > 0 && buf[nread - 1] == '\n')
1682fd5b09cSMasahiro Yamada 		nread--;
1692fd5b09cSMasahiro Yamada 
1702fd5b09cSMasahiro Yamada 	buf[nread] = 0;
1712fd5b09cSMasahiro Yamada 
1722fd5b09cSMasahiro Yamada 	/* replace a new line with a space */
1732fd5b09cSMasahiro Yamada 	for (i = 0; i < nread; i++) {
1742fd5b09cSMasahiro Yamada 		if (buf[i] == '\n')
1752fd5b09cSMasahiro Yamada 			buf[i] = ' ';
1762fd5b09cSMasahiro Yamada 	}
1772fd5b09cSMasahiro Yamada 
1782fd5b09cSMasahiro Yamada 	if (pclose(p) == -1) {
1792fd5b09cSMasahiro Yamada 		perror(cmd);
1802fd5b09cSMasahiro Yamada 		exit(1);
1812fd5b09cSMasahiro Yamada 	}
1822fd5b09cSMasahiro Yamada 
1832fd5b09cSMasahiro Yamada 	return xstrdup(buf);
1842fd5b09cSMasahiro Yamada }
1852fd5b09cSMasahiro Yamada 
do_warning_if(int argc,char * argv[])1861d6272e6SMasahiro Yamada static char *do_warning_if(int argc, char *argv[])
1871d6272e6SMasahiro Yamada {
1881d6272e6SMasahiro Yamada 	if (!strcmp(argv[0], "y"))
1894ff7ceaeSMasahiro Yamada 		fprintf(stderr, "%s:%d: %s\n", cur_filename, yylineno, argv[1]);
1901d6272e6SMasahiro Yamada 
1911d6272e6SMasahiro Yamada 	return xstrdup("");
1921d6272e6SMasahiro Yamada }
1931d6272e6SMasahiro Yamada 
194e298f3b4SMasahiro Yamada static const struct function function_table[] = {
195e298f3b4SMasahiro Yamada 	/* Name		MIN	MAX	Function */
1961d6272e6SMasahiro Yamada 	{ "error-if",	2,	2,	do_error_if },
197a702a617SMasahiro Yamada 	{ "filename",	0,	0,	do_filename },
1981d6272e6SMasahiro Yamada 	{ "info",	1,	1,	do_info },
199a702a617SMasahiro Yamada 	{ "lineno",	0,	0,	do_lineno },
2002fd5b09cSMasahiro Yamada 	{ "shell",	1,	1,	do_shell },
2011d6272e6SMasahiro Yamada 	{ "warning-if",	2,	2,	do_warning_if },
202e298f3b4SMasahiro Yamada };
203e298f3b4SMasahiro Yamada 
204e298f3b4SMasahiro Yamada #define FUNCTION_MAX_ARGS		16
205e298f3b4SMasahiro Yamada 
function_expand(const char * name,int argc,char * argv[])206e298f3b4SMasahiro Yamada static char *function_expand(const char *name, int argc, char *argv[])
207104daea1SMasahiro Yamada {
208e298f3b4SMasahiro Yamada 	const struct function *f;
209e298f3b4SMasahiro Yamada 	int i;
210e298f3b4SMasahiro Yamada 
211e298f3b4SMasahiro Yamada 	for (i = 0; i < ARRAY_SIZE(function_table); i++) {
212e298f3b4SMasahiro Yamada 		f = &function_table[i];
213e298f3b4SMasahiro Yamada 		if (strcmp(f->name, name))
214e298f3b4SMasahiro Yamada 			continue;
215e298f3b4SMasahiro Yamada 
216e298f3b4SMasahiro Yamada 		if (argc < f->min_args)
217e298f3b4SMasahiro Yamada 			pperror("too few function arguments passed to '%s'",
218e298f3b4SMasahiro Yamada 				name);
219e298f3b4SMasahiro Yamada 
220e298f3b4SMasahiro Yamada 		if (argc > f->max_args)
221e298f3b4SMasahiro Yamada 			pperror("too many function arguments passed to '%s'",
222e298f3b4SMasahiro Yamada 				name);
223e298f3b4SMasahiro Yamada 
224e298f3b4SMasahiro Yamada 		return f->func(argc, argv);
225e298f3b4SMasahiro Yamada 	}
226e298f3b4SMasahiro Yamada 
227e298f3b4SMasahiro Yamada 	return NULL;
228e298f3b4SMasahiro Yamada }
229e298f3b4SMasahiro Yamada 
230e298f3b4SMasahiro Yamada /*
2319ced3bddSMasahiro Yamada  * Variables (and user-defined functions)
2329ced3bddSMasahiro Yamada  */
2339ced3bddSMasahiro Yamada static LIST_HEAD(variable_list);
2349ced3bddSMasahiro Yamada 
2359ced3bddSMasahiro Yamada struct variable {
2369ced3bddSMasahiro Yamada 	char *name;
2379ced3bddSMasahiro Yamada 	char *value;
2381175c025SMasahiro Yamada 	enum variable_flavor flavor;
239915f6490SMasahiro Yamada 	int exp_count;
2409ced3bddSMasahiro Yamada 	struct list_head node;
2419ced3bddSMasahiro Yamada };
2429ced3bddSMasahiro Yamada 
variable_lookup(const char * name)2439ced3bddSMasahiro Yamada static struct variable *variable_lookup(const char *name)
2449ced3bddSMasahiro Yamada {
2459ced3bddSMasahiro Yamada 	struct variable *v;
2469ced3bddSMasahiro Yamada 
2479ced3bddSMasahiro Yamada 	list_for_each_entry(v, &variable_list, node) {
2489ced3bddSMasahiro Yamada 		if (!strcmp(name, v->name))
2499ced3bddSMasahiro Yamada 			return v;
2509ced3bddSMasahiro Yamada 	}
2519ced3bddSMasahiro Yamada 
2529ced3bddSMasahiro Yamada 	return NULL;
2539ced3bddSMasahiro Yamada }
2549ced3bddSMasahiro Yamada 
variable_expand(const char * name,int argc,char * argv[])2559ced3bddSMasahiro Yamada static char *variable_expand(const char *name, int argc, char *argv[])
2569ced3bddSMasahiro Yamada {
2579ced3bddSMasahiro Yamada 	struct variable *v;
2581175c025SMasahiro Yamada 	char *res;
2599ced3bddSMasahiro Yamada 
2609ced3bddSMasahiro Yamada 	v = variable_lookup(name);
2619ced3bddSMasahiro Yamada 	if (!v)
2629ced3bddSMasahiro Yamada 		return NULL;
2639ced3bddSMasahiro Yamada 
264915f6490SMasahiro Yamada 	if (argc == 0 && v->exp_count)
265915f6490SMasahiro Yamada 		pperror("Recursive variable '%s' references itself (eventually)",
266915f6490SMasahiro Yamada 			name);
267915f6490SMasahiro Yamada 
268915f6490SMasahiro Yamada 	if (v->exp_count > 1000)
269915f6490SMasahiro Yamada 		pperror("Too deep recursive expansion");
270915f6490SMasahiro Yamada 
271915f6490SMasahiro Yamada 	v->exp_count++;
272915f6490SMasahiro Yamada 
2731175c025SMasahiro Yamada 	if (v->flavor == VAR_RECURSIVE)
2741175c025SMasahiro Yamada 		res = expand_string_with_args(v->value, argc, argv);
2751175c025SMasahiro Yamada 	else
2761175c025SMasahiro Yamada 		res = xstrdup(v->value);
2771175c025SMasahiro Yamada 
278915f6490SMasahiro Yamada 	v->exp_count--;
279915f6490SMasahiro Yamada 
2801175c025SMasahiro Yamada 	return res;
2819ced3bddSMasahiro Yamada }
2829ced3bddSMasahiro Yamada 
variable_add(const char * name,const char * value,enum variable_flavor flavor)2831175c025SMasahiro Yamada void variable_add(const char *name, const char *value,
2841175c025SMasahiro Yamada 		  enum variable_flavor flavor)
2859ced3bddSMasahiro Yamada {
2869ced3bddSMasahiro Yamada 	struct variable *v;
287ed2a22f2SMasahiro Yamada 	char *new_value;
288ed2a22f2SMasahiro Yamada 	bool append = false;
2899ced3bddSMasahiro Yamada 
2909ced3bddSMasahiro Yamada 	v = variable_lookup(name);
2919ced3bddSMasahiro Yamada 	if (v) {
292ed2a22f2SMasahiro Yamada 		/* For defined variables, += inherits the existing flavor */
293ed2a22f2SMasahiro Yamada 		if (flavor == VAR_APPEND) {
294ed2a22f2SMasahiro Yamada 			flavor = v->flavor;
295ed2a22f2SMasahiro Yamada 			append = true;
2969ced3bddSMasahiro Yamada 		} else {
297ed2a22f2SMasahiro Yamada 			free(v->value);
298ed2a22f2SMasahiro Yamada 		}
299ed2a22f2SMasahiro Yamada 	} else {
300ed2a22f2SMasahiro Yamada 		/* For undefined variables, += assumes the recursive flavor */
301ed2a22f2SMasahiro Yamada 		if (flavor == VAR_APPEND)
302ed2a22f2SMasahiro Yamada 			flavor = VAR_RECURSIVE;
303ed2a22f2SMasahiro Yamada 
3049ced3bddSMasahiro Yamada 		v = xmalloc(sizeof(*v));
3059ced3bddSMasahiro Yamada 		v->name = xstrdup(name);
306915f6490SMasahiro Yamada 		v->exp_count = 0;
3079ced3bddSMasahiro Yamada 		list_add_tail(&v->node, &variable_list);
3089ced3bddSMasahiro Yamada 	}
3099ced3bddSMasahiro Yamada 
3101175c025SMasahiro Yamada 	v->flavor = flavor;
3111175c025SMasahiro Yamada 
3121175c025SMasahiro Yamada 	if (flavor == VAR_SIMPLE)
313ed2a22f2SMasahiro Yamada 		new_value = expand_string(value);
3141175c025SMasahiro Yamada 	else
315ed2a22f2SMasahiro Yamada 		new_value = xstrdup(value);
316ed2a22f2SMasahiro Yamada 
317ed2a22f2SMasahiro Yamada 	if (append) {
318ed2a22f2SMasahiro Yamada 		v->value = xrealloc(v->value,
319ed2a22f2SMasahiro Yamada 				    strlen(v->value) + strlen(new_value) + 2);
320ed2a22f2SMasahiro Yamada 		strcat(v->value, " ");
321ed2a22f2SMasahiro Yamada 		strcat(v->value, new_value);
322ed2a22f2SMasahiro Yamada 		free(new_value);
323ed2a22f2SMasahiro Yamada 	} else {
324ed2a22f2SMasahiro Yamada 		v->value = new_value;
325ed2a22f2SMasahiro Yamada 	}
3269ced3bddSMasahiro Yamada }
3279ced3bddSMasahiro Yamada 
variable_del(struct variable * v)3289ced3bddSMasahiro Yamada static void variable_del(struct variable *v)
3299ced3bddSMasahiro Yamada {
3309ced3bddSMasahiro Yamada 	list_del(&v->node);
3319ced3bddSMasahiro Yamada 	free(v->name);
3329ced3bddSMasahiro Yamada 	free(v->value);
3339ced3bddSMasahiro Yamada 	free(v);
3349ced3bddSMasahiro Yamada }
3359ced3bddSMasahiro Yamada 
variable_all_del(void)3369ced3bddSMasahiro Yamada void variable_all_del(void)
3379ced3bddSMasahiro Yamada {
3389ced3bddSMasahiro Yamada 	struct variable *v, *tmp;
3399ced3bddSMasahiro Yamada 
3409ced3bddSMasahiro Yamada 	list_for_each_entry_safe(v, tmp, &variable_list, node)
3419ced3bddSMasahiro Yamada 		variable_del(v);
3429ced3bddSMasahiro Yamada }
3439ced3bddSMasahiro Yamada 
3449ced3bddSMasahiro Yamada /*
345e298f3b4SMasahiro Yamada  * Evaluate a clause with arguments.  argc/argv are arguments from the upper
346e298f3b4SMasahiro Yamada  * function call.
347e298f3b4SMasahiro Yamada  *
348e298f3b4SMasahiro Yamada  * Returned string must be freed when done
349e298f3b4SMasahiro Yamada  */
eval_clause(const char * str,size_t len,int argc,char * argv[])350e298f3b4SMasahiro Yamada static char *eval_clause(const char *str, size_t len, int argc, char *argv[])
351e298f3b4SMasahiro Yamada {
3529ced3bddSMasahiro Yamada 	char *tmp, *name, *res, *endptr, *prev, *p;
353e298f3b4SMasahiro Yamada 	int new_argc = 0;
354e298f3b4SMasahiro Yamada 	char *new_argv[FUNCTION_MAX_ARGS];
355e298f3b4SMasahiro Yamada 	int nest = 0;
356e298f3b4SMasahiro Yamada 	int i;
3579ced3bddSMasahiro Yamada 	unsigned long n;
358104daea1SMasahiro Yamada 
359104daea1SMasahiro Yamada 	tmp = xstrndup(str, len);
360104daea1SMasahiro Yamada 
3619ced3bddSMasahiro Yamada 	/*
3629ced3bddSMasahiro Yamada 	 * If variable name is '1', '2', etc.  It is generally an argument
3639ced3bddSMasahiro Yamada 	 * from a user-function call (i.e. local-scope variable).  If not
3649ced3bddSMasahiro Yamada 	 * available, then look-up global-scope variables.
3659ced3bddSMasahiro Yamada 	 */
3669ced3bddSMasahiro Yamada 	n = strtoul(tmp, &endptr, 10);
3679ced3bddSMasahiro Yamada 	if (!*endptr && n > 0 && n <= argc) {
3689ced3bddSMasahiro Yamada 		res = xstrdup(argv[n - 1]);
3699ced3bddSMasahiro Yamada 		goto free_tmp;
3709ced3bddSMasahiro Yamada 	}
3719ced3bddSMasahiro Yamada 
372e298f3b4SMasahiro Yamada 	prev = p = tmp;
373104daea1SMasahiro Yamada 
374e298f3b4SMasahiro Yamada 	/*
375e298f3b4SMasahiro Yamada 	 * Split into tokens
376e298f3b4SMasahiro Yamada 	 * The function name and arguments are separated by a comma.
377e298f3b4SMasahiro Yamada 	 * For example, if the function call is like this:
378e298f3b4SMasahiro Yamada 	 *   $(foo,$(x),$(y))
379e298f3b4SMasahiro Yamada 	 *
380e298f3b4SMasahiro Yamada 	 * The input string for this helper should be:
381e298f3b4SMasahiro Yamada 	 *   foo,$(x),$(y)
382e298f3b4SMasahiro Yamada 	 *
383e298f3b4SMasahiro Yamada 	 * and split into:
384e298f3b4SMasahiro Yamada 	 *   new_argv[0] = 'foo'
385e298f3b4SMasahiro Yamada 	 *   new_argv[1] = '$(x)'
386e298f3b4SMasahiro Yamada 	 *   new_argv[2] = '$(y)'
387e298f3b4SMasahiro Yamada 	 */
388e298f3b4SMasahiro Yamada 	while (*p) {
389e298f3b4SMasahiro Yamada 		if (nest == 0 && *p == ',') {
390e298f3b4SMasahiro Yamada 			*p = 0;
391e298f3b4SMasahiro Yamada 			if (new_argc >= FUNCTION_MAX_ARGS)
392e298f3b4SMasahiro Yamada 				pperror("too many function arguments");
393e298f3b4SMasahiro Yamada 			new_argv[new_argc++] = prev;
394e298f3b4SMasahiro Yamada 			prev = p + 1;
395e298f3b4SMasahiro Yamada 		} else if (*p == '(') {
396e298f3b4SMasahiro Yamada 			nest++;
397e298f3b4SMasahiro Yamada 		} else if (*p == ')') {
398e298f3b4SMasahiro Yamada 			nest--;
399e298f3b4SMasahiro Yamada 		}
400e298f3b4SMasahiro Yamada 
401e298f3b4SMasahiro Yamada 		p++;
402e298f3b4SMasahiro Yamada 	}
403a3b7039bSKonstantin Meskhidze 
404a3b7039bSKonstantin Meskhidze 	if (new_argc >= FUNCTION_MAX_ARGS)
405a3b7039bSKonstantin Meskhidze 		pperror("too many function arguments");
406e298f3b4SMasahiro Yamada 	new_argv[new_argc++] = prev;
407e298f3b4SMasahiro Yamada 
408e298f3b4SMasahiro Yamada 	/*
409e298f3b4SMasahiro Yamada 	 * Shift arguments
410e298f3b4SMasahiro Yamada 	 * new_argv[0] represents a function name or a variable name.  Put it
411e298f3b4SMasahiro Yamada 	 * into 'name', then shift the rest of the arguments.  This simplifies
412e298f3b4SMasahiro Yamada 	 * 'const' handling.
413e298f3b4SMasahiro Yamada 	 */
414e298f3b4SMasahiro Yamada 	name = expand_string_with_args(new_argv[0], argc, argv);
415e298f3b4SMasahiro Yamada 	new_argc--;
416e298f3b4SMasahiro Yamada 	for (i = 0; i < new_argc; i++)
417e298f3b4SMasahiro Yamada 		new_argv[i] = expand_string_with_args(new_argv[i + 1],
418e298f3b4SMasahiro Yamada 						      argc, argv);
419e298f3b4SMasahiro Yamada 
4209ced3bddSMasahiro Yamada 	/* Search for variables */
4219ced3bddSMasahiro Yamada 	res = variable_expand(name, new_argc, new_argv);
4229ced3bddSMasahiro Yamada 	if (res)
4239ced3bddSMasahiro Yamada 		goto free;
4249ced3bddSMasahiro Yamada 
425e298f3b4SMasahiro Yamada 	/* Look for built-in functions */
426e298f3b4SMasahiro Yamada 	res = function_expand(name, new_argc, new_argv);
427104daea1SMasahiro Yamada 	if (res)
428104daea1SMasahiro Yamada 		goto free;
429104daea1SMasahiro Yamada 
430e298f3b4SMasahiro Yamada 	/* Last, try environment variable */
431e298f3b4SMasahiro Yamada 	if (new_argc == 0) {
432e298f3b4SMasahiro Yamada 		res = env_expand(name);
433e298f3b4SMasahiro Yamada 		if (res)
434e298f3b4SMasahiro Yamada 			goto free;
435e298f3b4SMasahiro Yamada 	}
436e298f3b4SMasahiro Yamada 
437104daea1SMasahiro Yamada 	res = xstrdup("");
438104daea1SMasahiro Yamada free:
439e298f3b4SMasahiro Yamada 	for (i = 0; i < new_argc; i++)
440e298f3b4SMasahiro Yamada 		free(new_argv[i]);
441104daea1SMasahiro Yamada 	free(name);
4429ced3bddSMasahiro Yamada free_tmp:
443104daea1SMasahiro Yamada 	free(tmp);
444104daea1SMasahiro Yamada 
445104daea1SMasahiro Yamada 	return res;
446104daea1SMasahiro Yamada }
447104daea1SMasahiro Yamada 
448104daea1SMasahiro Yamada /*
449104daea1SMasahiro Yamada  * Expand a string that follows '$'
450104daea1SMasahiro Yamada  *
451104daea1SMasahiro Yamada  * For example, if the input string is
452104daea1SMasahiro Yamada  *     ($(FOO)$($(BAR)))$(BAZ)
453104daea1SMasahiro Yamada  * this helper evaluates
454104daea1SMasahiro Yamada  *     $($(FOO)$($(BAR)))
455104daea1SMasahiro Yamada  * and returns a new string containing the expansion (note that the string is
456104daea1SMasahiro Yamada  * recursively expanded), also advancing 'str' to point to the next character
457104daea1SMasahiro Yamada  * after the corresponding closing parenthesis, in this case, *str will be
458104daea1SMasahiro Yamada  *     $(BAR)
459104daea1SMasahiro Yamada  */
expand_dollar_with_args(const char ** str,int argc,char * argv[])460e298f3b4SMasahiro Yamada static char *expand_dollar_with_args(const char **str, int argc, char *argv[])
461104daea1SMasahiro Yamada {
462104daea1SMasahiro Yamada 	const char *p = *str;
463104daea1SMasahiro Yamada 	const char *q;
464104daea1SMasahiro Yamada 	int nest = 0;
465104daea1SMasahiro Yamada 
466104daea1SMasahiro Yamada 	/*
467e298f3b4SMasahiro Yamada 	 * In Kconfig, variable/function references always start with "$(".
468104daea1SMasahiro Yamada 	 * Neither single-letter variables as in $A nor curly braces as in ${CC}
469104daea1SMasahiro Yamada 	 * are supported.  '$' not followed by '(' loses its special meaning.
470104daea1SMasahiro Yamada 	 */
471104daea1SMasahiro Yamada 	if (*p != '(') {
472104daea1SMasahiro Yamada 		*str = p;
473104daea1SMasahiro Yamada 		return xstrdup("$");
474104daea1SMasahiro Yamada 	}
475104daea1SMasahiro Yamada 
476104daea1SMasahiro Yamada 	p++;
477104daea1SMasahiro Yamada 	q = p;
478104daea1SMasahiro Yamada 	while (*q) {
479104daea1SMasahiro Yamada 		if (*q == '(') {
480104daea1SMasahiro Yamada 			nest++;
481104daea1SMasahiro Yamada 		} else if (*q == ')') {
482104daea1SMasahiro Yamada 			if (nest-- == 0)
483104daea1SMasahiro Yamada 				break;
484104daea1SMasahiro Yamada 		}
485104daea1SMasahiro Yamada 		q++;
486104daea1SMasahiro Yamada 	}
487104daea1SMasahiro Yamada 
488104daea1SMasahiro Yamada 	if (!*q)
489104daea1SMasahiro Yamada 		pperror("unterminated reference to '%s': missing ')'", p);
490104daea1SMasahiro Yamada 
491104daea1SMasahiro Yamada 	/* Advance 'str' to after the expanded initial portion of the string */
492104daea1SMasahiro Yamada 	*str = q + 1;
493104daea1SMasahiro Yamada 
494e298f3b4SMasahiro Yamada 	return eval_clause(p, q - p, argc, argv);
495104daea1SMasahiro Yamada }
496104daea1SMasahiro Yamada 
expand_dollar(const char ** str)497e298f3b4SMasahiro Yamada char *expand_dollar(const char **str)
498e298f3b4SMasahiro Yamada {
499e298f3b4SMasahiro Yamada 	return expand_dollar_with_args(str, 0, NULL);
500e298f3b4SMasahiro Yamada }
501e298f3b4SMasahiro Yamada 
__expand_string(const char ** str,bool (* is_end)(char c),int argc,char * argv[])502e298f3b4SMasahiro Yamada static char *__expand_string(const char **str, bool (*is_end)(char c),
503e298f3b4SMasahiro Yamada 			     int argc, char *argv[])
504104daea1SMasahiro Yamada {
505104daea1SMasahiro Yamada 	const char *in, *p;
506104daea1SMasahiro Yamada 	char *expansion, *out;
507104daea1SMasahiro Yamada 	size_t in_len, out_len;
508104daea1SMasahiro Yamada 
509104daea1SMasahiro Yamada 	out = xmalloc(1);
510104daea1SMasahiro Yamada 	*out = 0;
511104daea1SMasahiro Yamada 	out_len = 1;
512104daea1SMasahiro Yamada 
513104daea1SMasahiro Yamada 	p = in = *str;
514104daea1SMasahiro Yamada 
515104daea1SMasahiro Yamada 	while (1) {
516104daea1SMasahiro Yamada 		if (*p == '$') {
517104daea1SMasahiro Yamada 			in_len = p - in;
518104daea1SMasahiro Yamada 			p++;
519e298f3b4SMasahiro Yamada 			expansion = expand_dollar_with_args(&p, argc, argv);
520104daea1SMasahiro Yamada 			out_len += in_len + strlen(expansion);
521104daea1SMasahiro Yamada 			out = xrealloc(out, out_len);
522104daea1SMasahiro Yamada 			strncat(out, in, in_len);
523104daea1SMasahiro Yamada 			strcat(out, expansion);
524104daea1SMasahiro Yamada 			free(expansion);
525104daea1SMasahiro Yamada 			in = p;
526104daea1SMasahiro Yamada 			continue;
527104daea1SMasahiro Yamada 		}
528104daea1SMasahiro Yamada 
529104daea1SMasahiro Yamada 		if (is_end(*p))
530104daea1SMasahiro Yamada 			break;
531104daea1SMasahiro Yamada 
532104daea1SMasahiro Yamada 		p++;
533104daea1SMasahiro Yamada 	}
534104daea1SMasahiro Yamada 
535104daea1SMasahiro Yamada 	in_len = p - in;
536104daea1SMasahiro Yamada 	out_len += in_len;
537104daea1SMasahiro Yamada 	out = xrealloc(out, out_len);
538104daea1SMasahiro Yamada 	strncat(out, in, in_len);
539104daea1SMasahiro Yamada 
540104daea1SMasahiro Yamada 	/* Advance 'str' to the end character */
541104daea1SMasahiro Yamada 	*str = p;
542104daea1SMasahiro Yamada 
543104daea1SMasahiro Yamada 	return out;
544104daea1SMasahiro Yamada }
545104daea1SMasahiro Yamada 
is_end_of_str(char c)546104daea1SMasahiro Yamada static bool is_end_of_str(char c)
547104daea1SMasahiro Yamada {
548104daea1SMasahiro Yamada 	return !c;
549104daea1SMasahiro Yamada }
550104daea1SMasahiro Yamada 
551104daea1SMasahiro Yamada /*
552e298f3b4SMasahiro Yamada  * Expand variables and functions in the given string.  Undefined variables
553104daea1SMasahiro Yamada  * expand to an empty string.
554104daea1SMasahiro Yamada  * The returned string must be freed when done.
555104daea1SMasahiro Yamada  */
expand_string_with_args(const char * in,int argc,char * argv[])556e298f3b4SMasahiro Yamada static char *expand_string_with_args(const char *in, int argc, char *argv[])
557e298f3b4SMasahiro Yamada {
558e298f3b4SMasahiro Yamada 	return __expand_string(&in, is_end_of_str, argc, argv);
559e298f3b4SMasahiro Yamada }
560e298f3b4SMasahiro Yamada 
expand_string(const char * in)5615533397dSMasahiro Yamada static char *expand_string(const char *in)
562104daea1SMasahiro Yamada {
563e298f3b4SMasahiro Yamada 	return expand_string_with_args(in, 0, NULL);
564104daea1SMasahiro Yamada }
565104daea1SMasahiro Yamada 
is_end_of_token(char c)566104daea1SMasahiro Yamada static bool is_end_of_token(char c)
567104daea1SMasahiro Yamada {
568f5451582SMasahiro Yamada 	return !(isalnum(c) || c == '_' || c == '-');
569104daea1SMasahiro Yamada }
570104daea1SMasahiro Yamada 
571104daea1SMasahiro Yamada /*
572104daea1SMasahiro Yamada  * Expand variables in a token.  The parsing stops when a token separater
573104daea1SMasahiro Yamada  * (in most cases, it is a whitespace) is encountered.  'str' is updated to
574104daea1SMasahiro Yamada  * point to the next character.
575104daea1SMasahiro Yamada  *
576104daea1SMasahiro Yamada  * The returned string must be freed when done.
577104daea1SMasahiro Yamada  */
expand_one_token(const char ** str)578104daea1SMasahiro Yamada char *expand_one_token(const char **str)
579104daea1SMasahiro Yamada {
580e298f3b4SMasahiro Yamada 	return __expand_string(str, is_end_of_token, 0, NULL);
581104daea1SMasahiro Yamada }
582