| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: var.c,v 1.604 2020/10/30 16:54:38 rillig Exp $ */ | | 1 | /* $NetBSD: var.c,v 1.605 2020/10/30 17:10:48 rillig Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1988, 1989, 1990, 1993 | | 4 | * Copyright (c) 1988, 1989, 1990, 1993 |
5 | * The Regents of the University of California. All rights reserved. | | 5 | * The Regents of the University of California. All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to Berkeley by | | 7 | * This code is derived from software contributed to Berkeley by |
8 | * Adam de Boor. | | 8 | * Adam de Boor. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -119,27 +119,27 @@ | | | @@ -119,27 +119,27 @@ |
119 | #include <sys/types.h> | | 119 | #include <sys/types.h> |
120 | #include <regex.h> | | 120 | #include <regex.h> |
121 | #endif | | 121 | #endif |
122 | #include <inttypes.h> | | 122 | #include <inttypes.h> |
123 | #include <limits.h> | | 123 | #include <limits.h> |
124 | #include <time.h> | | 124 | #include <time.h> |
125 | | | 125 | |
126 | #include "make.h" | | 126 | #include "make.h" |
127 | #include "dir.h" | | 127 | #include "dir.h" |
128 | #include "job.h" | | 128 | #include "job.h" |
129 | #include "metachar.h" | | 129 | #include "metachar.h" |
130 | | | 130 | |
131 | /* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ | | 131 | /* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ |
132 | MAKE_RCSID("$NetBSD: var.c,v 1.604 2020/10/30 16:54:38 rillig Exp $"); | | 132 | MAKE_RCSID("$NetBSD: var.c,v 1.605 2020/10/30 17:10:48 rillig Exp $"); |
133 | | | 133 | |
134 | #define VAR_DEBUG1(fmt, arg1) DEBUG1(VAR, fmt, arg1) | | 134 | #define VAR_DEBUG1(fmt, arg1) DEBUG1(VAR, fmt, arg1) |
135 | #define VAR_DEBUG2(fmt, arg1, arg2) DEBUG2(VAR, fmt, arg1, arg2) | | 135 | #define VAR_DEBUG2(fmt, arg1, arg2) DEBUG2(VAR, fmt, arg1, arg2) |
136 | #define VAR_DEBUG3(fmt, arg1, arg2, arg3) DEBUG3(VAR, fmt, arg1, arg2, arg3) | | 136 | #define VAR_DEBUG3(fmt, arg1, arg2, arg3) DEBUG3(VAR, fmt, arg1, arg2, arg3) |
137 | #define VAR_DEBUG4(fmt, arg1, arg2, arg3, arg4) DEBUG4(VAR, fmt, arg1, arg2, arg3, arg4) | | 137 | #define VAR_DEBUG4(fmt, arg1, arg2, arg3, arg4) DEBUG4(VAR, fmt, arg1, arg2, arg3, arg4) |
138 | | | 138 | |
139 | ENUM_FLAGS_RTTI_3(VarEvalFlags, | | 139 | ENUM_FLAGS_RTTI_3(VarEvalFlags, |
140 | VARE_UNDEFERR, VARE_WANTRES, VARE_ASSIGN); | | 140 | VARE_UNDEFERR, VARE_WANTRES, VARE_ASSIGN); |
141 | | | 141 | |
142 | /* | | 142 | /* |
143 | * This lets us tell if we have replaced the original environ | | 143 | * This lets us tell if we have replaced the original environ |
144 | * (which we cannot free). | | 144 | * (which we cannot free). |
145 | */ | | 145 | */ |
| @@ -338,66 +338,60 @@ CanonicalVarname(const char *name) | | | @@ -338,66 +338,60 @@ CanonicalVarname(const char *name) |
338 | } | | 338 | } |
339 | | | 339 | |
340 | /* GNU make has an additional alias $^ == ${.ALLSRC}. */ | | 340 | /* GNU make has an additional alias $^ == ${.ALLSRC}. */ |
341 | | | 341 | |
342 | return name; | | 342 | return name; |
343 | } | | 343 | } |
344 | | | 344 | |
345 | static Var * | | 345 | static Var * |
346 | GNode_FindVar(GNode *ctxt, const char *varname, unsigned int hash) | | 346 | GNode_FindVar(GNode *ctxt, const char *varname, unsigned int hash) |
347 | { | | 347 | { |
348 | return HashTable_FindValueHash(&ctxt->context, varname, hash); | | 348 | return HashTable_FindValueHash(&ctxt->context, varname, hash); |
349 | } | | 349 | } |
350 | | | 350 | |
351 | /*- | | 351 | /* Find the variable in the context, and maybe in other contexts as well. |
352 | *----------------------------------------------------------------------- | | | |
353 | * VarFind -- | | | |
354 | * Find the given variable in the given context and any other contexts | | | |
355 | * indicated. | | | |
356 | * | | 352 | * |
357 | * Input: | | 353 | * Input: |
358 | * name name to find | | 354 | * name name to find |
359 | * ctxt context in which to find it | | 355 | * ctxt context in which to look first |
360 | * elsewhere to look in other contexts as well | | 356 | * elsewhere TRUE to look in other contexts as well |
361 | * | | 357 | * |
362 | * Results: | | 358 | * Results: |
363 | * A pointer to the structure describing the desired variable or | | 359 | * The found variable, or NULL if the variable does not exist. |
364 | * NULL if the variable does not exist. | | 360 | * If the variable is an environment variable, it must be freed using |
365 | *----------------------------------------------------------------------- | | 361 | * VarFreeEnv after use. |
366 | */ | | 362 | */ |
367 | static Var * | | 363 | static Var * |
368 | VarFind(const char *name, GNode *ctxt, Boolean elsewhere) | | 364 | VarFind(const char *name, GNode *ctxt, Boolean elsewhere) |
369 | { | | 365 | { |
370 | Var *var; | | 366 | Var *var; |
371 | unsigned int nameHash; | | 367 | unsigned int nameHash; |
372 | | | 368 | |
373 | /* | | 369 | /* |
374 | * If the variable name begins with a '.', it could very well be one of | | 370 | * If the variable name begins with a '.', it could very well be one of |
375 | * the local ones. We check the name against all the local variables | | 371 | * the local ones. We check the name against all the local variables |
376 | * and substitute the short version in for 'name' if it matches one of | | 372 | * and substitute the short version in for 'name' if it matches one of |
377 | * them. | | 373 | * them. |
378 | */ | | 374 | */ |
379 | name = CanonicalVarname(name); | | 375 | name = CanonicalVarname(name); |
380 | nameHash = Hash_Hash(name); | | 376 | nameHash = Hash_Hash(name); |
381 | | | 377 | |
382 | /* | | 378 | /* First look for the variable in the given context. */ |
383 | * First look for the variable in the given context. If it's not there, | | | |
384 | * look for it in VAR_CMDLINE, VAR_GLOBAL and the environment, in that order, | | | |
385 | * depending on the FIND_* flags in 'flags' | | | |
386 | */ | | | |
387 | var = GNode_FindVar(ctxt, name, nameHash); | | 379 | var = GNode_FindVar(ctxt, name, nameHash); |
388 | if (!elsewhere) | | 380 | if (!elsewhere) |
389 | return var; | | 381 | return var; |
390 | | | 382 | |
| | | 383 | /* The variable was not found in the given context. Now look for it in |
| | | 384 | * the other contexts as well. */ |
391 | if (var == NULL && ctxt != VAR_CMDLINE) | | 385 | if (var == NULL && ctxt != VAR_CMDLINE) |
392 | var = GNode_FindVar(VAR_CMDLINE, name, nameHash); | | 386 | var = GNode_FindVar(VAR_CMDLINE, name, nameHash); |
393 | | | 387 | |
394 | if (!opts.checkEnvFirst && var == NULL && ctxt != VAR_GLOBAL) { | | 388 | if (!opts.checkEnvFirst && var == NULL && ctxt != VAR_GLOBAL) { |
395 | var = GNode_FindVar(VAR_GLOBAL, name, nameHash); | | 389 | var = GNode_FindVar(VAR_GLOBAL, name, nameHash); |
396 | if (var == NULL && ctxt != VAR_INTERNAL) { | | 390 | if (var == NULL && ctxt != VAR_INTERNAL) { |
397 | /* VAR_INTERNAL is subordinate to VAR_GLOBAL */ | | 391 | /* VAR_INTERNAL is subordinate to VAR_GLOBAL */ |
398 | var = GNode_FindVar(VAR_INTERNAL, name, nameHash); | | 392 | var = GNode_FindVar(VAR_INTERNAL, name, nameHash); |
399 | } | | 393 | } |
400 | } | | 394 | } |
401 | | | 395 | |
402 | if (var == NULL) { | | 396 | if (var == NULL) { |
403 | char *env; | | 397 | char *env; |
| @@ -410,65 +404,62 @@ VarFind(const char *name, GNode *ctxt, B | | | @@ -410,65 +404,62 @@ VarFind(const char *name, GNode *ctxt, B |
410 | if (opts.checkEnvFirst && ctxt != VAR_GLOBAL) { | | 404 | if (opts.checkEnvFirst && ctxt != VAR_GLOBAL) { |
411 | var = GNode_FindVar(VAR_GLOBAL, name, nameHash); | | 405 | var = GNode_FindVar(VAR_GLOBAL, name, nameHash); |
412 | if (var == NULL && ctxt != VAR_INTERNAL) | | 406 | if (var == NULL && ctxt != VAR_INTERNAL) |
413 | var = GNode_FindVar(VAR_INTERNAL, name, nameHash); | | 407 | var = GNode_FindVar(VAR_INTERNAL, name, nameHash); |
414 | return var; | | 408 | return var; |
415 | } | | 409 | } |
416 | | | 410 | |
417 | return NULL; | | 411 | return NULL; |
418 | } | | 412 | } |
419 | | | 413 | |
420 | return var; | | 414 | return var; |
421 | } | | 415 | } |
422 | | | 416 | |
423 | /*- | | 417 | /* If the variable is an environment variable, free it. |
424 | *----------------------------------------------------------------------- | | | |
425 | * VarFreeEnv -- | | | |
426 | * If the variable is an environment variable, free it | | | |
427 | * | | 418 | * |
428 | * Input: | | 419 | * Input: |
429 | * v the variable | | 420 | * v the variable |
430 | * destroy true if the value buffer should be destroyed. | | 421 | * freeValue true if the variable value should be freed as well |
431 | * | | 422 | * |
432 | * Results: | | 423 | * Results: |
433 | * TRUE if it is an environment variable, FALSE otherwise. | | 424 | * TRUE if it is an environment variable, FALSE otherwise. |
434 | *----------------------------------------------------------------------- | | | |
435 | */ | | 425 | */ |
436 | static Boolean | | 426 | static Boolean |
437 | VarFreeEnv(Var *v, Boolean destroy) | | 427 | VarFreeEnv(Var *v, Boolean freeValue) |
438 | { | | 428 | { |
439 | if (!(v->flags & VAR_FROM_ENV)) | | 429 | if (!(v->flags & VAR_FROM_ENV)) |
440 | return FALSE; | | 430 | return FALSE; |
| | | 431 | |
441 | free(v->name_freeIt); | | 432 | free(v->name_freeIt); |
442 | Buf_Destroy(&v->val, destroy); | | 433 | Buf_Destroy(&v->val, freeValue); |
443 | free(v); | | 434 | free(v); |
444 | return TRUE; | | 435 | return TRUE; |
445 | } | | 436 | } |
446 | | | 437 | |
447 | /* Add a new variable of the given name and value to the given context. | | 438 | /* Add a new variable of the given name and value to the given context. |
448 | * The name and val arguments are duplicated so they may safely be freed. */ | | 439 | * The name and val arguments are duplicated so they may safely be freed. */ |
449 | static void | | 440 | static void |
450 | VarAdd(const char *name, const char *val, GNode *ctxt, VarSet_Flags flags) | | 441 | VarAdd(const char *name, const char *val, GNode *ctxt, VarSet_Flags flags) |
451 | { | | 442 | { |
452 | HashEntry *he = HashTable_CreateEntry(&ctxt->context, name, NULL); | | 443 | HashEntry *he = HashTable_CreateEntry(&ctxt->context, name, NULL); |
453 | Var *v = VarNew(he->key, NULL, val, | | 444 | Var *v = VarNew(he->key /* aliased */, NULL, val, |
454 | flags & VAR_SET_READONLY ? VAR_READONLY : 0); | | 445 | flags & VAR_SET_READONLY ? VAR_READONLY : 0); |
455 | HashEntry_Set(he, v); | | 446 | HashEntry_Set(he, v); |
456 | if (!(ctxt->flags & INTERNAL)) { | | 447 | if (!(ctxt->flags & INTERNAL)) { |
457 | VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val); | | 448 | VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val); |
458 | } | | 449 | } |
459 | } | | 450 | } |
460 | | | 451 | |
461 | /* Remove a variable from a context, freeing the Var structure as well. */ | | 452 | /* Remove a variable from a context, freeing all related memory as well. */ |
462 | void | | 453 | void |
463 | Var_Delete(const char *name, GNode *ctxt) | | 454 | Var_Delete(const char *name, GNode *ctxt) |
464 | { | | 455 | { |
465 | char *name_freeIt = NULL; | | 456 | char *name_freeIt = NULL; |
466 | HashEntry *he; | | 457 | HashEntry *he; |
467 | | | 458 | |
468 | if (strchr(name, '$') != NULL) { | | 459 | if (strchr(name, '$') != NULL) { |
469 | (void)Var_Subst(name, VAR_GLOBAL, VARE_WANTRES, &name_freeIt); | | 460 | (void)Var_Subst(name, VAR_GLOBAL, VARE_WANTRES, &name_freeIt); |
470 | /* TODO: handle errors */ | | 461 | /* TODO: handle errors */ |
471 | name = name_freeIt; | | 462 | name = name_freeIt; |
472 | } | | 463 | } |
473 | he = HashTable_FindEntry(&ctxt->context, name); | | 464 | he = HashTable_FindEntry(&ctxt->context, name); |
474 | VAR_DEBUG3("%s:delete %s%s\n", | | 465 | VAR_DEBUG3("%s:delete %s%s\n", |
| @@ -533,64 +524,65 @@ Var_Export1(const char *name, VarExportF | | | @@ -533,64 +524,65 @@ Var_Export1(const char *name, VarExportF |
533 | v = VarFind(name, VAR_GLOBAL, 0); | | 524 | v = VarFind(name, VAR_GLOBAL, 0); |
534 | if (v == NULL) | | 525 | if (v == NULL) |
535 | return FALSE; | | 526 | return FALSE; |
536 | | | 527 | |
537 | if (!parent && (v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT)) | | 528 | if (!parent && (v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT)) |
538 | return FALSE; /* nothing to do */ | | 529 | return FALSE; /* nothing to do */ |
539 | | | 530 | |
540 | val = Buf_GetAll(&v->val, NULL); | | 531 | val = Buf_GetAll(&v->val, NULL); |
541 | if (!(flags & VAR_EXPORT_LITERAL) && strchr(val, '$') != NULL) { | | 532 | if (!(flags & VAR_EXPORT_LITERAL) && strchr(val, '$') != NULL) { |
542 | char *expr; | | 533 | char *expr; |
543 | | | 534 | |
544 | if (parent) { | | 535 | if (parent) { |
545 | /* | | 536 | /* |
546 | * Flag this as something we need to re-export. | | 537 | * Flag the variable as something we need to re-export. |
547 | * No point actually exporting it now though, | | 538 | * No point actually exporting it now though, |
548 | * the child can do it at the last minute. | | 539 | * the child process can do it at the last minute. |
549 | */ | | 540 | */ |
550 | v->flags |= VAR_EXPORTED | VAR_REEXPORT; | | 541 | v->flags |= VAR_EXPORTED | VAR_REEXPORT; |
551 | return TRUE; | | 542 | return TRUE; |
552 | } | | 543 | } |
553 | if (v->flags & VAR_IN_USE) { | | 544 | if (v->flags & VAR_IN_USE) { |
554 | /* | | 545 | /* |
555 | * We recursed while exporting in a child. | | 546 | * We recursed while exporting in a child. |
556 | * This isn't going to end well, just skip it. | | 547 | * This isn't going to end well, just skip it. |
557 | */ | | 548 | */ |
558 | return FALSE; | | 549 | return FALSE; |
559 | } | | 550 | } |
560 | | | 551 | |
561 | expr = str_concat3("${", name, "}"); | | 552 | expr = str_concat3("${", name, "}"); |
562 | (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &val); | | 553 | (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &val); |
563 | /* TODO: handle errors */ | | 554 | /* TODO: handle errors */ |
564 | setenv(name, val, 1); | | 555 | setenv(name, val, 1); |
565 | free(val); | | 556 | free(val); |
566 | free(expr); | | 557 | free(expr); |
567 | } else { | | 558 | } else { |
568 | if (parent) | | 559 | if (parent) |
569 | v->flags &= ~(unsigned)VAR_REEXPORT; /* once will do */ | | 560 | v->flags &= ~(unsigned)VAR_REEXPORT; /* once will do */ |
570 | if (parent || !(v->flags & VAR_EXPORTED)) | | 561 | if (parent || !(v->flags & VAR_EXPORTED)) |
571 | setenv(name, val, 1); | | 562 | setenv(name, val, 1); |
572 | } | | 563 | } |
| | | 564 | |
573 | /* | | 565 | /* |
574 | * This is so Var_Set knows to call Var_Export again... | | 566 | * This is so Var_Set knows to call Var_Export again... |
575 | */ | | 567 | */ |
576 | if (parent) { | | 568 | if (parent) { |
577 | v->flags |= VAR_EXPORTED; | | 569 | v->flags |= VAR_EXPORTED; |
578 | } | | 570 | } |
579 | return TRUE; | | 571 | return TRUE; |
580 | } | | 572 | } |
581 | | | 573 | |
582 | /* | | 574 | /* |
583 | * This gets called from our children. | | 575 | * This gets called from our child processes. |
584 | */ | | 576 | */ |
585 | void | | 577 | void |
586 | Var_ExportVars(void) | | 578 | Var_ExportVars(void) |
587 | { | | 579 | { |
588 | char *val; | | 580 | char *val; |
589 | | | 581 | |
590 | /* | | 582 | /* |
591 | * Several make's support this sort of mechanism for tracking | | 583 | * Several make's support this sort of mechanism for tracking |
592 | * recursion - but each uses a different name. | | 584 | * recursion - but each uses a different name. |
593 | * We allow the makefiles to update MAKELEVEL and ensure | | 585 | * We allow the makefiles to update MAKELEVEL and ensure |
594 | * children see a correctly incremented value. | | 586 | * children see a correctly incremented value. |
595 | */ | | 587 | */ |
596 | char tmp[BUFSIZ]; | | 588 | char tmp[BUFSIZ]; |