make(1): add more detailed debug logging for variable modifiers
Before a modifier is applied to a variable, it is not yet parsed, therefore it is only possible to log a rough estimate of the modifier. But after applying it, the parsing position has advanced, and the full modifier can be logged. In addition, to fully understand how the modifiers work, it's not enough to just know the variable names and values, there are also some flags that influence how the modifiers behave. The most influential is VARE_WANTRES. Thanks to sjg for the extensive review and valuable feedback on the first drafts.
This commit is contained in:
parent
2b496df1e1
commit
619278f158
@ -1,4 +1,4 @@
|
||||
# $NetBSD: Makefile,v 1.82 2020/08/07 05:13:04 rillig Exp $
|
||||
# $NetBSD: Makefile,v 1.83 2020/08/08 13:50:23 rillig Exp $
|
||||
# @(#)Makefile 5.2 (Berkeley) 12/28/90
|
||||
|
||||
PROG= make
|
||||
@ -7,6 +7,7 @@ SRCS+= buf.c
|
||||
SRCS+= compat.c
|
||||
SRCS+= cond.c
|
||||
SRCS+= dir.c
|
||||
SRCS+= enum.c
|
||||
SRCS+= for.c
|
||||
SRCS+= hash.c
|
||||
SRCS+= job.c
|
||||
@ -26,6 +27,7 @@ SRCS+= util.c
|
||||
HDRS= buf.h
|
||||
HDRS+= config.h
|
||||
HDRS+= dir.h
|
||||
HDRS+= enum.h
|
||||
HDRS+= hash.h
|
||||
HDRS+= job.h
|
||||
HDRS+= lst.h
|
||||
|
83
usr.bin/make/enum.c
Normal file
83
usr.bin/make/enum.c
Normal file
@ -0,0 +1,83 @@
|
||||
/* $NetBSD: enum.c,v 1.1 2020/08/08 13:50:23 rillig Exp $ */
|
||||
|
||||
/*
|
||||
Copyright (c) 2020 Roland Illig <rillig@NetBSD.org>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
|
||||
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef MAKE_NATIVE
|
||||
static char rcsid[] = "$NetBSD: enum.c,v 1.1 2020/08/08 13:50:23 rillig Exp $";
|
||||
#else
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: enum.c,v 1.1 2020/08/08 13:50:23 rillig Exp $");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "enum.h"
|
||||
|
||||
/* Convert a bitset into a string representation showing the names of the
|
||||
* individual bits, or optionally shortcuts for groups of bits. */
|
||||
const char *
|
||||
Enum_ToString(char *buf, size_t buf_size, int value,
|
||||
const EnumToStringSpec *spec)
|
||||
{
|
||||
const char *buf_start = buf;
|
||||
const char *sep = "";
|
||||
size_t sep_len = 0;
|
||||
|
||||
for (; spec->es_value != 0; spec++) {
|
||||
size_t name_len;
|
||||
|
||||
if ((value & spec->es_value) != spec->es_value)
|
||||
continue;
|
||||
value &= ~spec->es_value;
|
||||
|
||||
assert(buf_size >= sep_len + 1);
|
||||
memcpy(buf, sep, sep_len);
|
||||
buf += sep_len;
|
||||
buf_size -= sep_len;
|
||||
|
||||
name_len = strlen(spec->es_name);
|
||||
assert(buf_size >= name_len + 1);
|
||||
memcpy(buf, spec->es_name, name_len);
|
||||
buf += name_len;
|
||||
buf_size -= name_len;
|
||||
|
||||
sep = ENUM__SEP;
|
||||
sep_len = sizeof ENUM__SEP - 1;
|
||||
}
|
||||
assert(value == 0);
|
||||
|
||||
if (buf == buf_start)
|
||||
return "none";
|
||||
|
||||
assert(buf_size >= 1);
|
||||
buf[0] = '\0';
|
||||
return buf_start;
|
||||
}
|
93
usr.bin/make/enum.h
Normal file
93
usr.bin/make/enum.h
Normal file
@ -0,0 +1,93 @@
|
||||
/* $NetBSD: enum.h,v 1.1 2020/08/08 13:50:23 rillig Exp $ */
|
||||
|
||||
/*
|
||||
Copyright (c) 2020 Roland Illig <rillig@NetBSD.org>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
|
||||
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef MAKE_ENUM_H
|
||||
#define MAKE_ENUM_H
|
||||
|
||||
/*
|
||||
* Generate string representation for bitmasks.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
int es_value;
|
||||
const char *es_name;
|
||||
} EnumToStringSpec;
|
||||
|
||||
const char *Enum_ToString(char *, size_t, int, const EnumToStringSpec *);
|
||||
|
||||
#define ENUM__SEP "|"
|
||||
|
||||
#define ENUM__JOIN_1(v1) \
|
||||
#v1
|
||||
#define ENUM__JOIN_2(v1, v2) \
|
||||
#v1 ENUM__SEP ENUM__JOIN_1(v2)
|
||||
#define ENUM__JOIN_3(v1, v2, v3) \
|
||||
#v1 ENUM__SEP ENUM__JOIN_2(v2, v3)
|
||||
#define ENUM__JOIN_4(v1, v2, v3, v4) \
|
||||
#v1 ENUM__SEP ENUM__JOIN_3(v2, v3, v4)
|
||||
#define ENUM__JOIN_5(v1, v2, v3, v4, v5) \
|
||||
#v1 ENUM__SEP ENUM__JOIN_4(v2, v3, v4, v5)
|
||||
#define ENUM__JOIN_6(v1, v2, v3, v4, v5, v6) \
|
||||
#v1 ENUM__SEP ENUM__JOIN_5(v2, v3, v4, v5, v6)
|
||||
#define ENUM__JOIN_7(v1, v2, v3, v4, v5, v6, v7) \
|
||||
#v1 ENUM__SEP ENUM__JOIN_6(v2, v3, v4, v5, v6, v7)
|
||||
|
||||
#define ENUM__RTTI(typnam, specs, joined) \
|
||||
static const EnumToStringSpec typnam ## _ ## ToStringSpecs[] = specs; \
|
||||
static const size_t typnam ## _ ## ToStringSize = sizeof joined
|
||||
|
||||
#define ENUM__SPEC(v) { v, #v }
|
||||
|
||||
#define ENUM__SPEC_3(v1, v2, v3) { \
|
||||
ENUM__SPEC(v1), \
|
||||
ENUM__SPEC(v2), \
|
||||
ENUM__SPEC(v3), \
|
||||
{ 0, "" } }
|
||||
|
||||
#define ENUM__SPEC_7(v1, v2, v3, v4, v5, v6, v7) { \
|
||||
ENUM__SPEC(v1), \
|
||||
ENUM__SPEC(v2), \
|
||||
ENUM__SPEC(v3), \
|
||||
ENUM__SPEC(v4), \
|
||||
ENUM__SPEC(v5), \
|
||||
ENUM__SPEC(v6), \
|
||||
ENUM__SPEC(v7), \
|
||||
{ 0, "" } }
|
||||
|
||||
#define ENUM_RTTI_3(typnam, v1, v2, v3) \
|
||||
ENUM__RTTI(typnam, \
|
||||
ENUM__SPEC_3(v1, v2, v3), \
|
||||
ENUM__JOIN_3(v1, v2, v3))
|
||||
|
||||
#define ENUM_RTTI_7(typnam, v1, v2, v3, v4, v5, v6, v7) \
|
||||
ENUM__RTTI(typnam, \
|
||||
ENUM__SPEC_7(v1, v2, v3, v4, v5, v6, v7), \
|
||||
ENUM__JOIN_7(v1, v2, v3, v4, v5, v6, v7))
|
||||
|
||||
#endif
|
@ -2,64 +2,64 @@ Global:RELEVANT = yes (load-time part)
|
||||
Global:COUNTER =
|
||||
Global:NEXT = ${COUNTER::=${COUNTER} a}${COUNTER:[#]}
|
||||
Global:A =
|
||||
Applying[COUNTER] :: to ""
|
||||
Applying ${COUNTER::...} to "" (eflags = VARE_WANTRES|VARE_ASSIGN, vflags = none)
|
||||
Modifier part: " a"
|
||||
Global:COUNTER = a
|
||||
Result[COUNTER] of :: is ""
|
||||
Applying[COUNTER] :[ to " a"
|
||||
Result of ${COUNTER::=${COUNTER} a} is "" (eflags = VARE_WANTRES|VARE_ASSIGN, vflags = none)
|
||||
Applying ${COUNTER:[...} to " a" (eflags = VARE_WANTRES|VARE_ASSIGN, vflags = none)
|
||||
Modifier part: "#"
|
||||
Result[COUNTER] of :[ is "1"
|
||||
Result of ${COUNTER:[#]} is "1" (eflags = VARE_WANTRES|VARE_ASSIGN, vflags = none)
|
||||
Global:A = ${COUNTER::= a a}1
|
||||
Global:B =
|
||||
Applying[COUNTER] :: to " a"
|
||||
Applying ${COUNTER::...} to " a" (eflags = VARE_WANTRES|VARE_ASSIGN, vflags = none)
|
||||
Modifier part: " a a"
|
||||
Global:COUNTER = a a
|
||||
Result[COUNTER] of :: is ""
|
||||
Applying[COUNTER] :[ to " a a"
|
||||
Result of ${COUNTER::=${COUNTER} a} is "" (eflags = VARE_WANTRES|VARE_ASSIGN, vflags = none)
|
||||
Applying ${COUNTER:[...} to " a a" (eflags = VARE_WANTRES|VARE_ASSIGN, vflags = none)
|
||||
Modifier part: "#"
|
||||
Result[COUNTER] of :[ is "2"
|
||||
Result of ${COUNTER:[#]} is "2" (eflags = VARE_WANTRES|VARE_ASSIGN, vflags = none)
|
||||
Global:B = ${COUNTER::= a a a}2
|
||||
Global:C =
|
||||
Applying[COUNTER] :: to " a a"
|
||||
Applying ${COUNTER::...} to " a a" (eflags = VARE_WANTRES|VARE_ASSIGN, vflags = none)
|
||||
Modifier part: " a a a"
|
||||
Global:COUNTER = a a a
|
||||
Result[COUNTER] of :: is ""
|
||||
Applying[COUNTER] :[ to " a a a"
|
||||
Result of ${COUNTER::=${COUNTER} a} is "" (eflags = VARE_WANTRES|VARE_ASSIGN, vflags = none)
|
||||
Applying ${COUNTER:[...} to " a a a" (eflags = VARE_WANTRES|VARE_ASSIGN, vflags = none)
|
||||
Modifier part: "#"
|
||||
Result[COUNTER] of :[ is "3"
|
||||
Result of ${COUNTER:[#]} is "3" (eflags = VARE_WANTRES|VARE_ASSIGN, vflags = none)
|
||||
Global:C = ${COUNTER::= a a a a}3
|
||||
Global:RELEVANT = no
|
||||
Global:RELEVANT = yes (run-time part)
|
||||
Result[RELEVANT] of :: is ""
|
||||
Applying[COUNTER] :: to " a a a"
|
||||
Result of ${RELEVANT::=yes (run-time part)} is "" (eflags = VARE_WANTRES, vflags = none)
|
||||
Applying ${COUNTER::...} to " a a a" (eflags = VARE_WANTRES, vflags = none)
|
||||
Modifier part: " a a"
|
||||
Global:COUNTER = a a
|
||||
Result[COUNTER] of :: is ""
|
||||
Applying[A] :Q to "1"
|
||||
Result of ${COUNTER::= a a} is "" (eflags = VARE_WANTRES, vflags = none)
|
||||
Applying ${A:Q} to "1" (eflags = VARE_WANTRES, vflags = none)
|
||||
QuoteMeta: [1]
|
||||
Result[A] of :Q is "1"
|
||||
Applying[COUNTER] :: to " a a"
|
||||
Result of ${A:Q} is "1" (eflags = VARE_WANTRES, vflags = none)
|
||||
Applying ${COUNTER::...} to " a a" (eflags = VARE_WANTRES, vflags = none)
|
||||
Modifier part: " a a a"
|
||||
Global:COUNTER = a a a
|
||||
Result[COUNTER] of :: is ""
|
||||
Applying[B] :Q to "2"
|
||||
Result of ${COUNTER::= a a a} is "" (eflags = VARE_WANTRES, vflags = none)
|
||||
Applying ${B:Q} to "2" (eflags = VARE_WANTRES, vflags = none)
|
||||
QuoteMeta: [2]
|
||||
Result[B] of :Q is "2"
|
||||
Applying[COUNTER] :: to " a a a"
|
||||
Result of ${B:Q} is "2" (eflags = VARE_WANTRES, vflags = none)
|
||||
Applying ${COUNTER::...} to " a a a" (eflags = VARE_WANTRES, vflags = none)
|
||||
Modifier part: " a a a a"
|
||||
Global:COUNTER = a a a a
|
||||
Result[COUNTER] of :: is ""
|
||||
Applying[C] :Q to "3"
|
||||
Result of ${COUNTER::= a a a a} is "" (eflags = VARE_WANTRES, vflags = none)
|
||||
Applying ${C:Q} to "3" (eflags = VARE_WANTRES, vflags = none)
|
||||
QuoteMeta: [3]
|
||||
Result[C] of :Q is "3"
|
||||
Applying[COUNTER] :[ to " a a a a"
|
||||
Result of ${C:Q} is "3" (eflags = VARE_WANTRES, vflags = none)
|
||||
Applying ${COUNTER:[...} to " a a a a" (eflags = VARE_WANTRES, vflags = none)
|
||||
Modifier part: "#"
|
||||
Result[COUNTER] of :[ is "4"
|
||||
Applying[COUNTER] :Q to "4"
|
||||
Result of ${COUNTER:[#]} is "4" (eflags = VARE_WANTRES, vflags = none)
|
||||
Applying ${COUNTER:Q} to "4" (eflags = VARE_WANTRES, vflags = none)
|
||||
QuoteMeta: [4]
|
||||
Result[COUNTER] of :Q is "4"
|
||||
Result of ${COUNTER:Q} is "4" (eflags = VARE_WANTRES, vflags = none)
|
||||
A=1 B=2 C=3 COUNTER=4
|
||||
Applying[RELEVANT] :: to "yes (run-time part)"
|
||||
Applying ${RELEVANT::...} to "yes (run-time part)" (eflags = VARE_WANTRES, vflags = none)
|
||||
Modifier part: "no"
|
||||
Global:RELEVANT = no
|
||||
exit status 0
|
||||
|
@ -3,59 +3,59 @@ Global:VAR = added
|
||||
Global:VAR = overwritten
|
||||
Global:delete VAR
|
||||
Global:delete VAR (not found)
|
||||
Applying[] :U to ""
|
||||
Result[] of :U is ""
|
||||
Applying ${:U} to "" (eflags = VARE_WANTRES, vflags = VAR_JUNK)
|
||||
Result of ${:U} is "" (eflags = VARE_WANTRES, vflags = VAR_JUNK|VAR_KEEP)
|
||||
Var_Set("${:U}", "empty name", ...) name expands to empty string - ignored
|
||||
Applying[] :U to ""
|
||||
Result[] of :U is ""
|
||||
Applying ${:U} to "" (eflags = VARE_WANTRES, vflags = VAR_JUNK)
|
||||
Result of ${:U} is "" (eflags = VARE_WANTRES, vflags = VAR_JUNK|VAR_KEEP)
|
||||
Var_Append("${:U}", "empty name", ...) name expands to empty string - ignored
|
||||
Global:FROM_CMDLINE = overwritten ignored!
|
||||
Global:VAR = 1
|
||||
Global:VAR = 1 2
|
||||
Global:VAR = 1 2 3
|
||||
Applying[VAR] :M to "1 2 3"
|
||||
Applying ${VAR:M...} to "1 2 3" (eflags = VARE_UNDEFERR|VARE_WANTRES, vflags = none)
|
||||
Pattern[VAR] for [1 2 3] is [[2]]
|
||||
ModifyWords: split "1 2 3" into 3 words
|
||||
VarMatch [1] [[2]]
|
||||
VarMatch [2] [[2]]
|
||||
VarMatch [3] [[2]]
|
||||
Result[VAR] of :M is "2"
|
||||
Applying[VAR] :N to "1 2 3"
|
||||
Result of ${VAR:M[2]} is "2" (eflags = VARE_UNDEFERR|VARE_WANTRES, vflags = none)
|
||||
Applying ${VAR:N...} to "1 2 3" (eflags = VARE_UNDEFERR|VARE_WANTRES, vflags = none)
|
||||
Pattern[VAR] for [1 2 3] is [[2]]
|
||||
ModifyWords: split "1 2 3" into 3 words
|
||||
Result[VAR] of :N is "1 3"
|
||||
Applying[VAR] :S to "1 2 3"
|
||||
Result of ${VAR:N[2]} is "1 3" (eflags = VARE_UNDEFERR|VARE_WANTRES, vflags = none)
|
||||
Applying ${VAR:S...} to "1 2 3" (eflags = VARE_UNDEFERR|VARE_WANTRES, vflags = none)
|
||||
Modifier part: "2"
|
||||
Modifier part: "two"
|
||||
ModifyWords: split "1 2 3" into 3 words
|
||||
Result[VAR] of :S is "1 two 3"
|
||||
Applying[VAR] :Q to "1 2 3"
|
||||
Result of ${VAR:S,2,two,} is "1 two 3" (eflags = VARE_UNDEFERR|VARE_WANTRES, vflags = none)
|
||||
Applying ${VAR:Q} to "1 2 3" (eflags = VARE_UNDEFERR|VARE_WANTRES, vflags = none)
|
||||
QuoteMeta: [1\ 2\ 3]
|
||||
Result[VAR] of :Q is "1\ 2\ 3"
|
||||
Applying[VAR] :t to "1 2 3"
|
||||
Result[VAR] of :t is "1 2 3"
|
||||
Applying[VAR] :t to "1 2 3"
|
||||
Result[VAR] of :t is "1 2 3"
|
||||
Applying[VAR] :Q to "1 2 3"
|
||||
Result of ${VAR:Q} is "1\ 2\ 3" (eflags = VARE_UNDEFERR|VARE_WANTRES, vflags = none)
|
||||
Applying ${VAR:t...} to "1 2 3" (eflags = VARE_UNDEFERR|VARE_WANTRES, vflags = none)
|
||||
Result of ${VAR:tu} is "1 2 3" (eflags = VARE_UNDEFERR|VARE_WANTRES, vflags = none)
|
||||
Applying ${VAR:t...} to "1 2 3" (eflags = VARE_UNDEFERR|VARE_WANTRES, vflags = none)
|
||||
Result of ${VAR:tl} is "1 2 3" (eflags = VARE_UNDEFERR|VARE_WANTRES, vflags = none)
|
||||
Applying ${VAR:Q} to "1 2 3" (eflags = VARE_UNDEFERR|VARE_WANTRES, vflags = none)
|
||||
QuoteMeta: [1\ 2\ 3]
|
||||
Result[VAR] of :Q is "1\ 2\ 3"
|
||||
Applying[] :U to ""
|
||||
Result[] of :U is "value"
|
||||
Applying[] :U to ""
|
||||
Result[] of :U is "M*e"
|
||||
Result of ${VAR:Q} is "1\ 2\ 3" (eflags = VARE_UNDEFERR|VARE_WANTRES, vflags = none)
|
||||
Applying ${:U...} to "" (eflags = VARE_UNDEFERR|VARE_WANTRES, vflags = VAR_JUNK)
|
||||
Result of ${:Uvalue} is "value" (eflags = VARE_UNDEFERR|VARE_WANTRES, vflags = VAR_JUNK|VAR_KEEP)
|
||||
Applying ${:U...} to "" (eflags = VARE_UNDEFERR|VARE_WANTRES, vflags = VAR_JUNK)
|
||||
Result of ${:UM*e} is "M*e" (eflags = VARE_UNDEFERR|VARE_WANTRES, vflags = VAR_JUNK|VAR_KEEP)
|
||||
Indirect modifier "M*e" from "${:UM*e}"
|
||||
Applying[] :M to "value"
|
||||
Applying ${:M...} to "value" (eflags = VARE_UNDEFERR|VARE_WANTRES, vflags = VAR_JUNK|VAR_KEEP)
|
||||
Pattern[] for [value] is [*e]
|
||||
ModifyWords: split "value" into 1 words
|
||||
VarMatch [value] [*e]
|
||||
Result[] of :M is "value"
|
||||
Applying[] :M to "value"
|
||||
Result of ${:M*e} is "value" (eflags = VARE_UNDEFERR|VARE_WANTRES, vflags = VAR_JUNK|VAR_KEEP)
|
||||
Applying ${:M...} to "value" (eflags = VARE_UNDEFERR|VARE_WANTRES, vflags = VAR_JUNK|VAR_KEEP)
|
||||
Pattern[] for [value] is [valu[e]]
|
||||
ModifyWords: split "value" into 1 words
|
||||
VarMatch [value] [valu[e]]
|
||||
Result[] of :M is "value"
|
||||
Applying[] :U to ""
|
||||
Result[] of :U is "VAR"
|
||||
Result of ${:Mvalu[e]} is "value" (eflags = VARE_UNDEFERR|VARE_WANTRES, vflags = VAR_JUNK|VAR_KEEP)
|
||||
Applying ${:U...} to "" (eflags = VARE_WANTRES, vflags = VAR_JUNK)
|
||||
Result of ${:UVAR} is "VAR" (eflags = VARE_WANTRES, vflags = VAR_JUNK|VAR_KEEP)
|
||||
Global:delete VAR
|
||||
Global:RELEVANT = no
|
||||
exit status 0
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: var.c,v 1.429 2020/08/08 13:31:24 rillig Exp $ */
|
||||
/* $NetBSD: var.c,v 1.430 2020/08/08 13:50:23 rillig Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1988, 1989, 1990, 1993
|
||||
@ -69,14 +69,14 @@
|
||||
*/
|
||||
|
||||
#ifndef MAKE_NATIVE
|
||||
static char rcsid[] = "$NetBSD: var.c,v 1.429 2020/08/08 13:31:24 rillig Exp $";
|
||||
static char rcsid[] = "$NetBSD: var.c,v 1.430 2020/08/08 13:50:23 rillig Exp $";
|
||||
#else
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94";
|
||||
#else
|
||||
__RCSID("$NetBSD: var.c,v 1.429 2020/08/08 13:31:24 rillig Exp $");
|
||||
__RCSID("$NetBSD: var.c,v 1.430 2020/08/08 13:50:23 rillig Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
#endif
|
||||
@ -131,6 +131,7 @@ __RCSID("$NetBSD: var.c,v 1.429 2020/08/08 13:31:24 rillig Exp $");
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "enum.h"
|
||||
#include "make.h"
|
||||
#include "buf.h"
|
||||
#include "dir.h"
|
||||
@ -145,6 +146,11 @@ __RCSID("$NetBSD: var.c,v 1.429 2020/08/08 13:31:24 rillig Exp $");
|
||||
|
||||
#define VAR_DEBUG(fmt, ...) VAR_DEBUG_IF(TRUE, fmt, __VA_ARGS__)
|
||||
|
||||
ENUM_RTTI_3(VarEvalFlags,
|
||||
VARE_UNDEFERR,
|
||||
VARE_WANTRES,
|
||||
VARE_ASSIGN);
|
||||
|
||||
/*
|
||||
* This lets us tell if we have replaced the original environ
|
||||
* (which we cannot free).
|
||||
@ -218,6 +224,15 @@ typedef enum {
|
||||
VAR_FROM_CMD = 0x40 /* Variable came from command line */
|
||||
} VarFlags;
|
||||
|
||||
ENUM_RTTI_7(VarFlags,
|
||||
VAR_IN_USE,
|
||||
VAR_FROM_ENV,
|
||||
VAR_JUNK,
|
||||
VAR_KEEP,
|
||||
VAR_EXPORTED,
|
||||
VAR_REEXPORT,
|
||||
VAR_FROM_CMD);
|
||||
|
||||
typedef struct Var {
|
||||
char *name; /* the variable's name; it is allocated for
|
||||
* environment variables and aliased to the
|
||||
@ -3019,10 +3034,27 @@ ApplyModifiers(
|
||||
continue;
|
||||
}
|
||||
apply_mods:
|
||||
VAR_DEBUG("Applying[%s] :%c to \"%s\"\n", st.v->name, *p, st.val);
|
||||
st.newVal = var_Error; /* default value, in case of errors */
|
||||
res = AMR_BAD; /* just a safe fallback */
|
||||
mod = p;
|
||||
|
||||
if (DEBUG(VAR)) {
|
||||
char vflags_str[VarFlags_ToStringSize];
|
||||
char eflags_str[VarEvalFlags_ToStringSize];
|
||||
Boolean is_single_char = mod[0] != '\0' &&
|
||||
(mod[1] == endc || mod[1] == ':');
|
||||
|
||||
/* At this point, only the first character of the modifier can
|
||||
* be used since the end of the modifier is not yet known. */
|
||||
VAR_DEBUG("Applying ${%s:%c%s} to \"%s\" "
|
||||
"(eflags = %s, vflags = %s)\n",
|
||||
st.v->name, mod[0], is_single_char ? "" : "...", st.val,
|
||||
Enum_ToString(eflags_str, sizeof eflags_str, st.eflags,
|
||||
VarEvalFlags_ToStringSpecs),
|
||||
Enum_ToString(vflags_str, sizeof vflags_str, st.v->flags,
|
||||
VarFlags_ToStringSpecs));
|
||||
}
|
||||
|
||||
switch (*mod) {
|
||||
case ':':
|
||||
res = ApplyModifier_Assign(&p, &st);
|
||||
@ -3177,7 +3209,18 @@ ApplyModifiers(
|
||||
if (res == AMR_BAD)
|
||||
goto bad_modifier;
|
||||
|
||||
VAR_DEBUG("Result[%s] of :%c is \"%s\"\n", st.v->name, *mod, st.newVal);
|
||||
if (DEBUG(VAR)) {
|
||||
char eflags_str[VarEvalFlags_ToStringSize];
|
||||
char vflags_str[VarFlags_ToStringSize];
|
||||
|
||||
VAR_DEBUG("Result of ${%s:%.*s} is \"%s\" "
|
||||
"(eflags = %s, vflags = %s)\n",
|
||||
st.v->name, (int)(p - mod), mod, st.newVal,
|
||||
Enum_ToString(eflags_str, sizeof eflags_str, st.eflags,
|
||||
VarEvalFlags_ToStringSpecs),
|
||||
Enum_ToString(vflags_str, sizeof vflags_str, st.v->flags,
|
||||
VarFlags_ToStringSpecs));
|
||||
}
|
||||
|
||||
if (st.newVal != st.val) {
|
||||
if (*freePtr) {
|
||||
|
Loading…
Reference in New Issue
Block a user