| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: var.c,v 1.339 2020/07/27 21:08:41 rillig Exp $ */ | | 1 | /* $NetBSD: var.c,v 1.340 2020/07/27 21:54:25 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. |
| @@ -59,34 +59,34 @@ | | | @@ -59,34 +59,34 @@ |
59 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 59 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
60 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 60 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
61 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 61 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
62 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 62 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
63 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 63 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
64 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 64 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
65 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 65 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
66 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 66 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
67 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 67 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
68 | * SUCH DAMAGE. | | 68 | * SUCH DAMAGE. |
69 | */ | | 69 | */ |
70 | | | 70 | |
71 | #ifndef MAKE_NATIVE | | 71 | #ifndef MAKE_NATIVE |
72 | static char rcsid[] = "$NetBSD: var.c,v 1.339 2020/07/27 21:08:41 rillig Exp $"; | | 72 | static char rcsid[] = "$NetBSD: var.c,v 1.340 2020/07/27 21:54:25 rillig Exp $"; |
73 | #else | | 73 | #else |
74 | #include <sys/cdefs.h> | | 74 | #include <sys/cdefs.h> |
75 | #ifndef lint | | 75 | #ifndef lint |
76 | #if 0 | | 76 | #if 0 |
77 | static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94"; | | 77 | static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94"; |
78 | #else | | 78 | #else |
79 | __RCSID("$NetBSD: var.c,v 1.339 2020/07/27 21:08:41 rillig Exp $"); | | 79 | __RCSID("$NetBSD: var.c,v 1.340 2020/07/27 21:54:25 rillig Exp $"); |
80 | #endif | | 80 | #endif |
81 | #endif /* not lint */ | | 81 | #endif /* not lint */ |
82 | #endif | | 82 | #endif |
83 | | | 83 | |
84 | /*- | | 84 | /*- |
85 | * var.c -- | | 85 | * var.c -- |
86 | * Variable-handling functions | | 86 | * Variable-handling functions |
87 | * | | 87 | * |
88 | * Interface: | | 88 | * Interface: |
89 | * Var_Set Set the value of a variable in the given | | 89 | * Var_Set Set the value of a variable in the given |
90 | * context. The variable is created if it doesn't | | 90 | * context. The variable is created if it doesn't |
91 | * yet exist. | | 91 | * yet exist. |
92 | * | | 92 | * |
| @@ -2057,32 +2057,41 @@ typedef struct { | | | @@ -2057,32 +2057,41 @@ typedef struct { |
2057 | | | 2057 | |
2058 | Byte sep; /* Word separator in expansions */ | | 2058 | Byte sep; /* Word separator in expansions */ |
2059 | Boolean oneBigWord; /* TRUE if we will treat the variable as a | | 2059 | Boolean oneBigWord; /* TRUE if we will treat the variable as a |
2060 | * single big word, even if it contains | | 2060 | * single big word, even if it contains |
2061 | * embedded spaces (as opposed to the | | 2061 | * embedded spaces (as opposed to the |
2062 | * usual behaviour of treating it as | | 2062 | * usual behaviour of treating it as |
2063 | * several space-separated words). */ | | 2063 | * several space-separated words). */ |
2064 | | | 2064 | |
2065 | /* result */ | | 2065 | /* result */ |
2066 | char *newStr; /* New value to return */ | | 2066 | char *newStr; /* New value to return */ |
2067 | } ApplyModifiersState; | | 2067 | } ApplyModifiersState; |
2068 | | | 2068 | |
2069 | /* we now have some modifiers with long names */ | | 2069 | /* we now have some modifiers with long names */ |
2070 | #define STRMOD_MATCH(s, want, n) \ | | 2070 | static Boolean |
2071 | (strncmp(s, want, n) == 0 && (s[n] == st->endc || s[n] == ':')) | | 2071 | ModMatch(const char *mod, const char *modname, char endc) |
2072 | #define STRMOD_MATCHX(s, want, n) \ | | 2072 | { |
2073 | (strncmp(s, want, n) == 0 && \ | | 2073 | size_t n = strlen(modname); |
2074 | (s[n] == st->endc || s[n] == ':' || s[n] == '=')) | | 2074 | return strncmp(mod, modname, n) == 0 && |
2075 | #define CHARMOD_MATCH(c) (c == st->endc || c == ':') | | 2075 | (mod[n] == endc || mod[n] == ':'); |
| | | 2076 | } |
| | | 2077 | |
| | | 2078 | static inline Boolean |
| | | 2079 | ModMatchEq(const char *mod, const char *modname, char endc) |
| | | 2080 | { |
| | | 2081 | size_t n = strlen(modname); |
| | | 2082 | return strncmp(mod, modname, n) == 0 && |
| | | 2083 | (mod[n] == endc || mod[n] == ':' || mod[n] == '='); |
| | | 2084 | } |
2076 | | | 2085 | |
2077 | /* :@var@...${var}...@ */ | | 2086 | /* :@var@...${var}...@ */ |
2078 | static Boolean | | 2087 | static Boolean |
2079 | ApplyModifier_Loop(const char *mod, ApplyModifiersState *st) { | | 2088 | ApplyModifier_Loop(const char *mod, ApplyModifiersState *st) { |
2080 | ModifyWord_LoopArgs args; | | 2089 | ModifyWord_LoopArgs args; |
2081 | | | 2090 | |
2082 | args.ctx = st->ctxt; | | 2091 | args.ctx = st->ctxt; |
2083 | st->cp = mod + 1; | | 2092 | st->cp = mod + 1; |
2084 | char delim = '@'; | | 2093 | char delim = '@'; |
2085 | args.tvar = ParseModifierPart(&st->cp, delim, st->eflags & ~VARE_WANTRES, | | 2094 | args.tvar = ParseModifierPart(&st->cp, delim, st->eflags & ~VARE_WANTRES, |
2086 | st->ctxt, NULL, NULL, NULL); | | 2095 | st->ctxt, NULL, NULL, NULL); |
2087 | if (args.tvar == NULL) { | | 2096 | if (args.tvar == NULL) { |
2088 | st->missing_delim = delim; | | 2097 | st->missing_delim = delim; |
| @@ -2169,74 +2178,77 @@ ApplyModifier_Defined(const char *mod, A | | | @@ -2169,74 +2178,77 @@ ApplyModifier_Defined(const char *mod, A |
2169 | st->v->flags |= VAR_KEEP; | | 2178 | st->v->flags |= VAR_KEEP; |
2170 | if (neflags & VARE_WANTRES) { | | 2179 | if (neflags & VARE_WANTRES) { |
2171 | st->newStr = Buf_Destroy(&buf, FALSE); | | 2180 | st->newStr = Buf_Destroy(&buf, FALSE); |
2172 | } else { | | 2181 | } else { |
2173 | st->newStr = st->nstr; | | 2182 | st->newStr = st->nstr; |
2174 | Buf_Destroy(&buf, TRUE); | | 2183 | Buf_Destroy(&buf, TRUE); |
2175 | } | | 2184 | } |
2176 | } | | 2185 | } |
2177 | | | 2186 | |
2178 | /* :gmtime */ | | 2187 | /* :gmtime */ |
2179 | static Boolean | | 2188 | static Boolean |
2180 | ApplyModifier_Gmtime(const char *mod, ApplyModifiersState *st) | | 2189 | ApplyModifier_Gmtime(const char *mod, ApplyModifiersState *st) |
2181 | { | | 2190 | { |
2182 | time_t utc; | | 2191 | if (!ModMatchEq(mod, "gmtime", st->endc)) { |
2183 | char *ep; | | 2192 | st->cp = mod + 1; |
2184 | | | | |
2185 | st->cp = mod + 1; /* make sure it is set */ | | | |
2186 | if (!STRMOD_MATCHX(mod, "gmtime", 6)) | | | |
2187 | return FALSE; | | 2193 | return FALSE; |
| | | 2194 | } |
| | | 2195 | |
| | | 2196 | time_t utc; |
2188 | if (mod[6] == '=') { | | 2197 | if (mod[6] == '=') { |
| | | 2198 | char *ep; |
2189 | utc = strtoul(mod + 7, &ep, 10); | | 2199 | utc = strtoul(mod + 7, &ep, 10); |
2190 | st->cp = ep; | | 2200 | st->cp = ep; |
2191 | } else { | | 2201 | } else { |
2192 | utc = 0; | | 2202 | utc = 0; |
2193 | st->cp = mod + 6; | | 2203 | st->cp = mod + 6; |
2194 | } | | 2204 | } |
2195 | st->newStr = VarStrftime(st->nstr, 1, utc); | | 2205 | st->newStr = VarStrftime(st->nstr, 1, utc); |
2196 | st->termc = *st->cp; | | 2206 | st->termc = *st->cp; |
2197 | return TRUE; | | 2207 | return TRUE; |
2198 | } | | 2208 | } |
2199 | | | 2209 | |
2200 | /* :localtime */ | | 2210 | /* :localtime */ |
2201 | static Boolean | | 2211 | static Boolean |
2202 | ApplyModifier_Localtime(const char *mod, ApplyModifiersState *st) | | 2212 | ApplyModifier_Localtime(const char *mod, ApplyModifiersState *st) |
2203 | { | | 2213 | { |
2204 | time_t utc; | | 2214 | if (!ModMatchEq(mod, "localtime", st->endc)) { |
2205 | char *ep; | | 2215 | st->cp = mod + 1; |
2206 | | | | |
2207 | st->cp = mod + 1; /* make sure it is set */ | | | |
2208 | if (!STRMOD_MATCHX(mod, "localtime", 9)) | | | |
2209 | return FALSE; | | 2216 | return FALSE; |
| | | 2217 | } |
2210 | | | 2218 | |
| | | 2219 | time_t utc; |
2211 | if (mod[9] == '=') { | | 2220 | if (mod[9] == '=') { |
| | | 2221 | char *ep; |
2212 | utc = strtoul(mod + 10, &ep, 10); | | 2222 | utc = strtoul(mod + 10, &ep, 10); |
2213 | st->cp = ep; | | 2223 | st->cp = ep; |
2214 | } else { | | 2224 | } else { |
2215 | utc = 0; | | 2225 | utc = 0; |
2216 | st->cp = mod + 9; | | 2226 | st->cp = mod + 9; |
2217 | } | | 2227 | } |
2218 | st->newStr = VarStrftime(st->nstr, 0, utc); | | 2228 | st->newStr = VarStrftime(st->nstr, 0, utc); |
2219 | st->termc = *st->cp; | | 2229 | st->termc = *st->cp; |
2220 | return TRUE; | | 2230 | return TRUE; |
2221 | } | | 2231 | } |
2222 | | | 2232 | |
2223 | /* :hash */ | | 2233 | /* :hash */ |
2224 | static Boolean | | 2234 | static Boolean |
2225 | ApplyModifier_Hash(const char *mod, ApplyModifiersState *st) | | 2235 | ApplyModifier_Hash(const char *mod, ApplyModifiersState *st) |
2226 | { | | 2236 | { |
2227 | st->cp = mod + 1; /* make sure it is set */ | | 2237 | if (!ModMatch(mod, "hash", st->endc)) { |
2228 | if (!STRMOD_MATCH(mod, "hash", 4)) | | 2238 | st->cp = mod + 1; |
2229 | return FALSE; | | 2239 | return FALSE; |
| | | 2240 | } |
| | | 2241 | |
2230 | st->newStr = VarHash(st->nstr); | | 2242 | st->newStr = VarHash(st->nstr); |
2231 | st->cp = mod + 4; | | 2243 | st->cp = mod + 4; |
2232 | st->termc = *st->cp; | | 2244 | st->termc = *st->cp; |
2233 | return TRUE; | | 2245 | return TRUE; |
2234 | } | | 2246 | } |
2235 | | | 2247 | |
2236 | /* :P */ | | 2248 | /* :P */ |
2237 | static void | | 2249 | static void |
2238 | ApplyModifier_Path(const char *mod, ApplyModifiersState *st) | | 2250 | ApplyModifier_Path(const char *mod, ApplyModifiersState *st) |
2239 | { | | 2251 | { |
2240 | if (st->v->flags & VAR_JUNK) | | 2252 | if (st->v->flags & VAR_JUNK) |
2241 | st->v->flags |= VAR_KEEP; | | 2253 | st->v->flags |= VAR_KEEP; |
2242 | GNode *gn = Targ_FindNode(st->v->name, TARG_NOCREATE); | | 2254 | GNode *gn = Targ_FindNode(st->v->name, TARG_NOCREATE); |
| @@ -2276,34 +2288,34 @@ ApplyModifier_Exclam(const char *mod, Ap | | | @@ -2276,34 +2288,34 @@ ApplyModifier_Exclam(const char *mod, Ap |
2276 | if (emsg) | | 2288 | if (emsg) |
2277 | Error(emsg, st->nstr); | | 2289 | Error(emsg, st->nstr); |
2278 | | | 2290 | |
2279 | st->termc = *st->cp; | | 2291 | st->termc = *st->cp; |
2280 | if (st->v->flags & VAR_JUNK) | | 2292 | if (st->v->flags & VAR_JUNK) |
2281 | st->v->flags |= VAR_KEEP; | | 2293 | st->v->flags |= VAR_KEEP; |
2282 | return TRUE; | | 2294 | return TRUE; |
2283 | } | | 2295 | } |
2284 | | | 2296 | |
2285 | /* :range */ | | 2297 | /* :range */ |
2286 | static Boolean | | 2298 | static Boolean |
2287 | ApplyModifier_Range(const char *mod, ApplyModifiersState *st) | | 2299 | ApplyModifier_Range(const char *mod, ApplyModifiersState *st) |
2288 | { | | 2300 | { |
2289 | int n; | | 2301 | if (!ModMatchEq(mod, "range", st->endc)) { |
2290 | char *ep; | | 2302 | st->cp = mod + 1; |
2291 | | | | |
2292 | st->cp = mod + 1; /* make sure it is set */ | | | |
2293 | if (!STRMOD_MATCHX(mod, "range", 5)) | | | |
2294 | return FALSE; | | 2303 | return FALSE; |
| | | 2304 | } |
2295 | | | 2305 | |
| | | 2306 | int n; |
2296 | if (mod[5] == '=') { | | 2307 | if (mod[5] == '=') { |
| | | 2308 | char *ep; |
2297 | n = strtoul(mod + 6, &ep, 10); | | 2309 | n = strtoul(mod + 6, &ep, 10); |
2298 | st->cp = ep; | | 2310 | st->cp = ep; |
2299 | } else { | | 2311 | } else { |
2300 | n = 0; | | 2312 | n = 0; |
2301 | st->cp = mod + 5; | | 2313 | st->cp = mod + 5; |
2302 | } | | 2314 | } |
2303 | st->newStr = VarRange(st->nstr, n); | | 2315 | st->newStr = VarRange(st->nstr, n); |
2304 | st->termc = *st->cp; | | 2316 | st->termc = *st->cp; |
2305 | return TRUE; | | 2317 | return TRUE; |
2306 | } | | 2318 | } |
2307 | | | 2319 | |
2308 | /* :Mpattern or :Npattern */ | | 2320 | /* :Mpattern or :Npattern */ |
2309 | static void | | 2321 | static void |
| @@ -2900,43 +2912,40 @@ ApplyModifier_Assign(const char *mod, Ap | | | @@ -2900,43 +2912,40 @@ ApplyModifier_Assign(const char *mod, Ap |
2900 | Var_Set(st->v->name, val, v_ctxt); | | 2912 | Var_Set(st->v->name, val, v_ctxt); |
2901 | break; | | 2913 | break; |
2902 | } | | 2914 | } |
2903 | } | | 2915 | } |
2904 | free(val); | | 2916 | free(val); |
2905 | st->newStr = varNoError; | | 2917 | st->newStr = varNoError; |
2906 | return 0; | | 2918 | return 0; |
2907 | } | | 2919 | } |
2908 | | | 2920 | |
2909 | /* remember current value */ | | 2921 | /* remember current value */ |
2910 | static Boolean | | 2922 | static Boolean |
2911 | ApplyModifier_Remember(const char *mod, ApplyModifiersState *st) | | 2923 | ApplyModifier_Remember(const char *mod, ApplyModifiersState *st) |
2912 | { | | 2924 | { |
2913 | st->cp = mod + 1; /* make sure it is set */ | | 2925 | if (!ModMatchEq(mod, "_", st->endc)) { |
2914 | if (!STRMOD_MATCHX(mod, "_", 1)) | | 2926 | st->cp = mod + 1; |
2915 | return FALSE; | | 2927 | return FALSE; |
| | | 2928 | } |
2916 | | | 2929 | |
2917 | if (mod[1] == '=') { | | 2930 | if (mod[1] == '=') { |
2918 | char *np; | | 2931 | size_t n = strcspn(mod + 2, ":)}"); |
2919 | int n; | | 2932 | char *name = bmake_strndup(mod + 2, n); |
2920 | | | 2933 | Var_Set(name, st->nstr, st->ctxt); |
2921 | st->cp++; | | 2934 | free(name); |
2922 | n = strcspn(st->cp, ":)}"); | | | |
2923 | np = bmake_strndup(st->cp, n + 1); | | | |
2924 | np[n] = '\0'; | | | |
2925 | st->cp = mod + 2 + n; | | 2935 | st->cp = mod + 2 + n; |
2926 | Var_Set(np, st->nstr, st->ctxt); | | | |
2927 | free(np); | | | |
2928 | } else { | | 2936 | } else { |
2929 | Var_Set("_", st->nstr, st->ctxt); | | 2937 | Var_Set("_", st->nstr, st->ctxt); |
| | | 2938 | st->cp = mod + 1; |
2930 | } | | 2939 | } |
2931 | st->newStr = st->nstr; | | 2940 | st->newStr = st->nstr; |
2932 | st->termc = *st->cp; | | 2941 | st->termc = *st->cp; |
2933 | return TRUE; | | 2942 | return TRUE; |
2934 | } | | 2943 | } |
2935 | | | 2944 | |
2936 | #ifdef SYSVVARSUB | | 2945 | #ifdef SYSVVARSUB |
2937 | /* :from=to */ | | 2946 | /* :from=to */ |
2938 | static int | | 2947 | static int |
2939 | ApplyModifier_SysV(const char *mod, ApplyModifiersState *st) | | 2948 | ApplyModifier_SysV(const char *mod, ApplyModifiersState *st) |
2940 | { | | 2949 | { |
2941 | Boolean eqFound = FALSE; | | 2950 | Boolean eqFound = FALSE; |
2942 | | | 2951 | |