| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: var.c,v 1.609 2020/10/30 22:49:07 rillig Exp $ */ | | 1 | /* $NetBSD: var.c,v 1.610 2020/10/30 22:55:34 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. |
| @@ -119,27 +119,27 @@ | | | @@ -119,27 +119,27 @@ |
119 | #include <sys/types.h> | | 119 | #include <sys/types.h> |
120 | #include <regex.h> | | 120 | #include <regex.h> |
121 | #endif | | 121 | #endif |
122 | #include <inttypes.h> | | 122 | #include <inttypes.h> |
123 | #include <limits.h> | | 123 | #include <limits.h> |
124 | #include <time.h> | | 124 | #include <time.h> |
125 | | | 125 | |
126 | #include "make.h" | | 126 | #include "make.h" |
127 | #include "dir.h" | | 127 | #include "dir.h" |
128 | #include "job.h" | | 128 | #include "job.h" |
129 | #include "metachar.h" | | 129 | #include "metachar.h" |
130 | | | 130 | |
131 | /* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ | | 131 | /* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ |
132 | MAKE_RCSID("$NetBSD: var.c,v 1.609 2020/10/30 22:49:07 rillig Exp $"); | | 132 | MAKE_RCSID("$NetBSD: var.c,v 1.610 2020/10/30 22:55:34 rillig Exp $"); |
133 | | | 133 | |
134 | #define VAR_DEBUG1(fmt, arg1) DEBUG1(VAR, fmt, arg1) | | 134 | #define VAR_DEBUG1(fmt, arg1) DEBUG1(VAR, fmt, arg1) |
135 | #define VAR_DEBUG2(fmt, arg1, arg2) DEBUG2(VAR, fmt, arg1, arg2) | | 135 | #define VAR_DEBUG2(fmt, arg1, arg2) DEBUG2(VAR, fmt, arg1, arg2) |
136 | #define VAR_DEBUG3(fmt, arg1, arg2, arg3) DEBUG3(VAR, fmt, arg1, arg2, arg3) | | 136 | #define VAR_DEBUG3(fmt, arg1, arg2, arg3) DEBUG3(VAR, fmt, arg1, arg2, arg3) |
137 | #define VAR_DEBUG4(fmt, arg1, arg2, arg3, arg4) DEBUG4(VAR, fmt, arg1, arg2, arg3, arg4) | | 137 | #define VAR_DEBUG4(fmt, arg1, arg2, arg3, arg4) DEBUG4(VAR, fmt, arg1, arg2, arg3, arg4) |
138 | | | 138 | |
139 | ENUM_FLAGS_RTTI_3(VarEvalFlags, | | 139 | ENUM_FLAGS_RTTI_3(VarEvalFlags, |
140 | VARE_UNDEFERR, VARE_WANTRES, VARE_ASSIGN); | | 140 | VARE_UNDEFERR, VARE_WANTRES, VARE_ASSIGN); |
141 | | | 141 | |
142 | /* | | 142 | /* |
143 | * This lets us tell if we have replaced the original environ | | 143 | * This lets us tell if we have replaced the original environ |
144 | * (which we cannot free). | | 144 | * (which we cannot free). |
145 | */ | | 145 | */ |
| @@ -1023,27 +1023,27 @@ Var_Value(const char *name, GNode *ctxt, | | | @@ -1023,27 +1023,27 @@ Var_Value(const char *name, GNode *ctxt, |
1023 | char *value; | | 1023 | char *value; |
1024 | | | 1024 | |
1025 | *freeIt = NULL; | | 1025 | *freeIt = NULL; |
1026 | if (v == NULL) | | 1026 | if (v == NULL) |
1027 | return NULL; | | 1027 | return NULL; |
1028 | | | 1028 | |
1029 | value = Buf_GetAll(&v->val, NULL); | | 1029 | value = Buf_GetAll(&v->val, NULL); |
1030 | if (VarFreeEnv(v, FALSE)) | | 1030 | if (VarFreeEnv(v, FALSE)) |
1031 | *freeIt = value; | | 1031 | *freeIt = value; |
1032 | return value; | | 1032 | return value; |
1033 | } | | 1033 | } |
1034 | | | 1034 | |
1035 | | | 1035 | |
1036 | /* SepBuf is a string being built from "words", interleaved with separators. */ | | 1036 | /* SepBuf is a string being built from words, interleaved with separators. */ |
1037 | typedef struct SepBuf { | | 1037 | typedef struct SepBuf { |
1038 | Buffer buf; | | 1038 | Buffer buf; |
1039 | Boolean needSep; | | 1039 | Boolean needSep; |
1040 | char sep; /* usually ' ', but see the :ts modifier */ | | 1040 | char sep; /* usually ' ', but see the :ts modifier */ |
1041 | } SepBuf; | | 1041 | } SepBuf; |
1042 | | | 1042 | |
1043 | static void | | 1043 | static void |
1044 | SepBuf_Init(SepBuf *buf, char sep) | | 1044 | SepBuf_Init(SepBuf *buf, char sep) |
1045 | { | | 1045 | { |
1046 | Buf_Init(&buf->buf, 32 /* bytes */); | | 1046 | Buf_Init(&buf->buf, 32 /* bytes */); |
1047 | buf->needSep = FALSE; | | 1047 | buf->needSep = FALSE; |
1048 | buf->sep = sep; | | 1048 | buf->sep = sep; |
1049 | } | | 1049 | } |
| @@ -1148,110 +1148,106 @@ ModifyWord_Match(const char *word, SepBu | | | @@ -1148,110 +1148,106 @@ ModifyWord_Match(const char *word, SepBu |
1148 | } | | 1148 | } |
1149 | | | 1149 | |
1150 | /* Callback for ModifyWords to implement the :N modifier. | | 1150 | /* Callback for ModifyWords to implement the :N modifier. |
1151 | * Place the word in the buffer if it doesn't match the given pattern. */ | | 1151 | * Place the word in the buffer if it doesn't match the given pattern. */ |
1152 | static void | | 1152 | static void |
1153 | ModifyWord_NoMatch(const char *word, SepBuf *buf, void *data) | | 1153 | ModifyWord_NoMatch(const char *word, SepBuf *buf, void *data) |
1154 | { | | 1154 | { |
1155 | const char *pattern = data; | | 1155 | const char *pattern = data; |
1156 | if (!Str_Match(word, pattern)) | | 1156 | if (!Str_Match(word, pattern)) |
1157 | SepBuf_AddStr(buf, word); | | 1157 | SepBuf_AddStr(buf, word); |
1158 | } | | 1158 | } |
1159 | | | 1159 | |
1160 | #ifdef SYSVVARSUB | | 1160 | #ifdef SYSVVARSUB |
1161 | /*- | | 1161 | /* Check word against pattern for a match (% is a wildcard). |
1162 | *----------------------------------------------------------------------- | | | |
1163 | * Str_SYSVMatch -- | | | |
1164 | * Check word against pattern for a match (% is wild), | | | |
1165 | * | | 1162 | * |
1166 | * Input: | | 1163 | * Input: |
1167 | * word Word to examine | | 1164 | * word Word to examine |
1168 | * pattern Pattern to examine against | | 1165 | * pattern Pattern to examine against |
1169 | * | | 1166 | * |
1170 | * Results: | | 1167 | * Results: |
1171 | * Returns the start of the match, or NULL. | | 1168 | * Returns the start of the match, or NULL. |
1172 | * *match_len returns the length of the match, if any. | | 1169 | * out_match_len returns the length of the match, if any. |
1173 | * *hasPercent returns whether the pattern contains a percent. | | 1170 | * out_hasPercent returns whether the pattern contains a percent. |
1174 | *----------------------------------------------------------------------- | | | |
1175 | */ | | 1171 | */ |
1176 | static const char * | | 1172 | static const char * |
1177 | Str_SYSVMatch(const char *word, const char *pattern, size_t *match_len, | | 1173 | SysVMatch(const char *word, const char *pattern, |
1178 | Boolean *hasPercent) | | 1174 | size_t *out_match_len, Boolean *out_hasPercent) |
1179 | { | | 1175 | { |
1180 | const char *p = pattern; | | 1176 | const char *p = pattern; |
1181 | const char *w = word; | | 1177 | const char *w = word; |
1182 | const char *percent; | | 1178 | const char *percent; |
1183 | size_t w_len; | | 1179 | size_t w_len; |
1184 | size_t p_len; | | 1180 | size_t p_len; |
1185 | const char *w_tail; | | 1181 | const char *w_tail; |
1186 | | | 1182 | |
1187 | *hasPercent = FALSE; | | 1183 | *out_hasPercent = FALSE; |
1188 | if (*p == '\0') { /* ${VAR:=suffix} */ | | 1184 | if (*p == '\0') { /* ${VAR:=suffix} */ |
1189 | *match_len = strlen(w); /* Null pattern is the whole string */ | | 1185 | *out_match_len = strlen(w); /* Null pattern is the whole string */ |
1190 | return w; | | 1186 | return w; |
1191 | } | | 1187 | } |
1192 | | | 1188 | |
1193 | percent = strchr(p, '%'); | | 1189 | percent = strchr(p, '%'); |
1194 | if (percent != NULL) { /* ${VAR:...%...=...} */ | | 1190 | if (percent != NULL) { /* ${VAR:...%...=...} */ |
1195 | *hasPercent = TRUE; | | 1191 | *out_hasPercent = TRUE; |
1196 | if (*w == '\0') | | 1192 | if (*w == '\0') |
1197 | return NULL; /* empty word does not match pattern */ | | 1193 | return NULL; /* empty word does not match pattern */ |
1198 | | | 1194 | |
1199 | /* check that the prefix matches */ | | 1195 | /* check that the prefix matches */ |
1200 | for (; p != percent && *w != '\0' && *w == *p; w++, p++) | | 1196 | for (; p != percent && *w != '\0' && *w == *p; w++, p++) |
1201 | continue; | | 1197 | continue; |
1202 | if (p != percent) | | 1198 | if (p != percent) |
1203 | return NULL; /* No match */ | | 1199 | return NULL; /* No match */ |
1204 | | | 1200 | |
1205 | p++; /* Skip the percent */ | | 1201 | p++; /* Skip the percent */ |
1206 | if (*p == '\0') { | | 1202 | if (*p == '\0') { |
1207 | /* No more pattern, return the rest of the string */ | | 1203 | /* No more pattern, return the rest of the string */ |
1208 | *match_len = strlen(w); | | 1204 | *out_match_len = strlen(w); |
1209 | return w; | | 1205 | return w; |
1210 | } | | 1206 | } |
1211 | } | | 1207 | } |
1212 | | | 1208 | |
1213 | /* Test whether the tail matches */ | | 1209 | /* Test whether the tail matches */ |
1214 | w_len = strlen(w); | | 1210 | w_len = strlen(w); |
1215 | p_len = strlen(p); | | 1211 | p_len = strlen(p); |
1216 | if (w_len < p_len) | | 1212 | if (w_len < p_len) |
1217 | return NULL; | | 1213 | return NULL; |
1218 | | | 1214 | |
1219 | w_tail = w + w_len - p_len; | | 1215 | w_tail = w + w_len - p_len; |
1220 | if (memcmp(p, w_tail, p_len) != 0) | | 1216 | if (memcmp(p, w_tail, p_len) != 0) |
1221 | return NULL; | | 1217 | return NULL; |
1222 | | | 1218 | |
1223 | *match_len = (size_t)(w_tail - w); | | 1219 | *out_match_len = (size_t)(w_tail - w); |
1224 | return w; | | 1220 | return w; |
1225 | } | | 1221 | } |
1226 | | | 1222 | |
1227 | struct ModifyWord_SYSVSubstArgs { | | 1223 | struct ModifyWord_SYSVSubstArgs { |
1228 | GNode *ctx; | | 1224 | GNode *ctx; |
1229 | const char *lhs; | | 1225 | const char *lhs; |
1230 | const char *rhs; | | 1226 | const char *rhs; |
1231 | }; | | 1227 | }; |
1232 | | | 1228 | |
1233 | /* Callback for ModifyWords to implement the :%.from=%.to modifier. */ | | 1229 | /* Callback for ModifyWords to implement the :%.from=%.to modifier. */ |
1234 | static void | | 1230 | static void |
1235 | ModifyWord_SYSVSubst(const char *word, SepBuf *buf, void *data) | | 1231 | ModifyWord_SYSVSubst(const char *word, SepBuf *buf, void *data) |
1236 | { | | 1232 | { |
1237 | const struct ModifyWord_SYSVSubstArgs *args = data; | | 1233 | const struct ModifyWord_SYSVSubstArgs *args = data; |
1238 | char *rhs_expanded; | | 1234 | char *rhs_expanded; |
1239 | const char *rhs; | | 1235 | const char *rhs; |
1240 | const char *percent; | | 1236 | const char *percent; |
1241 | | | 1237 | |
1242 | size_t match_len; | | 1238 | size_t match_len; |
1243 | Boolean lhsPercent; | | 1239 | Boolean lhsPercent; |
1244 | const char *match = Str_SYSVMatch(word, args->lhs, &match_len, &lhsPercent); | | 1240 | const char *match = SysVMatch(word, args->lhs, &match_len, &lhsPercent); |
1245 | if (match == NULL) { | | 1241 | if (match == NULL) { |
1246 | SepBuf_AddStr(buf, word); | | 1242 | SepBuf_AddStr(buf, word); |
1247 | return; | | 1243 | return; |
1248 | } | | 1244 | } |
1249 | | | 1245 | |
1250 | /* Append rhs to the buffer, substituting the first '%' with the | | 1246 | /* Append rhs to the buffer, substituting the first '%' with the |
1251 | * match, but only if the lhs had a '%' as well. */ | | 1247 | * match, but only if the lhs had a '%' as well. */ |
1252 | | | 1248 | |
1253 | (void)Var_Subst(args->rhs, args->ctx, VARE_WANTRES, &rhs_expanded); | | 1249 | (void)Var_Subst(args->rhs, args->ctx, VARE_WANTRES, &rhs_expanded); |
1254 | /* TODO: handle errors */ | | 1250 | /* TODO: handle errors */ |
1255 | | | 1251 | |
1256 | rhs = rhs_expanded; | | 1252 | rhs = rhs_expanded; |
1257 | percent = strchr(rhs, '%'); | | 1253 | percent = strchr(rhs, '%'); |