| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: var.c,v 1.347 2020/07/27 23:04:18 rillig Exp $ */ | | 1 | /* $NetBSD: var.c,v 1.348 2020/07/27 23:24:55 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.347 2020/07/27 23:04:18 rillig Exp $"; | | 72 | static char rcsid[] = "$NetBSD: var.c,v 1.348 2020/07/27 23:24:55 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.347 2020/07/27 23:04:18 rillig Exp $"); | | 79 | __RCSID("$NetBSD: var.c,v 1.348 2020/07/27 23:24:55 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 | * |
| @@ -2036,27 +2036,27 @@ VarStrftime(const char *fmt, int zulu, t | | | @@ -2036,27 +2036,27 @@ VarStrftime(const char *fmt, int zulu, t |
2036 | return bmake_strdup(buf); | | 2036 | return bmake_strdup(buf); |
2037 | } | | 2037 | } |
2038 | | | 2038 | |
2039 | typedef struct { | | 2039 | typedef struct { |
2040 | /* const parameters */ | | 2040 | /* const parameters */ |
2041 | int startc; /* '\0' or '{' or '(' */ | | 2041 | int startc; /* '\0' or '{' or '(' */ |
2042 | int endc; | | 2042 | int endc; |
2043 | Var *v; | | 2043 | Var *v; |
2044 | GNode *ctxt; | | 2044 | GNode *ctxt; |
2045 | VarEvalFlags eflags; | | 2045 | VarEvalFlags eflags; |
2046 | | | 2046 | |
2047 | /* read-write */ | | 2047 | /* read-write */ |
2048 | char *nstr; | | 2048 | char *nstr; |
2049 | const char *cp; /* The position where parsing continues | | 2049 | const char *next; /* The position where parsing continues |
2050 | * after the current modifier. */ | | 2050 | * after the current modifier. */ |
2051 | char termc; /* Character which terminated scan */ | | 2051 | char termc; /* Character which terminated scan */ |
2052 | char missing_delim; /* For error reporting */ | | 2052 | char missing_delim; /* For error reporting */ |
2053 | | | 2053 | |
2054 | Byte sep; /* Word separator in expansions */ | | 2054 | Byte sep; /* Word separator in expansions */ |
2055 | Boolean oneBigWord; /* TRUE if we will treat the variable as a | | 2055 | Boolean oneBigWord; /* TRUE if we will treat the variable as a |
2056 | * single big word, even if it contains | | 2056 | * single big word, even if it contains |
2057 | * embedded spaces (as opposed to the | | 2057 | * embedded spaces (as opposed to the |
2058 | * usual behaviour of treating it as | | 2058 | * usual behaviour of treating it as |
2059 | * several space-separated words). */ | | 2059 | * several space-separated words). */ |
2060 | | | 2060 | |
2061 | /* result */ | | 2061 | /* result */ |
2062 | char *newStr; /* New value to return */ | | 2062 | char *newStr; /* New value to return */ |
| @@ -2075,43 +2075,43 @@ static inline Boolean | | | @@ -2075,43 +2075,43 @@ static inline Boolean |
2075 | ModMatchEq(const char *mod, const char *modname, char endc) | | 2075 | ModMatchEq(const char *mod, const char *modname, char endc) |
2076 | { | | 2076 | { |
2077 | size_t n = strlen(modname); | | 2077 | size_t n = strlen(modname); |
2078 | return strncmp(mod, modname, n) == 0 && | | 2078 | return strncmp(mod, modname, n) == 0 && |
2079 | (mod[n] == endc || mod[n] == ':' || mod[n] == '='); | | 2079 | (mod[n] == endc || mod[n] == ':' || mod[n] == '='); |
2080 | } | | 2080 | } |
2081 | | | 2081 | |
2082 | /* :@var@...${var}...@ */ | | 2082 | /* :@var@...${var}...@ */ |
2083 | static Boolean | | 2083 | static Boolean |
2084 | ApplyModifier_Loop(const char *mod, ApplyModifiersState *st) { | | 2084 | ApplyModifier_Loop(const char *mod, ApplyModifiersState *st) { |
2085 | ModifyWord_LoopArgs args; | | 2085 | ModifyWord_LoopArgs args; |
2086 | | | 2086 | |
2087 | args.ctx = st->ctxt; | | 2087 | args.ctx = st->ctxt; |
2088 | st->cp = mod + 1; | | 2088 | st->next = mod + 1; |
2089 | char delim = '@'; | | 2089 | char delim = '@'; |
2090 | args.tvar = ParseModifierPart(&st->cp, delim, st->eflags & ~VARE_WANTRES, | | 2090 | args.tvar = ParseModifierPart(&st->next, delim, st->eflags & ~VARE_WANTRES, |
2091 | st->ctxt, NULL, NULL, NULL); | | 2091 | st->ctxt, NULL, NULL, NULL); |
2092 | if (args.tvar == NULL) { | | 2092 | if (args.tvar == NULL) { |
2093 | st->missing_delim = delim; | | 2093 | st->missing_delim = delim; |
2094 | return FALSE; | | 2094 | return FALSE; |
2095 | } | | 2095 | } |
2096 | | | 2096 | |
2097 | args.str = ParseModifierPart(&st->cp, delim, st->eflags & ~VARE_WANTRES, | | 2097 | args.str = ParseModifierPart(&st->next, delim, st->eflags & ~VARE_WANTRES, |
2098 | st->ctxt, NULL, NULL, NULL); | | 2098 | st->ctxt, NULL, NULL, NULL); |
2099 | if (args.str == NULL) { | | 2099 | if (args.str == NULL) { |
2100 | st->missing_delim = delim; | | 2100 | st->missing_delim = delim; |
2101 | return FALSE; | | 2101 | return FALSE; |
2102 | } | | 2102 | } |
2103 | | | 2103 | |
2104 | st->termc = *st->cp; | | 2104 | st->termc = *st->next; |
2105 | | | 2105 | |
2106 | args.eflags = st->eflags & (VARE_UNDEFERR | VARE_WANTRES); | | 2106 | args.eflags = st->eflags & (VARE_UNDEFERR | VARE_WANTRES); |
2107 | int prev_sep = st->sep; | | 2107 | int prev_sep = st->sep; |
2108 | st->sep = ' '; /* XXX: this is inconsistent */ | | 2108 | st->sep = ' '; /* XXX: this is inconsistent */ |
2109 | st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, | | 2109 | st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, |
2110 | ModifyWord_Loop, &args); | | 2110 | ModifyWord_Loop, &args); |
2111 | st->sep = prev_sep; | | 2111 | st->sep = prev_sep; |
2112 | Var_Delete(args.tvar, st->ctxt); | | 2112 | Var_Delete(args.tvar, st->ctxt); |
2113 | free(args.tvar); | | 2113 | free(args.tvar); |
2114 | free(args.str); | | 2114 | free(args.str); |
2115 | return TRUE; | | 2115 | return TRUE; |
2116 | } | | 2116 | } |
2117 | | | 2117 | |
| @@ -2157,169 +2157,169 @@ ApplyModifier_Defined(const char *mod, A | | | @@ -2157,169 +2157,169 @@ ApplyModifier_Defined(const char *mod, A |
2157 | int len; | | 2157 | int len; |
2158 | void *freeIt; | | 2158 | void *freeIt; |
2159 | | | 2159 | |
2160 | cp2 = Var_Parse(p, st->ctxt, neflags, &len, &freeIt); | | 2160 | cp2 = Var_Parse(p, st->ctxt, neflags, &len, &freeIt); |
2161 | Buf_AddStr(&buf, cp2); | | 2161 | Buf_AddStr(&buf, cp2); |
2162 | free(freeIt); | | 2162 | free(freeIt); |
2163 | p += len; | | 2163 | p += len; |
2164 | } else { | | 2164 | } else { |
2165 | Buf_AddByte(&buf, *p); | | 2165 | Buf_AddByte(&buf, *p); |
2166 | p++; | | 2166 | p++; |
2167 | } | | 2167 | } |
2168 | } | | 2168 | } |
2169 | | | 2169 | |
2170 | st->cp = p; | | 2170 | st->next = p; |
2171 | st->termc = *st->cp; | | 2171 | st->termc = *st->next; |
2172 | | | 2172 | |
2173 | if (st->v->flags & VAR_JUNK) | | 2173 | if (st->v->flags & VAR_JUNK) |
2174 | st->v->flags |= VAR_KEEP; | | 2174 | st->v->flags |= VAR_KEEP; |
2175 | if (neflags & VARE_WANTRES) { | | 2175 | if (neflags & VARE_WANTRES) { |
2176 | st->newStr = Buf_Destroy(&buf, FALSE); | | 2176 | st->newStr = Buf_Destroy(&buf, FALSE); |
2177 | } else { | | 2177 | } else { |
2178 | st->newStr = st->nstr; | | 2178 | st->newStr = st->nstr; |
2179 | Buf_Destroy(&buf, TRUE); | | 2179 | Buf_Destroy(&buf, TRUE); |
2180 | } | | 2180 | } |
2181 | } | | 2181 | } |
2182 | | | 2182 | |
2183 | /* :gmtime */ | | 2183 | /* :gmtime */ |
2184 | static Boolean | | 2184 | static Boolean |
2185 | ApplyModifier_Gmtime(const char *mod, ApplyModifiersState *st) | | 2185 | ApplyModifier_Gmtime(const char *mod, ApplyModifiersState *st) |
2186 | { | | 2186 | { |
2187 | if (!ModMatchEq(mod, "gmtime", st->endc)) { | | 2187 | if (!ModMatchEq(mod, "gmtime", st->endc)) { |
2188 | st->cp = mod + 1; | | 2188 | st->next = mod + 1; |
2189 | return FALSE; | | 2189 | return FALSE; |
2190 | } | | 2190 | } |
2191 | | | 2191 | |
2192 | time_t utc; | | 2192 | time_t utc; |
2193 | if (mod[6] == '=') { | | 2193 | if (mod[6] == '=') { |
2194 | char *ep; | | 2194 | char *ep; |
2195 | utc = strtoul(mod + 7, &ep, 10); | | 2195 | utc = strtoul(mod + 7, &ep, 10); |
2196 | st->cp = ep; | | 2196 | st->next = ep; |
2197 | } else { | | 2197 | } else { |
2198 | utc = 0; | | 2198 | utc = 0; |
2199 | st->cp = mod + 6; | | 2199 | st->next = mod + 6; |
2200 | } | | 2200 | } |
2201 | st->newStr = VarStrftime(st->nstr, 1, utc); | | 2201 | st->newStr = VarStrftime(st->nstr, 1, utc); |
2202 | st->termc = *st->cp; | | 2202 | st->termc = *st->next; |
2203 | return TRUE; | | 2203 | return TRUE; |
2204 | } | | 2204 | } |
2205 | | | 2205 | |
2206 | /* :localtime */ | | 2206 | /* :localtime */ |
2207 | static Boolean | | 2207 | static Boolean |
2208 | ApplyModifier_Localtime(const char *mod, ApplyModifiersState *st) | | 2208 | ApplyModifier_Localtime(const char *mod, ApplyModifiersState *st) |
2209 | { | | 2209 | { |
2210 | if (!ModMatchEq(mod, "localtime", st->endc)) { | | 2210 | if (!ModMatchEq(mod, "localtime", st->endc)) { |
2211 | st->cp = mod + 1; | | 2211 | st->next = mod + 1; |
2212 | return FALSE; | | 2212 | return FALSE; |
2213 | } | | 2213 | } |
2214 | | | 2214 | |
2215 | time_t utc; | | 2215 | time_t utc; |
2216 | if (mod[9] == '=') { | | 2216 | if (mod[9] == '=') { |
2217 | char *ep; | | 2217 | char *ep; |
2218 | utc = strtoul(mod + 10, &ep, 10); | | 2218 | utc = strtoul(mod + 10, &ep, 10); |
2219 | st->cp = ep; | | 2219 | st->next = ep; |
2220 | } else { | | 2220 | } else { |
2221 | utc = 0; | | 2221 | utc = 0; |
2222 | st->cp = mod + 9; | | 2222 | st->next = mod + 9; |
2223 | } | | 2223 | } |
2224 | st->newStr = VarStrftime(st->nstr, 0, utc); | | 2224 | st->newStr = VarStrftime(st->nstr, 0, utc); |
2225 | st->termc = *st->cp; | | 2225 | st->termc = *st->next; |
2226 | return TRUE; | | 2226 | return TRUE; |
2227 | } | | 2227 | } |
2228 | | | 2228 | |
2229 | /* :hash */ | | 2229 | /* :hash */ |
2230 | static Boolean | | 2230 | static Boolean |
2231 | ApplyModifier_Hash(const char *mod, ApplyModifiersState *st) | | 2231 | ApplyModifier_Hash(const char *mod, ApplyModifiersState *st) |
2232 | { | | 2232 | { |
2233 | if (!ModMatch(mod, "hash", st->endc)) { | | 2233 | if (!ModMatch(mod, "hash", st->endc)) { |
2234 | st->cp = mod + 1; | | 2234 | st->next = mod + 1; |
2235 | return FALSE; | | 2235 | return FALSE; |
2236 | } | | 2236 | } |
2237 | | | 2237 | |
2238 | st->newStr = VarHash(st->nstr); | | 2238 | st->newStr = VarHash(st->nstr); |
2239 | st->cp = mod + 4; | | 2239 | st->next = mod + 4; |
2240 | st->termc = *st->cp; | | 2240 | st->termc = *st->next; |
2241 | return TRUE; | | 2241 | return TRUE; |
2242 | } | | 2242 | } |
2243 | | | 2243 | |
2244 | /* :P */ | | 2244 | /* :P */ |
2245 | static void | | 2245 | static void |
2246 | ApplyModifier_Path(const char *mod, ApplyModifiersState *st) | | 2246 | ApplyModifier_Path(const char *mod, ApplyModifiersState *st) |
2247 | { | | 2247 | { |
2248 | if (st->v->flags & VAR_JUNK) | | 2248 | if (st->v->flags & VAR_JUNK) |
2249 | st->v->flags |= VAR_KEEP; | | 2249 | st->v->flags |= VAR_KEEP; |
2250 | GNode *gn = Targ_FindNode(st->v->name, TARG_NOCREATE); | | 2250 | GNode *gn = Targ_FindNode(st->v->name, TARG_NOCREATE); |
2251 | if (gn == NULL || gn->type & OP_NOPATH) { | | 2251 | if (gn == NULL || gn->type & OP_NOPATH) { |
2252 | st->newStr = NULL; | | 2252 | st->newStr = NULL; |
2253 | } else if (gn->path) { | | 2253 | } else if (gn->path) { |
2254 | st->newStr = bmake_strdup(gn->path); | | 2254 | st->newStr = bmake_strdup(gn->path); |
2255 | } else { | | 2255 | } else { |
2256 | st->newStr = Dir_FindFile(st->v->name, Suff_FindPath(gn)); | | 2256 | st->newStr = Dir_FindFile(st->v->name, Suff_FindPath(gn)); |
2257 | } | | 2257 | } |
2258 | if (!st->newStr) | | 2258 | if (!st->newStr) |
2259 | st->newStr = bmake_strdup(st->v->name); | | 2259 | st->newStr = bmake_strdup(st->v->name); |
2260 | st->cp = mod + 1; | | 2260 | st->next = mod + 1; |
2261 | st->termc = *st->cp; | | 2261 | st->termc = *st->next; |
2262 | } | | 2262 | } |
2263 | | | 2263 | |
2264 | /* :!cmd! */ | | 2264 | /* :!cmd! */ |
2265 | static Boolean | | 2265 | static Boolean |
2266 | ApplyModifier_Exclam(const char *mod, ApplyModifiersState *st) | | 2266 | ApplyModifier_Exclam(const char *mod, ApplyModifiersState *st) |
2267 | { | | 2267 | { |
2268 | st->cp = mod + 1; | | 2268 | st->next = mod + 1; |
2269 | char delim = '!'; | | 2269 | char delim = '!'; |
2270 | char *cmd = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, | | 2270 | char *cmd = ParseModifierPart(&st->next, delim, st->eflags, st->ctxt, |
2271 | NULL, NULL, NULL); | | 2271 | NULL, NULL, NULL); |
2272 | if (cmd == NULL) { | | 2272 | if (cmd == NULL) { |
2273 | st->missing_delim = delim; | | 2273 | st->missing_delim = delim; |
2274 | return FALSE; | | 2274 | return FALSE; |
2275 | } | | 2275 | } |
2276 | | | 2276 | |
2277 | const char *emsg = NULL; | | 2277 | const char *emsg = NULL; |
2278 | if (st->eflags & VARE_WANTRES) | | 2278 | if (st->eflags & VARE_WANTRES) |
2279 | st->newStr = Cmd_Exec(cmd, &emsg); | | 2279 | st->newStr = Cmd_Exec(cmd, &emsg); |
2280 | else | | 2280 | else |
2281 | st->newStr = varNoError; | | 2281 | st->newStr = varNoError; |
2282 | free(cmd); | | 2282 | free(cmd); |
2283 | | | 2283 | |
2284 | if (emsg) | | 2284 | if (emsg) |
2285 | Error(emsg, st->nstr); | | 2285 | Error(emsg, st->nstr); |
2286 | | | 2286 | |
2287 | st->termc = *st->cp; | | 2287 | st->termc = *st->next; |
2288 | if (st->v->flags & VAR_JUNK) | | 2288 | if (st->v->flags & VAR_JUNK) |
2289 | st->v->flags |= VAR_KEEP; | | 2289 | st->v->flags |= VAR_KEEP; |
2290 | return TRUE; | | 2290 | return TRUE; |
2291 | } | | 2291 | } |
2292 | | | 2292 | |
2293 | /* :range */ | | 2293 | /* :range */ |
2294 | static Boolean | | 2294 | static Boolean |
2295 | ApplyModifier_Range(const char *mod, ApplyModifiersState *st) | | 2295 | ApplyModifier_Range(const char *mod, ApplyModifiersState *st) |
2296 | { | | 2296 | { |
2297 | if (!ModMatchEq(mod, "range", st->endc)) { | | 2297 | if (!ModMatchEq(mod, "range", st->endc)) { |
2298 | st->cp = mod + 1; | | 2298 | st->next = mod + 1; |
2299 | return FALSE; | | 2299 | return FALSE; |
2300 | } | | 2300 | } |
2301 | | | 2301 | |
2302 | int n; | | 2302 | int n; |
2303 | if (mod[5] == '=') { | | 2303 | if (mod[5] == '=') { |
2304 | char *ep; | | 2304 | char *ep; |
2305 | n = strtoul(mod + 6, &ep, 10); | | 2305 | n = strtoul(mod + 6, &ep, 10); |
2306 | st->cp = ep; | | 2306 | st->next = ep; |
2307 | } else { | | 2307 | } else { |
2308 | n = 0; | | 2308 | n = 0; |
2309 | st->cp = mod + 5; | | 2309 | st->next = mod + 5; |
2310 | } | | 2310 | } |
2311 | st->newStr = VarRange(st->nstr, n); | | 2311 | st->newStr = VarRange(st->nstr, n); |
2312 | st->termc = *st->cp; | | 2312 | st->termc = *st->next; |
2313 | return TRUE; | | 2313 | return TRUE; |
2314 | } | | 2314 | } |
2315 | | | 2315 | |
2316 | /* :Mpattern or :Npattern */ | | 2316 | /* :Mpattern or :Npattern */ |
2317 | static void | | 2317 | static void |
2318 | ApplyModifier_Match(const char *mod, ApplyModifiersState *st) | | 2318 | ApplyModifier_Match(const char *mod, ApplyModifiersState *st) |
2319 | { | | 2319 | { |
2320 | Boolean copy = FALSE; /* pattern should be, or has been, copied */ | | 2320 | Boolean copy = FALSE; /* pattern should be, or has been, copied */ |
2321 | Boolean needSubst = FALSE; | | 2321 | Boolean needSubst = FALSE; |
2322 | /* | | 2322 | /* |
2323 | * In the loop below, ignore ':' unless we are at (or back to) the | | 2323 | * In the loop below, ignore ':' unless we are at (or back to) the |
2324 | * original brace level. | | 2324 | * original brace level. |
2325 | * XXX This will likely not work right if $() and ${} are intermixed. | | 2325 | * XXX This will likely not work right if $() and ${} are intermixed. |
| @@ -2334,29 +2334,29 @@ ApplyModifier_Match(const char *mod, App | | | @@ -2334,29 +2334,29 @@ ApplyModifier_Match(const char *mod, App |
2334 | p++; | | 2334 | p++; |
2335 | continue; | | 2335 | continue; |
2336 | } | | 2336 | } |
2337 | if (*p == '$') | | 2337 | if (*p == '$') |
2338 | needSubst = TRUE; | | 2338 | needSubst = TRUE; |
2339 | if (*p == '(' || *p == '{') | | 2339 | if (*p == '(' || *p == '{') |
2340 | ++nest; | | 2340 | ++nest; |
2341 | if (*p == ')' || *p == '}') { | | 2341 | if (*p == ')' || *p == '}') { |
2342 | --nest; | | 2342 | --nest; |
2343 | if (nest == 0) | | 2343 | if (nest == 0) |
2344 | break; | | 2344 | break; |
2345 | } | | 2345 | } |
2346 | } | | 2346 | } |
2347 | st->cp = p; | | 2347 | st->next = p; |
2348 | st->termc = *st->cp; | | 2348 | st->termc = *st->next; |
2349 | const char *endpat = st->cp; | | 2349 | const char *endpat = st->next; |
2350 | | | 2350 | |
2351 | char *pattern; | | 2351 | char *pattern; |
2352 | if (copy) { | | 2352 | if (copy) { |
2353 | /* Compress the \:'s out of the pattern. */ | | 2353 | /* Compress the \:'s out of the pattern. */ |
2354 | pattern = bmake_malloc(endpat - (mod + 1) + 1); | | 2354 | pattern = bmake_malloc(endpat - (mod + 1) + 1); |
2355 | char *dst = pattern; | | 2355 | char *dst = pattern; |
2356 | const char *src = mod + 1; | | 2356 | const char *src = mod + 1; |
2357 | for (; src < endpat; src++, dst++) { | | 2357 | for (; src < endpat; src++, dst++) { |
2358 | if (src[0] == '\\' && src + 1 < endpat && | | 2358 | if (src[0] == '\\' && src + 1 < endpat && |
2359 | /* XXX: st->startc is missing here; see above */ | | 2359 | /* XXX: st->startc is missing here; see above */ |
2360 | (src[1] == ':' || src[1] == st->endc)) | | 2360 | (src[1] == ':' || src[1] == st->endc)) |
2361 | src++; | | 2361 | src++; |
2362 | *dst = *src; | | 2362 | *dst = *src; |
| @@ -2387,128 +2387,128 @@ ApplyModifier_Match(const char *mod, App | | | @@ -2387,128 +2387,128 @@ ApplyModifier_Match(const char *mod, App |
2387 | st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, | | 2387 | st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, |
2388 | callback, pattern); | | 2388 | callback, pattern); |
2389 | free(pattern); | | 2389 | free(pattern); |
2390 | } | | 2390 | } |
2391 | | | 2391 | |
2392 | /* :S,from,to, */ | | 2392 | /* :S,from,to, */ |
2393 | static Boolean | | 2393 | static Boolean |
2394 | ApplyModifier_Subst(const char * const mod, ApplyModifiersState *st) | | 2394 | ApplyModifier_Subst(const char * const mod, ApplyModifiersState *st) |
2395 | { | | 2395 | { |
2396 | ModifyWord_SubstArgs args; | | 2396 | ModifyWord_SubstArgs args; |
2397 | Boolean oneBigWord = st->oneBigWord; | | 2397 | Boolean oneBigWord = st->oneBigWord; |
2398 | char delim = mod[1]; | | 2398 | char delim = mod[1]; |
2399 | | | 2399 | |
2400 | st->cp = mod + 2; | | 2400 | st->next = mod + 2; |
2401 | | | 2401 | |
2402 | /* | | 2402 | /* |
2403 | * If pattern begins with '^', it is anchored to the | | 2403 | * If pattern begins with '^', it is anchored to the |
2404 | * start of the word -- skip over it and flag pattern. | | 2404 | * start of the word -- skip over it and flag pattern. |
2405 | */ | | 2405 | */ |
2406 | args.pflags = 0; | | 2406 | args.pflags = 0; |
2407 | if (*st->cp == '^') { | | 2407 | if (*st->next == '^') { |
2408 | args.pflags |= VARP_ANCHOR_START; | | 2408 | args.pflags |= VARP_ANCHOR_START; |
2409 | st->cp++; | | 2409 | st->next++; |
2410 | } | | 2410 | } |
2411 | | | 2411 | |
2412 | char *lhs = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, | | 2412 | char *lhs = ParseModifierPart(&st->next, delim, st->eflags, st->ctxt, |
2413 | &args.lhsLen, &args.pflags, NULL); | | 2413 | &args.lhsLen, &args.pflags, NULL); |
2414 | if (lhs == NULL) { | | 2414 | if (lhs == NULL) { |
2415 | st->missing_delim = delim; | | 2415 | st->missing_delim = delim; |
2416 | return FALSE; | | 2416 | return FALSE; |
2417 | } | | 2417 | } |
2418 | args.lhs = lhs; | | 2418 | args.lhs = lhs; |
2419 | | | 2419 | |
2420 | char *rhs = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, | | 2420 | char *rhs = ParseModifierPart(&st->next, delim, st->eflags, st->ctxt, |
2421 | &args.rhsLen, NULL, &args); | | 2421 | &args.rhsLen, NULL, &args); |
2422 | if (rhs == NULL) { | | 2422 | if (rhs == NULL) { |
2423 | st->missing_delim = delim; | | 2423 | st->missing_delim = delim; |
2424 | return FALSE; | | 2424 | return FALSE; |
2425 | } | | 2425 | } |
2426 | args.rhs = rhs; | | 2426 | args.rhs = rhs; |
2427 | | | 2427 | |
2428 | /* | | 2428 | /* |
2429 | * Check for global substitution. If 'g' after the final | | 2429 | * Check for global substitution. If 'g' after the final |
2430 | * delimiter, substitution is global and is marked that | | 2430 | * delimiter, substitution is global and is marked that |
2431 | * way. | | 2431 | * way. |
2432 | */ | | 2432 | */ |
2433 | for (;; st->cp++) { | | 2433 | for (;; st->next++) { |
2434 | switch (*st->cp) { | | 2434 | switch (*st->next) { |
2435 | case 'g': | | 2435 | case 'g': |
2436 | args.pflags |= VARP_SUB_GLOBAL; | | 2436 | args.pflags |= VARP_SUB_GLOBAL; |
2437 | continue; | | 2437 | continue; |
2438 | case '1': | | 2438 | case '1': |
2439 | args.pflags |= VARP_SUB_ONE; | | 2439 | args.pflags |= VARP_SUB_ONE; |
2440 | continue; | | 2440 | continue; |
2441 | case 'W': | | 2441 | case 'W': |
2442 | oneBigWord = TRUE; | | 2442 | oneBigWord = TRUE; |
2443 | continue; | | 2443 | continue; |
2444 | } | | 2444 | } |
2445 | break; | | 2445 | break; |
2446 | } | | 2446 | } |
2447 | | | 2447 | |
2448 | st->termc = *st->cp; | | 2448 | st->termc = *st->next; |
2449 | st->newStr = ModifyWords(st->ctxt, st->sep, oneBigWord, st->nstr, | | 2449 | st->newStr = ModifyWords(st->ctxt, st->sep, oneBigWord, st->nstr, |
2450 | ModifyWord_Subst, &args); | | 2450 | ModifyWord_Subst, &args); |
2451 | | | 2451 | |
2452 | free(lhs); | | 2452 | free(lhs); |
2453 | free(rhs); | | 2453 | free(rhs); |
2454 | return TRUE; | | 2454 | return TRUE; |
2455 | } | | 2455 | } |
2456 | | | 2456 | |
2457 | #ifndef NO_REGEX | | 2457 | #ifndef NO_REGEX |
2458 | | | 2458 | |
2459 | /* :C,from,to, */ | | 2459 | /* :C,from,to, */ |
2460 | static Boolean | | 2460 | static Boolean |
2461 | ApplyModifier_Regex(const char *mod, ApplyModifiersState *st) | | 2461 | ApplyModifier_Regex(const char *mod, ApplyModifiersState *st) |
2462 | { | | 2462 | { |
2463 | ModifyWord_SubstRegexArgs args; | | 2463 | ModifyWord_SubstRegexArgs args; |
2464 | | | 2464 | |
2465 | args.pflags = 0; | | 2465 | args.pflags = 0; |
2466 | Boolean oneBigWord = st->oneBigWord; | | 2466 | Boolean oneBigWord = st->oneBigWord; |
2467 | char delim = mod[1]; | | 2467 | char delim = mod[1]; |
2468 | | | 2468 | |
2469 | st->cp = mod + 2; | | 2469 | st->next = mod + 2; |
2470 | | | 2470 | |
2471 | char *re = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, | | 2471 | char *re = ParseModifierPart(&st->next, delim, st->eflags, st->ctxt, |
2472 | NULL, NULL, NULL); | | 2472 | NULL, NULL, NULL); |
2473 | if (re == NULL) { | | 2473 | if (re == NULL) { |
2474 | st->missing_delim = delim; | | 2474 | st->missing_delim = delim; |
2475 | return FALSE; | | 2475 | return FALSE; |
2476 | } | | 2476 | } |
2477 | | | 2477 | |
2478 | args.replace = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, | | 2478 | args.replace = ParseModifierPart(&st->next, delim, st->eflags, st->ctxt, |
2479 | NULL, NULL, NULL); | | 2479 | NULL, NULL, NULL); |
2480 | if (args.replace == NULL) { | | 2480 | if (args.replace == NULL) { |
2481 | free(re); | | 2481 | free(re); |
2482 | st->missing_delim = delim; | | 2482 | st->missing_delim = delim; |
2483 | return FALSE; | | 2483 | return FALSE; |
2484 | } | | 2484 | } |
2485 | | | 2485 | |
2486 | for (;; st->cp++) { | | 2486 | for (;; st->next++) { |
2487 | switch (*st->cp) { | | 2487 | switch (*st->next) { |
2488 | case 'g': | | 2488 | case 'g': |
2489 | args.pflags |= VARP_SUB_GLOBAL; | | 2489 | args.pflags |= VARP_SUB_GLOBAL; |
2490 | continue; | | 2490 | continue; |
2491 | case '1': | | 2491 | case '1': |
2492 | args.pflags |= VARP_SUB_ONE; | | 2492 | args.pflags |= VARP_SUB_ONE; |
2493 | continue; | | 2493 | continue; |
2494 | case 'W': | | 2494 | case 'W': |
2495 | oneBigWord = TRUE; | | 2495 | oneBigWord = TRUE; |
2496 | continue; | | 2496 | continue; |
2497 | } | | 2497 | } |
2498 | break; | | 2498 | break; |
2499 | } | | 2499 | } |
2500 | | | 2500 | |
2501 | st->termc = *st->cp; | | 2501 | st->termc = *st->next; |
2502 | | | 2502 | |
2503 | int error = regcomp(&args.re, re, REG_EXTENDED); | | 2503 | int error = regcomp(&args.re, re, REG_EXTENDED); |
2504 | free(re); | | 2504 | free(re); |
2505 | if (error) { | | 2505 | if (error) { |
2506 | VarREError(error, &args.re, "RE substitution error"); | | 2506 | VarREError(error, &args.re, "RE substitution error"); |
2507 | free(args.replace); | | 2507 | free(args.replace); |
2508 | return FALSE; | | 2508 | return FALSE; |
2509 | } | | 2509 | } |
2510 | | | 2510 | |
2511 | args.nsub = args.re.re_nsub + 1; | | 2511 | args.nsub = args.re.re_nsub + 1; |
2512 | if (args.nsub < 1) | | 2512 | if (args.nsub < 1) |
2513 | args.nsub = 1; | | 2513 | args.nsub = 1; |
2514 | if (args.nsub > 10) | | 2514 | if (args.nsub > 10) |
| @@ -2524,132 +2524,132 @@ ApplyModifier_Regex(const char *mod, App | | | @@ -2524,132 +2524,132 @@ ApplyModifier_Regex(const char *mod, App |
2524 | static void | | 2524 | static void |
2525 | ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) | | 2525 | ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) |
2526 | { | | 2526 | { |
2527 | SepBuf_AddStr(buf, word); | | 2527 | SepBuf_AddStr(buf, word); |
2528 | } | | 2528 | } |
2529 | | | 2529 | |
2530 | /* :ts<separator> */ | | 2530 | /* :ts<separator> */ |
2531 | static Boolean | | 2531 | static Boolean |
2532 | ApplyModifier_ToSep(const char *sep, ApplyModifiersState *st) | | 2532 | ApplyModifier_ToSep(const char *sep, ApplyModifiersState *st) |
2533 | { | | 2533 | { |
2534 | if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) { | | 2534 | if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) { |
2535 | /* ":ts<unrecognised><endc>" or ":ts<unrecognised>:" */ | | 2535 | /* ":ts<unrecognised><endc>" or ":ts<unrecognised>:" */ |
2536 | st->sep = sep[0]; | | 2536 | st->sep = sep[0]; |
2537 | st->cp = sep + 1; | | 2537 | st->next = sep + 1; |
2538 | } else if (sep[0] == st->endc || sep[0] == ':') { | | 2538 | } else if (sep[0] == st->endc || sep[0] == ':') { |
2539 | /* ":ts<endc>" or ":ts:" */ | | 2539 | /* ":ts<endc>" or ":ts:" */ |
2540 | st->sep = '\0'; /* no separator */ | | 2540 | st->sep = '\0'; /* no separator */ |
2541 | st->cp = sep; | | 2541 | st->next = sep; |
2542 | } else if (sep[0] == '\\') { | | 2542 | } else if (sep[0] == '\\') { |
2543 | const char *xp = sep + 1; | | 2543 | const char *xp = sep + 1; |
2544 | int base = 8; /* assume octal */ | | 2544 | int base = 8; /* assume octal */ |
2545 | | | 2545 | |
2546 | switch (sep[1]) { | | 2546 | switch (sep[1]) { |
2547 | case 'n': | | 2547 | case 'n': |
2548 | st->sep = '\n'; | | 2548 | st->sep = '\n'; |
2549 | st->cp = sep + 2; | | 2549 | st->next = sep + 2; |
2550 | break; | | 2550 | break; |
2551 | case 't': | | 2551 | case 't': |
2552 | st->sep = '\t'; | | 2552 | st->sep = '\t'; |
2553 | st->cp = sep + 2; | | 2553 | st->next = sep + 2; |
2554 | break; | | 2554 | break; |
2555 | case 'x': | | 2555 | case 'x': |
2556 | base = 16; | | 2556 | base = 16; |
2557 | xp++; | | 2557 | xp++; |
2558 | goto get_numeric; | | 2558 | goto get_numeric; |
2559 | case '0': | | 2559 | case '0': |
2560 | base = 0; | | 2560 | base = 0; |
2561 | goto get_numeric; | | 2561 | goto get_numeric; |
2562 | default: | | 2562 | default: |
2563 | if (!isdigit((unsigned char)sep[1])) | | 2563 | if (!isdigit((unsigned char)sep[1])) |
2564 | return FALSE; /* ":ts<backslash><unrecognised>". */ | | 2564 | return FALSE; /* ":ts<backslash><unrecognised>". */ |
2565 | | | 2565 | |
2566 | char *end; | | 2566 | char *end; |
2567 | get_numeric: | | 2567 | get_numeric: |
2568 | st->sep = strtoul(sep + 1 + (sep[1] == 'x'), &end, base); | | 2568 | st->sep = strtoul(sep + 1 + (sep[1] == 'x'), &end, base); |
2569 | if (*end != ':' && *end != st->endc) | | 2569 | if (*end != ':' && *end != st->endc) |
2570 | return FALSE; | | 2570 | return FALSE; |
2571 | st->cp = end; | | 2571 | st->next = end; |
2572 | break; | | 2572 | break; |
2573 | } | | 2573 | } |
2574 | } else { | | 2574 | } else { |
2575 | return FALSE; /* Found ":ts<unrecognised><unrecognised>". */ | | 2575 | return FALSE; /* Found ":ts<unrecognised><unrecognised>". */ |
2576 | } | | 2576 | } |
2577 | | | 2577 | |
2578 | st->termc = *st->cp; | | 2578 | st->termc = *st->next; |
2579 | st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, | | 2579 | st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, |
2580 | ModifyWord_Copy, NULL); | | 2580 | ModifyWord_Copy, NULL); |
2581 | return TRUE; | | 2581 | return TRUE; |
2582 | } | | 2582 | } |
2583 | | | 2583 | |
2584 | /* :tA, :tu, :tl, :ts<separator>, etc. */ | | 2584 | /* :tA, :tu, :tl, :ts<separator>, etc. */ |
2585 | static Boolean | | 2585 | static Boolean |
2586 | ApplyModifier_To(const char *mod, ApplyModifiersState *st) | | 2586 | ApplyModifier_To(const char *mod, ApplyModifiersState *st) |
2587 | { | | 2587 | { |
2588 | st->cp = mod + 1; /* make sure it is set */ | | 2588 | st->next = mod + 1; /* make sure it is set */ |
2589 | if (mod[1] == st->endc || mod[1] == ':') | | 2589 | if (mod[1] == st->endc || mod[1] == ':') |
2590 | return FALSE; /* Found ":t<endc>" or ":t:". */ | | 2590 | return FALSE; /* Found ":t<endc>" or ":t:". */ |
2591 | | | 2591 | |
2592 | if (mod[1] == 's') | | 2592 | if (mod[1] == 's') |
2593 | return ApplyModifier_ToSep(mod + 2, st); | | 2593 | return ApplyModifier_ToSep(mod + 2, st); |
2594 | | | 2594 | |
2595 | if (mod[2] != st->endc && mod[2] != ':') | | 2595 | if (mod[2] != st->endc && mod[2] != ':') |
2596 | return FALSE; /* Found ":t<unrecognised><unrecognised>". */ | | 2596 | return FALSE; /* Found ":t<unrecognised><unrecognised>". */ |
2597 | | | 2597 | |
2598 | /* Check for two-character options: ":tu", ":tl" */ | | 2598 | /* Check for two-character options: ":tu", ":tl" */ |
2599 | if (mod[1] == 'A') { /* absolute path */ | | 2599 | if (mod[1] == 'A') { /* absolute path */ |
2600 | st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, | | 2600 | st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, |
2601 | ModifyWord_Realpath, NULL); | | 2601 | ModifyWord_Realpath, NULL); |
2602 | st->cp = mod + 2; | | 2602 | st->next = mod + 2; |
2603 | st->termc = *st->cp; | | 2603 | st->termc = *st->next; |
2604 | } else if (mod[1] == 'u') { | | 2604 | } else if (mod[1] == 'u') { |
2605 | char *dp = bmake_strdup(st->nstr); | | 2605 | char *dp = bmake_strdup(st->nstr); |
2606 | for (st->newStr = dp; *dp; dp++) | | 2606 | for (st->newStr = dp; *dp; dp++) |
2607 | *dp = toupper((unsigned char)*dp); | | 2607 | *dp = toupper((unsigned char)*dp); |
2608 | st->cp = mod + 2; | | 2608 | st->next = mod + 2; |
2609 | st->termc = *st->cp; | | 2609 | st->termc = *st->next; |
2610 | } else if (mod[1] == 'l') { | | 2610 | } else if (mod[1] == 'l') { |
2611 | char *dp = bmake_strdup(st->nstr); | | 2611 | char *dp = bmake_strdup(st->nstr); |
2612 | for (st->newStr = dp; *dp; dp++) | | 2612 | for (st->newStr = dp; *dp; dp++) |
2613 | *dp = tolower((unsigned char)*dp); | | 2613 | *dp = tolower((unsigned char)*dp); |
2614 | st->cp = mod + 2; | | 2614 | st->next = mod + 2; |
2615 | st->termc = *st->cp; | | 2615 | st->termc = *st->next; |
2616 | } else if (mod[1] == 'W' || mod[1] == 'w') { | | 2616 | } else if (mod[1] == 'W' || mod[1] == 'w') { |
2617 | st->oneBigWord = mod[1] == 'W'; | | 2617 | st->oneBigWord = mod[1] == 'W'; |
2618 | st->newStr = st->nstr; | | 2618 | st->newStr = st->nstr; |
2619 | st->cp = mod + 2; | | 2619 | st->next = mod + 2; |
2620 | st->termc = *st->cp; | | 2620 | st->termc = *st->next; |
2621 | } else { | | 2621 | } else { |
2622 | /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */ | | 2622 | /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */ |
2623 | return FALSE; | | 2623 | return FALSE; |
2624 | } | | 2624 | } |
2625 | return TRUE; | | 2625 | return TRUE; |
2626 | } | | 2626 | } |
2627 | | | 2627 | |
2628 | /* :[#], :[1], etc. */ | | 2628 | /* :[#], :[1], etc. */ |
2629 | static int | | 2629 | static int |
2630 | ApplyModifier_Words(const char *mod, ApplyModifiersState *st) | | 2630 | ApplyModifier_Words(const char *mod, ApplyModifiersState *st) |
2631 | { | | 2631 | { |
2632 | st->cp = mod + 1; /* point to char after '[' */ | | 2632 | st->next = mod + 1; /* point to char after '[' */ |
2633 | char delim = ']'; /* look for closing ']' */ | | 2633 | char delim = ']'; /* look for closing ']' */ |
2634 | char *estr = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, | | 2634 | char *estr = ParseModifierPart(&st->next, delim, st->eflags, st->ctxt, |
2635 | NULL, NULL, NULL); | | 2635 | NULL, NULL, NULL); |
2636 | if (estr == NULL) { | | 2636 | if (estr == NULL) { |
2637 | st->missing_delim = delim; | | 2637 | st->missing_delim = delim; |
2638 | return 'c'; | | 2638 | return 'c'; |
2639 | } | | 2639 | } |
2640 | | | 2640 | |
2641 | /* now st->cp points just after the closing ']' */ | | 2641 | /* now st->next points just after the closing ']' */ |
2642 | if (st->cp[0] != ':' && st->cp[0] != st->endc) | | 2642 | if (st->next[0] != ':' && st->next[0] != st->endc) |
2643 | goto bad_modifier; /* Found junk after ']' */ | | 2643 | goto bad_modifier; /* Found junk after ']' */ |
2644 | | | 2644 | |
2645 | if (estr[0] == '\0') | | 2645 | if (estr[0] == '\0') |
2646 | goto bad_modifier; /* empty square brackets in ":[]". */ | | 2646 | goto bad_modifier; /* empty square brackets in ":[]". */ |
2647 | | | 2647 | |
2648 | if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */ | | 2648 | if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */ |
2649 | if (st->oneBigWord) { | | 2649 | if (st->oneBigWord) { |
2650 | st->newStr = bmake_strdup("1"); | | 2650 | st->newStr = bmake_strdup("1"); |
2651 | } else { | | 2651 | } else { |
2652 | /* XXX: brk_string() is a rather expensive | | 2652 | /* XXX: brk_string() is a rather expensive |
2653 | * way of counting words. */ | | 2653 | * way of counting words. */ |
2654 | char *as; | | 2654 | char *as; |
2655 | int ac; | | 2655 | int ac; |
| @@ -2709,92 +2709,92 @@ ApplyModifier_Words(const char *mod, App | | | @@ -2709,92 +2709,92 @@ ApplyModifier_Words(const char *mod, App |
2709 | st->oneBigWord = TRUE; | | 2709 | st->oneBigWord = TRUE; |
2710 | st->newStr = st->nstr; | | 2710 | st->newStr = st->nstr; |
2711 | goto ok; | | 2711 | goto ok; |
2712 | } | | 2712 | } |
2713 | | | 2713 | |
2714 | /* ":[0..N]" or ":[N..0]" */ | | 2714 | /* ":[0..N]" or ":[N..0]" */ |
2715 | if (first == 0 || last == 0) | | 2715 | if (first == 0 || last == 0) |
2716 | goto bad_modifier; | | 2716 | goto bad_modifier; |
2717 | | | 2717 | |
2718 | /* Normal case: select the words described by seldata. */ | | 2718 | /* Normal case: select the words described by seldata. */ |
2719 | st->newStr = VarSelectWords(st->sep, st->oneBigWord, st->nstr, first, last); | | 2719 | st->newStr = VarSelectWords(st->sep, st->oneBigWord, st->nstr, first, last); |
2720 | | | 2720 | |
2721 | ok: | | 2721 | ok: |
2722 | st->termc = *st->cp; | | 2722 | st->termc = *st->next; |
2723 | free(estr); | | 2723 | free(estr); |
2724 | return 0; | | 2724 | return 0; |
2725 | | | 2725 | |
2726 | bad_modifier: | | 2726 | bad_modifier: |
2727 | free(estr); | | 2727 | free(estr); |
2728 | return 'b'; | | 2728 | return 'b'; |
2729 | } | | 2729 | } |
2730 | | | 2730 | |
2731 | /* :O or :Ox */ | | 2731 | /* :O or :Ox */ |
2732 | static Boolean | | 2732 | static Boolean |
2733 | ApplyModifier_Order(const char *mod, ApplyModifiersState *st) | | 2733 | ApplyModifier_Order(const char *mod, ApplyModifiersState *st) |
2734 | { | | 2734 | { |
2735 | char otype; | | 2735 | char otype; |
2736 | | | 2736 | |
2737 | st->cp = mod + 1; /* skip to the rest in any case */ | | 2737 | st->next = mod + 1; /* skip to the rest in any case */ |
2738 | if (mod[1] == st->endc || mod[1] == ':') { | | 2738 | if (mod[1] == st->endc || mod[1] == ':') { |
2739 | otype = 's'; | | 2739 | otype = 's'; |
2740 | st->termc = *st->cp; | | 2740 | st->termc = *st->next; |
2741 | } else if ((mod[1] == 'r' || mod[1] == 'x') && | | 2741 | } else if ((mod[1] == 'r' || mod[1] == 'x') && |
2742 | (mod[2] == st->endc || mod[2] == ':')) { | | 2742 | (mod[2] == st->endc || mod[2] == ':')) { |
2743 | otype = mod[1]; | | 2743 | otype = mod[1]; |
2744 | st->cp = mod + 2; | | 2744 | st->next = mod + 2; |
2745 | st->termc = *st->cp; | | 2745 | st->termc = *st->next; |
2746 | } else { | | 2746 | } else { |
2747 | return FALSE; | | 2747 | return FALSE; |
2748 | } | | 2748 | } |
2749 | st->newStr = VarOrder(st->nstr, otype); | | 2749 | st->newStr = VarOrder(st->nstr, otype); |
2750 | return TRUE; | | 2750 | return TRUE; |
2751 | } | | 2751 | } |
2752 | | | 2752 | |
2753 | /* :? then : else */ | | 2753 | /* :? then : else */ |
2754 | static Boolean | | 2754 | static Boolean |
2755 | ApplyModifier_IfElse(const char *mod, ApplyModifiersState *st) | | 2755 | ApplyModifier_IfElse(const char *mod, ApplyModifiersState *st) |
2756 | { | | 2756 | { |
2757 | Boolean value = FALSE; | | 2757 | Boolean value = FALSE; |
2758 | int cond_rc = 0; | | 2758 | int cond_rc = 0; |
2759 | VarEvalFlags then_eflags = st->eflags & ~VARE_WANTRES; | | 2759 | VarEvalFlags then_eflags = st->eflags & ~VARE_WANTRES; |
2760 | VarEvalFlags else_eflags = st->eflags & ~VARE_WANTRES; | | 2760 | VarEvalFlags else_eflags = st->eflags & ~VARE_WANTRES; |
2761 | | | 2761 | |
2762 | if (st->eflags & VARE_WANTRES) { | | 2762 | if (st->eflags & VARE_WANTRES) { |
2763 | cond_rc = Cond_EvalExpression(NULL, st->v->name, &value, 0, FALSE); | | 2763 | cond_rc = Cond_EvalExpression(NULL, st->v->name, &value, 0, FALSE); |
2764 | if (cond_rc != COND_INVALID && value) | | 2764 | if (cond_rc != COND_INVALID && value) |
2765 | then_eflags |= VARE_WANTRES; | | 2765 | then_eflags |= VARE_WANTRES; |
2766 | if (cond_rc != COND_INVALID && !value) | | 2766 | if (cond_rc != COND_INVALID && !value) |
2767 | else_eflags |= VARE_WANTRES; | | 2767 | else_eflags |= VARE_WANTRES; |
2768 | } | | 2768 | } |
2769 | | | 2769 | |
2770 | st->cp = mod + 1; | | 2770 | st->next = mod + 1; |
2771 | char delim = ':'; | | 2771 | char delim = ':'; |
2772 | char *then_expr = ParseModifierPart(&st->cp, delim, then_eflags, st->ctxt, | | 2772 | char *then_expr = ParseModifierPart(&st->next, delim, then_eflags, st->ctxt, |
2773 | NULL, NULL, NULL); | | 2773 | NULL, NULL, NULL); |
2774 | if (then_expr == NULL) { | | 2774 | if (then_expr == NULL) { |
2775 | st->missing_delim = delim; | | 2775 | st->missing_delim = delim; |
2776 | return FALSE; | | 2776 | return FALSE; |
2777 | } | | 2777 | } |
2778 | | | 2778 | |
2779 | delim = st->endc; /* BRCLOSE or PRCLOSE */ | | 2779 | delim = st->endc; /* BRCLOSE or PRCLOSE */ |
2780 | char *else_expr = ParseModifierPart(&st->cp, delim, else_eflags, st->ctxt, | | 2780 | char *else_expr = ParseModifierPart(&st->next, delim, else_eflags, st->ctxt, |
2781 | NULL, NULL, NULL); | | 2781 | NULL, NULL, NULL); |
2782 | if (else_expr == NULL) { | | 2782 | if (else_expr == NULL) { |
2783 | st->missing_delim = delim; | | 2783 | st->missing_delim = delim; |
2784 | return FALSE; | | 2784 | return FALSE; |
2785 | } | | 2785 | } |
2786 | | | 2786 | |
2787 | st->termc = *--st->cp; | | 2787 | st->termc = *--st->next; |
2788 | if (cond_rc == COND_INVALID) { | | 2788 | if (cond_rc == COND_INVALID) { |
2789 | Error("Bad conditional expression `%s' in %s?%s:%s", | | 2789 | Error("Bad conditional expression `%s' in %s?%s:%s", |
2790 | st->v->name, st->v->name, then_expr, else_expr); | | 2790 | st->v->name, st->v->name, then_expr, else_expr); |
2791 | return FALSE; | | 2791 | return FALSE; |
2792 | } | | 2792 | } |
2793 | | | 2793 | |
2794 | if (value) { | | 2794 | if (value) { |
2795 | st->newStr = then_expr; | | 2795 | st->newStr = then_expr; |
2796 | free(else_expr); | | 2796 | free(else_expr); |
2797 | } else { | | 2797 | } else { |
2798 | st->newStr = else_expr; | | 2798 | st->newStr = else_expr; |
2799 | free(then_expr); | | 2799 | free(then_expr); |
2800 | } | | 2800 | } |
| @@ -2848,47 +2848,47 @@ ApplyModifier_Assign(const char *mod, Ap | | | @@ -2848,47 +2848,47 @@ ApplyModifier_Assign(const char *mod, Ap |
2848 | st->v->name = bmake_strdup(st->v->name); | | 2848 | st->v->name = bmake_strdup(st->v->name); |
2849 | } else if (st->ctxt != VAR_GLOBAL) { | | 2849 | } else if (st->ctxt != VAR_GLOBAL) { |
2850 | Var *gv = VarFind(st->v->name, st->ctxt, 0); | | 2850 | Var *gv = VarFind(st->v->name, st->ctxt, 0); |
2851 | if (gv == NULL) | | 2851 | if (gv == NULL) |
2852 | v_ctxt = VAR_GLOBAL; | | 2852 | v_ctxt = VAR_GLOBAL; |
2853 | else | | 2853 | else |
2854 | VarFreeEnv(gv, TRUE); | | 2854 | VarFreeEnv(gv, TRUE); |
2855 | } | | 2855 | } |
2856 | | | 2856 | |
2857 | switch (op[0]) { | | 2857 | switch (op[0]) { |
2858 | case '+': | | 2858 | case '+': |
2859 | case '?': | | 2859 | case '?': |
2860 | case '!': | | 2860 | case '!': |
2861 | st->cp = mod + 3; | | 2861 | st->next = mod + 3; |
2862 | break; | | 2862 | break; |
2863 | default: | | 2863 | default: |
2864 | st->cp = mod + 2; | | 2864 | st->next = mod + 2; |
2865 | break; | | 2865 | break; |
2866 | } | | 2866 | } |
2867 | | | 2867 | |
2868 | char delim = st->startc == PROPEN ? PRCLOSE : BRCLOSE; | | 2868 | char delim = st->startc == PROPEN ? PRCLOSE : BRCLOSE; |
2869 | char *val = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, | | 2869 | char *val = ParseModifierPart(&st->next, delim, st->eflags, st->ctxt, |
2870 | NULL, NULL, NULL); | | 2870 | NULL, NULL, NULL); |
2871 | if (st->v->flags & VAR_JUNK) { | | 2871 | if (st->v->flags & VAR_JUNK) { |
2872 | /* restore original name */ | | 2872 | /* restore original name */ |
2873 | free(st->v->name); | | 2873 | free(st->v->name); |
2874 | st->v->name = sv_name; | | 2874 | st->v->name = sv_name; |
2875 | } | | 2875 | } |
2876 | if (val == NULL) { | | 2876 | if (val == NULL) { |
2877 | st->missing_delim = delim; | | 2877 | st->missing_delim = delim; |
2878 | return 'c'; | | 2878 | return 'c'; |
2879 | } | | 2879 | } |
2880 | | | 2880 | |
2881 | st->termc = *--st->cp; | | 2881 | st->termc = *--st->next; |
2882 | | | 2882 | |
2883 | if (st->eflags & VARE_WANTRES) { | | 2883 | if (st->eflags & VARE_WANTRES) { |
2884 | switch (op[0]) { | | 2884 | switch (op[0]) { |
2885 | case '+': | | 2885 | case '+': |
2886 | Var_Append(st->v->name, val, v_ctxt); | | 2886 | Var_Append(st->v->name, val, v_ctxt); |
2887 | break; | | 2887 | break; |
2888 | case '!': { | | 2888 | case '!': { |
2889 | const char *emsg; | | 2889 | const char *emsg; |
2890 | st->newStr = Cmd_Exec(val, &emsg); | | 2890 | st->newStr = Cmd_Exec(val, &emsg); |
2891 | if (emsg) | | 2891 | if (emsg) |
2892 | Error(emsg, st->nstr); | | 2892 | Error(emsg, st->nstr); |
2893 | else | | 2893 | else |
2894 | Var_Set(st->v->name, st->newStr, v_ctxt); | | 2894 | Var_Set(st->v->name, st->newStr, v_ctxt); |
| @@ -2904,95 +2904,95 @@ ApplyModifier_Assign(const char *mod, Ap | | | @@ -2904,95 +2904,95 @@ ApplyModifier_Assign(const char *mod, Ap |
2904 | break; | | 2904 | break; |
2905 | } | | 2905 | } |
2906 | } | | 2906 | } |
2907 | free(val); | | 2907 | free(val); |
2908 | st->newStr = varNoError; | | 2908 | st->newStr = varNoError; |
2909 | return 0; | | 2909 | return 0; |
2910 | } | | 2910 | } |
2911 | | | 2911 | |
2912 | /* remember current value */ | | 2912 | /* remember current value */ |
2913 | static Boolean | | 2913 | static Boolean |
2914 | ApplyModifier_Remember(const char *mod, ApplyModifiersState *st) | | 2914 | ApplyModifier_Remember(const char *mod, ApplyModifiersState *st) |
2915 | { | | 2915 | { |
2916 | if (!ModMatchEq(mod, "_", st->endc)) { | | 2916 | if (!ModMatchEq(mod, "_", st->endc)) { |
2917 | st->cp = mod + 1; | | 2917 | st->next = mod + 1; |
2918 | return FALSE; | | 2918 | return FALSE; |
2919 | } | | 2919 | } |
2920 | | | 2920 | |
2921 | if (mod[1] == '=') { | | 2921 | if (mod[1] == '=') { |
2922 | size_t n = strcspn(mod + 2, ":)}"); | | 2922 | size_t n = strcspn(mod + 2, ":)}"); |
2923 | char *name = bmake_strndup(mod + 2, n); | | 2923 | char *name = bmake_strndup(mod + 2, n); |
2924 | Var_Set(name, st->nstr, st->ctxt); | | 2924 | Var_Set(name, st->nstr, st->ctxt); |
2925 | free(name); | | 2925 | free(name); |
2926 | st->cp = mod + 2 + n; | | 2926 | st->next = mod + 2 + n; |
2927 | } else { | | 2927 | } else { |
2928 | Var_Set("_", st->nstr, st->ctxt); | | 2928 | Var_Set("_", st->nstr, st->ctxt); |
2929 | st->cp = mod + 1; | | 2929 | st->next = mod + 1; |
2930 | } | | 2930 | } |
2931 | st->newStr = st->nstr; | | 2931 | st->newStr = st->nstr; |
2932 | st->termc = *st->cp; | | 2932 | st->termc = *st->next; |
2933 | return TRUE; | | 2933 | return TRUE; |
2934 | } | | 2934 | } |
2935 | | | 2935 | |
2936 | #ifdef SYSVVARSUB | | 2936 | #ifdef SYSVVARSUB |
2937 | /* :from=to */ | | 2937 | /* :from=to */ |
2938 | static int | | 2938 | static int |
2939 | ApplyModifier_SysV(const char *mod, ApplyModifiersState *st) | | 2939 | ApplyModifier_SysV(const char *mod, ApplyModifiersState *st) |
2940 | { | | 2940 | { |
2941 | Boolean eqFound = FALSE; | | 2941 | Boolean eqFound = FALSE; |
2942 | | | 2942 | |
2943 | /* | | 2943 | /* |
2944 | * First we make a pass through the string trying | | 2944 | * First we make a pass through the string trying |
2945 | * to verify it is a SYSV-make-style translation: | | 2945 | * to verify it is a SYSV-make-style translation: |
2946 | * it must be: <string1>=<string2>) | | 2946 | * it must be: <string1>=<string2>) |
2947 | */ | | 2947 | */ |
2948 | st->cp = mod; | | 2948 | st->next = mod; |
2949 | int nest = 1; | | 2949 | int nest = 1; |
2950 | while (*st->cp != '\0' && nest > 0) { | | 2950 | while (*st->next != '\0' && nest > 0) { |
2951 | if (*st->cp == '=') { | | 2951 | if (*st->next == '=') { |
2952 | eqFound = TRUE; | | 2952 | eqFound = TRUE; |
2953 | /* continue looking for st->endc */ | | 2953 | /* continue looking for st->endc */ |
2954 | } else if (*st->cp == st->endc) | | 2954 | } else if (*st->next == st->endc) |
2955 | nest--; | | 2955 | nest--; |
2956 | else if (*st->cp == st->startc) | | 2956 | else if (*st->next == st->startc) |
2957 | nest++; | | 2957 | nest++; |
2958 | if (nest > 0) | | 2958 | if (nest > 0) |
2959 | st->cp++; | | 2959 | st->next++; |
2960 | } | | 2960 | } |
2961 | if (*st->cp != st->endc || !eqFound) | | 2961 | if (*st->next != st->endc || !eqFound) |
2962 | return 0; | | 2962 | return 0; |
2963 | | | 2963 | |
2964 | char delim = '='; | | 2964 | char delim = '='; |
2965 | st->cp = mod; | | 2965 | st->next = mod; |
2966 | char *lhs = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, | | 2966 | char *lhs = ParseModifierPart(&st->next, delim, st->eflags, st->ctxt, |
2967 | NULL, NULL, NULL); | | 2967 | NULL, NULL, NULL); |
2968 | if (lhs == NULL) { | | 2968 | if (lhs == NULL) { |
2969 | st->missing_delim = delim; | | 2969 | st->missing_delim = delim; |
2970 | return 'c'; | | 2970 | return 'c'; |
2971 | } | | 2971 | } |
2972 | | | 2972 | |
2973 | delim = st->endc; | | 2973 | delim = st->endc; |
2974 | char *rhs = ParseModifierPart(&st->cp, delim, st->eflags, st->ctxt, | | 2974 | char *rhs = ParseModifierPart(&st->next, delim, st->eflags, st->ctxt, |
2975 | NULL, NULL, NULL); | | 2975 | NULL, NULL, NULL); |
2976 | if (rhs == NULL) { | | 2976 | if (rhs == NULL) { |
2977 | st->missing_delim = delim; | | 2977 | st->missing_delim = delim; |
2978 | return 'c'; | | 2978 | return 'c'; |
2979 | } | | 2979 | } |
2980 | | | 2980 | |
2981 | /* | | 2981 | /* |
2982 | * SYSV modifications happen through the whole | | 2982 | * SYSV modifications happen through the whole |
2983 | * string. Note the pattern is anchored at the end. | | 2983 | * string. Note the pattern is anchored at the end. |
2984 | */ | | 2984 | */ |
2985 | st->termc = *--st->cp; | | 2985 | st->termc = *--st->next; |
2986 | if (lhs[0] == '\0' && *st->nstr == '\0') { | | 2986 | if (lhs[0] == '\0' && *st->nstr == '\0') { |
2987 | st->newStr = st->nstr; /* special case */ | | 2987 | st->newStr = st->nstr; /* special case */ |
2988 | } else { | | 2988 | } else { |
2989 | ModifyWord_SYSVSubstArgs args = { st->ctxt, lhs, rhs }; | | 2989 | ModifyWord_SYSVSubstArgs args = { st->ctxt, lhs, rhs }; |
2990 | st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, | | 2990 | st->newStr = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->nstr, |
2991 | ModifyWord_SYSVSubst, &args); | | 2991 | ModifyWord_SYSVSubst, &args); |
2992 | } | | 2992 | } |
2993 | free(lhs); | | 2993 | free(lhs); |
2994 | free(rhs); | | 2994 | free(rhs); |
2995 | return '='; | | 2995 | return '='; |
2996 | } | | 2996 | } |
2997 | #endif | | 2997 | #endif |
2998 | | | 2998 | |
| @@ -3154,28 +3154,28 @@ ApplyModifiers(char *nstr, const char * | | | @@ -3154,28 +3154,28 @@ ApplyModifiers(char *nstr, const char * |
3154 | case '_': | | 3154 | case '_': |
3155 | if (!ApplyModifier_Remember(p, &st)) | | 3155 | if (!ApplyModifier_Remember(p, &st)) |
3156 | goto default_case; | | 3156 | goto default_case; |
3157 | break; | | 3157 | break; |
3158 | case 'D': | | 3158 | case 'D': |
3159 | case 'U': | | 3159 | case 'U': |
3160 | ApplyModifier_Defined(p, &st); | | 3160 | ApplyModifier_Defined(p, &st); |
3161 | break; | | 3161 | break; |
3162 | case 'L': | | 3162 | case 'L': |
3163 | { | | 3163 | { |
3164 | if (st.v->flags & VAR_JUNK) | | 3164 | if (st.v->flags & VAR_JUNK) |
3165 | st.v->flags |= VAR_KEEP; | | 3165 | st.v->flags |= VAR_KEEP; |
3166 | st.newStr = bmake_strdup(st.v->name); | | 3166 | st.newStr = bmake_strdup(st.v->name); |
3167 | st.cp = p + 1; | | 3167 | st.next = p + 1; |
3168 | st.termc = *st.cp; | | 3168 | st.termc = *st.next; |
3169 | break; | | 3169 | break; |
3170 | } | | 3170 | } |
3171 | case 'P': | | 3171 | case 'P': |
3172 | ApplyModifier_Path(p, &st); | | 3172 | ApplyModifier_Path(p, &st); |
3173 | break; | | 3173 | break; |
3174 | case '!': | | 3174 | case '!': |
3175 | if (!ApplyModifier_Exclam(p, &st)) | | 3175 | if (!ApplyModifier_Exclam(p, &st)) |
3176 | goto cleanup; | | 3176 | goto cleanup; |
3177 | break; | | 3177 | break; |
3178 | case '[': | | 3178 | case '[': |
3179 | { | | 3179 | { |
3180 | int res = ApplyModifier_Words(p, &st); | | 3180 | int res = ApplyModifier_Words(p, &st); |
3181 | if (res == 'b') | | 3181 | if (res == 'b') |
| @@ -3212,153 +3212,154 @@ ApplyModifiers(char *nstr, const char * | | | @@ -3212,153 +3212,154 @@ ApplyModifiers(char *nstr, const char * |
3212 | if (!ApplyModifier_IfElse(p, &st)) | | 3212 | if (!ApplyModifier_IfElse(p, &st)) |
3213 | goto cleanup; | | 3213 | goto cleanup; |
3214 | break; | | 3214 | break; |
3215 | #ifndef NO_REGEX | | 3215 | #ifndef NO_REGEX |
3216 | case 'C': | | 3216 | case 'C': |
3217 | if (!ApplyModifier_Regex(p, &st)) | | 3217 | if (!ApplyModifier_Regex(p, &st)) |
3218 | goto cleanup; | | 3218 | goto cleanup; |
3219 | break; | | 3219 | break; |
3220 | #endif | | 3220 | #endif |
3221 | case 'q': | | 3221 | case 'q': |
3222 | case 'Q': | | 3222 | case 'Q': |
3223 | if (p[1] == st.endc || p[1] == ':') { | | 3223 | if (p[1] == st.endc || p[1] == ':') { |
3224 | st.newStr = VarQuote(st.nstr, modifier == 'q'); | | 3224 | st.newStr = VarQuote(st.nstr, modifier == 'q'); |
3225 | st.cp = p + 1; | | 3225 | st.next = p + 1; |
3226 | st.termc = *st.cp; | | 3226 | st.termc = *st.next; |
3227 | break; | | 3227 | break; |
3228 | } | | 3228 | } |
3229 | goto default_case; | | 3229 | goto default_case; |
3230 | case 'T': | | 3230 | case 'T': |
3231 | if (p[1] == st.endc || p[1] == ':') { | | 3231 | if (p[1] == st.endc || p[1] == ':') { |
3232 | st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord, | | 3232 | st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord, |
3233 | st.nstr, ModifyWord_Tail, NULL); | | 3233 | st.nstr, ModifyWord_Tail, NULL); |
3234 | st.cp = p + 1; | | 3234 | st.next = p + 1; |
3235 | st.termc = *st.cp; | | 3235 | st.termc = *st.next; |
3236 | break; | | 3236 | break; |
3237 | } | | 3237 | } |
3238 | goto default_case; | | 3238 | goto default_case; |
3239 | case 'H': | | 3239 | case 'H': |
3240 | if (p[1] == st.endc || p[1] == ':') { | | 3240 | if (p[1] == st.endc || p[1] == ':') { |
3241 | st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord, | | 3241 | st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord, |
3242 | st.nstr, ModifyWord_Head, NULL); | | 3242 | st.nstr, ModifyWord_Head, NULL); |
3243 | st.cp = p + 1; | | 3243 | st.next = p + 1; |
3244 | st.termc = *st.cp; | | 3244 | st.termc = *st.next; |
3245 | break; | | 3245 | break; |
3246 | } | | 3246 | } |
3247 | goto default_case; | | 3247 | goto default_case; |
3248 | case 'E': | | 3248 | case 'E': |
3249 | if (p[1] == st.endc || p[1] == ':') { | | 3249 | if (p[1] == st.endc || p[1] == ':') { |
3250 | st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord, | | 3250 | st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord, |
3251 | st.nstr, ModifyWord_Suffix, NULL); | | 3251 | st.nstr, ModifyWord_Suffix, NULL); |
3252 | st.cp = p + 1; | | 3252 | st.next = p + 1; |
3253 | st.termc = *st.cp; | | 3253 | st.termc = *st.next; |
3254 | break; | | 3254 | break; |
3255 | } | | 3255 | } |
3256 | goto default_case; | | 3256 | goto default_case; |
3257 | case 'R': | | 3257 | case 'R': |
3258 | if (p[1] == st.endc || p[1] == ':') { | | 3258 | if (p[1] == st.endc || p[1] == ':') { |
3259 | st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord, | | 3259 | st.newStr = ModifyWords(st.ctxt, st.sep, st.oneBigWord, |
3260 | st.nstr, ModifyWord_Root, NULL); | | 3260 | st.nstr, ModifyWord_Root, NULL); |
3261 | st.cp = p + 1; | | 3261 | st.next = p + 1; |
3262 | st.termc = *st.cp; | | 3262 | st.termc = *st.next; |
3263 | break; | | 3263 | break; |
3264 | } | | 3264 | } |
3265 | goto default_case; | | 3265 | goto default_case; |
3266 | case 'r': | | 3266 | case 'r': |
3267 | if (!ApplyModifier_Range(p, &st)) | | 3267 | if (!ApplyModifier_Range(p, &st)) |
3268 | goto default_case; | | 3268 | goto default_case; |
3269 | break; | | 3269 | break; |
3270 | case 'O': | | 3270 | case 'O': |
3271 | if (!ApplyModifier_Order(p, &st)) | | 3271 | if (!ApplyModifier_Order(p, &st)) |
3272 | goto bad_modifier; | | 3272 | goto bad_modifier; |
3273 | break; | | 3273 | break; |
3274 | case 'u': | | 3274 | case 'u': |
3275 | if (p[1] == st.endc || p[1] == ':') { | | 3275 | if (p[1] == st.endc || p[1] == ':') { |
3276 | st.newStr = VarUniq(st.nstr); | | 3276 | st.newStr = VarUniq(st.nstr); |
3277 | st.cp = p + 1; | | 3277 | st.next = p + 1; |
3278 | st.termc = *st.cp; | | 3278 | st.termc = *st.next; |
3279 | break; | | 3279 | break; |
3280 | } | | 3280 | } |
3281 | goto default_case; | | 3281 | goto default_case; |
3282 | #ifdef SUNSHCMD | | 3282 | #ifdef SUNSHCMD |
3283 | case 's': | | 3283 | case 's': |
3284 | if (p[1] == 'h' && (p[2] == st.endc || p[2] == ':')) { | | 3284 | if (p[1] == 'h' && (p[2] == st.endc || p[2] == ':')) { |
3285 | const char *emsg; | | 3285 | const char *emsg; |
3286 | if (st.eflags & VARE_WANTRES) { | | 3286 | if (st.eflags & VARE_WANTRES) { |
3287 | st.newStr = Cmd_Exec(st.nstr, &emsg); | | 3287 | st.newStr = Cmd_Exec(st.nstr, &emsg); |
3288 | if (emsg) | | 3288 | if (emsg) |
3289 | Error(emsg, st.nstr); | | 3289 | Error(emsg, st.nstr); |
3290 | } else | | 3290 | } else |
3291 | st.newStr = varNoError; | | 3291 | st.newStr = varNoError; |
3292 | st.cp = p + 2; | | 3292 | st.next = p + 2; |
3293 | st.termc = *st.cp; | | 3293 | st.termc = *st.next; |
3294 | break; | | 3294 | break; |
3295 | } | | 3295 | } |
3296 | goto default_case; | | 3296 | goto default_case; |
3297 | #endif | | 3297 | #endif |
3298 | default: | | 3298 | default: |
3299 | default_case: | | 3299 | default_case: |
3300 | { | | 3300 | { |
3301 | #ifdef SYSVVARSUB | | 3301 | #ifdef SYSVVARSUB |
3302 | int res = ApplyModifier_SysV(p, &st); | | 3302 | int res = ApplyModifier_SysV(p, &st); |
3303 | if (res == 'c') | | 3303 | if (res == 'c') |
3304 | goto cleanup; | | 3304 | goto cleanup; |
3305 | if (res != '=') | | 3305 | if (res != '=') |
3306 | #endif | | 3306 | #endif |
3307 | { | | 3307 | { |
3308 | Error("Unknown modifier '%c'", *p); | | 3308 | Error("Unknown modifier '%c'", *p); |
3309 | for (st.cp = p + 1; | | 3309 | for (st.next = p + 1; |
3310 | *st.cp != ':' && *st.cp != st.endc && *st.cp != '\0'; | | 3310 | *st.next != ':' && *st.next != st.endc && |
3311 | st.cp++) | | 3311 | *st.next != '\0'; |
| | | 3312 | st.next++) |
3312 | continue; | | 3313 | continue; |
3313 | st.termc = *st.cp; | | 3314 | st.termc = *st.next; |
3314 | st.newStr = var_Error; | | 3315 | st.newStr = var_Error; |
3315 | } | | 3316 | } |
3316 | } | | 3317 | } |
3317 | } | | 3318 | } |
3318 | if (DEBUG(VAR)) { | | 3319 | if (DEBUG(VAR)) { |
3319 | fprintf(debug_file, "Result[%s] of :%c is \"%s\"\n", | | 3320 | fprintf(debug_file, "Result[%s] of :%c is \"%s\"\n", |
3320 | st.v->name, modifier, st.newStr); | | 3321 | st.v->name, modifier, st.newStr); |
3321 | } | | 3322 | } |
3322 | | | 3323 | |
3323 | if (st.newStr != st.nstr) { | | 3324 | if (st.newStr != st.nstr) { |
3324 | if (*freePtr) { | | 3325 | if (*freePtr) { |
3325 | free(st.nstr); | | 3326 | free(st.nstr); |
3326 | *freePtr = NULL; | | 3327 | *freePtr = NULL; |
3327 | } | | 3328 | } |
3328 | st.nstr = st.newStr; | | 3329 | st.nstr = st.newStr; |
3329 | if (st.nstr != var_Error && st.nstr != varNoError) { | | 3330 | if (st.nstr != var_Error && st.nstr != varNoError) { |
3330 | *freePtr = st.nstr; | | 3331 | *freePtr = st.nstr; |
3331 | } | | 3332 | } |
3332 | } | | 3333 | } |
3333 | if (st.termc == '\0' && st.endc != '\0') { | | 3334 | if (st.termc == '\0' && st.endc != '\0') { |
3334 | Error("Unclosed variable specification (expecting '%c') " | | 3335 | Error("Unclosed variable specification (expecting '%c') " |
3335 | "for \"%s\" (value \"%s\") modifier %c", | | 3336 | "for \"%s\" (value \"%s\") modifier %c", |
3336 | st.endc, st.v->name, st.nstr, modifier); | | 3337 | st.endc, st.v->name, st.nstr, modifier); |
3337 | } else if (st.termc == ':') { | | 3338 | } else if (st.termc == ':') { |
3338 | st.cp++; | | 3339 | st.next++; |
3339 | } | | 3340 | } |
3340 | p = st.cp; | | 3341 | p = st.next; |
3341 | } | | 3342 | } |
3342 | out: | | 3343 | out: |
3343 | *lengthPtr = p - tstr; | | 3344 | *lengthPtr = p - tstr; |
3344 | return st.nstr; | | 3345 | return st.nstr; |
3345 | | | 3346 | |
3346 | bad_modifier: | | 3347 | bad_modifier: |
3347 | Error("Bad modifier `:%.*s' for %s", | | 3348 | Error("Bad modifier `:%.*s' for %s", |
3348 | (int)strcspn(p, ":)}"), p, st.v->name); | | 3349 | (int)strcspn(p, ":)}"), p, st.v->name); |
3349 | | | 3350 | |
3350 | cleanup: | | 3351 | cleanup: |
3351 | *lengthPtr = st.cp - tstr; | | 3352 | *lengthPtr = st.next - tstr; |
3352 | if (st.missing_delim != '\0') | | 3353 | if (st.missing_delim != '\0') |
3353 | Error("Unclosed substitution for %s (%c missing)", | | 3354 | Error("Unclosed substitution for %s (%c missing)", |
3354 | st.v->name, st.missing_delim); | | 3355 | st.v->name, st.missing_delim); |
3355 | free(*freePtr); | | 3356 | free(*freePtr); |
3356 | *freePtr = NULL; | | 3357 | *freePtr = NULL; |
3357 | return var_Error; | | 3358 | return var_Error; |
3358 | } | | 3359 | } |
3359 | | | 3360 | |
3360 | static Boolean | | 3361 | static Boolean |
3361 | VarIsDynamic(GNode *ctxt, const char *varname, size_t namelen) | | 3362 | VarIsDynamic(GNode *ctxt, const char *varname, size_t namelen) |
3362 | { | | 3363 | { |
3363 | if ((namelen == 1 || | | 3364 | if ((namelen == 1 || |
3364 | (namelen == 2 && (varname[1] == 'F' || varname[1] == 'D'))) && | | 3365 | (namelen == 2 && (varname[1] == 'F' || varname[1] == 'D'))) && |