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[]);
  18static char *expand_string(const char *in);
  19
  20static 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 */
  36static LIST_HEAD(env_list);
  37
  38struct env {
  39        char *name;
  40        char *value;
  41        struct list_head node;
  42};
  43
  44static 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
  55static 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 */
  64static 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
  90void 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 */
 105struct function {
 106        const char *name;
 107        unsigned int min_args;
 108        unsigned int max_args;
 109        char *(*func)(int argc, char *argv[]);
 110};
 111
 112static 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
 120static char *do_filename(int argc, char *argv[])
 121{
 122        return xstrdup(current_file->name);
 123}
 124
 125static char *do_info(int argc, char *argv[])
 126{
 127        printf("%s\n", argv[0]);
 128
 129        return xstrdup("");
 130}
 131
 132static 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
 141static 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
 181static 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
 190static 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
 202static 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 */
 229static LIST_HEAD(variable_list);
 230
 231struct variable {
 232        char *name;
 233        char *value;
 234        enum variable_flavor flavor;
 235        int exp_count;
 236        struct list_head node;
 237};
 238
 239static 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
 251static 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
 279void 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
 324static 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
 332void 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 */
 346static 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("");
 431free:
 432        for (i = 0; i < new_argc; i++)
 433                free(new_argv[i]);
 434        free(name);
 435free_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 */
 453static 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
 490char *expand_dollar(const char **str)
 491{
 492        return expand_dollar_with_args(str, 0, NULL);
 493}
 494
 495static 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
 539static 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 */
 549static 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
 554static char *expand_string(const char *in)
 555{
 556        return expand_string_with_args(in, 0, NULL);
 557}
 558
 559static 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 */
 571char *expand_one_token(const char **str)
 572{
 573        return __expand_string(str, is_end_of_token, 0, NULL);
 574}
 575