Sun Aug 30 19:56:02 2020 UTC ()
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.


(rillig)
diff -r1.137 -r1.138 src/usr.bin/make/compat.c
diff -r1.66 -r1.67 src/usr.bin/make/for.c
diff -r1.226 -r1.227 src/usr.bin/make/job.c
diff -r1.330 -r1.331 src/usr.bin/make/main.c
diff -r1.101 -r1.102 src/usr.bin/make/nonints.h
diff -r1.63 -r1.64 src/usr.bin/make/str.c
diff -r1.478 -r1.479 src/usr.bin/make/var.c

cvs diff -r1.137 -r1.138 src/usr.bin/make/compat.c (expand / switch to unified diff)

--- 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
73static char rcsid[] = "$NetBSD: compat.c,v 1.137 2020/08/30 14:11:42 rillig Exp $"; 73static 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
78static char sccsid[] = "@(#)compat.c 8.2 (Berkeley) 3/19/94"; 78static 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

cvs diff -r1.66 -r1.67 src/usr.bin/make/for.c (expand / switch to unified diff)

--- 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
33static char rcsid[] = "$NetBSD: for.c,v 1.66 2020/08/29 10:32:00 rillig Exp $"; 33static 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
38static char sccsid[] = "@(#)for.c 8.1 (Berkeley) 6/6/93"; 38static 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 */
128int 128int
129For_Eval(char *line) 129For_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 }

cvs diff -r1.226 -r1.227 src/usr.bin/make/job.c (expand / switch to unified diff)

--- 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
73static char rcsid[] = "$NetBSD: job.c,v 1.226 2020/08/30 13:53:02 rillig Exp $"; 73static 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
78static char sccsid[] = "@(#)job.c 8.2 (Berkeley) 3/19/94"; 78static 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 */
2414Boolean 2414Boolean
2415Job_ParseShell(char *line) 2415Job_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) {

cvs diff -r1.330 -r1.331 src/usr.bin/make/main.c (expand / switch to unified diff)

--- 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
72static char rcsid[] = "$NetBSD: main.c,v 1.330 2020/08/30 11:15:05 rillig Exp $"; 72static 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
82static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 3/19/94"; 82static 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 */
690void 690void
691Main_ParseArgLine(const char *line) 691Main_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
723Boolean 720Boolean
724Main_SetObjdir(const char *fmt, ...) 721Main_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);

cvs diff -r1.101 -r1.102 src/usr.bin/make/Attic/nonints.h (expand / switch to unified diff)

--- 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 */
125void Parse_Error(int, const char *, ...) MAKE_ATTR_PRINTFLIKE(2, 3); 125void Parse_Error(int, const char *, ...) MAKE_ATTR_PRINTFLIKE(2, 3);
126Boolean Parse_IsVar(char *); 126Boolean Parse_IsVar(char *);
127void Parse_DoVar(char *, GNode *); 127void Parse_DoVar(char *, GNode *);
128void Parse_AddIncludeDir(char *); 128void Parse_AddIncludeDir(char *);
129void Parse_File(const char *, int); 129void Parse_File(const char *, int);
130void Parse_Init(void); 130void Parse_Init(void);
131void Parse_End(void); 131void Parse_End(void);
132void Parse_SetInput(const char *, int, int, char *(*)(void *, size_t *), void *); 132void Parse_SetInput(const char *, int, int, char *(*)(void *, size_t *), void *);
133Lst Parse_MainName(void); 133Lst Parse_MainName(void);
134 134
135/* str.c */ 135/* str.c */
 136typedef struct {
 137 char **words;
 138 size_t len;
 139 void *freeIt;
 140} Words;
 141
 142Words Str_Words(const char *, Boolean);
 143static inline void MAKE_ATTR_UNUSED
 144Words_Free(Words w) {
 145 free(w.words);
 146 free(w.freeIt);
 147}
 148
136char *str_concat2(const char *, const char *); 149char *str_concat2(const char *, const char *);
137char *str_concat3(const char *, const char *, const char *); 150char *str_concat3(const char *, const char *, const char *);
138char *str_concat4(const char *, const char *, const char *, const char *); 151char *str_concat4(const char *, const char *, const char *, const char *);
139char **brk_string(const char *, Boolean, size_t *, char **); 
140char *Str_FindSubstring(const char *, const char *); 152char *Str_FindSubstring(const char *, const char *);
141Boolean Str_Match(const char *, const char *); 153Boolean Str_Match(const char *, const char *);
142 154
143/* suff.c */ 155/* suff.c */
144void Suff_ClearSuffixes(void); 156void Suff_ClearSuffixes(void);
145Boolean Suff_IsTransform(char *); 157Boolean Suff_IsTransform(char *);
146GNode *Suff_AddTransform(char *); 158GNode *Suff_AddTransform(char *);
147int Suff_EndTransform(void *, void *); 159int Suff_EndTransform(void *, void *);
148void Suff_AddSuffix(const char *, GNode **); 160void Suff_AddSuffix(const char *, GNode **);
149Lst Suff_GetPath(char *); 161Lst Suff_GetPath(char *);
150void Suff_DoPaths(void); 162void Suff_DoPaths(void);
151void Suff_AddInclude(char *); 163void Suff_AddInclude(char *);
152void Suff_AddLib(const char *); 164void Suff_AddLib(const char *);

cvs diff -r1.63 -r1.64 src/usr.bin/make/str.c (expand / switch to unified diff)

--- 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
72static char rcsid[] = "$NetBSD: str.c,v 1.63 2020/08/29 07:52:55 rillig Exp $"; 72static 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
77static char sccsid[] = "@(#)str.c 5.8 (Berkeley) 6/1/90"; 77static 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. */
87char * 87char *
88str_concat2(const char *s1, const char *s2) 88str_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 */
144char ** 139Words
145brk_string(const char *str, Boolean expand, 140Str_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 }
283done: 276done:
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.

cvs diff -r1.478 -r1.479 src/usr.bin/make/var.c (expand / switch to unified diff)

--- 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
72static char rcsid[] = "$NetBSD: var.c,v 1.478 2020/08/29 13:38:48 rillig Exp $"; 72static 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
77static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94"; 77static 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 */
625void 621void
@@ -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
670extern char **environ; 663extern 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 */
677void 670void
@@ -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. */
769void 759void
770Var_Set_with_flags(const char *name, const char *val, GNode *ctxt, 760Var_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 */
1482static char * 1472static char *
1483VarSelectWords(char sep, Boolean oneBigWord, const char *str, int first, 1473VarSelectWords(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. */
1543static void 1530static void
1544ModifyWord_Realpath(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) 1531ModifyWord_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 */
1569static char * 1556static char *
1570ModifyWords(GNode *ctx, char sep, Boolean oneBigWord, const char *str, 1557ModifyWords(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
1604static char * 1588static char *
1605WordList_JoinFree(char **av, size_t ac, char *as) 1589Words_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. */
1625static char * 1608static char *
1626VarUniq(const char *str) 1609VarUniq(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
2713static int 2691static int
2714str_cmp_desc(const void *a, const void *b) 2692str_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) */
2720static ApplyModifierResult 2698static ApplyModifierResult
2721ApplyModifier_Order(const char **pp, ApplyModifiersState *st) 2699ApplyModifier_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 */
2768static ApplyModifierResult 2743static ApplyModifierResult
2769ApplyModifier_IfElse(const char **pp, ApplyModifiersState *st) 2744ApplyModifier_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;