at v5.0 11 kB view raw
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}