make(1): replace brk_string with Str_Words The API is much simpler, and there is less detail that is exposed by default and fewer punctuation to type on the caller's side. To see that there is some memory to be freed, one would have to look into the struct. Having part of the return value as the actual return value and the rest in output parameters was unnecessarily asymmetrical.diff -r1.137 -r1.138 src/usr.bin/make/compat.c
(rillig)
--- src/usr.bin/make/compat.c 2020/08/30 14:11:42 1.137
+++ src/usr.bin/make/compat.c 2020/08/30 19:56:02 1.138
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: compat.c,v 1.137 2020/08/30 14:11:42 rillig Exp $ */ | 1 | /* $NetBSD: compat.c,v 1.138 2020/08/30 19:56:02 rillig Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. | 4 | * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. | |
5 | * All rights reserved. | 5 | * 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. | |
@@ -60,34 +60,34 @@ | @@ -60,34 +60,34 @@ | |||
60 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 60 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
61 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 61 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
62 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 62 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
63 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 63 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
64 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 64 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
65 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 65 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
66 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 66 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
67 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 67 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
68 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 68 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
69 | * SUCH DAMAGE. | 69 | * SUCH DAMAGE. | |
70 | */ | 70 | */ | |
71 | 71 | |||
72 | #ifndef MAKE_NATIVE | 72 | #ifndef MAKE_NATIVE | |
73 | static char rcsid[] = "$NetBSD: compat.c,v 1.137 2020/08/30 14:11:42 rillig Exp $"; | 73 | static char rcsid[] = "$NetBSD: compat.c,v 1.138 2020/08/30 19:56:02 rillig Exp $"; | |
74 | #else | 74 | #else | |
75 | #include <sys/cdefs.h> | 75 | #include <sys/cdefs.h> | |
76 | #ifndef lint | 76 | #ifndef lint | |
77 | #if 0 | 77 | #if 0 | |
78 | static char sccsid[] = "@(#)compat.c 8.2 (Berkeley) 3/19/94"; | 78 | static char sccsid[] = "@(#)compat.c 8.2 (Berkeley) 3/19/94"; | |
79 | #else | 79 | #else | |
80 | __RCSID("$NetBSD: compat.c,v 1.137 2020/08/30 14:11:42 rillig Exp $"); | 80 | __RCSID("$NetBSD: compat.c,v 1.138 2020/08/30 19:56:02 rillig Exp $"); | |
81 | #endif | 81 | #endif | |
82 | #endif /* not lint */ | 82 | #endif /* not lint */ | |
83 | #endif | 83 | #endif | |
84 | 84 | |||
85 | /*- | 85 | /*- | |
86 | * compat.c -- | 86 | * compat.c -- | |
87 | * The routines in this file implement the full-compatibility | 87 | * The routines in this file implement the full-compatibility | |
88 | * mode of PMake. Most of the special functionality of PMake | 88 | * mode of PMake. Most of the special functionality of PMake | |
89 | * is available in this mode. Things not supported: | 89 | * is available in this mode. Things not supported: | |
90 | * - different shells. | 90 | * - different shells. | |
91 | * - friendly variable substitution. | 91 | * - friendly variable substitution. | |
92 | * | 92 | * | |
93 | * Interface: | 93 | * Interface: | |
@@ -326,37 +326,38 @@ again: | @@ -326,37 +326,38 @@ again: | |||
326 | shargc = 0; | 326 | shargc = 0; | |
327 | shargv[shargc++] = shellPath; | 327 | shargv[shargc++] = shellPath; | |
328 | /* | 328 | /* | |
329 | * The following work for any of the builtin shell specs. | 329 | * The following work for any of the builtin shell specs. | |
330 | */ | 330 | */ | |
331 | if (errCheck && shellErrFlag) { | 331 | if (errCheck && shellErrFlag) { | |
332 | shargv[shargc++] = shellErrFlag; | 332 | shargv[shargc++] = shellErrFlag; | |
333 | } | 333 | } | |
334 | if (DEBUG(SHELL)) | 334 | if (DEBUG(SHELL)) | |
335 | shargv[shargc++] = "-xc"; | 335 | shargv[shargc++] = "-xc"; | |
336 | else | 336 | else | |
337 | shargv[shargc++] = "-c"; | 337 | shargv[shargc++] = "-c"; | |
338 | shargv[shargc++] = cmd; | 338 | shargv[shargc++] = cmd; | |
339 | shargv[shargc++] = NULL; | 339 | shargv[shargc] = NULL; | |
340 | av = shargv; | 340 | av = shargv; | |
341 | bp = NULL; | 341 | bp = NULL; | |
342 | mav = NULL; | 342 | mav = NULL; | |
343 | } else { | 343 | } else { | |
344 | size_t argc; | |||
345 | /* | 344 | /* | |
346 | * No meta-characters, so no need to exec a shell. Break the command | 345 | * No meta-characters, so no need to exec a shell. Break the command | |
347 | * into words to form an argument vector we can execute. | 346 | * into words to form an argument vector we can execute. | |
348 | */ | 347 | */ | |
349 | mav = brk_string(cmd, TRUE, &argc, &bp); | 348 | Words words = Str_Words(cmd, TRUE); | |
349 | mav = words.words; | |||
350 | bp = words.freeIt; | |||
350 | if (mav == NULL) { | 351 | if (mav == NULL) { | |
351 | useShell = 1; | 352 | useShell = 1; | |
352 | goto again; | 353 | goto again; | |
353 | } | 354 | } | |
354 | av = (void *)mav; | 355 | av = (void *)mav; | |
355 | } | 356 | } | |
356 | 357 | |||
357 | #ifdef USE_META | 358 | #ifdef USE_META | |
358 | if (useMeta) { | 359 | if (useMeta) { | |
359 | meta_compat_start(); | 360 | meta_compat_start(); | |
360 | } | 361 | } | |
361 | #endif | 362 | #endif | |
362 | 363 |
--- src/usr.bin/make/for.c 2020/08/29 10:32:00 1.66
+++ src/usr.bin/make/for.c 2020/08/30 19:56:02 1.67
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: for.c,v 1.66 2020/08/29 10:32:00 rillig Exp $ */ | 1 | /* $NetBSD: for.c,v 1.67 2020/08/30 19:56:02 rillig Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1992, The Regents of the University of California. | 4 | * Copyright (c) 1992, The Regents of the University of California. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
@@ -20,34 +20,34 @@ | @@ -20,34 +20,34 @@ | |||
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
29 | * SUCH DAMAGE. | 29 | * SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | #ifndef MAKE_NATIVE | 32 | #ifndef MAKE_NATIVE | |
33 | static char rcsid[] = "$NetBSD: for.c,v 1.66 2020/08/29 10:32:00 rillig Exp $"; | 33 | static char rcsid[] = "$NetBSD: for.c,v 1.67 2020/08/30 19:56:02 rillig Exp $"; | |
34 | #else | 34 | #else | |
35 | #include <sys/cdefs.h> | 35 | #include <sys/cdefs.h> | |
36 | #ifndef lint | 36 | #ifndef lint | |
37 | #if 0 | 37 | #if 0 | |
38 | static char sccsid[] = "@(#)for.c 8.1 (Berkeley) 6/6/93"; | 38 | static char sccsid[] = "@(#)for.c 8.1 (Berkeley) 6/6/93"; | |
39 | #else | 39 | #else | |
40 | __RCSID("$NetBSD: for.c,v 1.66 2020/08/29 10:32:00 rillig Exp $"); | 40 | __RCSID("$NetBSD: for.c,v 1.67 2020/08/30 19:56:02 rillig Exp $"); | |
41 | #endif | 41 | #endif | |
42 | #endif /* not lint */ | 42 | #endif /* not lint */ | |
43 | #endif | 43 | #endif | |
44 | 44 | |||
45 | /*- | 45 | /*- | |
46 | * for.c -- | 46 | * for.c -- | |
47 | * Functions to handle loops in a makefile. | 47 | * Functions to handle loops in a makefile. | |
48 | * | 48 | * | |
49 | * Interface: | 49 | * Interface: | |
50 | * For_Eval Evaluate the loop in the passed line. | 50 | * For_Eval Evaluate the loop in the passed line. | |
51 | * For_Run Run accumulated loop | 51 | * For_Run Run accumulated loop | |
52 | * | 52 | * | |
53 | */ | 53 | */ | |
@@ -123,28 +123,27 @@ For_Free(For *arg) | @@ -123,28 +123,27 @@ For_Free(For *arg) | |||
123 | * Side Effects: | 123 | * Side Effects: | |
124 | * None. | 124 | * None. | |
125 | * | 125 | * | |
126 | *----------------------------------------------------------------------- | 126 | *----------------------------------------------------------------------- | |
127 | */ | 127 | */ | |
128 | int | 128 | int | |
129 | For_Eval(char *line) | 129 | For_Eval(char *line) | |
130 | { | 130 | { | |
131 | For *new_for; | 131 | For *new_for; | |
132 | char *ptr = line, *sub; | 132 | char *ptr = line, *sub; | |
133 | size_t len; | 133 | size_t len; | |
134 | int escapes; | 134 | int escapes; | |
135 | unsigned char ch; | 135 | unsigned char ch; | |
136 | char **words, *word_buf; | 136 | Words words; | |
137 | size_t nwords; | |||
138 | 137 | |||
139 | /* Skip the '.' and any following whitespace */ | 138 | /* Skip the '.' and any following whitespace */ | |
140 | for (ptr++; *ptr && isspace((unsigned char)*ptr); ptr++) | 139 | for (ptr++; *ptr && isspace((unsigned char)*ptr); ptr++) | |
141 | continue; | 140 | continue; | |
142 | 141 | |||
143 | /* | 142 | /* | |
144 | * If we are not in a for loop quickly determine if the statement is | 143 | * If we are not in a for loop quickly determine if the statement is | |
145 | * a for. | 144 | * a for. | |
146 | */ | 145 | */ | |
147 | if (ptr[0] != 'f' || ptr[1] != 'o' || ptr[2] != 'r' || | 146 | if (ptr[0] != 'f' || ptr[1] != 'o' || ptr[2] != 'r' || | |
148 | !isspace((unsigned char)ptr[3])) { | 147 | !isspace((unsigned char)ptr[3])) { | |
149 | if (ptr[0] == 'e' && strncmp(ptr + 1, "ndfor", 5) == 0) { | 148 | if (ptr[0] == 'e' && strncmp(ptr + 1, "ndfor", 5) == 0) { | |
150 | Parse_Error(PARSE_FATAL, "for-less endfor"); | 149 | Parse_Error(PARSE_FATAL, "for-less endfor"); | |
@@ -193,62 +192,62 @@ For_Eval(char *line) | @@ -193,62 +192,62 @@ For_Eval(char *line) | |||
193 | /* | 192 | /* | |
194 | * Make a list with the remaining words | 193 | * Make a list with the remaining words | |
195 | * The values are substituted as ${:U<value>...} so we must \ escape | 194 | * The values are substituted as ${:U<value>...} so we must \ escape | |
196 | * characters that break that syntax. | 195 | * characters that break that syntax. | |
197 | * Variables are fully expanded - so it is safe for escape $. | 196 | * Variables are fully expanded - so it is safe for escape $. | |
198 | * We can't do the escapes here - because we don't know whether | 197 | * We can't do the escapes here - because we don't know whether | |
199 | * we are substuting into ${...} or $(...). | 198 | * we are substuting into ${...} or $(...). | |
200 | */ | 199 | */ | |
201 | sub = Var_Subst(ptr, VAR_GLOBAL, VARE_WANTRES); | 200 | sub = Var_Subst(ptr, VAR_GLOBAL, VARE_WANTRES); | |
202 | 201 | |||
203 | /* | 202 | /* | |
204 | * Split into words allowing for quoted strings. | 203 | * Split into words allowing for quoted strings. | |
205 | */ | 204 | */ | |
206 | words = brk_string(sub, FALSE, &nwords, &word_buf); | 205 | words = Str_Words(sub, FALSE); | |
207 | 206 | |||
208 | free(sub); | 207 | free(sub); | |
209 | 208 | |||
210 | if (words != NULL) { | 209 | { | |
211 | size_t n; | 210 | size_t n; | |
212 | 211 | |||
213 | for (n = 0; n < nwords; n++) { | 212 | for (n = 0; n < words.len; n++) { | |
214 | ptr = words[n]; | 213 | ptr = words.words[n]; | |
215 | if (!*ptr) | 214 | if (!*ptr) | |
216 | continue; | 215 | continue; | |
217 | escapes = 0; | 216 | escapes = 0; | |
218 | while ((ch = *ptr++)) { | 217 | while ((ch = *ptr++)) { | |
219 | switch (ch) { | 218 | switch (ch) { | |
220 | case ':': | 219 | case ':': | |
221 | case '$': | 220 | case '$': | |
222 | case '\\': | 221 | case '\\': | |
223 | escapes |= FOR_SUB_ESCAPE_CHAR; | 222 | escapes |= FOR_SUB_ESCAPE_CHAR; | |
224 | break; | 223 | break; | |
225 | case ')': | 224 | case ')': | |
226 | escapes |= FOR_SUB_ESCAPE_PAREN; | 225 | escapes |= FOR_SUB_ESCAPE_PAREN; | |
227 | break; | 226 | break; | |
228 | case /*{*/ '}': | 227 | case /*{*/ '}': | |
229 | escapes |= FOR_SUB_ESCAPE_BRACE; | 228 | escapes |= FOR_SUB_ESCAPE_BRACE; | |
230 | break; | 229 | break; | |
231 | } | 230 | } | |
232 | } | 231 | } | |
233 | /* | 232 | /* | |
234 | * We have to dup words[n] to maintain the semantics of | 233 | * We have to dup words[n] to maintain the semantics of | |
235 | * strlist. | 234 | * strlist. | |
236 | */ | 235 | */ | |
237 | strlist_add_str(&new_for->items, bmake_strdup(words[n]), escapes); | 236 | strlist_add_str(&new_for->items, bmake_strdup(words.words[n]), | |
237 | escapes); | |||
238 | } | 238 | } | |
239 | 239 | |||
240 | free(words); | 240 | Words_Free(words); | |
241 | free(word_buf); | |||
242 | 241 | |||
243 | if ((len = strlist_num(&new_for->items)) > 0 && | 242 | if ((len = strlist_num(&new_for->items)) > 0 && | |
244 | len % (n = strlist_num(&new_for->vars))) { | 243 | len % (n = strlist_num(&new_for->vars))) { | |
245 | Parse_Error(PARSE_FATAL, | 244 | Parse_Error(PARSE_FATAL, | |
246 | "Wrong number of words (%zu) in .for substitution list" | 245 | "Wrong number of words (%zu) in .for substitution list" | |
247 | " with %zu vars", len, n); | 246 | " with %zu vars", len, n); | |
248 | /* | 247 | /* | |
249 | * Return 'success' so that the body of the .for loop is | 248 | * Return 'success' so that the body of the .for loop is | |
250 | * accumulated. | 249 | * accumulated. | |
251 | * Remove all items so that the loop doesn't iterate. | 250 | * Remove all items so that the loop doesn't iterate. | |
252 | */ | 251 | */ | |
253 | strlist_clean(&new_for->items); | 252 | strlist_clean(&new_for->items); | |
254 | } | 253 | } |
--- src/usr.bin/make/job.c 2020/08/30 13:53:02 1.226
+++ src/usr.bin/make/job.c 2020/08/30 19:56:02 1.227
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: job.c,v 1.226 2020/08/30 13:53:02 rillig Exp $ */ | 1 | /* $NetBSD: job.c,v 1.227 2020/08/30 19:56:02 rillig Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. | 4 | * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. | |
5 | * All rights reserved. | 5 | * 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. | |
@@ -60,34 +60,34 @@ | @@ -60,34 +60,34 @@ | |||
60 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 60 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
61 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 61 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
62 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 62 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
63 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 63 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
64 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 64 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
65 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 65 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
66 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 66 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
67 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 67 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
68 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 68 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
69 | * SUCH DAMAGE. | 69 | * SUCH DAMAGE. | |
70 | */ | 70 | */ | |
71 | 71 | |||
72 | #ifndef MAKE_NATIVE | 72 | #ifndef MAKE_NATIVE | |
73 | static char rcsid[] = "$NetBSD: job.c,v 1.226 2020/08/30 13:53:02 rillig Exp $"; | 73 | static char rcsid[] = "$NetBSD: job.c,v 1.227 2020/08/30 19:56:02 rillig Exp $"; | |
74 | #else | 74 | #else | |
75 | #include <sys/cdefs.h> | 75 | #include <sys/cdefs.h> | |
76 | #ifndef lint | 76 | #ifndef lint | |
77 | #if 0 | 77 | #if 0 | |
78 | static char sccsid[] = "@(#)job.c 8.2 (Berkeley) 3/19/94"; | 78 | static char sccsid[] = "@(#)job.c 8.2 (Berkeley) 3/19/94"; | |
79 | #else | 79 | #else | |
80 | __RCSID("$NetBSD: job.c,v 1.226 2020/08/30 13:53:02 rillig Exp $"); | 80 | __RCSID("$NetBSD: job.c,v 1.227 2020/08/30 19:56:02 rillig Exp $"); | |
81 | #endif | 81 | #endif | |
82 | #endif /* not lint */ | 82 | #endif /* not lint */ | |
83 | #endif | 83 | #endif | |
84 | 84 | |||
85 | /*- | 85 | /*- | |
86 | * job.c -- | 86 | * job.c -- | |
87 | * handle the creation etc. of our child processes. | 87 | * handle the creation etc. of our child processes. | |
88 | * | 88 | * | |
89 | * Interface: | 89 | * Interface: | |
90 | * Job_Make Start the creation of the given target. | 90 | * Job_Make Start the creation of the given target. | |
91 | * | 91 | * | |
92 | * Job_CatchChildren Check for and handle the termination of any | 92 | * Job_CatchChildren Check for and handle the termination of any | |
93 | * children. This must be called reasonably | 93 | * children. This must be called reasonably | |
@@ -2404,46 +2404,50 @@ JobMatchShell(const char *name) | @@ -2404,46 +2404,50 @@ JobMatchShell(const char *name) | |||
2404 | * is TRUE or template of command to echo a command | 2404 | * is TRUE or template of command to echo a command | |
2405 | * for which error checking is off if hasErrCtl is | 2405 | * for which error checking is off if hasErrCtl is | |
2406 | * FALSE. | 2406 | * FALSE. | |
2407 | * ignore Command to turn off error checking if hasErrCtl | 2407 | * ignore Command to turn off error checking if hasErrCtl | |
2408 | * is TRUE or template of command to execute a | 2408 | * is TRUE or template of command to execute a | |
2409 | * command so as to ignore any errors it returns if | 2409 | * command so as to ignore any errors it returns if | |
2410 | * hasErrCtl is FALSE. | 2410 | * hasErrCtl is FALSE. | |
2411 | * | 2411 | * | |
2412 | *----------------------------------------------------------------------- | 2412 | *----------------------------------------------------------------------- | |
2413 | */ | 2413 | */ | |
2414 | Boolean | 2414 | Boolean | |
2415 | Job_ParseShell(char *line) | 2415 | Job_ParseShell(char *line) | |
2416 | { | 2416 | { | |
2417 | Words wordsList; | |||
2417 | char **words; | 2418 | char **words; | |
2418 | char **argv; | 2419 | char **argv; | |
2419 | size_t argc; | 2420 | size_t argc; | |
2420 | char *path; | 2421 | char *path; | |
2421 | Shell newShell; | 2422 | Shell newShell; | |
2422 | Boolean fullSpec = FALSE; | 2423 | Boolean fullSpec = FALSE; | |
2423 | Shell *sh; | 2424 | Shell *sh; | |
2424 | 2425 | |||
2425 | while (isspace((unsigned char)*line)) { | 2426 | while (isspace((unsigned char)*line)) { | |
2426 | line++; | 2427 | line++; | |
2427 | } | 2428 | } | |
2428 | 2429 | |||
2429 | free(shellArgv); | 2430 | free(shellArgv); | |
2430 | 2431 | |||
2431 | memset(&newShell, 0, sizeof(newShell)); | 2432 | memset(&newShell, 0, sizeof(newShell)); | |
2432 | 2433 | |||
2433 | /* | 2434 | /* | |
2434 | * Parse the specification by keyword | 2435 | * Parse the specification by keyword | |
2435 | */ | 2436 | */ | |
2436 | words = brk_string(line, TRUE, &argc, &path); | 2437 | wordsList = Str_Words(line, TRUE); | |
2438 | words = wordsList.words; | |||
2439 | argc = wordsList.len; | |||
2440 | path = wordsList.freeIt; | |||
2437 | if (words == NULL) { | 2441 | if (words == NULL) { | |
2438 | Error("Unterminated quoted string [%s]", line); | 2442 | Error("Unterminated quoted string [%s]", line); | |
2439 | return FALSE; | 2443 | return FALSE; | |
2440 | } | 2444 | } | |
2441 | shellArgv = path; | 2445 | shellArgv = path; | |
2442 | 2446 | |||
2443 | for (path = NULL, argv = words; argc != 0; argc--, argv++) { | 2447 | for (path = NULL, argv = words; argc != 0; argc--, argv++) { | |
2444 | if (strncmp(*argv, "path=", 5) == 0) { | 2448 | if (strncmp(*argv, "path=", 5) == 0) { | |
2445 | path = &argv[0][5]; | 2449 | path = &argv[0][5]; | |
2446 | } else if (strncmp(*argv, "name=", 5) == 0) { | 2450 | } else if (strncmp(*argv, "name=", 5) == 0) { | |
2447 | newShell.name = &argv[0][5]; | 2451 | newShell.name = &argv[0][5]; | |
2448 | } else { | 2452 | } else { | |
2449 | if (strncmp(*argv, "quiet=", 6) == 0) { | 2453 | if (strncmp(*argv, "quiet=", 6) == 0) { |
--- src/usr.bin/make/main.c 2020/08/30 11:15:05 1.330
+++ src/usr.bin/make/main.c 2020/08/30 19:56:02 1.331
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: main.c,v 1.330 2020/08/30 11:15:05 rillig Exp $ */ | 1 | /* $NetBSD: main.c,v 1.331 2020/08/30 19:56:02 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,39 +59,39 @@ | @@ -59,39 +59,39 @@ | |||
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: main.c,v 1.330 2020/08/30 11:15:05 rillig Exp $"; | 72 | static char rcsid[] = "$NetBSD: main.c,v 1.331 2020/08/30 19:56:02 rillig Exp $"; | |
73 | #else | 73 | #else | |
74 | #include <sys/cdefs.h> | 74 | #include <sys/cdefs.h> | |
75 | #ifndef lint | 75 | #ifndef lint | |
76 | __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993\ | 76 | __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993\ | |
77 | The Regents of the University of California. All rights reserved."); | 77 | The Regents of the University of California. All rights reserved."); | |
78 | #endif /* not lint */ | 78 | #endif /* not lint */ | |
79 | 79 | |||
80 | #ifndef lint | 80 | #ifndef lint | |
81 | #if 0 | 81 | #if 0 | |
82 | static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 3/19/94"; | 82 | static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 3/19/94"; | |
83 | #else | 83 | #else | |
84 | __RCSID("$NetBSD: main.c,v 1.330 2020/08/30 11:15:05 rillig Exp $"); | 84 | __RCSID("$NetBSD: main.c,v 1.331 2020/08/30 19:56:02 rillig Exp $"); | |
85 | #endif | 85 | #endif | |
86 | #endif /* not lint */ | 86 | #endif /* not lint */ | |
87 | #endif | 87 | #endif | |
88 | 88 | |||
89 | /*- | 89 | /*- | |
90 | * main.c -- | 90 | * main.c -- | |
91 | * The main file for this entire program. Exit routines etc | 91 | * The main file for this entire program. Exit routines etc | |
92 | * reside here. | 92 | * reside here. | |
93 | * | 93 | * | |
94 | * Utility functions defined in this file: | 94 | * Utility functions defined in this file: | |
95 | * Main_ParseArgLine Takes a line of arguments, breaks them and | 95 | * Main_ParseArgLine Takes a line of arguments, breaks them and | |
96 | * treats them as if they were given when first | 96 | * treats them as if they were given when first | |
97 | * invoked. Used by the parse module to implement | 97 | * invoked. Used by the parse module to implement | |
@@ -680,54 +680,51 @@ noarg: | @@ -680,54 +680,51 @@ noarg: | |||
680 | * | 680 | * | |
681 | * Input: | 681 | * Input: | |
682 | * line Line to fracture | 682 | * line Line to fracture | |
683 | * | 683 | * | |
684 | * Results: | 684 | * Results: | |
685 | * None | 685 | * None | |
686 | * | 686 | * | |
687 | * Side Effects: | 687 | * Side Effects: | |
688 | * Only those that come from the various arguments. | 688 | * Only those that come from the various arguments. | |
689 | */ | 689 | */ | |
690 | void | 690 | void | |
691 | Main_ParseArgLine(const char *line) | 691 | Main_ParseArgLine(const char *line) | |
692 | { | 692 | { | |
693 | char **argv; /* Manufactured argument vector */ | 693 | Words words; | |
694 | size_t argc; /* Number of arguments in argv */ | |||
695 | char *args; /* Space used by the args */ | |||
696 | char *p1; | 694 | char *p1; | |
697 | const char *argv0 = Var_Value(".MAKE", VAR_GLOBAL, &p1); | 695 | const char *argv0 = Var_Value(".MAKE", VAR_GLOBAL, &p1); | |
698 | char *buf; | 696 | char *buf; | |
699 | 697 | |||
700 | if (line == NULL) | 698 | if (line == NULL) | |
701 | return; | 699 | return; | |
702 | for (; *line == ' '; ++line) | 700 | for (; *line == ' '; ++line) | |
703 | continue; | 701 | continue; | |
704 | if (!*line) | 702 | if (!*line) | |
705 | return; | 703 | return; | |
706 | 704 | |||
707 | buf = str_concat3(argv0, " ", line); | 705 | buf = str_concat3(argv0, " ", line); | |
708 | free(p1); | 706 | free(p1); | |
709 | 707 | |||
710 | argv = brk_string(buf, TRUE, &argc, &args); | 708 | words = Str_Words(buf, TRUE); | |
711 | if (argv == NULL) { | 709 | if (words.words == NULL) { | |
712 | Error("Unterminated quoted string [%s]", buf); | 710 | Error("Unterminated quoted string [%s]", buf); | |
713 | free(buf); | 711 | free(buf); | |
714 | return; | 712 | return; | |
715 | } | 713 | } | |
716 | free(buf); | 714 | free(buf); | |
717 | MainParseArgs((int)argc, argv); | 715 | MainParseArgs((int)words.len, words.words); | |
718 | 716 | |||
719 | free(args); | 717 | Words_Free(words); | |
720 | free(argv); | |||
721 | } | 718 | } | |
722 | 719 | |||
723 | Boolean | 720 | Boolean | |
724 | Main_SetObjdir(const char *fmt, ...) | 721 | Main_SetObjdir(const char *fmt, ...) | |
725 | { | 722 | { | |
726 | struct stat sb; | 723 | struct stat sb; | |
727 | char *path; | 724 | char *path; | |
728 | char buf[MAXPATHLEN + 1]; | 725 | char buf[MAXPATHLEN + 1]; | |
729 | char buf2[MAXPATHLEN + 1]; | 726 | char buf2[MAXPATHLEN + 1]; | |
730 | Boolean rc = FALSE; | 727 | Boolean rc = FALSE; | |
731 | va_list ap; | 728 | va_list ap; | |
732 | 729 | |||
733 | va_start(ap, fmt); | 730 | va_start(ap, fmt); |
--- src/usr.bin/make/Attic/nonints.h 2020/08/29 12:01:46 1.101
+++ src/usr.bin/make/Attic/nonints.h 2020/08/30 19:56:02 1.102
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: nonints.h,v 1.101 2020/08/29 12:01:46 rillig Exp $ */ | 1 | /* $NetBSD: nonints.h,v 1.102 2020/08/30 19:56:02 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. | |
@@ -123,30 +123,42 @@ char *cached_realpath(const char *, char | @@ -123,30 +123,42 @@ char *cached_realpath(const char *, char | |||
123 | 123 | |||
124 | /* parse.c */ | 124 | /* parse.c */ | |
125 | void Parse_Error(int, const char *, ...) MAKE_ATTR_PRINTFLIKE(2, 3); | 125 | void Parse_Error(int, const char *, ...) MAKE_ATTR_PRINTFLIKE(2, 3); | |
126 | Boolean Parse_IsVar(char *); | 126 | Boolean Parse_IsVar(char *); | |
127 | void Parse_DoVar(char *, GNode *); | 127 | void Parse_DoVar(char *, GNode *); | |
128 | void Parse_AddIncludeDir(char *); | 128 | void Parse_AddIncludeDir(char *); | |
129 | void Parse_File(const char *, int); | 129 | void Parse_File(const char *, int); | |
130 | void Parse_Init(void); | 130 | void Parse_Init(void); | |
131 | void Parse_End(void); | 131 | void Parse_End(void); | |
132 | void Parse_SetInput(const char *, int, int, char *(*)(void *, size_t *), void *); | 132 | void Parse_SetInput(const char *, int, int, char *(*)(void *, size_t *), void *); | |
133 | Lst Parse_MainName(void); | 133 | Lst Parse_MainName(void); | |
134 | 134 | |||
135 | /* str.c */ | 135 | /* str.c */ | |
136 | typedef struct { | |||
137 | char **words; | |||
138 | size_t len; | |||
139 | void *freeIt; | |||
140 | } Words; | |||
141 | ||||
142 | Words Str_Words(const char *, Boolean); | |||
143 | static inline void MAKE_ATTR_UNUSED | |||
144 | Words_Free(Words w) { | |||
145 | free(w.words); | |||
146 | free(w.freeIt); | |||
147 | } | |||
148 | ||||
136 | char *str_concat2(const char *, const char *); | 149 | char *str_concat2(const char *, const char *); | |
137 | char *str_concat3(const char *, const char *, const char *); | 150 | char *str_concat3(const char *, const char *, const char *); | |
138 | char *str_concat4(const char *, const char *, const char *, const char *); | 151 | char *str_concat4(const char *, const char *, const char *, const char *); | |
139 | char **brk_string(const char *, Boolean, size_t *, char **); | |||
140 | char *Str_FindSubstring(const char *, const char *); | 152 | char *Str_FindSubstring(const char *, const char *); | |
141 | Boolean Str_Match(const char *, const char *); | 153 | Boolean Str_Match(const char *, const char *); | |
142 | 154 | |||
143 | /* suff.c */ | 155 | /* suff.c */ | |
144 | void Suff_ClearSuffixes(void); | 156 | void Suff_ClearSuffixes(void); | |
145 | Boolean Suff_IsTransform(char *); | 157 | Boolean Suff_IsTransform(char *); | |
146 | GNode *Suff_AddTransform(char *); | 158 | GNode *Suff_AddTransform(char *); | |
147 | int Suff_EndTransform(void *, void *); | 159 | int Suff_EndTransform(void *, void *); | |
148 | void Suff_AddSuffix(const char *, GNode **); | 160 | void Suff_AddSuffix(const char *, GNode **); | |
149 | Lst Suff_GetPath(char *); | 161 | Lst Suff_GetPath(char *); | |
150 | void Suff_DoPaths(void); | 162 | void Suff_DoPaths(void); | |
151 | void Suff_AddInclude(char *); | 163 | void Suff_AddInclude(char *); | |
152 | void Suff_AddLib(const char *); | 164 | void Suff_AddLib(const char *); |
--- src/usr.bin/make/str.c 2020/08/29 07:52:55 1.63
+++ src/usr.bin/make/str.c 2020/08/30 19:56:02 1.64
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: str.c,v 1.63 2020/08/29 07:52:55 rillig Exp $ */ | 1 | /* $NetBSD: str.c,v 1.64 2020/08/30 19:56:02 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: str.c,v 1.63 2020/08/29 07:52:55 rillig Exp $"; | 72 | static char rcsid[] = "$NetBSD: str.c,v 1.64 2020/08/30 19:56:02 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[] = "@(#)str.c 5.8 (Berkeley) 6/1/90"; | 77 | static char sccsid[] = "@(#)str.c 5.8 (Berkeley) 6/1/90"; | |
78 | #else | 78 | #else | |
79 | __RCSID("$NetBSD: str.c,v 1.63 2020/08/29 07:52:55 rillig Exp $"); | 79 | __RCSID("$NetBSD: str.c,v 1.64 2020/08/30 19:56:02 rillig Exp $"); | |
80 | #endif | 80 | #endif | |
81 | #endif /* not lint */ | 81 | #endif /* not lint */ | |
82 | #endif | 82 | #endif | |
83 | 83 | |||
84 | #include "make.h" | 84 | #include "make.h" | |
85 | 85 | |||
86 | /* Return the concatenation of s1 and s2, freshly allocated. */ | 86 | /* Return the concatenation of s1 and s2, freshly allocated. */ | |
87 | char * | 87 | char * | |
88 | str_concat2(const char *s1, const char *s2) | 88 | str_concat2(const char *s1, const char *s2) | |
89 | { | 89 | { | |
90 | size_t len1 = strlen(s1); | 90 | size_t len1 = strlen(s1); | |
91 | size_t len2 = strlen(s2); | 91 | size_t len2 = strlen(s2); | |
92 | char *result = bmake_malloc(len1 + len2 + 1); | 92 | char *result = bmake_malloc(len1 + len2 + 1); | |
@@ -115,45 +115,39 @@ str_concat4(const char *s1, const char * | @@ -115,45 +115,39 @@ str_concat4(const char *s1, const char * | |||
115 | { | 115 | { | |
116 | size_t len1 = strlen(s1); | 116 | size_t len1 = strlen(s1); | |
117 | size_t len2 = strlen(s2); | 117 | size_t len2 = strlen(s2); | |
118 | size_t len3 = strlen(s3); | 118 | size_t len3 = strlen(s3); | |
119 | size_t len4 = strlen(s4); | 119 | size_t len4 = strlen(s4); | |
120 | char *result = bmake_malloc(len1 + len2 + len3 + len4 + 1); | 120 | char *result = bmake_malloc(len1 + len2 + len3 + len4 + 1); | |
121 | memcpy(result, s1, len1); | 121 | memcpy(result, s1, len1); | |
122 | memcpy(result + len1, s2, len2); | 122 | memcpy(result + len1, s2, len2); | |
123 | memcpy(result + len1 + len2, s3, len3); | 123 | memcpy(result + len1 + len2, s3, len3); | |
124 | memcpy(result + len1 + len2 + len3, s4, len4 + 1); | 124 | memcpy(result + len1 + len2 + len3, s4, len4 + 1); | |
125 | return result; | 125 | return result; | |
126 | } | 126 | } | |
127 | 127 | |||
128 | /*- | 128 | /* Fracture a string into an array of words (as delineated by tabs or spaces) | |
129 | * brk_string -- | 129 | * taking quotation marks into account. Leading tabs/spaces are ignored. | |
130 | * Fracture a string into an array of words (as delineated by tabs or | 130 | * | |
131 | * spaces) taking quotation marks into account. Leading tabs/spaces | 131 | * If expand is TRUE, quotes are removed and escape sequences such as \r, \t, | |
132 | * are ignored. | 132 | * etc... are expanded. In this case, the return value is NULL on parse | |
133 | * | 133 | * errors. | |
134 | * If expand is TRUE, quotes are removed and escape sequences | 134 | * | |
135 | * such as \r, \t, etc... are expanded. In this case, the return value | 135 | * Returns the fractured words, which must be freed later using Words_Free. | |
136 | * is NULL on parse errors. | 136 | * If expand was TRUE and there was a parse error, words is NULL, and in that | |
137 | * | 137 | * case, nothing needs to be freed. | |
138 | * returns -- | |||
139 | * Pointer to the array of pointers to the words. | |||
140 | * Memory containing the actual words in *out_words_buf. | |||
141 | * Both of these must be free'd by the caller. | |||
142 | * Number of words in *out_words_len. | |||
143 | */ | 138 | */ | |
144 | char ** | 139 | Words | |
145 | brk_string(const char *str, Boolean expand, | 140 | Str_Words(const char *str, Boolean expand) | |
146 | size_t *out_words_len, char **out_words_buf) | |||
147 | { | 141 | { | |
148 | size_t str_len; | 142 | size_t str_len; | |
149 | char *words_buf; | 143 | char *words_buf; | |
150 | size_t words_cap; | 144 | size_t words_cap; | |
151 | char **words; | 145 | char **words; | |
152 | size_t words_len; | 146 | size_t words_len; | |
153 | char inquote; | 147 | char inquote; | |
154 | char *word_start; | 148 | char *word_start; | |
155 | char *word_end; | 149 | char *word_end; | |
156 | const char *str_p; | 150 | const char *str_p; | |
157 | 151 | |||
158 | /* skip leading space chars. */ | 152 | /* skip leading space chars. */ | |
159 | for (; *str == ' ' || *str == '\t'; ++str) | 153 | for (; *str == ' ' || *str == '\t'; ++str) | |
@@ -223,28 +217,27 @@ brk_string(const char *str, Boolean expa | @@ -223,28 +217,27 @@ brk_string(const char *str, Boolean expa | |||
223 | *word_end++ = '\0'; | 217 | *word_end++ = '\0'; | |
224 | if (words_len == words_cap) { | 218 | if (words_len == words_cap) { | |
225 | size_t new_size; | 219 | size_t new_size; | |
226 | words_cap *= 2; /* ramp up fast */ | 220 | words_cap *= 2; /* ramp up fast */ | |
227 | new_size = (words_cap + 1) * sizeof(char *); | 221 | new_size = (words_cap + 1) * sizeof(char *); | |
228 | words = bmake_realloc(words, new_size); | 222 | words = bmake_realloc(words, new_size); | |
229 | } | 223 | } | |
230 | words[words_len++] = word_start; | 224 | words[words_len++] = word_start; | |
231 | word_start = NULL; | 225 | word_start = NULL; | |
232 | if (ch == '\n' || ch == '\0') { | 226 | if (ch == '\n' || ch == '\0') { | |
233 | if (expand && inquote) { | 227 | if (expand && inquote) { | |
234 | free(words); | 228 | free(words); | |
235 | free(words_buf); | 229 | free(words_buf); | |
236 | *out_words_buf = NULL; | 230 | return (Words){ NULL, 0, NULL }; | |
237 | return NULL; | |||
238 | } | 231 | } | |
239 | goto done; | 232 | goto done; | |
240 | } | 233 | } | |
241 | continue; | 234 | continue; | |
242 | case '\\': | 235 | case '\\': | |
243 | if (!expand) { | 236 | if (!expand) { | |
244 | if (word_start == NULL) | 237 | if (word_start == NULL) | |
245 | word_start = word_end; | 238 | word_start = word_end; | |
246 | *word_end++ = '\\'; | 239 | *word_end++ = '\\'; | |
247 | /* catch '\' at end of line */ | 240 | /* catch '\' at end of line */ | |
248 | if (str_p[1] == '\0') | 241 | if (str_p[1] == '\0') | |
249 | continue; | 242 | continue; | |
250 | ch = *++str_p; | 243 | ch = *++str_p; | |
@@ -272,29 +265,27 @@ brk_string(const char *str, Boolean expa | @@ -272,29 +265,27 @@ brk_string(const char *str, Boolean expa | |||
272 | break; | 265 | break; | |
273 | case 't': | 266 | case 't': | |
274 | ch = '\t'; | 267 | ch = '\t'; | |
275 | break; | 268 | break; | |
276 | } | 269 | } | |
277 | break; | 270 | break; | |
278 | } | 271 | } | |
279 | if (word_start == NULL) | 272 | if (word_start == NULL) | |
280 | word_start = word_end; | 273 | word_start = word_end; | |
281 | *word_end++ = ch; | 274 | *word_end++ = ch; | |
282 | } | 275 | } | |
283 | done: | 276 | done: | |
284 | words[words_len] = NULL; | 277 | words[words_len] = NULL; | |
285 | *out_words_len = (int)words_len; | 278 | return (Words){ words, words_len, words_buf }; | |
286 | *out_words_buf = words_buf; | |||
287 | return words; | |||
288 | } | 279 | } | |
289 | 280 | |||
290 | /* | 281 | /* | |
291 | * Str_FindSubstring -- See if a string contains a particular substring. | 282 | * Str_FindSubstring -- See if a string contains a particular substring. | |
292 | * | 283 | * | |
293 | * Input: | 284 | * Input: | |
294 | * string String to search. | 285 | * string String to search. | |
295 | * substring Substring to find in string. | 286 | * substring Substring to find in string. | |
296 | * | 287 | * | |
297 | * Results: If string contains substring, the return value is the location of | 288 | * Results: If string contains substring, the return value is the location of | |
298 | * the first matching instance of substring in string. If string doesn't | 289 | * the first matching instance of substring in string. If string doesn't | |
299 | * contain substring, the return value is NULL. Matching is done on an exact | 290 | * contain substring, the return value is NULL. Matching is done on an exact | |
300 | * character-for-character basis with no wildcards or special characters. | 291 | * character-for-character basis with no wildcards or special characters. |
--- src/usr.bin/make/var.c 2020/08/29 13:38:48 1.478
+++ src/usr.bin/make/var.c 2020/08/30 19:56:02 1.479
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: var.c,v 1.478 2020/08/29 13:38:48 rillig Exp $ */ | 1 | /* $NetBSD: var.c,v 1.479 2020/08/30 19:56:02 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.478 2020/08/29 13:38:48 rillig Exp $"; | 72 | static char rcsid[] = "$NetBSD: var.c,v 1.479 2020/08/30 19:56:02 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.478 2020/08/29 13:38:48 rillig Exp $"); | 79 | __RCSID("$NetBSD: var.c,v 1.479 2020/08/30 19:56:02 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 | * | |
@@ -590,36 +590,32 @@ Var_ExportVars(void) | @@ -590,36 +590,32 @@ Var_ExportVars(void) | |||
590 | setenv(MAKE_LEVEL_ENV, tmp, 1); | 590 | setenv(MAKE_LEVEL_ENV, tmp, 1); | |
591 | 591 | |||
592 | if (var_exportedVars == VAR_EXPORTED_NONE) | 592 | if (var_exportedVars == VAR_EXPORTED_NONE) | |
593 | return; | 593 | return; | |
594 | 594 | |||
595 | if (var_exportedVars == VAR_EXPORTED_ALL) { | 595 | if (var_exportedVars == VAR_EXPORTED_ALL) { | |
596 | /* Ouch! This is crazy... */ | 596 | /* Ouch! This is crazy... */ | |
597 | Hash_ForEach(&VAR_GLOBAL->context, Var_ExportVars_callback, NULL); | 597 | Hash_ForEach(&VAR_GLOBAL->context, Var_ExportVars_callback, NULL); | |
598 | return; | 598 | return; | |
599 | } | 599 | } | |
600 | 600 | |||
601 | val = Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES); | 601 | val = Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES); | |
602 | if (*val) { | 602 | if (*val) { | |
603 | char **av; | 603 | Words words = Str_Words(val, FALSE); | |
604 | char *as; | |||
605 | size_t ac; | |||
606 | size_t i; | 604 | size_t i; | |
607 | 605 | |||
608 | av = brk_string(val, FALSE, &ac, &as); | 606 | for (i = 0; i < words.len; i++) | |
609 | for (i = 0; i < ac; i++) | 607 | Var_Export1(words.words[i], 0); | |
610 | Var_Export1(av[i], 0); | 608 | Words_Free(words); | |
611 | free(as); | |||
612 | free(av); | |||
613 | } | 609 | } | |
614 | free(val); | 610 | free(val); | |
615 | } | 611 | } | |
616 | 612 | |||
617 | /* | 613 | /* | |
618 | * This is called when .export is seen or .MAKE.EXPORTED is modified. | 614 | * This is called when .export is seen or .MAKE.EXPORTED is modified. | |
619 | * | 615 | * | |
620 | * It is also called when any exported variable is modified. | 616 | * It is also called when any exported variable is modified. | |
621 | * XXX: Is it really? | 617 | * XXX: Is it really? | |
622 | * | 618 | * | |
623 | * str has the format "[-env|-literal] varname...". | 619 | * str has the format "[-env|-literal] varname...". | |
624 | */ | 620 | */ | |
625 | void | 621 | void | |
@@ -635,43 +631,40 @@ Var_Export(const char *str, Boolean isEx | @@ -635,43 +631,40 @@ Var_Export(const char *str, Boolean isEx | |||
635 | 631 | |||
636 | flags = 0; | 632 | flags = 0; | |
637 | if (strncmp(str, "-env", 4) == 0) { | 633 | if (strncmp(str, "-env", 4) == 0) { | |
638 | str += 4; | 634 | str += 4; | |
639 | } else if (strncmp(str, "-literal", 8) == 0) { | 635 | } else if (strncmp(str, "-literal", 8) == 0) { | |
640 | str += 8; | 636 | str += 8; | |
641 | flags |= VAR_EXPORT_LITERAL; | 637 | flags |= VAR_EXPORT_LITERAL; | |
642 | } else { | 638 | } else { | |
643 | flags |= VAR_EXPORT_PARENT; | 639 | flags |= VAR_EXPORT_PARENT; | |
644 | } | 640 | } | |
645 | 641 | |||
646 | val = Var_Subst(str, VAR_GLOBAL, VARE_WANTRES); | 642 | val = Var_Subst(str, VAR_GLOBAL, VARE_WANTRES); | |
647 | if (val[0] != '\0') { | 643 | if (val[0] != '\0') { | |
648 | char *as; | 644 | Words words = Str_Words(val, FALSE); | |
649 | size_t ac; | |||
650 | char **av = brk_string(val, FALSE, &ac, &as); | |||
651 | 645 | |||
652 | size_t i; | 646 | size_t i; | |
653 | for (i = 0; i < ac; i++) { | 647 | for (i = 0; i < words.len; i++) { | |
654 | const char *name = av[i]; | 648 | const char *name = words.words[i]; | |
655 | if (Var_Export1(name, flags)) { | 649 | if (Var_Export1(name, flags)) { | |
656 | if (var_exportedVars != VAR_EXPORTED_ALL) | 650 | if (var_exportedVars != VAR_EXPORTED_ALL) | |
657 | var_exportedVars = VAR_EXPORTED_YES; | 651 | var_exportedVars = VAR_EXPORTED_YES; | |
658 | if (isExport && (flags & VAR_EXPORT_PARENT)) { | 652 | if (isExport && (flags & VAR_EXPORT_PARENT)) { | |
659 | Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL); | 653 | Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL); | |
660 | } | 654 | } | |
661 | } | 655 | } | |
662 | } | 656 | } | |
663 | free(as); | 657 | Words_Free(words); | |
664 | free(av); | |||
665 | } | 658 | } | |
666 | free(val); | 659 | free(val); | |
667 | } | 660 | } | |
668 | 661 | |||
669 | 662 | |||
670 | extern char **environ; | 663 | extern char **environ; | |
671 | 664 | |||
672 | /* | 665 | /* | |
673 | * This is called when .unexport[-env] is seen. | 666 | * This is called when .unexport[-env] is seen. | |
674 | * | 667 | * | |
675 | * str must have the form "unexport[-env] varname...". | 668 | * str must have the form "unexport[-env] varname...". | |
676 | */ | 669 | */ | |
677 | void | 670 | void | |
@@ -713,61 +706,58 @@ Var_UnExport(const char *str) | @@ -713,61 +706,58 @@ Var_UnExport(const char *str) | |||
713 | continue; | 706 | continue; | |
714 | if (str[0] != '\0') | 707 | if (str[0] != '\0') | |
715 | varnames = str; | 708 | varnames = str; | |
716 | } | 709 | } | |
717 | 710 | |||
718 | if (varnames == NULL) { | 711 | if (varnames == NULL) { | |
719 | /* Using .MAKE.EXPORTED */ | 712 | /* Using .MAKE.EXPORTED */ | |
720 | varnames = varnames_freeIt = Var_Subst("${" MAKE_EXPORTED ":O:u}", | 713 | varnames = varnames_freeIt = Var_Subst("${" MAKE_EXPORTED ":O:u}", | |
721 | VAR_GLOBAL, VARE_WANTRES); | 714 | VAR_GLOBAL, VARE_WANTRES); | |
722 | } | 715 | } | |
723 | 716 | |||
724 | { | 717 | { | |
725 | Var *v; | 718 | Var *v; | |
726 | char **av; | |||
727 | char *as; | |||
728 | size_t ac; | |||
729 | size_t i; | 719 | size_t i; | |
730 | 720 | |||
731 | av = brk_string(varnames, FALSE, &ac, &as); | 721 | Words words = Str_Words(varnames, FALSE); | |
732 | for (i = 0; i < ac; i++) { | 722 | for (i = 0; i < words.len; i++) { | |
733 | v = VarFind(av[i], VAR_GLOBAL, 0); | 723 | const char *varname = words.words[i]; | |
724 | v = VarFind(varname, VAR_GLOBAL, 0); | |||
734 | if (v == NULL) { | 725 | if (v == NULL) { | |
735 | VAR_DEBUG("Not unexporting \"%s\" (not found)\n", av[i]); | 726 | VAR_DEBUG("Not unexporting \"%s\" (not found)\n", varname); | |
736 | continue; | 727 | continue; | |
737 | } | 728 | } | |
738 | 729 | |||
739 | VAR_DEBUG("Unexporting \"%s\"\n", av[i]); | 730 | VAR_DEBUG("Unexporting \"%s\"\n", varname); | |
740 | if (!unexport_env && (v->flags & VAR_EXPORTED) && | 731 | if (!unexport_env && (v->flags & VAR_EXPORTED) && | |
741 | !(v->flags & VAR_REEXPORT)) | 732 | !(v->flags & VAR_REEXPORT)) | |
742 | unsetenv(v->name); | 733 | unsetenv(v->name); | |
743 | v->flags &= ~(unsigned)(VAR_EXPORTED | VAR_REEXPORT); | 734 | v->flags &= ~(unsigned)(VAR_EXPORTED | VAR_REEXPORT); | |
744 | 735 | |||
745 | /* | 736 | /* | |
746 | * If we are unexporting a list, | 737 | * If we are unexporting a list, | |
747 | * remove each one from .MAKE.EXPORTED. | 738 | * remove each one from .MAKE.EXPORTED. | |
748 | * If we are removing them all, | 739 | * If we are removing them all, | |
749 | * just delete .MAKE.EXPORTED below. | 740 | * just delete .MAKE.EXPORTED below. | |
750 | */ | 741 | */ | |
751 | if (varnames == str) { | 742 | if (varnames == str) { | |
752 | char *expr = str_concat3("${" MAKE_EXPORTED ":N", v->name, "}"); | 743 | char *expr = str_concat3("${" MAKE_EXPORTED ":N", v->name, "}"); | |
753 | char *cp = Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES); | 744 | char *cp = Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES); | |
754 | Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL); | 745 | Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL); | |
755 | free(cp); | 746 | free(cp); | |
756 | free(expr); | 747 | free(expr); | |
757 | } | 748 | } | |
758 | } | 749 | } | |
759 | free(as); | 750 | Words_Free(words); | |
760 | free(av); | |||
761 | if (varnames != str) { | 751 | if (varnames != str) { | |
762 | Var_Delete(MAKE_EXPORTED, VAR_GLOBAL); | 752 | Var_Delete(MAKE_EXPORTED, VAR_GLOBAL); | |
763 | free(varnames_freeIt); | 753 | free(varnames_freeIt); | |
764 | } | 754 | } | |
765 | } | 755 | } | |
766 | } | 756 | } | |
767 | 757 | |||
768 | /* See Var_Set for documentation. */ | 758 | /* See Var_Set for documentation. */ | |
769 | void | 759 | void | |
770 | Var_Set_with_flags(const char *name, const char *val, GNode *ctxt, | 760 | Var_Set_with_flags(const char *name, const char *val, GNode *ctxt, | |
771 | VarSet_Flags flags) | 761 | VarSet_Flags flags) | |
772 | { | 762 | { | |
773 | const char *unexpanded_name = name; | 763 | const char *unexpanded_name = name; | |
@@ -1473,76 +1463,73 @@ ModifyWord_Loop(const char *word, SepBuf | @@ -1473,76 +1463,73 @@ ModifyWord_Loop(const char *word, SepBuf | |||
1473 | free(s); | 1463 | free(s); | |
1474 | } | 1464 | } | |
1475 | 1465 | |||
1476 | 1466 | |||
1477 | /*- | 1467 | /*- | |
1478 | * Implements the :[first..last] modifier. | 1468 | * Implements the :[first..last] modifier. | |
1479 | * This is a special case of ModifyWords since we want to be able | 1469 | * This is a special case of ModifyWords since we want to be able | |
1480 | * to scan the list backwards if first > last. | 1470 | * to scan the list backwards if first > last. | |
1481 | */ | 1471 | */ | |
1482 | static char * | 1472 | static char * | |
1483 | VarSelectWords(char sep, Boolean oneBigWord, const char *str, int first, | 1473 | VarSelectWords(char sep, Boolean oneBigWord, const char *str, int first, | |
1484 | int last) | 1474 | int last) | |
1485 | { | 1475 | { | |
1486 | char **av; /* word list */ | 1476 | Words words; | |
1487 | char *as; /* word list memory */ | |||
1488 | size_t ac; | |||
1489 | int start, end, step; | 1477 | int start, end, step; | |
1490 | int i; | 1478 | int i; | |
1491 | 1479 | |||
1492 | SepBuf buf; | 1480 | SepBuf buf; | |
1493 | SepBuf_Init(&buf, sep); | 1481 | SepBuf_Init(&buf, sep); | |
1494 | 1482 | |||
1495 | if (oneBigWord) { | 1483 | if (oneBigWord) { | |
1496 | /* fake what brk_string() would do if there were only one word */ | 1484 | /* fake what Str_Words() would do if there were only one word */ | |
1497 | ac = 1; | 1485 | words.len = 1; | |
1498 | av = bmake_malloc((ac + 1) * sizeof(char *)); | 1486 | words.words = bmake_malloc((words.len + 1) * sizeof(char *)); | |
1499 | as = bmake_strdup(str); | 1487 | words.freeIt = bmake_strdup(str); | |
1500 | av[0] = as; | 1488 | words.words[0] = words.freeIt; | |
1501 | av[1] = NULL; | 1489 | words.words[1] = NULL; | |
1502 | } else { | 1490 | } else { | |
1503 | av = brk_string(str, FALSE, &ac, &as); | 1491 | words = Str_Words(str, FALSE); | |
1504 | } | 1492 | } | |
1505 | 1493 | |||
1506 | /* | 1494 | /* | |
1507 | * Now sanitize the given range. | 1495 | * Now sanitize the given range. | |
1508 | * If first or last are negative, convert them to the positive equivalents | 1496 | * If first or last are negative, convert them to the positive equivalents | |
1509 | * (-1 gets converted to ac, -2 gets converted to (ac - 1), etc.). | 1497 | * (-1 gets converted to ac, -2 gets converted to (ac - 1), etc.). | |
1510 | */ | 1498 | */ | |
1511 | if (first < 0) | 1499 | if (first < 0) | |
1512 | first += (int)ac + 1; | 1500 | first += (int)words.len + 1; | |
1513 | if (last < 0) | 1501 | if (last < 0) | |
1514 | last += (int)ac + 1; | 1502 | last += (int)words.len + 1; | |
1515 | 1503 | |||
1516 | /* | 1504 | /* | |
1517 | * We avoid scanning more of the list than we need to. | 1505 | * We avoid scanning more of the list than we need to. | |
1518 | */ | 1506 | */ | |
1519 | if (first > last) { | 1507 | if (first > last) { | |
1520 | start = MIN((int)ac, first) - 1; | 1508 | start = MIN((int)words.len, first) - 1; | |
1521 | end = MAX(0, last - 1); | 1509 | end = MAX(0, last - 1); | |
1522 | step = -1; | 1510 | step = -1; | |
1523 | } else { | 1511 | } else { | |
1524 | start = MAX(0, first - 1); | 1512 | start = MAX(0, first - 1); | |
1525 | end = MIN((int)ac, last); | 1513 | end = MIN((int)words.len, last); | |
1526 | step = 1; | 1514 | step = 1; | |
1527 | } | 1515 | } | |
1528 | 1516 | |||
1529 | for (i = start; (step < 0) == (i >= end); i += step) { | 1517 | for (i = start; (step < 0) == (i >= end); i += step) { | |
1530 | SepBuf_AddStr(&buf, av[i]); | 1518 | SepBuf_AddStr(&buf, words.words[i]); | |
1531 | SepBuf_Sep(&buf); | 1519 | SepBuf_Sep(&buf); | |
1532 | } | 1520 | } | |
1533 | 1521 | |||
1534 | free(as); | 1522 | Words_Free(words); | |
1535 | free(av); | |||
1536 | 1523 | |||
1537 | return SepBuf_Destroy(&buf, FALSE); | 1524 | return SepBuf_Destroy(&buf, FALSE); | |
1538 | } | 1525 | } | |
1539 | 1526 | |||
1540 | 1527 | |||
1541 | /* Callback for ModifyWords to implement the :tA modifier. | 1528 | /* Callback for ModifyWords to implement the :tA modifier. | |
1542 | * Replace each word with the result of realpath() if successful. */ | 1529 | * Replace each word with the result of realpath() if successful. */ | |
1543 | static void | 1530 | static void | |
1544 | ModifyWord_Realpath(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) | 1531 | ModifyWord_Realpath(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) | |
1545 | { | 1532 | { | |
1546 | struct stat st; | 1533 | struct stat st; | |
1547 | char rbuf[MAXPATHLEN]; | 1534 | char rbuf[MAXPATHLEN]; | |
1548 | 1535 | |||
@@ -1561,93 +1548,89 @@ ModifyWord_Realpath(const char *word, Se | @@ -1561,93 +1548,89 @@ ModifyWord_Realpath(const char *word, Se | |||
1561 | * str String whose words should be modified | 1548 | * str String whose words should be modified | |
1562 | * modifyWord Function that modifies a single word | 1549 | * modifyWord Function that modifies a single word | |
1563 | * modifyWord_args Custom arguments for modifyWord | 1550 | * modifyWord_args Custom arguments for modifyWord | |
1564 | * | 1551 | * | |
1565 | * Results: | 1552 | * Results: | |
1566 | * A string of all the words modified appropriately. | 1553 | * A string of all the words modified appropriately. | |
1567 | *----------------------------------------------------------------------- | 1554 | *----------------------------------------------------------------------- | |
1568 | */ | 1555 | */ | |
1569 | static char * | 1556 | static char * | |
1570 | ModifyWords(GNode *ctx, char sep, Boolean oneBigWord, const char *str, | 1557 | ModifyWords(GNode *ctx, char sep, Boolean oneBigWord, const char *str, | |
1571 | ModifyWordsCallback modifyWord, void *modifyWord_args) | 1558 | ModifyWordsCallback modifyWord, void *modifyWord_args) | |
1572 | { | 1559 | { | |
1573 | SepBuf result; | 1560 | SepBuf result; | |
1574 | char **av; /* word list */ | 1561 | Words words; | |
1575 | char *as; /* word list memory */ | |||
1576 | size_t ac; | |||
1577 | size_t i; | 1562 | size_t i; | |
1578 | 1563 | |||
1579 | if (oneBigWord) { | 1564 | if (oneBigWord) { | |
1580 | SepBuf_Init(&result, sep); | 1565 | SepBuf_Init(&result, sep); | |
1581 | modifyWord(str, &result, modifyWord_args); | 1566 | modifyWord(str, &result, modifyWord_args); | |
1582 | return SepBuf_Destroy(&result, FALSE); | 1567 | return SepBuf_Destroy(&result, FALSE); | |
1583 | } | 1568 | } | |
1584 | 1569 | |||
1585 | SepBuf_Init(&result, sep); | 1570 | SepBuf_Init(&result, sep); | |
1586 | 1571 | |||
1587 | av = brk_string(str, FALSE, &ac, &as); | 1572 | words = Str_Words(str, FALSE); | |
1588 | 1573 | |||
1589 | VAR_DEBUG("ModifyWords: split \"%s\" into %zu words\n", str, ac); | 1574 | VAR_DEBUG("ModifyWords: split \"%s\" into %zu words\n", str, words.len); | |
1590 | 1575 | |||
1591 | for (i = 0; i < ac; i++) { | 1576 | for (i = 0; i < words.len; i++) { | |
1592 | modifyWord(av[i], &result, modifyWord_args); | 1577 | modifyWord(words.words[i], &result, modifyWord_args); | |
1593 | if (result.buf.count > 0) | 1578 | if (result.buf.count > 0) | |
1594 | SepBuf_Sep(&result); | 1579 | SepBuf_Sep(&result); | |
1595 | } | 1580 | } | |
1596 | 1581 | |||
1597 | free(as); | 1582 | Words_Free(words); | |
1598 | free(av); | |||
1599 | 1583 | |||
1600 | return SepBuf_Destroy(&result, FALSE); | 1584 | return SepBuf_Destroy(&result, FALSE); | |
1601 | } | 1585 | } | |
1602 | 1586 | |||
1603 | 1587 | |||
1604 | static char * | 1588 | static char * | |
1605 | WordList_JoinFree(char **av, size_t ac, char *as) | 1589 | Words_JoinFree(Words words) | |
1606 | { | 1590 | { | |
1607 | Buffer buf; | 1591 | Buffer buf; | |
1608 | size_t i; | 1592 | size_t i; | |
1609 | 1593 | |||
1610 | Buf_Init(&buf, 0); | 1594 | Buf_Init(&buf, 0); | |
1611 | 1595 | |||
1612 | for (i = 0; i < ac; i++) { | 1596 | for (i = 0; i < words.len; i++) { | |
1613 | if (i != 0) | 1597 | if (i != 0) | |
1614 | Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */ | 1598 | Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */ | |
1615 | Buf_AddStr(&buf, av[i]); | 1599 | Buf_AddStr(&buf, words.words[i]); | |
1616 | } | 1600 | } | |
1617 | 1601 | |||
1618 | free(av); | 1602 | Words_Free(words); | |
1619 | free(as); | |||
1620 | 1603 | |||
1621 | return Buf_Destroy(&buf, FALSE); | 1604 | return Buf_Destroy(&buf, FALSE); | |
1622 | } | 1605 | } | |
1623 | 1606 | |||
1624 | /* Remove adjacent duplicate words. */ | 1607 | /* Remove adjacent duplicate words. */ | |
1625 | static char * | 1608 | static char * | |
1626 | VarUniq(const char *str) | 1609 | VarUniq(const char *str) | |
1627 | { | 1610 | { | |
1628 | char *as; /* Word list memory */ | 1611 | Words words = Str_Words(str, FALSE); | |
1629 | size_t ac; | 1612 | size_t ac = words.len; | |
1630 | char **av = brk_string(str, FALSE, &ac, &as); | 1613 | char **av = words.words; | |
1631 | 1614 | |||
1632 | if (ac > 1) { | 1615 | if (ac > 1) { | |
1633 | size_t i, j; | 1616 | size_t i, j; | |
1634 | for (j = 0, i = 1; i < ac; i++) | 1617 | for (j = 0, i = 1; i < ac; i++) | |
1635 | if (strcmp(av[i], av[j]) != 0 && (++j != i)) | 1618 | if (strcmp(av[i], av[j]) != 0 && (++j != i)) | |
1636 | av[j] = av[i]; | 1619 | av[j] = av[i]; | |
1637 | ac = j + 1; | 1620 | ac = j + 1; | |
1638 | } | 1621 | } | |
1639 | 1622 | |||
1640 | return WordList_JoinFree(av, ac, as); | 1623 | return Words_JoinFree(words); | |
1641 | } | 1624 | } | |
1642 | 1625 | |||
1643 | 1626 | |||
1644 | /*- | 1627 | /*- | |
1645 | * Parse a text part of a modifier such as the "from" and "to" in :S/from/to/ | 1628 | * Parse a text part of a modifier such as the "from" and "to" in :S/from/to/ | |
1646 | * or the :@ modifier, until the next unescaped delimiter. The delimiter, as | 1629 | * or the :@ modifier, until the next unescaped delimiter. The delimiter, as | |
1647 | * well as the backslash or the dollar, can be escaped with a backslash. | 1630 | * well as the backslash or the dollar, can be escaped with a backslash. | |
1648 | * | 1631 | * | |
1649 | * Return the parsed (and possibly expanded) string, or NULL if no delimiter | 1632 | * Return the parsed (and possibly expanded) string, or NULL if no delimiter | |
1650 | * was found. On successful return, the parsing position pp points right | 1633 | * was found. On successful return, the parsing position pp points right | |
1651 | * after the delimiter. The delimiter is not included in the returned | 1634 | * after the delimiter. The delimiter is not included in the returned | |
1652 | * value though. | 1635 | * value though. | |
1653 | */ | 1636 | */ | |
@@ -2228,30 +2211,29 @@ ApplyModifier_Range(const char **pp, App | @@ -2228,30 +2211,29 @@ ApplyModifier_Range(const char **pp, App | |||
2228 | if (!ModMatchEq(mod, "range", st->endc)) | 2211 | if (!ModMatchEq(mod, "range", st->endc)) | |
2229 | return AMR_UNKNOWN; | 2212 | return AMR_UNKNOWN; | |
2230 | 2213 | |||
2231 | if (mod[5] == '=') { | 2214 | if (mod[5] == '=') { | |
2232 | char *ep; | 2215 | char *ep; | |
2233 | n = (size_t)strtoul(mod + 6, &ep, 10); | 2216 | n = (size_t)strtoul(mod + 6, &ep, 10); | |
2234 | *pp = ep; | 2217 | *pp = ep; | |
2235 | } else { | 2218 | } else { | |
2236 | n = 0; | 2219 | n = 0; | |
2237 | *pp = mod + 5; | 2220 | *pp = mod + 5; | |
2238 | } | 2221 | } | |
2239 | 2222 | |||
2240 | if (n == 0) { | 2223 | if (n == 0) { | |
2241 | char *as; | 2224 | Words words = Str_Words(st->val, FALSE); | |
2242 | char **av = brk_string(st->val, FALSE, &n, &as); | 2225 | n = words.len; | |
2243 | free(as); | 2226 | Words_Free(words); | |
2244 | free(av); | |||
2245 | } | 2227 | } | |
2246 | 2228 | |||
2247 | Buf_Init(&buf, 0); | 2229 | Buf_Init(&buf, 0); | |
2248 | 2230 | |||
2249 | for (i = 0; i < n; i++) { | 2231 | for (i = 0; i < n; i++) { | |
2250 | if (i != 0) | 2232 | if (i != 0) | |
2251 | Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */ | 2233 | Buf_AddByte(&buf, ' '); /* XXX: st->sep, for consistency */ | |
2252 | Buf_AddInt(&buf, 1 + (int)i); | 2234 | Buf_AddInt(&buf, 1 + (int)i); | |
2253 | } | 2235 | } | |
2254 | 2236 | |||
2255 | st->newVal = Buf_Destroy(&buf, FALSE); | 2237 | st->newVal = Buf_Destroy(&buf, FALSE); | |
2256 | return AMR_OK; | 2238 | return AMR_OK; | |
2257 | } | 2239 | } | |
@@ -2619,35 +2601,31 @@ ApplyModifier_Words(const char **pp, App | @@ -2619,35 +2601,31 @@ ApplyModifier_Words(const char **pp, App | |||
2619 | /* now *pp points just after the closing ']' */ | 2601 | /* now *pp points just after the closing ']' */ | |
2620 | if (**pp != ':' && **pp != st->endc) | 2602 | if (**pp != ':' && **pp != st->endc) | |
2621 | goto bad_modifier; /* Found junk after ']' */ | 2603 | goto bad_modifier; /* Found junk after ']' */ | |
2622 | 2604 | |||
2623 | if (estr[0] == '\0') | 2605 | if (estr[0] == '\0') | |
2624 | goto bad_modifier; /* empty square brackets in ":[]". */ | 2606 | goto bad_modifier; /* empty square brackets in ":[]". */ | |
2625 | 2607 | |||
2626 | if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */ | 2608 | if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */ | |
2627 | if (st->oneBigWord) { | 2609 | if (st->oneBigWord) { | |
2628 | st->newVal = bmake_strdup("1"); | 2610 | st->newVal = bmake_strdup("1"); | |
2629 | } else { | 2611 | } else { | |
2630 | Buffer buf; | 2612 | Buffer buf; | |
2631 | 2613 | |||
2632 | /* XXX: brk_string() is a rather expensive | 2614 | Words words = Str_Words(st->val, FALSE); | |
2633 | * way of counting words. */ | 2615 | size_t ac = words.len; | |
2634 | char *as; | 2616 | Words_Free(words); | |
2635 | size_t ac; | 2617 | ||
2636 | char **av = brk_string(st->val, FALSE, &ac, &as); | 2618 | Buf_Init(&buf, 4); /* 3 digits + '\0' is usually enough */ | |
2637 | free(as); | |||
2638 | free(av); | |||
2639 | ||||
2640 | Buf_Init(&buf, 4); /* 3 digits + '\0' */ | |||
2641 | Buf_AddInt(&buf, (int)ac); | 2619 | Buf_AddInt(&buf, (int)ac); | |
2642 | st->newVal = Buf_Destroy(&buf, FALSE); | 2620 | st->newVal = Buf_Destroy(&buf, FALSE); | |
2643 | } | 2621 | } | |
2644 | goto ok; | 2622 | goto ok; | |
2645 | } | 2623 | } | |
2646 | 2624 | |||
2647 | if (estr[0] == '*' && estr[1] == '\0') { | 2625 | if (estr[0] == '*' && estr[1] == '\0') { | |
2648 | /* Found ":[*]" */ | 2626 | /* Found ":[*]" */ | |
2649 | st->oneBigWord = TRUE; | 2627 | st->oneBigWord = TRUE; | |
2650 | st->newVal = st->val; | 2628 | st->newVal = st->val; | |
2651 | goto ok; | 2629 | goto ok; | |
2652 | } | 2630 | } | |
2653 | 2631 | |||
@@ -2712,65 +2690,62 @@ str_cmp_asc(const void *a, const void *b | @@ -2712,65 +2690,62 @@ str_cmp_asc(const void *a, const void *b | |||
2712 | 2690 | |||
2713 | static int | 2691 | static int | |
2714 | str_cmp_desc(const void *a, const void *b) | 2692 | str_cmp_desc(const void *a, const void *b) | |
2715 | { | 2693 | { | |
2716 | return strcmp(*(const char * const *)b, *(const char * const *)a); | 2694 | return strcmp(*(const char * const *)b, *(const char * const *)a); | |
2717 | } | 2695 | } | |
2718 | 2696 | |||
2719 | /* :O (order ascending) or :Or (order descending) or :Ox (shuffle) */ | 2697 | /* :O (order ascending) or :Or (order descending) or :Ox (shuffle) */ | |
2720 | static ApplyModifierResult | 2698 | static ApplyModifierResult | |
2721 | ApplyModifier_Order(const char **pp, ApplyModifiersState *st) | 2699 | ApplyModifier_Order(const char **pp, ApplyModifiersState *st) | |
2722 | { | 2700 | { | |
2723 | const char *mod = (*pp)++; /* skip past the 'O' in any case */ | 2701 | const char *mod = (*pp)++; /* skip past the 'O' in any case */ | |
2724 | 2702 | |||
2725 | char *as; /* word list memory */ | 2703 | Words words = Str_Words(st->val, FALSE); | |
2726 | size_t ac; | |||
2727 | char **av = brk_string(st->val, FALSE, &ac, &as); | |||
2728 | 2704 | |||
2729 | if (mod[1] == st->endc || mod[1] == ':') { | 2705 | if (mod[1] == st->endc || mod[1] == ':') { | |
2730 | /* :O sorts ascending */ | 2706 | /* :O sorts ascending */ | |
2731 | qsort(av, ac, sizeof(char *), str_cmp_asc); | 2707 | qsort(words.words, words.len, sizeof(char *), str_cmp_asc); | |
2732 | 2708 | |||
2733 | } else if ((mod[1] == 'r' || mod[1] == 'x') && | 2709 | } else if ((mod[1] == 'r' || mod[1] == 'x') && | |
2734 | (mod[2] == st->endc || mod[2] == ':')) { | 2710 | (mod[2] == st->endc || mod[2] == ':')) { | |
2735 | (*pp)++; | 2711 | (*pp)++; | |
2736 | 2712 | |||
2737 | if (mod[1] == 'r') { | 2713 | if (mod[1] == 'r') { | |
2738 | /* :Or sorts descending */ | 2714 | /* :Or sorts descending */ | |
2739 | qsort(av, ac, sizeof(char *), str_cmp_desc); | 2715 | qsort(words.words, words.len, sizeof(char *), str_cmp_desc); | |
2740 | 2716 | |||
2741 | } else { | 2717 | } else { | |
2742 | /* :Ox shuffles | 2718 | /* :Ox shuffles | |
2743 | * | 2719 | * | |
2744 | * We will use [ac..2] range for mod factors. This will produce | 2720 | * We will use [ac..2] range for mod factors. This will produce | |
2745 | * random numbers in [(ac-1)..0] interval, and minimal | 2721 | * random numbers in [(ac-1)..0] interval, and minimal | |
2746 | * reasonable value for mod factor is 2 (the mod 1 will produce | 2722 | * reasonable value for mod factor is 2 (the mod 1 will produce | |
2747 | * 0 with probability 1). | 2723 | * 0 with probability 1). | |
2748 | */ | 2724 | */ | |
2749 | size_t i; | 2725 | size_t i; | |
2750 | for (i = ac - 1; i > 0; i--) { | 2726 | for (i = words.len - 1; i > 0; i--) { | |
2751 | size_t rndidx = (size_t)random() % (i + 1); | 2727 | size_t rndidx = (size_t)random() % (i + 1); | |
2752 | char *t = av[i]; | 2728 | char *t = words.words[i]; | |
2753 | av[i] = av[rndidx]; | 2729 | words.words[i] = words.words[rndidx]; | |
2754 | av[rndidx] = t; | 2730 | words.words[rndidx] = t; | |
2755 | } | 2731 | } | |
2756 | } | 2732 | } | |
2757 | } else { | 2733 | } else { | |
2758 | free(as); | 2734 | Words_Free(words); | |
2759 | free(av); | |||
2760 | return AMR_BAD; | 2735 | return AMR_BAD; | |
2761 | } | 2736 | } | |
2762 | 2737 | |||
2763 | st->newVal = WordList_JoinFree(av, ac, as); | 2738 | st->newVal = Words_JoinFree(words); | |
2764 | return AMR_OK; | 2739 | return AMR_OK; | |
2765 | } | 2740 | } | |
2766 | 2741 | |||
2767 | /* :? then : else */ | 2742 | /* :? then : else */ | |
2768 | static ApplyModifierResult | 2743 | static ApplyModifierResult | |
2769 | ApplyModifier_IfElse(const char **pp, ApplyModifiersState *st) | 2744 | ApplyModifier_IfElse(const char **pp, ApplyModifiersState *st) | |
2770 | { | 2745 | { | |
2771 | char delim; | 2746 | char delim; | |
2772 | char *then_expr, *else_expr; | 2747 | char *then_expr, *else_expr; | |
2773 | 2748 | |||
2774 | Boolean value = FALSE; | 2749 | Boolean value = FALSE; | |
2775 | VarEvalFlags then_eflags = st->eflags & ~(unsigned)VARE_WANTRES; | 2750 | VarEvalFlags then_eflags = st->eflags & ~(unsigned)VARE_WANTRES; | |
2776 | VarEvalFlags else_eflags = st->eflags & ~(unsigned)VARE_WANTRES; | 2751 | VarEvalFlags else_eflags = st->eflags & ~(unsigned)VARE_WANTRES; |