0001
0002
0003
0004
0005 #include <ctype.h>
0006 #include <stdarg.h>
0007 #include <stdbool.h>
0008 #include <stdio.h>
0009 #include <stdlib.h>
0010 #include <string.h>
0011
0012 #include "list.h"
0013 #include "lkc.h"
0014
0015 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
0016
0017 static char *expand_string_with_args(const char *in, int argc, char *argv[]);
0018 static char *expand_string(const char *in);
0019
0020 static void __attribute__((noreturn)) pperror(const char *format, ...)
0021 {
0022 va_list ap;
0023
0024 fprintf(stderr, "%s:%d: ", current_file->name, yylineno);
0025 va_start(ap, format);
0026 vfprintf(stderr, format, ap);
0027 va_end(ap);
0028 fprintf(stderr, "\n");
0029
0030 exit(1);
0031 }
0032
0033
0034
0035
0036 static LIST_HEAD(env_list);
0037
0038 struct env {
0039 char *name;
0040 char *value;
0041 struct list_head node;
0042 };
0043
0044 static void env_add(const char *name, const char *value)
0045 {
0046 struct env *e;
0047
0048 e = xmalloc(sizeof(*e));
0049 e->name = xstrdup(name);
0050 e->value = xstrdup(value);
0051
0052 list_add_tail(&e->node, &env_list);
0053 }
0054
0055 static void env_del(struct env *e)
0056 {
0057 list_del(&e->node);
0058 free(e->name);
0059 free(e->value);
0060 free(e);
0061 }
0062
0063
0064 static char *env_expand(const char *name)
0065 {
0066 struct env *e;
0067 const char *value;
0068
0069 if (!*name)
0070 return NULL;
0071
0072 list_for_each_entry(e, &env_list, node) {
0073 if (!strcmp(name, e->name))
0074 return xstrdup(e->value);
0075 }
0076
0077 value = getenv(name);
0078 if (!value)
0079 return NULL;
0080
0081
0082
0083
0084
0085 env_add(name, value);
0086
0087 return xstrdup(value);
0088 }
0089
0090 void env_write_dep(FILE *f, const char *autoconfig_name)
0091 {
0092 struct env *e, *tmp;
0093
0094 list_for_each_entry_safe(e, tmp, &env_list, node) {
0095 fprintf(f, "ifneq \"$(%s)\" \"%s\"\n", e->name, e->value);
0096 fprintf(f, "%s: FORCE\n", autoconfig_name);
0097 fprintf(f, "endif\n");
0098 env_del(e);
0099 }
0100 }
0101
0102
0103
0104
0105 struct function {
0106 const char *name;
0107 unsigned int min_args;
0108 unsigned int max_args;
0109 char *(*func)(int argc, char *argv[]);
0110 };
0111
0112 static char *do_error_if(int argc, char *argv[])
0113 {
0114 if (!strcmp(argv[0], "y"))
0115 pperror("%s", argv[1]);
0116
0117 return xstrdup("");
0118 }
0119
0120 static char *do_filename(int argc, char *argv[])
0121 {
0122 return xstrdup(current_file->name);
0123 }
0124
0125 static char *do_info(int argc, char *argv[])
0126 {
0127 printf("%s\n", argv[0]);
0128
0129 return xstrdup("");
0130 }
0131
0132 static char *do_lineno(int argc, char *argv[])
0133 {
0134 char buf[16];
0135
0136 sprintf(buf, "%d", yylineno);
0137
0138 return xstrdup(buf);
0139 }
0140
0141 static char *do_shell(int argc, char *argv[])
0142 {
0143 FILE *p;
0144 char buf[4096];
0145 char *cmd;
0146 size_t nread;
0147 int i;
0148
0149 cmd = argv[0];
0150
0151 p = popen(cmd, "r");
0152 if (!p) {
0153 perror(cmd);
0154 exit(1);
0155 }
0156
0157 nread = fread(buf, 1, sizeof(buf), p);
0158 if (nread == sizeof(buf))
0159 nread--;
0160
0161
0162 while (nread > 0 && buf[nread - 1] == '\n')
0163 nread--;
0164
0165 buf[nread] = 0;
0166
0167
0168 for (i = 0; i < nread; i++) {
0169 if (buf[i] == '\n')
0170 buf[i] = ' ';
0171 }
0172
0173 if (pclose(p) == -1) {
0174 perror(cmd);
0175 exit(1);
0176 }
0177
0178 return xstrdup(buf);
0179 }
0180
0181 static char *do_warning_if(int argc, char *argv[])
0182 {
0183 if (!strcmp(argv[0], "y"))
0184 fprintf(stderr, "%s:%d: %s\n",
0185 current_file->name, yylineno, argv[1]);
0186
0187 return xstrdup("");
0188 }
0189
0190 static const struct function function_table[] = {
0191
0192 { "error-if", 2, 2, do_error_if },
0193 { "filename", 0, 0, do_filename },
0194 { "info", 1, 1, do_info },
0195 { "lineno", 0, 0, do_lineno },
0196 { "shell", 1, 1, do_shell },
0197 { "warning-if", 2, 2, do_warning_if },
0198 };
0199
0200 #define FUNCTION_MAX_ARGS 16
0201
0202 static char *function_expand(const char *name, int argc, char *argv[])
0203 {
0204 const struct function *f;
0205 int i;
0206
0207 for (i = 0; i < ARRAY_SIZE(function_table); i++) {
0208 f = &function_table[i];
0209 if (strcmp(f->name, name))
0210 continue;
0211
0212 if (argc < f->min_args)
0213 pperror("too few function arguments passed to '%s'",
0214 name);
0215
0216 if (argc > f->max_args)
0217 pperror("too many function arguments passed to '%s'",
0218 name);
0219
0220 return f->func(argc, argv);
0221 }
0222
0223 return NULL;
0224 }
0225
0226
0227
0228
0229 static LIST_HEAD(variable_list);
0230
0231 struct variable {
0232 char *name;
0233 char *value;
0234 enum variable_flavor flavor;
0235 int exp_count;
0236 struct list_head node;
0237 };
0238
0239 static struct variable *variable_lookup(const char *name)
0240 {
0241 struct variable *v;
0242
0243 list_for_each_entry(v, &variable_list, node) {
0244 if (!strcmp(name, v->name))
0245 return v;
0246 }
0247
0248 return NULL;
0249 }
0250
0251 static char *variable_expand(const char *name, int argc, char *argv[])
0252 {
0253 struct variable *v;
0254 char *res;
0255
0256 v = variable_lookup(name);
0257 if (!v)
0258 return NULL;
0259
0260 if (argc == 0 && v->exp_count)
0261 pperror("Recursive variable '%s' references itself (eventually)",
0262 name);
0263
0264 if (v->exp_count > 1000)
0265 pperror("Too deep recursive expansion");
0266
0267 v->exp_count++;
0268
0269 if (v->flavor == VAR_RECURSIVE)
0270 res = expand_string_with_args(v->value, argc, argv);
0271 else
0272 res = xstrdup(v->value);
0273
0274 v->exp_count--;
0275
0276 return res;
0277 }
0278
0279 void variable_add(const char *name, const char *value,
0280 enum variable_flavor flavor)
0281 {
0282 struct variable *v;
0283 char *new_value;
0284 bool append = false;
0285
0286 v = variable_lookup(name);
0287 if (v) {
0288
0289 if (flavor == VAR_APPEND) {
0290 flavor = v->flavor;
0291 append = true;
0292 } else {
0293 free(v->value);
0294 }
0295 } else {
0296
0297 if (flavor == VAR_APPEND)
0298 flavor = VAR_RECURSIVE;
0299
0300 v = xmalloc(sizeof(*v));
0301 v->name = xstrdup(name);
0302 v->exp_count = 0;
0303 list_add_tail(&v->node, &variable_list);
0304 }
0305
0306 v->flavor = flavor;
0307
0308 if (flavor == VAR_SIMPLE)
0309 new_value = expand_string(value);
0310 else
0311 new_value = xstrdup(value);
0312
0313 if (append) {
0314 v->value = xrealloc(v->value,
0315 strlen(v->value) + strlen(new_value) + 2);
0316 strcat(v->value, " ");
0317 strcat(v->value, new_value);
0318 free(new_value);
0319 } else {
0320 v->value = new_value;
0321 }
0322 }
0323
0324 static void variable_del(struct variable *v)
0325 {
0326 list_del(&v->node);
0327 free(v->name);
0328 free(v->value);
0329 free(v);
0330 }
0331
0332 void variable_all_del(void)
0333 {
0334 struct variable *v, *tmp;
0335
0336 list_for_each_entry_safe(v, tmp, &variable_list, node)
0337 variable_del(v);
0338 }
0339
0340
0341
0342
0343
0344
0345
0346 static char *eval_clause(const char *str, size_t len, int argc, char *argv[])
0347 {
0348 char *tmp, *name, *res, *endptr, *prev, *p;
0349 int new_argc = 0;
0350 char *new_argv[FUNCTION_MAX_ARGS];
0351 int nest = 0;
0352 int i;
0353 unsigned long n;
0354
0355 tmp = xstrndup(str, len);
0356
0357
0358
0359
0360
0361
0362 n = strtoul(tmp, &endptr, 10);
0363 if (!*endptr && n > 0 && n <= argc) {
0364 res = xstrdup(argv[n - 1]);
0365 goto free_tmp;
0366 }
0367
0368 prev = p = tmp;
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384 while (*p) {
0385 if (nest == 0 && *p == ',') {
0386 *p = 0;
0387 if (new_argc >= FUNCTION_MAX_ARGS)
0388 pperror("too many function arguments");
0389 new_argv[new_argc++] = prev;
0390 prev = p + 1;
0391 } else if (*p == '(') {
0392 nest++;
0393 } else if (*p == ')') {
0394 nest--;
0395 }
0396
0397 p++;
0398 }
0399 new_argv[new_argc++] = prev;
0400
0401
0402
0403
0404
0405
0406
0407 name = expand_string_with_args(new_argv[0], argc, argv);
0408 new_argc--;
0409 for (i = 0; i < new_argc; i++)
0410 new_argv[i] = expand_string_with_args(new_argv[i + 1],
0411 argc, argv);
0412
0413
0414 res = variable_expand(name, new_argc, new_argv);
0415 if (res)
0416 goto free;
0417
0418
0419 res = function_expand(name, new_argc, new_argv);
0420 if (res)
0421 goto free;
0422
0423
0424 if (new_argc == 0) {
0425 res = env_expand(name);
0426 if (res)
0427 goto free;
0428 }
0429
0430 res = xstrdup("");
0431 free:
0432 for (i = 0; i < new_argc; i++)
0433 free(new_argv[i]);
0434 free(name);
0435 free_tmp:
0436 free(tmp);
0437
0438 return res;
0439 }
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452
0453 static char *expand_dollar_with_args(const char **str, int argc, char *argv[])
0454 {
0455 const char *p = *str;
0456 const char *q;
0457 int nest = 0;
0458
0459
0460
0461
0462
0463
0464 if (*p != '(') {
0465 *str = p;
0466 return xstrdup("$");
0467 }
0468
0469 p++;
0470 q = p;
0471 while (*q) {
0472 if (*q == '(') {
0473 nest++;
0474 } else if (*q == ')') {
0475 if (nest-- == 0)
0476 break;
0477 }
0478 q++;
0479 }
0480
0481 if (!*q)
0482 pperror("unterminated reference to '%s': missing ')'", p);
0483
0484
0485 *str = q + 1;
0486
0487 return eval_clause(p, q - p, argc, argv);
0488 }
0489
0490 char *expand_dollar(const char **str)
0491 {
0492 return expand_dollar_with_args(str, 0, NULL);
0493 }
0494
0495 static char *__expand_string(const char **str, bool (*is_end)(char c),
0496 int argc, char *argv[])
0497 {
0498 const char *in, *p;
0499 char *expansion, *out;
0500 size_t in_len, out_len;
0501
0502 out = xmalloc(1);
0503 *out = 0;
0504 out_len = 1;
0505
0506 p = in = *str;
0507
0508 while (1) {
0509 if (*p == '$') {
0510 in_len = p - in;
0511 p++;
0512 expansion = expand_dollar_with_args(&p, argc, argv);
0513 out_len += in_len + strlen(expansion);
0514 out = xrealloc(out, out_len);
0515 strncat(out, in, in_len);
0516 strcat(out, expansion);
0517 free(expansion);
0518 in = p;
0519 continue;
0520 }
0521
0522 if (is_end(*p))
0523 break;
0524
0525 p++;
0526 }
0527
0528 in_len = p - in;
0529 out_len += in_len;
0530 out = xrealloc(out, out_len);
0531 strncat(out, in, in_len);
0532
0533
0534 *str = p;
0535
0536 return out;
0537 }
0538
0539 static bool is_end_of_str(char c)
0540 {
0541 return !c;
0542 }
0543
0544
0545
0546
0547
0548
0549 static char *expand_string_with_args(const char *in, int argc, char *argv[])
0550 {
0551 return __expand_string(&in, is_end_of_str, argc, argv);
0552 }
0553
0554 static char *expand_string(const char *in)
0555 {
0556 return expand_string_with_args(in, 0, NULL);
0557 }
0558
0559 static bool is_end_of_token(char c)
0560 {
0561 return !(isalnum(c) || c == '_' || c == '-');
0562 }
0563
0564
0565
0566
0567
0568
0569
0570
0571 char *expand_one_token(const char **str)
0572 {
0573 return __expand_string(str, is_end_of_token, 0, NULL);
0574 }