preprocess.c 11 KB

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