| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: var.c,v 1.248 2020/07/04 10:19:39 rillig Exp $ */ | | 1 | /* $NetBSD: var.c,v 1.249 2020/07/04 10:35:30 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.248 2020/07/04 10:19:39 rillig Exp $"; | | 72 | static char rcsid[] = "$NetBSD: var.c,v 1.249 2020/07/04 10:35:30 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.248 2020/07/04 10:19:39 rillig Exp $"); | | 79 | __RCSID("$NetBSD: var.c,v 1.249 2020/07/04 10:35:30 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. The value and variable name need not | | 91 | * yet exist. The value and variable name need not |
92 | * be preserved. | | 92 | * be preserved. |
| @@ -142,34 +142,34 @@ __RCSID("$NetBSD: var.c,v 1.248 2020/07/ | | | @@ -142,34 +142,34 @@ __RCSID("$NetBSD: var.c,v 1.248 2020/07/ |
142 | | | 142 | |
143 | extern int makelevel; | | 143 | extern int makelevel; |
144 | /* | | 144 | /* |
145 | * This lets us tell if we have replaced the original environ | | 145 | * This lets us tell if we have replaced the original environ |
146 | * (which we cannot free). | | 146 | * (which we cannot free). |
147 | */ | | 147 | */ |
148 | char **savedEnv = NULL; | | 148 | char **savedEnv = NULL; |
149 | | | 149 | |
150 | /* | | 150 | /* |
151 | * This is a harmless return value for Var_Parse that can be used by Var_Subst | | 151 | * This is a harmless return value for Var_Parse that can be used by Var_Subst |
152 | * to determine if there was an error in parsing -- easier than returning | | 152 | * to determine if there was an error in parsing -- easier than returning |
153 | * a flag, as things outside this module don't give a hoot. | | 153 | * a flag, as things outside this module don't give a hoot. |
154 | */ | | 154 | */ |
155 | char var_Error[] = ""; | | 155 | char var_Error[] = ""; |
156 | | | 156 | |
157 | /* | | 157 | /* |
158 | * Similar to var_Error, but returned when the 'VARF_UNDEFERR' flag for | | 158 | * Similar to var_Error, but returned when the 'VARF_UNDEFERR' flag for |
159 | * Var_Parse is not set. Why not just use a constant? Well, gcc likes | | 159 | * Var_Parse is not set. Why not just use a constant? Well, gcc likes |
160 | * to condense identical string instances... | | 160 | * to condense identical string instances... |
161 | */ | | 161 | */ |
162 | static char varNoError[] = ""; | | 162 | static char varNoError[] = ""; |
163 | | | 163 | |
164 | /* | | 164 | /* |
165 | * Traditionally we consume $$ during := like any other expansion. | | 165 | * Traditionally we consume $$ during := like any other expansion. |
166 | * Other make's do not. | | 166 | * Other make's do not. |
167 | * This knob allows controlling the behavior. | | 167 | * This knob allows controlling the behavior. |
168 | * FALSE for old behavior. | | 168 | * FALSE for old behavior. |
169 | * TRUE for new compatible. | | 169 | * TRUE for new compatible. |
170 | */ | | 170 | */ |
171 | #define SAVE_DOLLARS ".MAKE.SAVE_DOLLARS" | | 171 | #define SAVE_DOLLARS ".MAKE.SAVE_DOLLARS" |
172 | static Boolean save_dollars = TRUE; | | 172 | static Boolean save_dollars = TRUE; |
173 | | | 173 | |
174 | /* | | 174 | /* |
175 | * Internally, variables are contained in four different contexts. | | 175 | * Internally, variables are contained in four different contexts. |
| @@ -289,39 +289,26 @@ typedef struct { | | | @@ -289,39 +289,26 @@ typedef struct { |
289 | int nsub; | | 289 | int nsub; |
290 | regmatch_t *matches; | | 290 | regmatch_t *matches; |
291 | char *replace; | | 291 | char *replace; |
292 | int flags; | | 292 | int flags; |
293 | } VarREPattern; | | 293 | } VarREPattern; |
294 | #endif | | 294 | #endif |
295 | | | 295 | |
296 | /* struct passed to VarSelectWords() for ":[start..end]" */ | | 296 | /* struct passed to VarSelectWords() for ":[start..end]" */ |
297 | typedef struct { | | 297 | typedef struct { |
298 | int start; /* first word to select */ | | 298 | int start; /* first word to select */ |
299 | int end; /* last word to select */ | | 299 | int end; /* last word to select */ |
300 | } VarSelectWords_t; | | 300 | } VarSelectWords_t; |
301 | | | 301 | |
302 | static char *VarGetPattern(GNode *, Var_Parse_State *, | | | |
303 | VarPattern_Flags, const char **, int, | | | |
304 | VarPattern_Flags *, int *, VarPattern *); | | | |
305 | static char *VarQuote(char *, Boolean); | | | |
306 | static char *VarHash(char *); | | | |
307 | static char *VarModify(GNode *, Var_Parse_State *, | | | |
308 | const char *, | | | |
309 | Boolean (*)(GNode *, Var_Parse_State *, char *, Boolean, Buffer *, void *), | | | |
310 | void *); | | | |
311 | static char *VarOrder(const char *, const char); | | | |
312 | static char *VarUniq(const char *); | | | |
313 | static int VarWordCompare(const void *, const void *); | | | |
314 | | | | |
315 | #define BROPEN '{' | | 302 | #define BROPEN '{' |
316 | #define BRCLOSE '}' | | 303 | #define BRCLOSE '}' |
317 | #define PROPEN '(' | | 304 | #define PROPEN '(' |
318 | #define PRCLOSE ')' | | 305 | #define PRCLOSE ')' |
319 | | | 306 | |
320 | /*- | | 307 | /*- |
321 | *----------------------------------------------------------------------- | | 308 | *----------------------------------------------------------------------- |
322 | * VarFind -- | | 309 | * VarFind -- |
323 | * Find the given variable in the given context and any other contexts | | 310 | * Find the given variable in the given context and any other contexts |
324 | * indicated. | | 311 | * indicated. |
325 | * | | 312 | * |
326 | * Input: | | 313 | * Input: |
327 | * name name to find | | 314 | * name name to find |
| @@ -864,27 +851,27 @@ Var_UnExport(char *str) | | | @@ -864,27 +851,27 @@ Var_UnExport(char *str) |
864 | free(as); | | 851 | free(as); |
865 | free(av); | | 852 | free(av); |
866 | if (vlist != str) { | | 853 | if (vlist != str) { |
867 | Var_Delete(MAKE_EXPORTED, VAR_GLOBAL); | | 854 | Var_Delete(MAKE_EXPORTED, VAR_GLOBAL); |
868 | free(vlist); | | 855 | free(vlist); |
869 | } | | 856 | } |
870 | } | | 857 | } |
871 | } | | 858 | } |
872 | | | 859 | |
873 | static void | | 860 | static void |
874 | Var_Set_with_flags(const char *name, const char *val, GNode *ctxt, | | 861 | Var_Set_with_flags(const char *name, const char *val, GNode *ctxt, |
875 | VarSet_Flags flags) | | 862 | VarSet_Flags flags) |
876 | { | | 863 | { |
877 | Var *v; | | 864 | Var *v; |
878 | char *expanded_name = NULL; | | 865 | char *expanded_name = NULL; |
879 | | | 866 | |
880 | /* | | 867 | /* |
881 | * We only look for a variable in the given context since anything set | | 868 | * We only look for a variable in the given context since anything set |
882 | * here will override anything in a lower context, so there's not much | | 869 | * here will override anything in a lower context, so there's not much |
883 | * point in searching them all just to save a bit of memory... | | 870 | * point in searching them all just to save a bit of memory... |
884 | */ | | 871 | */ |
885 | if (strchr(name, '$') != NULL) { | | 872 | if (strchr(name, '$') != NULL) { |
886 | expanded_name = Var_Subst(NULL, name, ctxt, VARF_WANTRES); | | 873 | expanded_name = Var_Subst(NULL, name, ctxt, VARF_WANTRES); |
887 | if (expanded_name[0] == 0) { | | 874 | if (expanded_name[0] == 0) { |
888 | if (DEBUG(VAR)) { | | 875 | if (DEBUG(VAR)) { |
889 | fprintf(debug_file, "Var_Set(\"%s\", \"%s\", ...) " | | 876 | fprintf(debug_file, "Var_Set(\"%s\", \"%s\", ...) " |
890 | "name expands to empty string - ignored\n", | | 877 | "name expands to empty string - ignored\n", |
| @@ -1017,28 +1004,28 @@ Var_Set(const char *name, const char *va | | | @@ -1017,28 +1004,28 @@ Var_Set(const char *name, const char *va |
1017 | * | | 1004 | * |
1018 | * Notes: | | 1005 | * Notes: |
1019 | * Only if the variable is being sought in the global context is the | | 1006 | * Only if the variable is being sought in the global context is the |
1020 | * environment searched. | | 1007 | * environment searched. |
1021 | * XXX: Knows its calling circumstances in that if called with ctxt | | 1008 | * XXX: Knows its calling circumstances in that if called with ctxt |
1022 | * an actual target, it will only search that context since only | | 1009 | * an actual target, it will only search that context since only |
1023 | * a local variable could be being appended to. This is actually | | 1010 | * a local variable could be being appended to. This is actually |
1024 | * a big win and must be tolerated. | | 1011 | * a big win and must be tolerated. |
1025 | *----------------------------------------------------------------------- | | 1012 | *----------------------------------------------------------------------- |
1026 | */ | | 1013 | */ |
1027 | void | | 1014 | void |
1028 | Var_Append(const char *name, const char *val, GNode *ctxt) | | 1015 | Var_Append(const char *name, const char *val, GNode *ctxt) |
1029 | { | | 1016 | { |
1030 | Var *v; | | 1017 | Var *v; |
1031 | Hash_Entry *h; | | 1018 | Hash_Entry *h; |
1032 | char *expanded_name = NULL; | | 1019 | char *expanded_name = NULL; |
1033 | | | 1020 | |
1034 | if (strchr(name, '$') != NULL) { | | 1021 | if (strchr(name, '$') != NULL) { |
1035 | expanded_name = Var_Subst(NULL, name, ctxt, VARF_WANTRES); | | 1022 | expanded_name = Var_Subst(NULL, name, ctxt, VARF_WANTRES); |
1036 | if (expanded_name[0] == 0) { | | 1023 | if (expanded_name[0] == 0) { |
1037 | if (DEBUG(VAR)) { | | 1024 | if (DEBUG(VAR)) { |
1038 | fprintf(debug_file, "Var_Append(\"%s\", \"%s\", ...) " | | 1025 | fprintf(debug_file, "Var_Append(\"%s\", \"%s\", ...) " |
1039 | "name expands to empty string - ignored\n", | | 1026 | "name expands to empty string - ignored\n", |
1040 | name, val); | | 1027 | name, val); |
1041 | } | | 1028 | } |
1042 | free(expanded_name); | | 1029 | free(expanded_name); |
1043 | return; | | 1030 | return; |
1044 | } | | 1031 | } |
| @@ -1320,27 +1307,27 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSE | | | @@ -1320,27 +1307,27 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSE |
1320 | addSpace = TRUE; | | 1307 | addSpace = TRUE; |
1321 | Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); | | 1308 | Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); |
1322 | } | | 1309 | } |
1323 | pattern->flags |= VAR_SUB_MATCHED; | | 1310 | pattern->flags |= VAR_SUB_MATCHED; |
1324 | } else if (pattern->flags & VAR_MATCH_END) { | | 1311 | } else if (pattern->flags & VAR_MATCH_END) { |
1325 | /* | | 1312 | /* |
1326 | * Doesn't match to end -- copy word wholesale | | 1313 | * Doesn't match to end -- copy word wholesale |
1327 | */ | | 1314 | */ |
1328 | goto nosub; | | 1315 | goto nosub; |
1329 | } else { | | 1316 | } else { |
1330 | /* | | 1317 | /* |
1331 | * Matches at start but need to copy in trailing characters | | 1318 | * Matches at start but need to copy in trailing characters |
1332 | */ | | 1319 | */ |
1333 | if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){ | | 1320 | if ((pattern->rightLen + wordLen - pattern->leftLen) != 0) { |
1334 | if (addSpace && vpstate->varSpace) { | | 1321 | if (addSpace && vpstate->varSpace) { |
1335 | Buf_AddByte(buf, vpstate->varSpace); | | 1322 | Buf_AddByte(buf, vpstate->varSpace); |
1336 | } | | 1323 | } |
1337 | addSpace = TRUE; | | 1324 | addSpace = TRUE; |
1338 | } | | 1325 | } |
1339 | Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); | | 1326 | Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); |
1340 | Buf_AddBytes(buf, wordLen - pattern->leftLen, | | 1327 | Buf_AddBytes(buf, wordLen - pattern->leftLen, |
1341 | (word + pattern->leftLen)); | | 1328 | (word + pattern->leftLen)); |
1342 | pattern->flags |= VAR_SUB_MATCHED; | | 1329 | pattern->flags |= VAR_SUB_MATCHED; |
1343 | } | | 1330 | } |
1344 | } else if (pattern->flags & VAR_MATCH_START) { | | 1331 | } else if (pattern->flags & VAR_MATCH_START) { |
1345 | /* | | 1332 | /* |
1346 | * Had to match at start of word and didn't -- copy whole word. | | 1333 | * Had to match at start of word and didn't -- copy whole word. |
| @@ -1387,27 +1374,27 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSE | | | @@ -1387,27 +1374,27 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSE |
1387 | * accordingly through the loop) is copied straight into the | | 1374 | * accordingly through the loop) is copied straight into the |
1388 | * buffer. | | 1375 | * buffer. |
1389 | * addSpace is set FALSE as soon as a space is added to the | | 1376 | * addSpace is set FALSE as soon as a space is added to the |
1390 | * buffer. | | 1377 | * buffer. |
1391 | */ | | 1378 | */ |
1392 | Boolean done; | | 1379 | Boolean done; |
1393 | int origSize; | | 1380 | int origSize; |
1394 | | | 1381 | |
1395 | done = FALSE; | | 1382 | done = FALSE; |
1396 | origSize = Buf_Size(buf); | | 1383 | origSize = Buf_Size(buf); |
1397 | while (!done) { | | 1384 | while (!done) { |
1398 | cp = Str_FindSubstring(word, pattern->lhs); | | 1385 | cp = Str_FindSubstring(word, pattern->lhs); |
1399 | if (cp != NULL) { | | 1386 | if (cp != NULL) { |
1400 | if (addSpace && (((cp - word) + pattern->rightLen) != 0)){ | | 1387 | if (addSpace && (((cp - word) + pattern->rightLen) != 0)) { |
1401 | Buf_AddByte(buf, vpstate->varSpace); | | 1388 | Buf_AddByte(buf, vpstate->varSpace); |
1402 | addSpace = FALSE; | | 1389 | addSpace = FALSE; |
1403 | } | | 1390 | } |
1404 | Buf_AddBytes(buf, cp-word, word); | | 1391 | Buf_AddBytes(buf, cp-word, word); |
1405 | Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); | | 1392 | Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); |
1406 | wordLen -= (cp - word) + pattern->leftLen; | | 1393 | wordLen -= (cp - word) + pattern->leftLen; |
1407 | word = cp + pattern->leftLen; | | 1394 | word = cp + pattern->leftLen; |
1408 | if (wordLen == 0) { | | 1395 | if (wordLen == 0) { |
1409 | done = TRUE; | | 1396 | done = TRUE; |
1410 | } | | 1397 | } |
1411 | if ((pattern->flags & VAR_SUB_GLOBAL) == 0) { | | 1398 | if ((pattern->flags & VAR_SUB_GLOBAL) == 0) { |
1412 | done = TRUE; | | 1399 | done = TRUE; |
1413 | } | | 1400 | } |
| @@ -1585,34 +1572,34 @@ VarRESubstitute(GNode *ctx MAKE_ATTR_UNU | | | @@ -1585,34 +1572,34 @@ VarRESubstitute(GNode *ctx MAKE_ATTR_UNU |
1585 | * ODE make. We set the temp variable named in pattern.lhs to word and | | 1572 | * ODE make. We set the temp variable named in pattern.lhs to word and |
1586 | * expand pattern.rhs. */ | | 1573 | * expand pattern.rhs. */ |
1587 | static Boolean | | 1574 | static Boolean |
1588 | VarLoopExpand(GNode *ctx MAKE_ATTR_UNUSED, | | 1575 | VarLoopExpand(GNode *ctx MAKE_ATTR_UNUSED, |
1589 | Var_Parse_State *vpstate MAKE_ATTR_UNUSED, | | 1576 | Var_Parse_State *vpstate MAKE_ATTR_UNUSED, |
1590 | char *word, Boolean addSpace, Buffer *buf, | | 1577 | char *word, Boolean addSpace, Buffer *buf, |
1591 | void *data) | | 1578 | void *data) |
1592 | { | | 1579 | { |
1593 | VarLoop_t *loop = data; | | 1580 | VarLoop_t *loop = data; |
1594 | char *s; | | 1581 | char *s; |
1595 | int slen; | | 1582 | int slen; |
1596 | | | 1583 | |
1597 | if (*word) { | | 1584 | if (*word) { |
1598 | Var_Set_with_flags(loop->tvar, word, loop->ctxt, VAR_NO_EXPORT); | | 1585 | Var_Set_with_flags(loop->tvar, word, loop->ctxt, VAR_NO_EXPORT); |
1599 | s = Var_Subst(NULL, loop->str, loop->ctxt, loop->flags); | | 1586 | s = Var_Subst(NULL, loop->str, loop->ctxt, loop->flags); |
1600 | if (s != NULL && *s != '\0') { | | 1587 | if (s != NULL && *s != '\0') { |
1601 | if (addSpace && *s != '\n') | | 1588 | if (addSpace && *s != '\n') |
1602 | Buf_AddByte(buf, ' '); | | 1589 | Buf_AddByte(buf, ' '); |
1603 | Buf_AddBytes(buf, (slen = strlen(s)), s); | | 1590 | Buf_AddBytes(buf, (slen = strlen(s)), s); |
1604 | addSpace = (slen > 0 && s[slen - 1] != '\n'); | | 1591 | addSpace = (slen > 0 && s[slen - 1] != '\n'); |
1605 | } | | 1592 | } |
1606 | free(s); | | 1593 | free(s); |
1607 | } | | 1594 | } |
1608 | return addSpace; | | 1595 | return addSpace; |
1609 | } | | 1596 | } |
1610 | | | 1597 | |
1611 | | | 1598 | |
1612 | /*- | | 1599 | /*- |
1613 | *----------------------------------------------------------------------- | | 1600 | *----------------------------------------------------------------------- |
1614 | * VarSelectWords -- | | 1601 | * VarSelectWords -- |
1615 | * Implements the :[start..end] modifier. | | 1602 | * Implements the :[start..end] modifier. |
1616 | * This is a special case of VarModify since we want to be able | | 1603 | * This is a special case of VarModify since we want to be able |
1617 | * to scan the list backwards if start > end. | | 1604 | * to scan the list backwards if start > end. |
1618 | * | | 1605 | * |
| @@ -2008,28 +1995,28 @@ VarGetPattern(GNode *ctxt, Var_Parse_Sta | | | @@ -2008,28 +1995,28 @@ VarGetPattern(GNode *ctxt, Var_Parse_Sta |
2008 | */ | | 1995 | */ |
2009 | *vflags |= VAR_MATCH_END; | | 1996 | *vflags |= VAR_MATCH_END; |
2010 | } else { | | 1997 | } else { |
2011 | if (vflags == NULL || (*vflags & VAR_NOSUBST) == 0) { | | 1998 | if (vflags == NULL || (*vflags & VAR_NOSUBST) == 0) { |
2012 | char *cp2; | | 1999 | char *cp2; |
2013 | int len; | | 2000 | int len; |
2014 | void *freeIt; | | 2001 | void *freeIt; |
2015 | | | 2002 | |
2016 | /* | | 2003 | /* |
2017 | * If unescaped dollar sign not before the | | 2004 | * If unescaped dollar sign not before the |
2018 | * delimiter, assume it's a variable | | 2005 | * delimiter, assume it's a variable |
2019 | * substitution and recurse. | | 2006 | * substitution and recurse. |
2020 | */ | | 2007 | */ |
2021 | cp2 = Var_Parse(cp, ctxt, errnum | | | 2008 | cp2 = Var_Parse(cp, ctxt, errnum | (flags & VARF_WANTRES), |
2022 | (flags & VARF_WANTRES), &len, &freeIt); | | 2009 | &len, &freeIt); |
2023 | Buf_AddBytes(&buf, strlen(cp2), cp2); | | 2010 | Buf_AddBytes(&buf, strlen(cp2), cp2); |
2024 | free(freeIt); | | 2011 | free(freeIt); |
2025 | cp += len - 1; | | 2012 | cp += len - 1; |
2026 | } else { | | 2013 | } else { |
2027 | const char *cp2 = &cp[1]; | | 2014 | const char *cp2 = &cp[1]; |
2028 | | | 2015 | |
2029 | if (*cp2 == PROPEN || *cp2 == BROPEN) { | | 2016 | if (*cp2 == PROPEN || *cp2 == BROPEN) { |
2030 | /* | | 2017 | /* |
2031 | * Find the end of this variable reference | | 2018 | * Find the end of this variable reference |
2032 | * and suck it in without further ado. | | 2019 | * and suck it in without further ado. |
2033 | * It will be interpreted later. | | 2020 | * It will be interpreted later. |
2034 | */ | | 2021 | */ |
2035 | int have = *cp2; | | 2022 | int have = *cp2; |
| @@ -2174,29 +2161,29 @@ VarHash(char *str) | | | @@ -2174,29 +2161,29 @@ VarHash(char *str) |
2174 | h = h * 5 + 0x52dce729U; | | 2161 | h = h * 5 + 0x52dce729U; |
2175 | h ^= k; | | 2162 | h ^= k; |
2176 | } | | 2163 | } |
2177 | h ^= len2; | | 2164 | h ^= len2; |
2178 | h *= 0x85ebca6b; | | 2165 | h *= 0x85ebca6b; |
2179 | h ^= h >> 13; | | 2166 | h ^= h >> 13; |
2180 | h *= 0xc2b2ae35; | | 2167 | h *= 0xc2b2ae35; |
2181 | h ^= h >> 16; | | 2168 | h ^= h >> 16; |
2182 | | | 2169 | |
2183 | Buf_Init(&buf, 0); | | 2170 | Buf_Init(&buf, 0); |
2184 | for (len = 0; len < 8; ++len) { | | 2171 | for (len = 0; len < 8; ++len) { |
2185 | Buf_AddByte(&buf, hexdigits[h & 15]); | | 2172 | Buf_AddByte(&buf, hexdigits[h & 15]); |
2186 | h >>= 4; | | 2173 | h >>= 4; |
2187 | } | | 2174 | } |
2188 | | | 2175 | |
2189 | return Buf_Destroy(&buf, FALSE); | | 2176 | return Buf_Destroy(&buf, FALSE); |
2190 | } | | 2177 | } |
2191 | | | 2178 | |
2192 | static char * | | 2179 | static char * |
2193 | VarStrftime(const char *fmt, int zulu, time_t utc) | | 2180 | VarStrftime(const char *fmt, int zulu, time_t utc) |
2194 | { | | 2181 | { |
2195 | char buf[BUFSIZ]; | | 2182 | char buf[BUFSIZ]; |
2196 | | | 2183 | |
2197 | if (!utc) | | 2184 | if (!utc) |
2198 | time(&utc); | | 2185 | time(&utc); |
2199 | if (!*fmt) | | 2186 | if (!*fmt) |
2200 | fmt = "%c"; | | 2187 | fmt = "%c"; |
2201 | strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&utc) : localtime(&utc)); | | 2188 | strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&utc) : localtime(&utc)); |
2202 | | | 2189 | |
| @@ -3124,27 +3111,27 @@ ApplyModifier_Assign(ApplyModifiersState | | | @@ -3124,27 +3111,27 @@ ApplyModifier_Assign(ApplyModifiersState |
3124 | static Boolean | | 3111 | static Boolean |
3125 | ApplyModifier_Remember(ApplyModifiersState *st) | | 3112 | ApplyModifier_Remember(ApplyModifiersState *st) |
3126 | { | | 3113 | { |
3127 | st->cp = st->tstr + 1; /* make sure it is set */ | | 3114 | st->cp = st->tstr + 1; /* make sure it is set */ |
3128 | if (!STRMOD_MATCHX(st->tstr, "_", 1)) | | 3115 | if (!STRMOD_MATCHX(st->tstr, "_", 1)) |
3129 | return FALSE; | | 3116 | return FALSE; |
3130 | | | 3117 | |
3131 | if (st->tstr[1] == '=') { | | 3118 | if (st->tstr[1] == '=') { |
3132 | char *np; | | 3119 | char *np; |
3133 | int n; | | 3120 | int n; |
3134 | | | 3121 | |
3135 | st->cp++; | | 3122 | st->cp++; |
3136 | n = strcspn(st->cp, ":)}"); | | 3123 | n = strcspn(st->cp, ":)}"); |
3137 | np = bmake_strndup(st->cp, n+1); | | 3124 | np = bmake_strndup(st->cp, n + 1); |
3138 | np[n] = '\0'; | | 3125 | np[n] = '\0'; |
3139 | st->cp = st->tstr + 2 + n; | | 3126 | st->cp = st->tstr + 2 + n; |
3140 | Var_Set(np, st->nstr, st->ctxt); | | 3127 | Var_Set(np, st->nstr, st->ctxt); |
3141 | free(np); | | 3128 | free(np); |
3142 | } else { | | 3129 | } else { |
3143 | Var_Set("_", st->nstr, st->ctxt); | | 3130 | Var_Set("_", st->nstr, st->ctxt); |
3144 | } | | 3131 | } |
3145 | st->newStr = st->nstr; | | 3132 | st->newStr = st->nstr; |
3146 | st->termc = *st->cp; | | 3133 | st->termc = *st->cp; |
3147 | return TRUE; | | 3134 | return TRUE; |
3148 | } | | 3135 | } |
3149 | | | 3136 | |
3150 | #ifdef SYSVVARSUB | | 3137 | #ifdef SYSVVARSUB |
| @@ -3696,28 +3683,27 @@ Var_Parse(const char *str, GNode *ctxt, | | | @@ -3696,28 +3683,27 @@ Var_Parse(const char *str, GNode *ctxt, |
3696 | tstr = &str[1]; | | 3683 | tstr = &str[1]; |
3697 | endc = str[1]; | | 3684 | endc = str[1]; |
3698 | } | | 3685 | } |
3699 | } else { | | 3686 | } else { |
3700 | Buffer buf; /* Holds the variable name */ | | 3687 | Buffer buf; /* Holds the variable name */ |
3701 | int depth = 1; | | 3688 | int depth = 1; |
3702 | | | 3689 | |
3703 | endc = startc == PROPEN ? PRCLOSE : BRCLOSE; | | 3690 | endc = startc == PROPEN ? PRCLOSE : BRCLOSE; |
3704 | Buf_Init(&buf, 0); | | 3691 | Buf_Init(&buf, 0); |
3705 | | | 3692 | |
3706 | /* | | 3693 | /* |
3707 | * Skip to the end character or a colon, whichever comes first. | | 3694 | * Skip to the end character or a colon, whichever comes first. |
3708 | */ | | 3695 | */ |
3709 | for (tstr = str + 2; *tstr != '\0'; tstr++) | | 3696 | for (tstr = str + 2; *tstr != '\0'; tstr++) { |
3710 | { | | | |
3711 | /* Track depth so we can spot parse errors. */ | | 3697 | /* Track depth so we can spot parse errors. */ |
3712 | if (*tstr == startc) | | 3698 | if (*tstr == startc) |
3713 | depth++; | | 3699 | depth++; |
3714 | if (*tstr == endc) { | | 3700 | if (*tstr == endc) { |
3715 | if (--depth == 0) | | 3701 | if (--depth == 0) |
3716 | break; | | 3702 | break; |
3717 | } | | 3703 | } |
3718 | if (depth == 1 && *tstr == ':') | | 3704 | if (depth == 1 && *tstr == ':') |
3719 | break; | | 3705 | break; |
3720 | /* A variable inside a variable, expand. */ | | 3706 | /* A variable inside a variable, expand. */ |
3721 | if (*tstr == '$') { | | 3707 | if (*tstr == '$') { |
3722 | int rlen; | | 3708 | int rlen; |
3723 | void *freeIt; | | 3709 | void *freeIt; |
| @@ -3884,27 +3870,27 @@ Var_Parse(const char *str, GNode *ctxt, | | | @@ -3884,27 +3870,27 @@ Var_Parse(const char *str, GNode *ctxt, |
3884 | tstr++; | | 3870 | tstr++; |
3885 | | | 3871 | |
3886 | nstr = ApplyModifiers(nstr, tstr, startc, endc, | | 3872 | nstr = ApplyModifiers(nstr, tstr, startc, endc, |
3887 | v, ctxt, flags, &used, freePtr); | | 3873 | v, ctxt, flags, &used, freePtr); |
3888 | tstr += used; | | 3874 | tstr += used; |
3889 | free(extraFree); | | 3875 | free(extraFree); |
3890 | } else { | | 3876 | } else { |
3891 | *freePtr = extraFree; | | 3877 | *freePtr = extraFree; |
3892 | } | | 3878 | } |
3893 | } | | 3879 | } |
3894 | *lengthPtr = tstr - start + (*tstr ? 1 : 0); | | 3880 | *lengthPtr = tstr - start + (*tstr ? 1 : 0); |
3895 | | | 3881 | |
3896 | if (v->flags & VAR_FROM_ENV) { | | 3882 | if (v->flags & VAR_FROM_ENV) { |
3897 | Boolean destroy = FALSE; | | 3883 | Boolean destroy = FALSE; |
3898 | | | 3884 | |
3899 | if (nstr != Buf_GetAll(&v->val, NULL)) { | | 3885 | if (nstr != Buf_GetAll(&v->val, NULL)) { |
3900 | destroy = TRUE; | | 3886 | destroy = TRUE; |
3901 | } else { | | 3887 | } else { |
3902 | /* | | 3888 | /* |
3903 | * Returning the value unmodified, so tell the caller to free | | 3889 | * Returning the value unmodified, so tell the caller to free |
3904 | * the thing. | | 3890 | * the thing. |
3905 | */ | | 3891 | */ |
3906 | *freePtr = nstr; | | 3892 | *freePtr = nstr; |
3907 | } | | 3893 | } |
3908 | VarFreeEnv(v, destroy); | | 3894 | VarFreeEnv(v, destroy); |
3909 | } else if (v->flags & VAR_JUNK) { | | 3895 | } else if (v->flags & VAR_JUNK) { |
3910 | /* | | 3896 | /* |
| @@ -3979,27 +3965,27 @@ Var_Subst(const char *var, const char *s | | | @@ -3979,27 +3965,27 @@ Var_Subst(const char *var, const char *s |
3979 | * In such a case, we skip over the escape character and store the | | 3965 | * In such a case, we skip over the escape character and store the |
3980 | * dollar sign into the buffer directly. | | 3966 | * dollar sign into the buffer directly. |
3981 | */ | | 3967 | */ |
3982 | if (save_dollars && (flags & VARF_ASSIGN)) | | 3968 | if (save_dollars && (flags & VARF_ASSIGN)) |
3983 | Buf_AddByte(&buf, *str); | | 3969 | Buf_AddByte(&buf, *str); |
3984 | str++; | | 3970 | str++; |
3985 | Buf_AddByte(&buf, *str); | | 3971 | Buf_AddByte(&buf, *str); |
3986 | str++; | | 3972 | str++; |
3987 | } else if (*str != '$') { | | 3973 | } else if (*str != '$') { |
3988 | /* | | 3974 | /* |
3989 | * Skip as many characters as possible -- either to the end of | | 3975 | * Skip as many characters as possible -- either to the end of |
3990 | * the string or to the next dollar sign (variable invocation). | | 3976 | * the string or to the next dollar sign (variable invocation). |
3991 | */ | | 3977 | */ |
3992 | const char *cp; | | 3978 | const char *cp; |
3993 | | | 3979 | |
3994 | for (cp = str++; *str != '$' && *str != '\0'; str++) | | 3980 | for (cp = str++; *str != '$' && *str != '\0'; str++) |
3995 | continue; | | 3981 | continue; |
3996 | Buf_AddBytes(&buf, str - cp, cp); | | 3982 | Buf_AddBytes(&buf, str - cp, cp); |
3997 | } else { | | 3983 | } else { |
3998 | if (var != NULL) { | | 3984 | if (var != NULL) { |
3999 | int expand; | | 3985 | int expand; |
4000 | for (;;) { | | 3986 | for (;;) { |
4001 | if (str[1] == '\0') { | | 3987 | if (str[1] == '\0') { |
4002 | /* A trailing $ is kind of a special case */ | | 3988 | /* A trailing $ is kind of a special case */ |
4003 | Buf_AddByte(&buf, str[0]); | | 3989 | Buf_AddByte(&buf, str[0]); |
4004 | str++; | | 3990 | str++; |
4005 | expand = FALSE; | | 3991 | expand = FALSE; |
| @@ -4026,27 +4012,27 @@ Var_Subst(const char *var, const char *s | | | @@ -4026,27 +4012,27 @@ Var_Subst(const char *var, const char *s |
4026 | */ | | 4012 | */ |
4027 | if (*p == '$') { | | 4013 | if (*p == '$') { |
4028 | Buf_AddBytes(&buf, p - str, str); | | 4014 | Buf_AddBytes(&buf, p - str, str); |
4029 | str = p; | | 4015 | str = p; |
4030 | continue; | | 4016 | continue; |
4031 | } | | 4017 | } |
4032 | | | 4018 | |
4033 | if (strncmp(var, str + 2, p - str - 2) != 0 || | | 4019 | if (strncmp(var, str + 2, p - str - 2) != 0 || |
4034 | var[p - str - 2] != '\0') { | | 4020 | var[p - str - 2] != '\0') { |
4035 | /* | | 4021 | /* |
4036 | * Not the variable we want to expand, scan | | 4022 | * Not the variable we want to expand, scan |
4037 | * until the next variable | | 4023 | * until the next variable |
4038 | */ | | 4024 | */ |
4039 | for (;*p != '$' && *p != '\0'; p++) | | 4025 | for (; *p != '$' && *p != '\0'; p++) |
4040 | continue; | | 4026 | continue; |
4041 | Buf_AddBytes(&buf, p - str, str); | | 4027 | Buf_AddBytes(&buf, p - str, str); |
4042 | str = p; | | 4028 | str = p; |
4043 | expand = FALSE; | | 4029 | expand = FALSE; |
4044 | } else | | 4030 | } else |
4045 | expand = TRUE; | | 4031 | expand = TRUE; |
4046 | break; | | 4032 | break; |
4047 | } | | 4033 | } |
4048 | } | | 4034 | } |
4049 | if (!expand) | | 4035 | if (!expand) |
4050 | continue; | | 4036 | continue; |
4051 | } | | 4037 | } |
4052 | | | 4038 | |