| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: var.c,v 1.313 2020/07/26 15:09:10 rillig Exp $ */ | | 1 | /* $NetBSD: var.c,v 1.314 2020/07/26 15:26:27 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.313 2020/07/26 15:09:10 rillig Exp $"; | | 72 | static char rcsid[] = "$NetBSD: var.c,v 1.314 2020/07/26 15:26:27 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.313 2020/07/26 15:09:10 rillig Exp $"); | | 79 | __RCSID("$NetBSD: var.c,v 1.314 2020/07/26 15:26:27 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 | * |
| @@ -1049,112 +1049,124 @@ SepBuf_Init(SepBuf *buf, char sep) | | | @@ -1049,112 +1049,124 @@ SepBuf_Init(SepBuf *buf, char sep) |
1049 | { | | 1049 | { |
1050 | Buf_Init(&buf->buf, 32 /* bytes */); | | 1050 | Buf_Init(&buf->buf, 32 /* bytes */); |
1051 | buf->needSep = FALSE; | | 1051 | buf->needSep = FALSE; |
1052 | buf->sep = sep; | | 1052 | buf->sep = sep; |
1053 | } | | 1053 | } |
1054 | | | 1054 | |
1055 | static void | | 1055 | static void |
1056 | SepBuf_Sep(SepBuf *buf) | | 1056 | SepBuf_Sep(SepBuf *buf) |
1057 | { | | 1057 | { |
1058 | buf->needSep = TRUE; | | 1058 | buf->needSep = TRUE; |
1059 | } | | 1059 | } |
1060 | | | 1060 | |
1061 | static void | | 1061 | static void |
1062 | SepBuf_AddBytes(SepBuf *buf, const void *mem, size_t mem_size) | | 1062 | SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size) |
1063 | { | | 1063 | { |
1064 | if (mem_size == 0) | | 1064 | if (mem_size == 0) |
1065 | return; | | 1065 | return; |
1066 | if (buf->needSep && buf->sep != '\0') { | | 1066 | if (buf->needSep && buf->sep != '\0') { |
1067 | Buf_AddByte(&buf->buf, buf->sep); | | 1067 | Buf_AddByte(&buf->buf, buf->sep); |
1068 | buf->needSep = FALSE; | | 1068 | buf->needSep = FALSE; |
1069 | } | | 1069 | } |
1070 | Buf_AddBytes(&buf->buf, mem_size, mem); | | 1070 | Buf_AddBytes(&buf->buf, mem_size, mem); |
1071 | } | | 1071 | } |
1072 | | | 1072 | |
| | | 1073 | static void |
| | | 1074 | SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end) |
| | | 1075 | { |
| | | 1076 | SepBuf_AddBytes(buf, start, (size_t)(end - start)); |
| | | 1077 | } |
| | | 1078 | |
| | | 1079 | static void |
| | | 1080 | SepBuf_AddStr(SepBuf *buf, const char *str) |
| | | 1081 | { |
| | | 1082 | SepBuf_AddBytes(buf, str, strlen(str)); |
| | | 1083 | } |
| | | 1084 | |
1073 | static char * | | 1085 | static char * |
1074 | SepBuf_Destroy(SepBuf *buf, Boolean free_buf) | | 1086 | SepBuf_Destroy(SepBuf *buf, Boolean free_buf) |
1075 | { | | 1087 | { |
1076 | return Buf_Destroy(&buf->buf, free_buf); | | 1088 | return Buf_Destroy(&buf->buf, free_buf); |
1077 | } | | 1089 | } |
1078 | | | 1090 | |
1079 | | | 1091 | |
1080 | /* This callback for ModifyWords gets a single word from an expression and | | 1092 | /* This callback for ModifyWords gets a single word from an expression and |
1081 | * typically adds a modification of this word to the buffer. It may also do | | 1093 | * typically adds a modification of this word to the buffer. It may also do |
1082 | * nothing or add several words. */ | | 1094 | * nothing or add several words. */ |
1083 | typedef void (*ModifyWordsCallback)(const char *word, SepBuf *buf, void *data); | | 1095 | typedef void (*ModifyWordsCallback)(const char *word, SepBuf *buf, void *data); |
1084 | | | 1096 | |
1085 | | | 1097 | |
1086 | /* Callback for ModifyWords to implement the :H modifier. | | 1098 | /* Callback for ModifyWords to implement the :H modifier. |
1087 | * Add the dirname of the given word to the buffer. */ | | 1099 | * Add the dirname of the given word to the buffer. */ |
1088 | static void | | 1100 | static void |
1089 | ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) | | 1101 | ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) |
1090 | { | | 1102 | { |
1091 | const char *slash = strrchr(word, '/'); | | 1103 | const char *slash = strrchr(word, '/'); |
1092 | if (slash != NULL) | | 1104 | if (slash != NULL) |
1093 | SepBuf_AddBytes(buf, word, slash - word); | | 1105 | SepBuf_AddBytesBetween(buf, word, slash); |
1094 | else | | 1106 | else |
1095 | SepBuf_AddBytes(buf, ".", 1); | | 1107 | SepBuf_AddStr(buf, "."); |
1096 | } | | 1108 | } |
1097 | | | 1109 | |
1098 | /* Callback for ModifyWords to implement the :T modifier. | | 1110 | /* Callback for ModifyWords to implement the :T modifier. |
1099 | * Add the basename of the given word to the buffer. */ | | 1111 | * Add the basename of the given word to the buffer. */ |
1100 | static void | | 1112 | static void |
1101 | ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) | | 1113 | ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) |
1102 | { | | 1114 | { |
1103 | const char *slash = strrchr(word, '/'); | | 1115 | const char *slash = strrchr(word, '/'); |
1104 | const char *base = slash != NULL ? slash + 1 : word; | | 1116 | const char *base = slash != NULL ? slash + 1 : word; |
1105 | SepBuf_AddBytes(buf, base, strlen(base)); | | 1117 | SepBuf_AddStr(buf, base); |
1106 | } | | 1118 | } |
1107 | | | 1119 | |
1108 | /* Callback for ModifyWords to implement the :E modifier. | | 1120 | /* Callback for ModifyWords to implement the :E modifier. |
1109 | * Add the filename suffix of the given word to the buffer, if it exists. */ | | 1121 | * Add the filename suffix of the given word to the buffer, if it exists. */ |
1110 | static void | | 1122 | static void |
1111 | ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) | | 1123 | ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) |
1112 | { | | 1124 | { |
1113 | const char *dot = strrchr(word, '.'); | | 1125 | const char *dot = strrchr(word, '.'); |
1114 | if (dot != NULL) | | 1126 | if (dot != NULL) |
1115 | SepBuf_AddBytes(buf, dot + 1, strlen(dot + 1)); | | 1127 | SepBuf_AddStr(buf, dot + 1); |
1116 | } | | 1128 | } |
1117 | | | 1129 | |
1118 | /* Callback for ModifyWords to implement the :R modifier. | | 1130 | /* Callback for ModifyWords to implement the :R modifier. |
1119 | * Add the basename of the given word to the buffer. */ | | 1131 | * Add the basename of the given word to the buffer. */ |
1120 | static void | | 1132 | static void |
1121 | ModifyWord_Root(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) | | 1133 | ModifyWord_Root(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) |
1122 | { | | 1134 | { |
1123 | char *dot = strrchr(word, '.'); | | 1135 | const char *dot = strrchr(word, '.'); |
1124 | size_t len = dot != NULL ? (size_t)(dot - word) : strlen(word); | | 1136 | size_t len = dot != NULL ? (size_t)(dot - word) : strlen(word); |
1125 | SepBuf_AddBytes(buf, word, len); | | 1137 | SepBuf_AddBytes(buf, word, len); |
1126 | } | | 1138 | } |
1127 | | | 1139 | |
1128 | /* Callback for ModifyWords to implement the :M modifier. | | 1140 | /* Callback for ModifyWords to implement the :M modifier. |
1129 | * Place the word in the buffer if it matches the given pattern. */ | | 1141 | * Place the word in the buffer if it matches the given pattern. */ |
1130 | static void | | 1142 | static void |
1131 | ModifyWord_Match(const char *word, SepBuf *buf, void *data) | | 1143 | ModifyWord_Match(const char *word, SepBuf *buf, void *data) |
1132 | { | | 1144 | { |
1133 | const char *pattern = data; | | 1145 | const char *pattern = data; |
1134 | if (DEBUG(VAR)) | | 1146 | if (DEBUG(VAR)) |
1135 | fprintf(debug_file, "VarMatch [%s] [%s]\n", word, pattern); | | 1147 | fprintf(debug_file, "VarMatch [%s] [%s]\n", word, pattern); |
1136 | if (Str_Match(word, pattern)) | | 1148 | if (Str_Match(word, pattern)) |
1137 | SepBuf_AddBytes(buf, word, strlen(word)); | | 1149 | SepBuf_AddStr(buf, word); |
1138 | } | | 1150 | } |
1139 | | | 1151 | |
1140 | /* Callback for ModifyWords to implement the :N modifier. | | 1152 | /* Callback for ModifyWords to implement the :N modifier. |
1141 | * Place the word in the buffer if it doesn't match the given pattern. */ | | 1153 | * Place the word in the buffer if it doesn't match the given pattern. */ |
1142 | static void | | 1154 | static void |
1143 | ModifyWord_NoMatch(const char *word, SepBuf *buf, void *data) | | 1155 | ModifyWord_NoMatch(const char *word, SepBuf *buf, void *data) |
1144 | { | | 1156 | { |
1145 | const char *pattern = data; | | 1157 | const char *pattern = data; |
1146 | if (!Str_Match(word, pattern)) | | 1158 | if (!Str_Match(word, pattern)) |
1147 | SepBuf_AddBytes(buf, word, strlen(word)); | | 1159 | SepBuf_AddStr(buf, word); |
1148 | } | | 1160 | } |
1149 | | | 1161 | |
1150 | #ifdef SYSVVARSUB | | 1162 | #ifdef SYSVVARSUB |
1151 | /*- | | 1163 | /*- |
1152 | *----------------------------------------------------------------------- | | 1164 | *----------------------------------------------------------------------- |
1153 | * Str_SYSVMatch -- | | 1165 | * Str_SYSVMatch -- |
1154 | * Check word against pattern for a match (% is wild), | | 1166 | * Check word against pattern for a match (% is wild), |
1155 | * | | 1167 | * |
1156 | * Input: | | 1168 | * Input: |
1157 | * word Word to examine | | 1169 | * word Word to examine |
1158 | * pattern Pattern to examine against | | 1170 | * pattern Pattern to examine against |
1159 | * len Number of characters to substitute | | 1171 | * len Number of characters to substitute |
1160 | * | | 1172 | * |
| @@ -1221,61 +1233,61 @@ Str_SYSVMatch(const char *word, const ch | | | @@ -1221,61 +1233,61 @@ Str_SYSVMatch(const char *word, const ch |
1221 | * | | 1233 | * |
1222 | * Side Effects: | | 1234 | * Side Effects: |
1223 | * Places result on buf | | 1235 | * Places result on buf |
1224 | *----------------------------------------------------------------------- | | 1236 | *----------------------------------------------------------------------- |
1225 | */ | | 1237 | */ |
1226 | static void | | 1238 | static void |
1227 | Str_SYSVSubst(SepBuf *buf, const char *pat, const char *src, size_t len, | | 1239 | Str_SYSVSubst(SepBuf *buf, const char *pat, const char *src, size_t len, |
1228 | Boolean lhsHasPercent) | | 1240 | Boolean lhsHasPercent) |
1229 | { | | 1241 | { |
1230 | const char *m; | | 1242 | const char *m; |
1231 | | | 1243 | |
1232 | if ((m = strchr(pat, '%')) != NULL && lhsHasPercent) { | | 1244 | if ((m = strchr(pat, '%')) != NULL && lhsHasPercent) { |
1233 | /* Copy the prefix */ | | 1245 | /* Copy the prefix */ |
1234 | SepBuf_AddBytes(buf, pat, m - pat); | | 1246 | SepBuf_AddBytesBetween(buf, pat, m); |
1235 | /* skip the % */ | | 1247 | /* skip the % */ |
1236 | pat = m + 1; | | 1248 | pat = m + 1; |
1237 | } | | 1249 | } |
1238 | if (m != NULL || !lhsHasPercent) { | | 1250 | if (m != NULL || !lhsHasPercent) { |
1239 | /* Copy the pattern */ | | 1251 | /* Copy the pattern */ |
1240 | SepBuf_AddBytes(buf, src, len); | | 1252 | SepBuf_AddBytes(buf, src, len); |
1241 | } | | 1253 | } |
1242 | | | 1254 | |
1243 | /* append the rest */ | | 1255 | /* append the rest */ |
1244 | SepBuf_AddBytes(buf, pat, strlen(pat)); | | 1256 | SepBuf_AddStr(buf, pat); |
1245 | } | | 1257 | } |
1246 | | | 1258 | |
1247 | | | 1259 | |
1248 | typedef struct { | | 1260 | typedef struct { |
1249 | GNode *ctx; | | 1261 | GNode *ctx; |
1250 | const char *lhs; | | 1262 | const char *lhs; |
1251 | const char *rhs; | | 1263 | const char *rhs; |
1252 | } ModifyWord_SYSVSubstArgs; | | 1264 | } ModifyWord_SYSVSubstArgs; |
1253 | | | 1265 | |
1254 | /* Callback for ModifyWords to implement the :%.from=%.to modifier. */ | | 1266 | /* Callback for ModifyWords to implement the :%.from=%.to modifier. */ |
1255 | static void | | 1267 | static void |
1256 | ModifyWord_SYSVSubst(const char *word, SepBuf *buf, void *data) | | 1268 | ModifyWord_SYSVSubst(const char *word, SepBuf *buf, void *data) |
1257 | { | | 1269 | { |
1258 | const ModifyWord_SYSVSubstArgs *args = data; | | 1270 | const ModifyWord_SYSVSubstArgs *args = data; |
1259 | | | 1271 | |
1260 | size_t len; | | 1272 | size_t len; |
1261 | Boolean hasPercent; | | 1273 | Boolean hasPercent; |
1262 | const char *ptr = Str_SYSVMatch(word, args->lhs, &len, &hasPercent); | | 1274 | const char *ptr = Str_SYSVMatch(word, args->lhs, &len, &hasPercent); |
1263 | if (ptr != NULL) { | | 1275 | if (ptr != NULL) { |
1264 | char *varexp = Var_Subst(NULL, args->rhs, args->ctx, VARE_WANTRES); | | 1276 | char *varexp = Var_Subst(NULL, args->rhs, args->ctx, VARE_WANTRES); |
1265 | Str_SYSVSubst(buf, varexp, ptr, len, hasPercent); | | 1277 | Str_SYSVSubst(buf, varexp, ptr, len, hasPercent); |
1266 | free(varexp); | | 1278 | free(varexp); |
1267 | } else { | | 1279 | } else { |
1268 | SepBuf_AddBytes(buf, word, strlen(word)); | | 1280 | SepBuf_AddStr(buf, word); |
1269 | } | | 1281 | } |
1270 | } | | 1282 | } |
1271 | #endif | | 1283 | #endif |
1272 | | | 1284 | |
1273 | | | 1285 | |
1274 | typedef struct { | | 1286 | typedef struct { |
1275 | const char *lhs; | | 1287 | const char *lhs; |
1276 | size_t lhsLen; | | 1288 | size_t lhsLen; |
1277 | const char *rhs; | | 1289 | const char *rhs; |
1278 | size_t rhsLen; | | 1290 | size_t rhsLen; |
1279 | VarPatternFlags pflags; | | 1291 | VarPatternFlags pflags; |
1280 | } ModifyWord_SubstArgs; | | 1292 | } ModifyWord_SubstArgs; |
1281 | | | 1293 | |
| @@ -1307,36 +1319,36 @@ ModifyWord_Subst(const char *word, SepBu | | | @@ -1307,36 +1319,36 @@ ModifyWord_Subst(const char *word, SepBu |
1307 | SepBuf_AddBytes(buf, word + args->lhsLen, wordLen - args->lhsLen); | | 1319 | SepBuf_AddBytes(buf, word + args->lhsLen, wordLen - args->lhsLen); |
1308 | args->pflags |= VARP_SUB_MATCHED; | | 1320 | args->pflags |= VARP_SUB_MATCHED; |
1309 | } | | 1321 | } |
1310 | return; | | 1322 | return; |
1311 | } | | 1323 | } |
1312 | | | 1324 | |
1313 | if (args->pflags & VARP_ANCHOR_END) { | | 1325 | if (args->pflags & VARP_ANCHOR_END) { |
1314 | if (wordLen < args->lhsLen) | | 1326 | if (wordLen < args->lhsLen) |
1315 | goto nosub; | | 1327 | goto nosub; |
1316 | const char *start = word + (wordLen - args->lhsLen); | | 1328 | const char *start = word + (wordLen - args->lhsLen); |
1317 | if (memcmp(start, args->lhs, args->lhsLen) != 0) | | 1329 | if (memcmp(start, args->lhs, args->lhsLen) != 0) |
1318 | goto nosub; | | 1330 | goto nosub; |
1319 | | | 1331 | |
1320 | SepBuf_AddBytes(buf, word, start - word); | | 1332 | SepBuf_AddBytesBetween(buf, word, start); |
1321 | SepBuf_AddBytes(buf, args->rhs, args->rhsLen); | | 1333 | SepBuf_AddBytes(buf, args->rhs, args->rhsLen); |
1322 | args->pflags |= VARP_SUB_MATCHED; | | 1334 | args->pflags |= VARP_SUB_MATCHED; |
1323 | return; | | 1335 | return; |
1324 | } | | 1336 | } |
1325 | | | 1337 | |
1326 | /* unanchored */ | | 1338 | /* unanchored */ |
1327 | const char *cp; | | 1339 | const char *cp; |
1328 | while ((cp = Str_FindSubstring(word, args->lhs)) != NULL) { | | 1340 | while ((cp = Str_FindSubstring(word, args->lhs)) != NULL) { |
1329 | SepBuf_AddBytes(buf, word, cp - word); | | 1341 | SepBuf_AddBytesBetween(buf, word, cp); |
1330 | SepBuf_AddBytes(buf, args->rhs, args->rhsLen); | | 1342 | SepBuf_AddBytes(buf, args->rhs, args->rhsLen); |
1331 | args->pflags |= VARP_SUB_MATCHED; | | 1343 | args->pflags |= VARP_SUB_MATCHED; |
1332 | wordLen -= (cp - word) + args->lhsLen; | | 1344 | wordLen -= (cp - word) + args->lhsLen; |
1333 | word = cp + args->lhsLen; | | 1345 | word = cp + args->lhsLen; |
1334 | if (wordLen == 0 || !(args->pflags & VARP_SUB_GLOBAL)) | | 1346 | if (wordLen == 0 || !(args->pflags & VARP_SUB_GLOBAL)) |
1335 | break; | | 1347 | break; |
1336 | } | | 1348 | } |
1337 | nosub: | | 1349 | nosub: |
1338 | SepBuf_AddBytes(buf, word, wordLen); | | 1350 | SepBuf_AddBytes(buf, word, wordLen); |
1339 | } | | 1351 | } |
1340 | | | 1352 | |
1341 | #ifndef NO_REGEX | | 1353 | #ifndef NO_REGEX |
1342 | /*- | | 1354 | /*- |
| @@ -1408,54 +1420,54 @@ tryagain: | | | @@ -1408,54 +1420,54 @@ tryagain: |
1408 | } else { | | 1420 | } else { |
1409 | n = rp[1] - '0'; | | 1421 | n = rp[1] - '0'; |
1410 | errstr[0] = '\\'; | | 1422 | errstr[0] = '\\'; |
1411 | errstr[1] = rp[1]; | | 1423 | errstr[1] = rp[1]; |
1412 | errstr[2] = '\0'; | | 1424 | errstr[2] = '\0'; |
1413 | rp++; | | 1425 | rp++; |
1414 | } | | 1426 | } |
1415 | | | 1427 | |
1416 | if (n >= args->nsub) { | | 1428 | if (n >= args->nsub) { |
1417 | Error("No subexpression %s", errstr); | | 1429 | Error("No subexpression %s", errstr); |
1418 | } else if (m[n].rm_so == -1 && m[n].rm_eo == -1) { | | 1430 | } else if (m[n].rm_so == -1 && m[n].rm_eo == -1) { |
1419 | Error("No match for subexpression %s", errstr); | | 1431 | Error("No match for subexpression %s", errstr); |
1420 | } else { | | 1432 | } else { |
1421 | SepBuf_AddBytes(buf, wp + m[n].rm_so, | | 1433 | SepBuf_AddBytesBetween(buf, wp + m[n].rm_so, |
1422 | m[n].rm_eo - m[n].rm_so); | | 1434 | wp + m[n].rm_eo); |
1423 | } | | 1435 | } |
1424 | | | 1436 | |
1425 | } else { | | 1437 | } else { |
1426 | SepBuf_AddBytes(buf, rp, 1); | | 1438 | SepBuf_AddBytes(buf, rp, 1); |
1427 | } | | 1439 | } |
1428 | } | | 1440 | } |
1429 | wp += m[0].rm_eo; | | 1441 | wp += m[0].rm_eo; |
1430 | if (args->pflags & VARP_SUB_GLOBAL) { | | 1442 | if (args->pflags & VARP_SUB_GLOBAL) { |
1431 | flags |= REG_NOTBOL; | | 1443 | flags |= REG_NOTBOL; |
1432 | if (m[0].rm_so == 0 && m[0].rm_eo == 0) { | | 1444 | if (m[0].rm_so == 0 && m[0].rm_eo == 0) { |
1433 | SepBuf_AddBytes(buf, wp, 1); | | 1445 | SepBuf_AddBytes(buf, wp, 1); |
1434 | wp++; | | 1446 | wp++; |
1435 | } | | 1447 | } |
1436 | if (*wp) | | 1448 | if (*wp) |
1437 | goto tryagain; | | 1449 | goto tryagain; |
1438 | } | | 1450 | } |
1439 | if (*wp) { | | 1451 | if (*wp) { |
1440 | SepBuf_AddBytes(buf, wp, strlen(wp)); | | 1452 | SepBuf_AddStr(buf, wp); |
1441 | } | | 1453 | } |
1442 | break; | | 1454 | break; |
1443 | default: | | 1455 | default: |
1444 | VarREError(xrv, &args->re, "Unexpected regex error"); | | 1456 | VarREError(xrv, &args->re, "Unexpected regex error"); |
1445 | /* fall through */ | | 1457 | /* fall through */ |
1446 | case REG_NOMATCH: | | 1458 | case REG_NOMATCH: |
1447 | nosub: | | 1459 | nosub: |
1448 | SepBuf_AddBytes(buf, wp, strlen(wp)); | | 1460 | SepBuf_AddStr(buf, wp); |
1449 | break; | | 1461 | break; |
1450 | } | | 1462 | } |
1451 | } | | 1463 | } |
1452 | #endif | | 1464 | #endif |
1453 | | | 1465 | |
1454 | | | 1466 | |
1455 | typedef struct { | | 1467 | typedef struct { |
1456 | GNode *ctx; | | 1468 | GNode *ctx; |
1457 | char *tvar; /* name of temporary variable */ | | 1469 | char *tvar; /* name of temporary variable */ |
1458 | char *str; /* string to expand */ | | 1470 | char *str; /* string to expand */ |
1459 | VarEvalFlags eflags; | | 1471 | VarEvalFlags eflags; |
1460 | } ModifyWord_LoopArgs; | | 1472 | } ModifyWord_LoopArgs; |
1461 | | | 1473 | |
| @@ -1470,27 +1482,27 @@ ModifyWord_Loop(const char *word, SepBuf | | | @@ -1470,27 +1482,27 @@ ModifyWord_Loop(const char *word, SepBuf |
1470 | Var_Set_with_flags(args->tvar, word, args->ctx, VAR_NO_EXPORT); | | 1482 | Var_Set_with_flags(args->tvar, word, args->ctx, VAR_NO_EXPORT); |
1471 | char *s = Var_Subst(NULL, args->str, args->ctx, args->eflags); | | 1483 | char *s = Var_Subst(NULL, args->str, args->ctx, args->eflags); |
1472 | if (DEBUG(VAR)) { | | 1484 | if (DEBUG(VAR)) { |
1473 | fprintf(debug_file, | | 1485 | fprintf(debug_file, |
1474 | "ModifyWord_Loop: in \"%s\", replace \"%s\" with \"%s\" " | | 1486 | "ModifyWord_Loop: in \"%s\", replace \"%s\" with \"%s\" " |
1475 | "to \"%s\"\n", | | 1487 | "to \"%s\"\n", |
1476 | word, args->tvar, args->str, s ? s : "(null)"); | | 1488 | word, args->tvar, args->str, s ? s : "(null)"); |
1477 | } | | 1489 | } |
1478 | | | 1490 | |
1479 | if (s != NULL && s[0] != '\0') { | | 1491 | if (s != NULL && s[0] != '\0') { |
1480 | if (s[0] == '\n' || (buf->buf.count > 0 && | | 1492 | if (s[0] == '\n' || (buf->buf.count > 0 && |
1481 | buf->buf.buffer[buf->buf.count - 1] == '\n')) | | 1493 | buf->buf.buffer[buf->buf.count - 1] == '\n')) |
1482 | buf->needSep = FALSE; | | 1494 | buf->needSep = FALSE; |
1483 | SepBuf_AddBytes(buf, s, strlen(s)); | | 1495 | SepBuf_AddStr(buf, s); |
1484 | } | | 1496 | } |
1485 | free(s); | | 1497 | free(s); |
1486 | } | | 1498 | } |
1487 | | | 1499 | |
1488 | | | 1500 | |
1489 | /*- | | 1501 | /*- |
1490 | * Implements the :[first..last] modifier. | | 1502 | * Implements the :[first..last] modifier. |
1491 | * This is a special case of ModifyWords since we want to be able | | 1503 | * This is a special case of ModifyWords since we want to be able |
1492 | * to scan the list backwards if first > last. | | 1504 | * to scan the list backwards if first > last. |
1493 | */ | | 1505 | */ |
1494 | static char * | | 1506 | static char * |
1495 | VarSelectWords(Byte sep, Boolean oneBigWord, const char *str, int first, | | 1507 | VarSelectWords(Byte sep, Boolean oneBigWord, const char *str, int first, |
1496 | int last) | | 1508 | int last) |
| @@ -1529,50 +1541,50 @@ VarSelectWords(Byte sep, Boolean oneBigW | | | @@ -1529,50 +1541,50 @@ VarSelectWords(Byte sep, Boolean oneBigW |
1529 | * We avoid scanning more of the list than we need to. | | 1541 | * We avoid scanning more of the list than we need to. |
1530 | */ | | 1542 | */ |
1531 | if (first > last) { | | 1543 | if (first > last) { |
1532 | start = MIN(ac, first) - 1; | | 1544 | start = MIN(ac, first) - 1; |
1533 | end = MAX(0, last - 1); | | 1545 | end = MAX(0, last - 1); |
1534 | step = -1; | | 1546 | step = -1; |
1535 | } else { | | 1547 | } else { |
1536 | start = MAX(0, first - 1); | | 1548 | start = MAX(0, first - 1); |
1537 | end = MIN(ac, last); | | 1549 | end = MIN(ac, last); |
1538 | step = 1; | | 1550 | step = 1; |
1539 | } | | 1551 | } |
1540 | | | 1552 | |
1541 | for (i = start; (step < 0) == (i >= end); i += step) { | | 1553 | for (i = start; (step < 0) == (i >= end); i += step) { |
1542 | SepBuf_AddBytes(&buf, av[i], strlen(av[i])); | | 1554 | SepBuf_AddStr(&buf, av[i]); |
1543 | SepBuf_Sep(&buf); | | 1555 | SepBuf_Sep(&buf); |
1544 | } | | 1556 | } |
1545 | | | 1557 | |
1546 | free(as); | | 1558 | free(as); |
1547 | free(av); | | 1559 | free(av); |
1548 | | | 1560 | |
1549 | return SepBuf_Destroy(&buf, FALSE); | | 1561 | return SepBuf_Destroy(&buf, FALSE); |
1550 | } | | 1562 | } |
1551 | | | 1563 | |
1552 | | | 1564 | |
1553 | /* Callback for ModifyWords to implement the :tA modifier. | | 1565 | /* Callback for ModifyWords to implement the :tA modifier. |
1554 | * Replace each word with the result of realpath() if successful. */ | | 1566 | * Replace each word with the result of realpath() if successful. */ |
1555 | static void | | 1567 | static void |
1556 | ModifyWord_Realpath(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) | | 1568 | ModifyWord_Realpath(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) |
1557 | { | | 1569 | { |
1558 | struct stat st; | | 1570 | struct stat st; |
1559 | char rbuf[MAXPATHLEN]; | | 1571 | char rbuf[MAXPATHLEN]; |
1560 | | | 1572 | |
1561 | char *rp = cached_realpath(word, rbuf); | | 1573 | const char *rp = cached_realpath(word, rbuf); |
1562 | if (rp != NULL && *rp == '/' && stat(rp, &st) == 0) | | 1574 | if (rp != NULL && *rp == '/' && stat(rp, &st) == 0) |
1563 | word = rp; | | 1575 | word = rp; |
1564 | | | 1576 | |
1565 | SepBuf_AddBytes(buf, word, strlen(word)); | | 1577 | SepBuf_AddStr(buf, word); |
1566 | } | | 1578 | } |
1567 | | | 1579 | |
1568 | /*- | | 1580 | /*- |
1569 | *----------------------------------------------------------------------- | | 1581 | *----------------------------------------------------------------------- |
1570 | * Modify each of the words of the passed string using the given function. | | 1582 | * Modify each of the words of the passed string using the given function. |
1571 | * | | 1583 | * |
1572 | * Input: | | 1584 | * Input: |
1573 | * str String whose words should be modified | | 1585 | * str String whose words should be modified |
1574 | * modifyWord Function that modifies a single word | | 1586 | * modifyWord Function that modifies a single word |
1575 | * data Custom data for modifyWord | | 1587 | * data Custom data for modifyWord |
1576 | * | | 1588 | * |
1577 | * Results: | | 1589 | * Results: |
1578 | * A string of all the words modified appropriately. | | 1590 | * A string of all the words modified appropriately. |
| @@ -2511,27 +2523,27 @@ ApplyModifier_Regex(const char *mod, App | | | @@ -2511,27 +2523,27 @@ ApplyModifier_Regex(const char *mod, App |
2511 | if (args.nsub > 10) | | 2523 | if (args.nsub > 10) |
2512 | args.nsub = 10; | | 2524 | args.nsub = 10; |
2513 | st->newStr = ModifyWords(st->ctxt, st->sep, oneBigWord, st->nstr, | | 2525 | st->newStr = ModifyWords(st->ctxt, st->sep, oneBigWord, st->nstr, |
2514 | ModifyWord_SubstRegex, &args); | | 2526 | ModifyWord_SubstRegex, &args); |
2515 | regfree(&args.re); | | 2527 | regfree(&args.re); |
2516 | free(args.replace); | | 2528 | free(args.replace); |
2517 | return TRUE; | | 2529 | return TRUE; |
2518 | } | | 2530 | } |
2519 | #endif | | 2531 | #endif |
2520 | | | 2532 | |
2521 | static void | | 2533 | static void |
2522 | ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) | | 2534 | ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) |
2523 | { | | 2535 | { |
2524 | SepBuf_AddBytes(buf, word, strlen(word)); | | 2536 | SepBuf_AddStr(buf, word); |
2525 | } | | 2537 | } |
2526 | | | 2538 | |
2527 | /* :ts<separator> */ | | 2539 | /* :ts<separator> */ |
2528 | static Boolean | | 2540 | static Boolean |
2529 | ApplyModifier_ToSep(const char *sep, ApplyModifiersState *st) | | 2541 | ApplyModifier_ToSep(const char *sep, ApplyModifiersState *st) |
2530 | { | | 2542 | { |
2531 | if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) { | | 2543 | if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) { |
2532 | /* ":ts<unrecognised><endc>" or ":ts<unrecognised>:" */ | | 2544 | /* ":ts<unrecognised><endc>" or ":ts<unrecognised>:" */ |
2533 | st->sep = sep[0]; | | 2545 | st->sep = sep[0]; |
2534 | st->cp = sep + 1; | | 2546 | st->cp = sep + 1; |
2535 | } else if (sep[0] == st->endc || sep[0] == ':') { | | 2547 | } else if (sep[0] == st->endc || sep[0] == ':') { |
2536 | /* ":ts<endc>" or ":ts:" */ | | 2548 | /* ":ts<endc>" or ":ts:" */ |
2537 | st->sep = '\0'; /* no separator */ | | 2549 | st->sep = '\0'; /* no separator */ |