root/scripts/kconfig/preprocess.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pperror
  2. env_add
  3. env_del
  4. env_expand
  5. env_write_dep
  6. do_error_if
  7. do_filename
  8. do_info
  9. do_lineno
  10. do_shell
  11. do_warning_if
  12. function_expand
  13. variable_lookup
  14. variable_expand
  15. variable_add
  16. variable_del
  17. variable_all_del
  18. eval_clause
  19. expand_dollar_with_args
  20. expand_dollar
  21. __expand_string
  22. is_end_of_str
  23. expand_string_with_args
  24. expand_string
  25. is_end_of_token
  26. expand_one_token

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

/* [<][>][^][v][top][bottom][index][help] */