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