linux/scripts/kconfig/preprocess.c
<<
>>
Prefs
   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
  17static char *expand_string_with_args(const char *in, int argc, char *argv[]);
  18
  19static 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 */
  35static LIST_HEAD(env_list);
  36
  37struct env {
  38        char *name;
  39        char *value;
  40        struct list_head node;
  41};
  42
  43static 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
  54static 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 */
  63static 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
  89void 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 */
 104struct function {
 105        const char *name;
 106        unsigned int min_args;
 107        unsigned int max_args;
 108        char *(*func)(int argc, char *argv[]);
 109};
 110
 111static 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
 119static char *do_filename(int argc, char *argv[])
 120{
 121        return xstrdup(current_file->name);
 122}
 123
 124static char *do_info(int argc, char *argv[])
 125{
 126        printf("%s\n", argv[0]);
 127
 128        return xstrdup("");
 129}
 130
 131static 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
 140static 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
 180static 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
 189static 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
 201static 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 */
 228static LIST_HEAD(variable_list);
 229
 230struct variable {
 231        char *name;
 232        char *value;
 233        enum variable_flavor flavor;
 234        int exp_count;
 235        struct list_head node;
 236};
 237
 238static 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
 250static 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
 278void 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
 323static 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
 331void 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 */
 345static 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("");
 430free:
 431        for (i = 0; i < new_argc; i++)
 432                free(new_argv[i]);
 433        free(name);
 434free_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 */
 452static 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
 489char *expand_dollar(const char **str)
 490{
 491        return expand_dollar_with_args(str, 0, NULL);
 492}
 493
 494static 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
 538static 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 */
 548static 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
 553char *expand_string(const char *in)
 554{
 555        return expand_string_with_args(in, 0, NULL);
 556}
 557
 558static 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 */
 570char *expand_one_token(const char **str)
 571{
 572        return __expand_string(str, is_end_of_token, 0, NULL);
 573}
 574