Blame view

scripts/kconfig/preprocess.c 11 KB
104daea14   Masahiro Yamada   kconfig: referenc...
1
2
3
  // SPDX-License-Identifier: GPL-2.0
  //
  // Copyright (C) 2018 Masahiro Yamada <yamada.masahiro@socionext.com>
558e78e3c   Masahiro Yamada   kconfig: split so...
4
  #include <ctype.h>
104daea14   Masahiro Yamada   kconfig: referenc...
5
6
7
8
9
10
11
  #include <stdarg.h>
  #include <stdbool.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  
  #include "list.h"
558e78e3c   Masahiro Yamada   kconfig: split so...
12
  #include "lkc.h"
104daea14   Masahiro Yamada   kconfig: referenc...
13

e298f3b49   Masahiro Yamada   kconfig: add buil...
14
15
16
  #define ARRAY_SIZE(arr)		(sizeof(arr) / sizeof((arr)[0]))
  
  static char *expand_string_with_args(const char *in, int argc, char *argv[]);
5533397d1   Masahiro Yamada   kconfig: add stat...
17
  static char *expand_string(const char *in);
e298f3b49   Masahiro Yamada   kconfig: add buil...
18

104daea14   Masahiro Yamada   kconfig: referenc...
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
  static void __attribute__((noreturn)) pperror(const char *format, ...)
  {
  	va_list ap;
  
  	fprintf(stderr, "%s:%d: ", current_file->name, yylineno);
  	va_start(ap, format);
  	vfprintf(stderr, format, ap);
  	va_end(ap);
  	fprintf(stderr, "
  ");
  
  	exit(1);
  }
  
  /*
   * Environment variables
   */
  static LIST_HEAD(env_list);
  
  struct env {
  	char *name;
  	char *value;
  	struct list_head node;
  };
  
  static void env_add(const char *name, const char *value)
  {
  	struct env *e;
  
  	e = xmalloc(sizeof(*e));
  	e->name = xstrdup(name);
  	e->value = xstrdup(value);
  
  	list_add_tail(&e->node, &env_list);
  }
  
  static void env_del(struct env *e)
  {
  	list_del(&e->node);
  	free(e->name);
  	free(e->value);
  	free(e);
  }
  
  /* The returned pointer must be freed when done */
  static char *env_expand(const char *name)
  {
  	struct env *e;
  	const char *value;
  
  	if (!*name)
  		return NULL;
  
  	list_for_each_entry(e, &env_list, node) {
  		if (!strcmp(name, e->name))
  			return xstrdup(e->value);
  	}
  
  	value = getenv(name);
  	if (!value)
  		return NULL;
  
  	/*
  	 * We need to remember all referenced environment variables.
  	 * They will be written out to include/config/auto.conf.cmd
  	 */
  	env_add(name, value);
  
  	return xstrdup(value);
  }
  
  void env_write_dep(FILE *f, const char *autoconfig_name)
  {
  	struct env *e, *tmp;
  
  	list_for_each_entry_safe(e, tmp, &env_list, node) {
  		fprintf(f, "ifneq \"$(%s)\" \"%s\"
  ", e->name, e->value);
  		fprintf(f, "%s: FORCE
  ", autoconfig_name);
  		fprintf(f, "endif
  ");
  		env_del(e);
  	}
  }
e298f3b49   Masahiro Yamada   kconfig: add buil...
104
105
106
107
108
109
110
111
112
  /*
   * Built-in functions
   */
  struct function {
  	const char *name;
  	unsigned int min_args;
  	unsigned int max_args;
  	char *(*func)(int argc, char *argv[]);
  };
1d6272e6f   Masahiro Yamada   kconfig: add 'inf...
113
114
115
116
  static char *do_error_if(int argc, char *argv[])
  {
  	if (!strcmp(argv[0], "y"))
  		pperror("%s", argv[1]);
87c0d2ab8   Masahiro Yamada   kconfig: fix retu...
117
  	return xstrdup("");
1d6272e6f   Masahiro Yamada   kconfig: add 'inf...
118
  }
a702a6176   Masahiro Yamada   kconfig: add 'fil...
119
120
121
122
  static char *do_filename(int argc, char *argv[])
  {
  	return xstrdup(current_file->name);
  }
1d6272e6f   Masahiro Yamada   kconfig: add 'inf...
123
124
125
126
127
128
129
  static char *do_info(int argc, char *argv[])
  {
  	printf("%s
  ", argv[0]);
  
  	return xstrdup("");
  }
a702a6176   Masahiro Yamada   kconfig: add 'fil...
130
131
132
133
134
135
136
137
  static char *do_lineno(int argc, char *argv[])
  {
  	char buf[16];
  
  	sprintf(buf, "%d", yylineno);
  
  	return xstrdup(buf);
  }
2fd5b09c2   Masahiro Yamada   kconfig: add 'she...
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
  static char *do_shell(int argc, char *argv[])
  {
  	FILE *p;
  	char buf[256];
  	char *cmd;
  	size_t nread;
  	int i;
  
  	cmd = argv[0];
  
  	p = popen(cmd, "r");
  	if (!p) {
  		perror(cmd);
  		exit(1);
  	}
  
  	nread = fread(buf, 1, sizeof(buf), p);
  	if (nread == sizeof(buf))
  		nread--;
  
  	/* remove trailing new lines */
73d1c580f   Jerry James   kconfig: loop bou...
159
160
  	while (nread > 0 && buf[nread - 1] == '
  ')
2fd5b09c2   Masahiro Yamada   kconfig: add 'she...
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
  		nread--;
  
  	buf[nread] = 0;
  
  	/* replace a new line with a space */
  	for (i = 0; i < nread; i++) {
  		if (buf[i] == '
  ')
  			buf[i] = ' ';
  	}
  
  	if (pclose(p) == -1) {
  		perror(cmd);
  		exit(1);
  	}
  
  	return xstrdup(buf);
  }
1d6272e6f   Masahiro Yamada   kconfig: add 'inf...
179
180
181
182
183
184
185
186
187
  static char *do_warning_if(int argc, char *argv[])
  {
  	if (!strcmp(argv[0], "y"))
  		fprintf(stderr, "%s:%d: %s
  ",
  			current_file->name, yylineno, argv[1]);
  
  	return xstrdup("");
  }
e298f3b49   Masahiro Yamada   kconfig: add buil...
188
189
  static const struct function function_table[] = {
  	/* Name		MIN	MAX	Function */
1d6272e6f   Masahiro Yamada   kconfig: add 'inf...
190
  	{ "error-if",	2,	2,	do_error_if },
a702a6176   Masahiro Yamada   kconfig: add 'fil...
191
  	{ "filename",	0,	0,	do_filename },
1d6272e6f   Masahiro Yamada   kconfig: add 'inf...
192
  	{ "info",	1,	1,	do_info },
a702a6176   Masahiro Yamada   kconfig: add 'fil...
193
  	{ "lineno",	0,	0,	do_lineno },
2fd5b09c2   Masahiro Yamada   kconfig: add 'she...
194
  	{ "shell",	1,	1,	do_shell },
1d6272e6f   Masahiro Yamada   kconfig: add 'inf...
195
  	{ "warning-if",	2,	2,	do_warning_if },
e298f3b49   Masahiro Yamada   kconfig: add buil...
196
197
198
199
200
  };
  
  #define FUNCTION_MAX_ARGS		16
  
  static char *function_expand(const char *name, int argc, char *argv[])
104daea14   Masahiro Yamada   kconfig: referenc...
201
  {
e298f3b49   Masahiro Yamada   kconfig: add buil...
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
  	const struct function *f;
  	int i;
  
  	for (i = 0; i < ARRAY_SIZE(function_table); i++) {
  		f = &function_table[i];
  		if (strcmp(f->name, name))
  			continue;
  
  		if (argc < f->min_args)
  			pperror("too few function arguments passed to '%s'",
  				name);
  
  		if (argc > f->max_args)
  			pperror("too many function arguments passed to '%s'",
  				name);
  
  		return f->func(argc, argv);
  	}
  
  	return NULL;
  }
  
  /*
9ced3bdde   Masahiro Yamada   kconfig: support ...
225
226
227
228
229
230
231
   * Variables (and user-defined functions)
   */
  static LIST_HEAD(variable_list);
  
  struct variable {
  	char *name;
  	char *value;
1175c0250   Masahiro Yamada   kconfig: support ...
232
  	enum variable_flavor flavor;
915f64901   Masahiro Yamada   kconfig: error ou...
233
  	int exp_count;
9ced3bdde   Masahiro Yamada   kconfig: support ...
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
  	struct list_head node;
  };
  
  static struct variable *variable_lookup(const char *name)
  {
  	struct variable *v;
  
  	list_for_each_entry(v, &variable_list, node) {
  		if (!strcmp(name, v->name))
  			return v;
  	}
  
  	return NULL;
  }
  
  static char *variable_expand(const char *name, int argc, char *argv[])
  {
  	struct variable *v;
1175c0250   Masahiro Yamada   kconfig: support ...
252
  	char *res;
9ced3bdde   Masahiro Yamada   kconfig: support ...
253
254
255
256
  
  	v = variable_lookup(name);
  	if (!v)
  		return NULL;
915f64901   Masahiro Yamada   kconfig: error ou...
257
258
259
260
261
262
263
264
  	if (argc == 0 && v->exp_count)
  		pperror("Recursive variable '%s' references itself (eventually)",
  			name);
  
  	if (v->exp_count > 1000)
  		pperror("Too deep recursive expansion");
  
  	v->exp_count++;
1175c0250   Masahiro Yamada   kconfig: support ...
265
266
267
268
  	if (v->flavor == VAR_RECURSIVE)
  		res = expand_string_with_args(v->value, argc, argv);
  	else
  		res = xstrdup(v->value);
915f64901   Masahiro Yamada   kconfig: error ou...
269
  	v->exp_count--;
1175c0250   Masahiro Yamada   kconfig: support ...
270
  	return res;
9ced3bdde   Masahiro Yamada   kconfig: support ...
271
  }
1175c0250   Masahiro Yamada   kconfig: support ...
272
273
  void variable_add(const char *name, const char *value,
  		  enum variable_flavor flavor)
9ced3bdde   Masahiro Yamada   kconfig: support ...
274
275
  {
  	struct variable *v;
ed2a22f27   Masahiro Yamada   kconfig: support ...
276
277
  	char *new_value;
  	bool append = false;
9ced3bdde   Masahiro Yamada   kconfig: support ...
278
279
280
  
  	v = variable_lookup(name);
  	if (v) {
ed2a22f27   Masahiro Yamada   kconfig: support ...
281
282
283
284
285
286
287
  		/* For defined variables, += inherits the existing flavor */
  		if (flavor == VAR_APPEND) {
  			flavor = v->flavor;
  			append = true;
  		} else {
  			free(v->value);
  		}
9ced3bdde   Masahiro Yamada   kconfig: support ...
288
  	} else {
ed2a22f27   Masahiro Yamada   kconfig: support ...
289
290
291
  		/* For undefined variables, += assumes the recursive flavor */
  		if (flavor == VAR_APPEND)
  			flavor = VAR_RECURSIVE;
9ced3bdde   Masahiro Yamada   kconfig: support ...
292
293
  		v = xmalloc(sizeof(*v));
  		v->name = xstrdup(name);
915f64901   Masahiro Yamada   kconfig: error ou...
294
  		v->exp_count = 0;
9ced3bdde   Masahiro Yamada   kconfig: support ...
295
296
  		list_add_tail(&v->node, &variable_list);
  	}
1175c0250   Masahiro Yamada   kconfig: support ...
297
298
299
  	v->flavor = flavor;
  
  	if (flavor == VAR_SIMPLE)
ed2a22f27   Masahiro Yamada   kconfig: support ...
300
  		new_value = expand_string(value);
1175c0250   Masahiro Yamada   kconfig: support ...
301
  	else
ed2a22f27   Masahiro Yamada   kconfig: support ...
302
303
304
305
306
307
308
309
310
311
312
  		new_value = xstrdup(value);
  
  	if (append) {
  		v->value = xrealloc(v->value,
  				    strlen(v->value) + strlen(new_value) + 2);
  		strcat(v->value, " ");
  		strcat(v->value, new_value);
  		free(new_value);
  	} else {
  		v->value = new_value;
  	}
9ced3bdde   Masahiro Yamada   kconfig: support ...
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
  }
  
  static void variable_del(struct variable *v)
  {
  	list_del(&v->node);
  	free(v->name);
  	free(v->value);
  	free(v);
  }
  
  void variable_all_del(void)
  {
  	struct variable *v, *tmp;
  
  	list_for_each_entry_safe(v, tmp, &variable_list, node)
  		variable_del(v);
  }
  
  /*
e298f3b49   Masahiro Yamada   kconfig: add buil...
332
333
334
335
336
337
338
   * Evaluate a clause with arguments.  argc/argv are arguments from the upper
   * function call.
   *
   * Returned string must be freed when done
   */
  static char *eval_clause(const char *str, size_t len, int argc, char *argv[])
  {
9ced3bdde   Masahiro Yamada   kconfig: support ...
339
  	char *tmp, *name, *res, *endptr, *prev, *p;
e298f3b49   Masahiro Yamada   kconfig: add buil...
340
341
342
343
  	int new_argc = 0;
  	char *new_argv[FUNCTION_MAX_ARGS];
  	int nest = 0;
  	int i;
9ced3bdde   Masahiro Yamada   kconfig: support ...
344
  	unsigned long n;
104daea14   Masahiro Yamada   kconfig: referenc...
345
346
  
  	tmp = xstrndup(str, len);
9ced3bdde   Masahiro Yamada   kconfig: support ...
347
348
349
350
351
352
353
354
355
356
  	/*
  	 * If variable name is '1', '2', etc.  It is generally an argument
  	 * from a user-function call (i.e. local-scope variable).  If not
  	 * available, then look-up global-scope variables.
  	 */
  	n = strtoul(tmp, &endptr, 10);
  	if (!*endptr && n > 0 && n <= argc) {
  		res = xstrdup(argv[n - 1]);
  		goto free_tmp;
  	}
e298f3b49   Masahiro Yamada   kconfig: add buil...
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
  	prev = p = tmp;
  
  	/*
  	 * Split into tokens
  	 * The function name and arguments are separated by a comma.
  	 * For example, if the function call is like this:
  	 *   $(foo,$(x),$(y))
  	 *
  	 * The input string for this helper should be:
  	 *   foo,$(x),$(y)
  	 *
  	 * and split into:
  	 *   new_argv[0] = 'foo'
  	 *   new_argv[1] = '$(x)'
  	 *   new_argv[2] = '$(y)'
  	 */
  	while (*p) {
  		if (nest == 0 && *p == ',') {
  			*p = 0;
  			if (new_argc >= FUNCTION_MAX_ARGS)
  				pperror("too many function arguments");
  			new_argv[new_argc++] = prev;
  			prev = p + 1;
  		} else if (*p == '(') {
  			nest++;
  		} else if (*p == ')') {
  			nest--;
  		}
104daea14   Masahiro Yamada   kconfig: referenc...
385

e298f3b49   Masahiro Yamada   kconfig: add buil...
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
  		p++;
  	}
  	new_argv[new_argc++] = prev;
  
  	/*
  	 * Shift arguments
  	 * new_argv[0] represents a function name or a variable name.  Put it
  	 * into 'name', then shift the rest of the arguments.  This simplifies
  	 * 'const' handling.
  	 */
  	name = expand_string_with_args(new_argv[0], argc, argv);
  	new_argc--;
  	for (i = 0; i < new_argc; i++)
  		new_argv[i] = expand_string_with_args(new_argv[i + 1],
  						      argc, argv);
9ced3bdde   Masahiro Yamada   kconfig: support ...
401
402
403
404
  	/* Search for variables */
  	res = variable_expand(name, new_argc, new_argv);
  	if (res)
  		goto free;
e298f3b49   Masahiro Yamada   kconfig: add buil...
405
406
  	/* Look for built-in functions */
  	res = function_expand(name, new_argc, new_argv);
104daea14   Masahiro Yamada   kconfig: referenc...
407
408
  	if (res)
  		goto free;
e298f3b49   Masahiro Yamada   kconfig: add buil...
409
410
411
412
413
414
  	/* Last, try environment variable */
  	if (new_argc == 0) {
  		res = env_expand(name);
  		if (res)
  			goto free;
  	}
104daea14   Masahiro Yamada   kconfig: referenc...
415
416
  	res = xstrdup("");
  free:
e298f3b49   Masahiro Yamada   kconfig: add buil...
417
418
  	for (i = 0; i < new_argc; i++)
  		free(new_argv[i]);
104daea14   Masahiro Yamada   kconfig: referenc...
419
  	free(name);
9ced3bdde   Masahiro Yamada   kconfig: support ...
420
  free_tmp:
104daea14   Masahiro Yamada   kconfig: referenc...
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
  	free(tmp);
  
  	return res;
  }
  
  /*
   * Expand a string that follows '$'
   *
   * For example, if the input string is
   *     ($(FOO)$($(BAR)))$(BAZ)
   * this helper evaluates
   *     $($(FOO)$($(BAR)))
   * and returns a new string containing the expansion (note that the string is
   * recursively expanded), also advancing 'str' to point to the next character
   * after the corresponding closing parenthesis, in this case, *str will be
   *     $(BAR)
   */
e298f3b49   Masahiro Yamada   kconfig: add buil...
438
  static char *expand_dollar_with_args(const char **str, int argc, char *argv[])
104daea14   Masahiro Yamada   kconfig: referenc...
439
440
441
442
443
444
  {
  	const char *p = *str;
  	const char *q;
  	int nest = 0;
  
  	/*
e298f3b49   Masahiro Yamada   kconfig: add buil...
445
  	 * In Kconfig, variable/function references always start with "$(".
104daea14   Masahiro Yamada   kconfig: referenc...
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
  	 * Neither single-letter variables as in $A nor curly braces as in ${CC}
  	 * are supported.  '$' not followed by '(' loses its special meaning.
  	 */
  	if (*p != '(') {
  		*str = p;
  		return xstrdup("$");
  	}
  
  	p++;
  	q = p;
  	while (*q) {
  		if (*q == '(') {
  			nest++;
  		} else if (*q == ')') {
  			if (nest-- == 0)
  				break;
  		}
  		q++;
  	}
  
  	if (!*q)
  		pperror("unterminated reference to '%s': missing ')'", p);
  
  	/* Advance 'str' to after the expanded initial portion of the string */
  	*str = q + 1;
e298f3b49   Masahiro Yamada   kconfig: add buil...
471
472
473
474
475
476
  	return eval_clause(p, q - p, argc, argv);
  }
  
  char *expand_dollar(const char **str)
  {
  	return expand_dollar_with_args(str, 0, NULL);
104daea14   Masahiro Yamada   kconfig: referenc...
477
  }
e298f3b49   Masahiro Yamada   kconfig: add buil...
478
479
  static char *__expand_string(const char **str, bool (*is_end)(char c),
  			     int argc, char *argv[])
104daea14   Masahiro Yamada   kconfig: referenc...
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
  {
  	const char *in, *p;
  	char *expansion, *out;
  	size_t in_len, out_len;
  
  	out = xmalloc(1);
  	*out = 0;
  	out_len = 1;
  
  	p = in = *str;
  
  	while (1) {
  		if (*p == '$') {
  			in_len = p - in;
  			p++;
e298f3b49   Masahiro Yamada   kconfig: add buil...
495
  			expansion = expand_dollar_with_args(&p, argc, argv);
104daea14   Masahiro Yamada   kconfig: referenc...
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
  			out_len += in_len + strlen(expansion);
  			out = xrealloc(out, out_len);
  			strncat(out, in, in_len);
  			strcat(out, expansion);
  			free(expansion);
  			in = p;
  			continue;
  		}
  
  		if (is_end(*p))
  			break;
  
  		p++;
  	}
  
  	in_len = p - in;
  	out_len += in_len;
  	out = xrealloc(out, out_len);
  	strncat(out, in, in_len);
  
  	/* Advance 'str' to the end character */
  	*str = p;
  
  	return out;
  }
  
  static bool is_end_of_str(char c)
  {
  	return !c;
  }
  
  /*
e298f3b49   Masahiro Yamada   kconfig: add buil...
528
   * Expand variables and functions in the given string.  Undefined variables
104daea14   Masahiro Yamada   kconfig: referenc...
529
530
531
   * expand to an empty string.
   * The returned string must be freed when done.
   */
e298f3b49   Masahiro Yamada   kconfig: add buil...
532
533
534
535
  static char *expand_string_with_args(const char *in, int argc, char *argv[])
  {
  	return __expand_string(&in, is_end_of_str, argc, argv);
  }
5533397d1   Masahiro Yamada   kconfig: add stat...
536
  static char *expand_string(const char *in)
104daea14   Masahiro Yamada   kconfig: referenc...
537
  {
e298f3b49   Masahiro Yamada   kconfig: add buil...
538
  	return expand_string_with_args(in, 0, NULL);
104daea14   Masahiro Yamada   kconfig: referenc...
539
540
541
542
  }
  
  static bool is_end_of_token(char c)
  {
f5451582c   Masahiro Yamada   kconfig: stop sup...
543
  	return !(isalnum(c) || c == '_' || c == '-');
104daea14   Masahiro Yamada   kconfig: referenc...
544
545
546
547
548
549
550
551
552
553
554
  }
  
  /*
   * Expand variables in a token.  The parsing stops when a token separater
   * (in most cases, it is a whitespace) is encountered.  'str' is updated to
   * point to the next character.
   *
   * The returned string must be freed when done.
   */
  char *expand_one_token(const char **str)
  {
e298f3b49   Masahiro Yamada   kconfig: add buil...
555
  	return __expand_string(str, is_end_of_token, 0, NULL);
104daea14   Masahiro Yamada   kconfig: referenc...
556
  }