| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: var.c,v 1.340 2020/07/27 21:54:25 rillig Exp $ */ | | 1 | /* $NetBSD: var.c,v 1.341 2020/07/27 22:02:26 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.340 2020/07/27 21:54:25 rillig Exp $"; | | 72 | static char rcsid[] = "$NetBSD: var.c,v 1.341 2020/07/27 22:02:26 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.340 2020/07/27 21:54:25 rillig Exp $"); | | 79 | __RCSID("$NetBSD: var.c,v 1.341 2020/07/27 22:02:26 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 | * |
| @@ -2043,27 +2043,26 @@ typedef struct { | | | @@ -2043,27 +2043,26 @@ typedef struct { |
2043 | Var *v; | | 2043 | Var *v; |
2044 | GNode *ctxt; | | 2044 | GNode *ctxt; |
2045 | VarEvalFlags eflags; | | 2045 | VarEvalFlags eflags; |
2046 | int *lengthPtr; | | 2046 | int *lengthPtr; |
2047 | void **freePtr; | | 2047 | void **freePtr; |
2048 | | | 2048 | |
2049 | /* read-write */ | | 2049 | /* read-write */ |
2050 | char *nstr; | | 2050 | char *nstr; |
2051 | const char *start; | | 2051 | const char *start; |
2052 | const char *cp; /* The position where parsing continues | | 2052 | const char *cp; /* The position where parsing continues |
2053 | * after the current modifier. */ | | 2053 | * after the current modifier. */ |
2054 | char termc; /* Character which terminated scan */ | | 2054 | char termc; /* Character which terminated scan */ |
2055 | char missing_delim; /* For error reporting */ | | 2055 | char missing_delim; /* For error reporting */ |
2056 | int modifier; /* that we are processing */ | | | |
2057 | | | 2056 | |
2058 | Byte sep; /* Word separator in expansions */ | | 2057 | Byte sep; /* Word separator in expansions */ |
2059 | Boolean oneBigWord; /* TRUE if we will treat the variable as a | | 2058 | Boolean oneBigWord; /* TRUE if we will treat the variable as a |
2060 | * single big word, even if it contains | | 2059 | * single big word, even if it contains |
2061 | * embedded spaces (as opposed to the | | 2060 | * embedded spaces (as opposed to the |
2062 | * usual behaviour of treating it as | | 2061 | * usual behaviour of treating it as |
2063 | * several space-separated words). */ | | 2062 | * several space-separated words). */ |
2064 | | | 2063 | |
2065 | /* result */ | | 2064 | /* result */ |
2066 | char *newStr; /* New value to return */ | | 2065 | char *newStr; /* New value to return */ |
2067 | } ApplyModifiersState; | | 2066 | } ApplyModifiersState; |
2068 | | | 2067 | |
2069 | /* we now have some modifiers with long names */ | | 2068 | /* we now have some modifiers with long names */ |
| @@ -3070,27 +3069,27 @@ ApplyModifier_SysV(const char *mod, Appl | | | @@ -3070,27 +3069,27 @@ ApplyModifier_SysV(const char *mod, Appl |
3070 | * :!<cmd>! Run cmd much the same as :sh run's the | | 3069 | * :!<cmd>! Run cmd much the same as :sh run's the |
3071 | * current value of the variable. | | 3070 | * current value of the variable. |
3072 | * Assignment operators (see ApplyModifier_Assign). | | 3071 | * Assignment operators (see ApplyModifier_Assign). |
3073 | */ | | 3072 | */ |
3074 | static char * | | 3073 | static char * |
3075 | ApplyModifiers(char *nstr, const char *tstr, | | 3074 | ApplyModifiers(char *nstr, const char *tstr, |
3076 | int const startc, int const endc, | | 3075 | int const startc, int const endc, |
3077 | Var * const v, GNode * const ctxt, VarEvalFlags const eflags, | | 3076 | Var * const v, GNode * const ctxt, VarEvalFlags const eflags, |
3078 | int * const lengthPtr, void ** const freePtr) | | 3077 | int * const lengthPtr, void ** const freePtr) |
3079 | { | | 3078 | { |
3080 | ApplyModifiersState st = { | | 3079 | ApplyModifiersState st = { |
3081 | startc, endc, v, ctxt, eflags, lengthPtr, freePtr, | | 3080 | startc, endc, v, ctxt, eflags, lengthPtr, freePtr, |
3082 | nstr, tstr, tstr, | | 3081 | nstr, tstr, tstr, |
3083 | '\0', '\0', 0, ' ', FALSE, NULL | | 3082 | '\0', '\0', ' ', FALSE, NULL |
3084 | }; | | 3083 | }; |
3085 | | | 3084 | |
3086 | const char *p = tstr; | | 3085 | const char *p = tstr; |
3087 | while (*p != '\0' && *p != endc) { | | 3086 | while (*p != '\0' && *p != endc) { |
3088 | | | 3087 | |
3089 | if (*p == '$') { | | 3088 | if (*p == '$') { |
3090 | /* | | 3089 | /* |
3091 | * We may have some complex modifiers in a variable. | | 3090 | * We may have some complex modifiers in a variable. |
3092 | */ | | 3091 | */ |
3093 | void *freeIt; | | 3092 | void *freeIt; |
3094 | const char *rval; | | 3093 | const char *rval; |
3095 | int rlen; | | 3094 | int rlen; |
3096 | int c; | | 3095 | int c; |
| @@ -3134,27 +3133,28 @@ ApplyModifiers(char *nstr, const char *t | | | @@ -3134,27 +3133,28 @@ ApplyModifiers(char *nstr, const char *t |
3134 | else if (*p == '\0' && endc != '\0') { | | 3133 | else if (*p == '\0' && endc != '\0') { |
3135 | Error("Unclosed variable specification after complex " | | 3134 | Error("Unclosed variable specification after complex " |
3136 | "modifier (expecting '%c') for %s", st.endc, st.v->name); | | 3135 | "modifier (expecting '%c') for %s", st.endc, st.v->name); |
3137 | goto out; | | 3136 | goto out; |
3138 | } | | 3137 | } |
3139 | continue; | | 3138 | continue; |
3140 | } | | 3139 | } |
3141 | apply_mods: | | 3140 | apply_mods: |
3142 | if (DEBUG(VAR)) { | | 3141 | if (DEBUG(VAR)) { |
3143 | fprintf(debug_file, "Applying[%s] :%c to \"%s\"\n", st.v->name, | | 3142 | fprintf(debug_file, "Applying[%s] :%c to \"%s\"\n", st.v->name, |
3144 | *p, st.nstr); | | 3143 | *p, st.nstr); |
3145 | } | | 3144 | } |
3146 | st.newStr = var_Error; | | 3145 | st.newStr = var_Error; |
3147 | switch ((st.modifier = *p)) { | | 3146 | char modifier = *p; |
| | | 3147 | switch (modifier) { |
3148 | case ':': | | 3148 | case ':': |
3149 | { | | 3149 | { |
3150 | int res = ApplyModifier_Assign(p, &st); | | 3150 | int res = ApplyModifier_Assign(p, &st); |
3151 | if (res == 'b') | | 3151 | if (res == 'b') |
3152 | goto bad_modifier; | | 3152 | goto bad_modifier; |
3153 | if (res == 'c') | | 3153 | if (res == 'c') |
3154 | goto cleanup; | | 3154 | goto cleanup; |
3155 | if (res == 'd') | | 3155 | if (res == 'd') |
3156 | goto default_case; | | 3156 | goto default_case; |
3157 | break; | | 3157 | break; |
3158 | } | | 3158 | } |
3159 | case '@': | | 3159 | case '@': |
3160 | if (!ApplyModifier_Loop(p, &st)) | | 3160 | if (!ApplyModifier_Loop(p, &st)) |
| @@ -3220,27 +3220,27 @@ ApplyModifiers(char *nstr, const char *t | | | @@ -3220,27 +3220,27 @@ ApplyModifiers(char *nstr, const char *t |
3220 | case '?': | | 3220 | case '?': |
3221 | if (!ApplyModifier_IfElse(p, &st)) | | 3221 | if (!ApplyModifier_IfElse(p, &st)) |
3222 | goto cleanup; | | 3222 | goto cleanup; |
3223 | break; | | 3223 | break; |
3224 | #ifndef NO_REGEX | | 3224 | #ifndef NO_REGEX |
3225 | case 'C': | | 3225 | case 'C': |
3226 | if (!ApplyModifier_Regex(p, &st)) | | 3226 | if (!ApplyModifier_Regex(p, &st)) |
3227 | goto cleanup; | | 3227 | goto cleanup; |
3228 | break; | | 3228 | break; |
3229 | #endif | | 3229 | #endif |
3230 | case 'q': | | 3230 | case 'q': |
3231 | case 'Q': | | 3231 | case 'Q': |
3232 | if (p[1] == st.endc || p[1] == ':') { | | 3232 | if (p[1] == st.endc || p[1] == ':') { |
3233 | st.newStr = VarQuote(st.nstr, st.modifier == 'q'); | | 3233 | st.newStr = VarQuote(st.nstr, modifier == 'q'); |
3234 | st.cp = p + 1; | | 3234 | st.cp = p + 1; |
3235 | st.termc = *st.cp; | | 3235 | st.termc = *st.cp; |
3236 | break; | | 3236 | break; |
3237 | } | | 3237 | } |
3238 | goto default_case; | | 3238 | goto default_case; |
3239 | case 'T': | | 3239 | case 'T': |
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_Tail, NULL); | | 3242 | st.nstr, ModifyWord_Tail, NULL); |
3243 | st.cp = p + 1; | | 3243 | st.cp = p + 1; |
3244 | st.termc = *st.cp; | | 3244 | st.termc = *st.cp; |
3245 | break; | | 3245 | break; |
3246 | } | | 3246 | } |
| @@ -3316,43 +3316,43 @@ ApplyModifiers(char *nstr, const char *t | | | @@ -3316,43 +3316,43 @@ ApplyModifiers(char *nstr, const char *t |
3316 | { | | 3316 | { |
3317 | Error("Unknown modifier '%c'", *p); | | 3317 | Error("Unknown modifier '%c'", *p); |
3318 | for (st.cp = p + 1; | | 3318 | for (st.cp = p + 1; |
3319 | *st.cp != ':' && *st.cp != st.endc && *st.cp != '\0'; | | 3319 | *st.cp != ':' && *st.cp != st.endc && *st.cp != '\0'; |
3320 | st.cp++) | | 3320 | st.cp++) |
3321 | continue; | | 3321 | continue; |
3322 | st.termc = *st.cp; | | 3322 | st.termc = *st.cp; |
3323 | st.newStr = var_Error; | | 3323 | st.newStr = var_Error; |
3324 | } | | 3324 | } |
3325 | } | | 3325 | } |
3326 | } | | 3326 | } |
3327 | if (DEBUG(VAR)) { | | 3327 | if (DEBUG(VAR)) { |
3328 | fprintf(debug_file, "Result[%s] of :%c is \"%s\"\n", | | 3328 | fprintf(debug_file, "Result[%s] of :%c is \"%s\"\n", |
3329 | st.v->name, st.modifier, st.newStr); | | 3329 | st.v->name, modifier, st.newStr); |
3330 | } | | 3330 | } |
3331 | | | 3331 | |
3332 | if (st.newStr != st.nstr) { | | 3332 | if (st.newStr != st.nstr) { |
3333 | if (*st.freePtr) { | | 3333 | if (*st.freePtr) { |
3334 | free(st.nstr); | | 3334 | free(st.nstr); |
3335 | *st.freePtr = NULL; | | 3335 | *st.freePtr = NULL; |
3336 | } | | 3336 | } |
3337 | st.nstr = st.newStr; | | 3337 | st.nstr = st.newStr; |
3338 | if (st.nstr != var_Error && st.nstr != varNoError) { | | 3338 | if (st.nstr != var_Error && st.nstr != varNoError) { |
3339 | *st.freePtr = st.nstr; | | 3339 | *st.freePtr = st.nstr; |
3340 | } | | 3340 | } |
3341 | } | | 3341 | } |
3342 | if (st.termc == '\0' && st.endc != '\0') { | | 3342 | if (st.termc == '\0' && st.endc != '\0') { |
3343 | Error("Unclosed variable specification (expecting '%c') " | | 3343 | Error("Unclosed variable specification (expecting '%c') " |
3344 | "for \"%s\" (value \"%s\") modifier %c", | | 3344 | "for \"%s\" (value \"%s\") modifier %c", |
3345 | st.endc, st.v->name, st.nstr, st.modifier); | | 3345 | st.endc, st.v->name, st.nstr, modifier); |
3346 | } else if (st.termc == ':') { | | 3346 | } else if (st.termc == ':') { |
3347 | st.cp++; | | 3347 | st.cp++; |
3348 | } | | 3348 | } |
3349 | p = st.cp; | | 3349 | p = st.cp; |
3350 | } | | 3350 | } |
3351 | out: | | 3351 | out: |
3352 | *st.lengthPtr = p - st.start; | | 3352 | *st.lengthPtr = p - st.start; |
3353 | return st.nstr; | | 3353 | return st.nstr; |
3354 | | | 3354 | |
3355 | bad_modifier: | | 3355 | bad_modifier: |
3356 | Error("Bad modifier `:%.*s' for %s", | | 3356 | Error("Bad modifier `:%.*s' for %s", |
3357 | (int)strcspn(p, ":)}"), p, st.v->name); | | 3357 | (int)strcspn(p, ":)}"), p, st.v->name); |
3358 | | | 3358 | |