Fri Oct 30 17:10:48 2020 UTC ()
make(1): clean up comments and local variables in var.c


(rillig)
diff -r1.176 -r1.177 src/usr.bin/make/make.h
diff -r1.604 -r1.605 src/usr.bin/make/var.c

cvs diff -r1.176 -r1.177 src/usr.bin/make/make.h (switch to unified diff)

--- src/usr.bin/make/make.h 2020/10/30 07:19:30 1.176
+++ src/usr.bin/make/make.h 2020/10/30 17:10:48 1.177
@@ -1,711 +1,711 @@ @@ -1,711 +1,711 @@
1/* $NetBSD: make.h,v 1.176 2020/10/30 07:19:30 rillig Exp $ */ 1/* $NetBSD: make.h,v 1.177 2020/10/30 17:10:48 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.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors 18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software 19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission. 20 * without specific prior written permission.
21 * 21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE. 32 * SUCH DAMAGE.
33 * 33 *
34 * from: @(#)make.h 8.3 (Berkeley) 6/13/95 34 * from: @(#)make.h 8.3 (Berkeley) 6/13/95
35 */ 35 */
36 36
37/* 37/*
38 * Copyright (c) 1989 by Berkeley Softworks 38 * Copyright (c) 1989 by Berkeley Softworks
39 * All rights reserved. 39 * All rights reserved.
40 * 40 *
41 * This code is derived from software contributed to Berkeley by 41 * This code is derived from software contributed to Berkeley by
42 * Adam de Boor. 42 * Adam de Boor.
43 * 43 *
44 * Redistribution and use in source and binary forms, with or without 44 * Redistribution and use in source and binary forms, with or without
45 * modification, are permitted provided that the following conditions 45 * modification, are permitted provided that the following conditions
46 * are met: 46 * are met:
47 * 1. Redistributions of source code must retain the above copyright 47 * 1. Redistributions of source code must retain the above copyright
48 * notice, this list of conditions and the following disclaimer. 48 * notice, this list of conditions and the following disclaimer.
49 * 2. Redistributions in binary form must reproduce the above copyright 49 * 2. Redistributions in binary form must reproduce the above copyright
50 * notice, this list of conditions and the following disclaimer in the 50 * notice, this list of conditions and the following disclaimer in the
51 * documentation and/or other materials provided with the distribution. 51 * documentation and/or other materials provided with the distribution.
52 * 3. All advertising materials mentioning features or use of this software 52 * 3. All advertising materials mentioning features or use of this software
53 * must display the following acknowledgement: 53 * must display the following acknowledgement:
54 * This product includes software developed by the University of 54 * This product includes software developed by the University of
55 * California, Berkeley and its contributors. 55 * California, Berkeley and its contributors.
56 * 4. Neither the name of the University nor the names of its contributors 56 * 4. Neither the name of the University nor the names of its contributors
57 * may be used to endorse or promote products derived from this software 57 * may be used to endorse or promote products derived from this software
58 * without specific prior written permission. 58 * without specific prior written permission.
59 * 59 *
60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
63 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 63 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
70 * SUCH DAMAGE. 70 * SUCH DAMAGE.
71 * 71 *
72 * from: @(#)make.h 8.3 (Berkeley) 6/13/95 72 * from: @(#)make.h 8.3 (Berkeley) 6/13/95
73 */ 73 */
74 74
75/*- 75/*-
76 * make.h -- 76 * make.h --
77 * The global definitions for pmake 77 * The global definitions for pmake
78 */ 78 */
79 79
80#ifndef MAKE_MAKE_H 80#ifndef MAKE_MAKE_H
81#define MAKE_MAKE_H 81#define MAKE_MAKE_H
82 82
83#include <sys/types.h> 83#include <sys/types.h>
84#include <sys/param.h> 84#include <sys/param.h>
85#include <sys/stat.h> 85#include <sys/stat.h>
86 86
87#include <assert.h> 87#include <assert.h>
88#include <ctype.h> 88#include <ctype.h>
89#include <fcntl.h> 89#include <fcntl.h>
90#include <stdarg.h> 90#include <stdarg.h>
91#include <stdio.h> 91#include <stdio.h>
92#include <stdlib.h> 92#include <stdlib.h>
93#include <string.h> 93#include <string.h>
94#include <unistd.h> 94#include <unistd.h>
95 95
96#ifdef BSD4_4 96#ifdef BSD4_4
97# include <sys/cdefs.h> 97# include <sys/cdefs.h>
98#endif 98#endif
99 99
100#ifndef FD_CLOEXEC 100#ifndef FD_CLOEXEC
101#define FD_CLOEXEC 1 101#define FD_CLOEXEC 1
102#endif 102#endif
103 103
104#if defined(__GNUC__) 104#if defined(__GNUC__)
105#define MAKE_GNUC_PREREQ(x, y) \ 105#define MAKE_GNUC_PREREQ(x, y) \
106 ((__GNUC__ == (x) && __GNUC_MINOR__ >= (y)) || \ 106 ((__GNUC__ == (x) && __GNUC_MINOR__ >= (y)) || \
107 (__GNUC__ > (x))) 107 (__GNUC__ > (x)))
108#else /* defined(__GNUC__) */ 108#else /* defined(__GNUC__) */
109#define MAKE_GNUC_PREREQ(x, y) 0 109#define MAKE_GNUC_PREREQ(x, y) 0
110#endif /* defined(__GNUC__) */ 110#endif /* defined(__GNUC__) */
111 111
112#if MAKE_GNUC_PREREQ(2, 7) 112#if MAKE_GNUC_PREREQ(2, 7)
113#define MAKE_ATTR_UNUSED __attribute__((__unused__)) 113#define MAKE_ATTR_UNUSED __attribute__((__unused__))
114#else 114#else
115#define MAKE_ATTR_UNUSED /* delete */ 115#define MAKE_ATTR_UNUSED /* delete */
116#endif 116#endif
117 117
118#if MAKE_GNUC_PREREQ(2, 5) 118#if MAKE_GNUC_PREREQ(2, 5)
119#define MAKE_ATTR_DEAD __attribute__((__noreturn__)) 119#define MAKE_ATTR_DEAD __attribute__((__noreturn__))
120#elif defined(__GNUC__) 120#elif defined(__GNUC__)
121#define MAKE_ATTR_DEAD __volatile 121#define MAKE_ATTR_DEAD __volatile
122#else 122#else
123#define MAKE_ATTR_DEAD /* delete */ 123#define MAKE_ATTR_DEAD /* delete */
124#endif 124#endif
125 125
126#if MAKE_GNUC_PREREQ(2, 7) 126#if MAKE_GNUC_PREREQ(2, 7)
127#define MAKE_ATTR_PRINTFLIKE(fmtarg, firstvararg) \ 127#define MAKE_ATTR_PRINTFLIKE(fmtarg, firstvararg) \
128 __attribute__((__format__ (__printf__, fmtarg, firstvararg))) 128 __attribute__((__format__ (__printf__, fmtarg, firstvararg)))
129#else 129#else
130#define MAKE_ATTR_PRINTFLIKE(fmtarg, firstvararg) /* delete */ 130#define MAKE_ATTR_PRINTFLIKE(fmtarg, firstvararg) /* delete */
131#endif 131#endif
132 132
133/* 133/*
134 * A boolean type is defined as an integer, not an enum, for historic reasons. 134 * A boolean type is defined as an integer, not an enum, for historic reasons.
135 * The only allowed values are the constants TRUE and FALSE (1 and 0). 135 * The only allowed values are the constants TRUE and FALSE (1 and 0).
136 */ 136 */
137 137
138#ifdef USE_DOUBLE_BOOLEAN 138#ifdef USE_DOUBLE_BOOLEAN
139/* During development, to find type mismatches in function declarations. */ 139/* During development, to find type mismatches in function declarations. */
140typedef double Boolean; 140typedef double Boolean;
141#define TRUE 1.0 141#define TRUE 1.0
142#define FALSE 0.0 142#define FALSE 0.0
143#elif defined(USE_UCHAR_BOOLEAN) 143#elif defined(USE_UCHAR_BOOLEAN)
144/* During development, to find code that depends on the exact value of TRUE or 144/* During development, to find code that depends on the exact value of TRUE or
145 * that stores other values in Boolean variables. */ 145 * that stores other values in Boolean variables. */
146typedef unsigned char Boolean; 146typedef unsigned char Boolean;
147#define TRUE ((unsigned char)0xFF) 147#define TRUE ((unsigned char)0xFF)
148#define FALSE ((unsigned char)0x00) 148#define FALSE ((unsigned char)0x00)
149#elif defined(USE_CHAR_BOOLEAN) 149#elif defined(USE_CHAR_BOOLEAN)
150/* During development, to find code that uses a boolean as array index, via 150/* During development, to find code that uses a boolean as array index, via
151 * -Wchar-subscripts. */ 151 * -Wchar-subscripts. */
152typedef char Boolean; 152typedef char Boolean;
153#define TRUE ((char)-1) 153#define TRUE ((char)-1)
154#define FALSE ((char)0x00) 154#define FALSE ((char)0x00)
155#elif defined(USE_ENUM_BOOLEAN) 155#elif defined(USE_ENUM_BOOLEAN)
156typedef enum Boolean { FALSE, TRUE } Boolean; 156typedef enum Boolean { FALSE, TRUE } Boolean;
157#else 157#else
158typedef int Boolean; 158typedef int Boolean;
159#ifndef TRUE 159#ifndef TRUE
160#define TRUE 1 160#define TRUE 1
161#endif 161#endif
162#ifndef FALSE 162#ifndef FALSE
163#define FALSE 0 163#define FALSE 0
164#endif 164#endif
165#endif 165#endif
166 166
167#include "lst.h" 167#include "lst.h"
168#include "enum.h" 168#include "enum.h"
169#include "hash.h" 169#include "hash.h"
170#include "config.h" 170#include "config.h"
171#include "buf.h" 171#include "buf.h"
172#include "make_malloc.h" 172#include "make_malloc.h"
173 173
174typedef enum { 174typedef enum {
175 UNMADE, /* Not examined yet */ 175 UNMADE, /* Not examined yet */
176 DEFERRED, /* Examined once (building child) */ 176 DEFERRED, /* Examined once (building child) */
177 REQUESTED, /* on toBeMade list */ 177 REQUESTED, /* on toBeMade list */
178 BEINGMADE, /* Target is already being made. 178 BEINGMADE, /* Target is already being made.
179 * Indicates a cycle in the graph. */ 179 * Indicates a cycle in the graph. */
180 MADE, /* Was out-of-date and has been made */ 180 MADE, /* Was out-of-date and has been made */
181 UPTODATE, /* Was already up-to-date */ 181 UPTODATE, /* Was already up-to-date */
182 ERROR, /* An error occurred while it was being 182 ERROR, /* An error occurred while it was being
183 * made (used only in compat mode) */ 183 * made (used only in compat mode) */
184 ABORTED /* The target was aborted due to an error 184 ABORTED /* The target was aborted due to an error
185 * making an inferior (compat). */ 185 * making an inferior (compat). */
186} GNodeMade; 186} GNodeMade;
187 187
188/* The OP_ constants are used when parsing a dependency line as a way of 188/* The OP_ constants are used when parsing a dependency line as a way of
189 * communicating to other parts of the program the way in which a target 189 * communicating to other parts of the program the way in which a target
190 * should be made. 190 * should be made.
191 * 191 *
192 * Some of the OP_ constants can be combined, others cannot. */ 192 * Some of the OP_ constants can be combined, others cannot. */
193typedef enum GNodeType { 193typedef enum GNodeType {
194 /* The dependency operator ':' is the most common one. The commands of 194 /* The dependency operator ':' is the most common one. The commands of
195 * this node are executed if any child is out-of-date. */ 195 * this node are executed if any child is out-of-date. */
196 OP_DEPENDS = 1 << 0, 196 OP_DEPENDS = 1 << 0,
197 /* The dependency operator '!' always executes its commands, even if 197 /* The dependency operator '!' always executes its commands, even if
198 * its children are up-to-date. */ 198 * its children are up-to-date. */
199 OP_FORCE = 1 << 1, 199 OP_FORCE = 1 << 1,
200 /* The dependency operator '::' behaves like ':', except that it allows 200 /* The dependency operator '::' behaves like ':', except that it allows
201 * multiple dependency groups to be defined. Each of these groups is 201 * multiple dependency groups to be defined. Each of these groups is
202 * executed on its own, independently from the others. */ 202 * executed on its own, independently from the others. */
203 OP_DOUBLEDEP = 1 << 2, 203 OP_DOUBLEDEP = 1 << 2,
204 204
205 /* Matches the dependency operators ':', '!' and '::'. */ 205 /* Matches the dependency operators ':', '!' and '::'. */
206 OP_OPMASK = OP_DEPENDS|OP_FORCE|OP_DOUBLEDEP, 206 OP_OPMASK = OP_DEPENDS|OP_FORCE|OP_DOUBLEDEP,
207 207
208 /* Don't care if the target doesn't exist and can't be created */ 208 /* Don't care if the target doesn't exist and can't be created */
209 OP_OPTIONAL = 1 << 3, 209 OP_OPTIONAL = 1 << 3,
210 /* Use associated commands for parents */ 210 /* Use associated commands for parents */
211 OP_USE = 1 << 4, 211 OP_USE = 1 << 4,
212 /* Target is never out of date, but always execute commands anyway. 212 /* Target is never out of date, but always execute commands anyway.
213 * Its time doesn't matter, so it has none...sort of */ 213 * Its time doesn't matter, so it has none...sort of */
214 OP_EXEC = 1 << 5, 214 OP_EXEC = 1 << 5,
215 /* Ignore non-zero exit status from shell commands when creating the node */ 215 /* Ignore non-zero exit status from shell commands when creating the node */
216 OP_IGNORE = 1 << 6, 216 OP_IGNORE = 1 << 6,
217 /* Don't remove the target when interrupted */ 217 /* Don't remove the target when interrupted */
218 OP_PRECIOUS = 1 << 7, 218 OP_PRECIOUS = 1 << 7,
219 /* Don't echo commands when executed */ 219 /* Don't echo commands when executed */
220 OP_SILENT = 1 << 8, 220 OP_SILENT = 1 << 8,
221 /* Target is a recursive make so its commands should always be executed 221 /* Target is a recursive make so its commands should always be executed
222 * when it is out of date, regardless of the state of the -n or -t flags */ 222 * when it is out of date, regardless of the state of the -n or -t flags */
223 OP_MAKE = 1 << 9, 223 OP_MAKE = 1 << 9,
224 /* Target is out-of-date only if any of its children was out-of-date */ 224 /* Target is out-of-date only if any of its children was out-of-date */
225 OP_JOIN = 1 << 10, 225 OP_JOIN = 1 << 10,
226 /* Assume the children of the node have been already made */ 226 /* Assume the children of the node have been already made */
227 OP_MADE = 1 << 11, 227 OP_MADE = 1 << 11,
228 /* Special .BEGIN, .END, .INTERRUPT */ 228 /* Special .BEGIN, .END, .INTERRUPT */
229 OP_SPECIAL = 1 << 12, 229 OP_SPECIAL = 1 << 12,
230 /* Like .USE, only prepend commands */ 230 /* Like .USE, only prepend commands */
231 OP_USEBEFORE = 1 << 13, 231 OP_USEBEFORE = 1 << 13,
232 /* The node is invisible to its parents. I.e. it doesn't show up in the 232 /* The node is invisible to its parents. I.e. it doesn't show up in the
233 * parents' local variables. */ 233 * parents' local variables. */
234 OP_INVISIBLE = 1 << 14, 234 OP_INVISIBLE = 1 << 14,
235 /* The node is exempt from normal 'main target' processing in parse.c */ 235 /* The node is exempt from normal 'main target' processing in parse.c */
236 OP_NOTMAIN = 1 << 15, 236 OP_NOTMAIN = 1 << 15,
237 /* Not a file target; run always */ 237 /* Not a file target; run always */
238 OP_PHONY = 1 << 16, 238 OP_PHONY = 1 << 16,
239 /* Don't search for file in the path */ 239 /* Don't search for file in the path */
240 OP_NOPATH = 1 << 17, 240 OP_NOPATH = 1 << 17,
241 /* .WAIT phony node */ 241 /* .WAIT phony node */
242 OP_WAIT = 1 << 18, 242 OP_WAIT = 1 << 18,
243 /* .NOMETA do not create a .meta file */ 243 /* .NOMETA do not create a .meta file */
244 OP_NOMETA = 1 << 19, 244 OP_NOMETA = 1 << 19,
245 /* .META we _do_ want a .meta file */ 245 /* .META we _do_ want a .meta file */
246 OP_META = 1 << 20, 246 OP_META = 1 << 20,
247 /* Do not compare commands in .meta file */ 247 /* Do not compare commands in .meta file */
248 OP_NOMETA_CMP = 1 << 21, 248 OP_NOMETA_CMP = 1 << 21,
249 /* Possibly a submake node */ 249 /* Possibly a submake node */
250 OP_SUBMAKE = 1 << 22, 250 OP_SUBMAKE = 1 << 22,
251 251
252 /* Attributes applied by PMake */ 252 /* Attributes applied by PMake */
253 253
254 /* The node is a transformation rule */ 254 /* The node is a transformation rule */
255 OP_TRANSFORM = 1 << 31, 255 OP_TRANSFORM = 1 << 31,
256 /* Target is a member of an archive */ 256 /* Target is a member of an archive */
257 /* XXX: How does this differ from OP_ARCHV? */ 257 /* XXX: How does this differ from OP_ARCHV? */
258 OP_MEMBER = 1 << 30, 258 OP_MEMBER = 1 << 30,
259 /* The node is a library, 259 /* The node is a library,
260 * its name has the form "-l<libname>" */ 260 * its name has the form "-l<libname>" */
261 OP_LIB = 1 << 29, 261 OP_LIB = 1 << 29,
262 /* The node is an archive member, 262 /* The node is an archive member,
263 * its name has the form "archive(member)" */ 263 * its name has the form "archive(member)" */
264 /* XXX: How does this differ from OP_MEMBER? */ 264 /* XXX: How does this differ from OP_MEMBER? */
265 OP_ARCHV = 1 << 28, 265 OP_ARCHV = 1 << 28,
266 /* Target has all the commands it should. Used when parsing to catch 266 /* Target has all the commands it should. Used when parsing to catch
267 * multiple command groups for a target. Only applies to the dependency 267 * multiple command groups for a target. Only applies to the dependency
268 * operators ':' and '!', but not to '::'. */ 268 * operators ':' and '!', but not to '::'. */
269 OP_HAS_COMMANDS = 1 << 27, 269 OP_HAS_COMMANDS = 1 << 27,
270 /* The special command "..." has been seen. All further commands from 270 /* The special command "..." has been seen. All further commands from
271 * this node will be saved on the .END node instead, to be executed at 271 * this node will be saved on the .END node instead, to be executed at
272 * the very end. */ 272 * the very end. */
273 OP_SAVE_CMDS = 1 << 26, 273 OP_SAVE_CMDS = 1 << 26,
274 /* Already processed by Suff_FindDeps */ 274 /* Already processed by Suff_FindDeps */
275 OP_DEPS_FOUND = 1 << 25, 275 OP_DEPS_FOUND = 1 << 25,
276 /* Node found while expanding .ALLSRC */ 276 /* Node found while expanding .ALLSRC */
277 OP_MARK = 1 << 24, 277 OP_MARK = 1 << 24,
278 278
279 OP_NOTARGET = OP_NOTMAIN | OP_USE | OP_EXEC | OP_TRANSFORM 279 OP_NOTARGET = OP_NOTMAIN | OP_USE | OP_EXEC | OP_TRANSFORM
280} GNodeType; 280} GNodeType;
281 281
282typedef enum GNodeFlags { 282typedef enum GNodeFlags {
283 REMAKE = 0x0001, /* this target needs to be (re)made */ 283 REMAKE = 0x0001, /* this target needs to be (re)made */
284 CHILDMADE = 0x0002, /* children of this target were made */ 284 CHILDMADE = 0x0002, /* children of this target were made */
285 FORCE = 0x0004, /* children don't exist, and we pretend made */ 285 FORCE = 0x0004, /* children don't exist, and we pretend made */
286 DONE_WAIT = 0x0008, /* Set by Make_ProcessWait() */ 286 DONE_WAIT = 0x0008, /* Set by Make_ProcessWait() */
287 DONE_ORDER = 0x0010, /* Build requested by .ORDER processing */ 287 DONE_ORDER = 0x0010, /* Build requested by .ORDER processing */
288 FROM_DEPEND = 0x0020, /* Node created from .depend */ 288 FROM_DEPEND = 0x0020, /* Node created from .depend */
289 DONE_ALLSRC = 0x0040, /* We do it once only */ 289 DONE_ALLSRC = 0x0040, /* We do it once only */
290 CYCLE = 0x1000, /* Used by MakePrintStatus */ 290 CYCLE = 0x1000, /* Used by MakePrintStatus */
291 DONECYCLE = 0x2000, /* Used by MakePrintStatus */ 291 DONECYCLE = 0x2000, /* Used by MakePrintStatus */
292 INTERNAL = 0x4000 /* Internal use only */ 292 INTERNAL = 0x4000 /* Internal use only */
293} GNodeFlags; 293} GNodeFlags;
294 294
295typedef struct List StringList; 295typedef struct List StringList;
296typedef struct ListNode StringListNode; 296typedef struct ListNode StringListNode;
297 297
298typedef struct List GNodeList; 298typedef struct List GNodeList;
299typedef struct ListNode GNodeListNode; 299typedef struct ListNode GNodeListNode;
300 300
301typedef struct List /* of CachedDir */ SearchPath; 301typedef struct List /* of CachedDir */ SearchPath;
302 302
303/* A graph node represents a target that can possibly be made, including its 303/* A graph node represents a target that can possibly be made, including its
304 * relation to other targets and a lot of other details. */ 304 * relation to other targets and a lot of other details. */
305typedef struct GNode { 305typedef struct GNode {
306 /* The target's name, such as "clean" or "make.c" */ 306 /* The target's name, such as "clean" or "make.c" */
307 char *name; 307 char *name;
308 /* The unexpanded name of a .USE node */ 308 /* The unexpanded name of a .USE node */
309 char *uname; 309 char *uname;
310 /* The full pathname of the file belonging to the target. 310 /* The full pathname of the file belonging to the target.
311 * XXX: What about .PHONY targets? These don't have an associated path. */ 311 * XXX: What about .PHONY targets? These don't have an associated path. */
312 char *path; 312 char *path;
313 313
314 /* The type of operator used to define the sources (see the OP flags below). 314 /* The type of operator used to define the sources (see the OP flags below).
315 * XXX: This looks like a wild mixture of type and flags. */ 315 * XXX: This looks like a wild mixture of type and flags. */
316 GNodeType type; 316 GNodeType type;
317 GNodeFlags flags; 317 GNodeFlags flags;
318 318
319 /* The state of processing on this node */ 319 /* The state of processing on this node */
320 GNodeMade made; 320 GNodeMade made;
321 int unmade; /* The number of unmade children */ 321 int unmade; /* The number of unmade children */
322 322
323 /* The modification time; 0 means the node does not have a corresponding 323 /* The modification time; 0 means the node does not have a corresponding
324 * file; see Make_OODate. */ 324 * file; see Make_OODate. */
325 time_t mtime; 325 time_t mtime;
326 struct GNode *youngestChild; 326 struct GNode *youngestChild;
327 327
328 /* The GNodes for which this node is an implied source. May be empty. 328 /* The GNodes for which this node is an implied source. May be empty.
329 * For example, when there is an inference rule for .c.o, the node for 329 * For example, when there is an inference rule for .c.o, the node for
330 * file.c has the node for file.o in this list. */ 330 * file.c has the node for file.o in this list. */
331 GNodeList *implicitParents; 331 GNodeList *implicitParents;
332 332
333 /* Other nodes of the same name, for the '::' operator. */ 333 /* Other nodes of the same name, for the '::' operator. */
334 GNodeList *cohorts; 334 GNodeList *cohorts;
335 335
336 /* The nodes that depend on this one, or in other words, the nodes for 336 /* The nodes that depend on this one, or in other words, the nodes for
337 * which this is a source. */ 337 * which this is a source. */
338 GNodeList *parents; 338 GNodeList *parents;
339 /* The nodes on which this one depends. */ 339 /* The nodes on which this one depends. */
340 GNodeList *children; 340 GNodeList *children;
341 341
342 /* .ORDER nodes we need made. The nodes that must be made (if they're 342 /* .ORDER nodes we need made. The nodes that must be made (if they're
343 * made) before this node can be made, but that do not enter into the 343 * made) before this node can be made, but that do not enter into the
344 * datedness of this node. */ 344 * datedness of this node. */
345 GNodeList *order_pred; 345 GNodeList *order_pred;
346 /* .ORDER nodes who need us. The nodes that must be made (if they're made 346 /* .ORDER nodes who need us. The nodes that must be made (if they're made
347 * at all) after this node is made, but that do not depend on this node, 347 * at all) after this node is made, but that do not depend on this node,
348 * in the normal sense. */ 348 * in the normal sense. */
349 GNodeList *order_succ; 349 GNodeList *order_succ;
350 350
351 /* The "#n" suffix for this cohort, or "" for other nodes */ 351 /* The "#n" suffix for this cohort, or "" for other nodes */
352 char cohort_num[8]; 352 char cohort_num[8];
353 /* The number of unmade instances on the cohorts list */ 353 /* The number of unmade instances on the cohorts list */
354 int unmade_cohorts; 354 int unmade_cohorts;
355 /* Pointer to the first instance of a '::' node; only set when on a 355 /* Pointer to the first instance of a '::' node; only set when on a
356 * cohorts list */ 356 * cohorts list */
357 struct GNode *centurion; 357 struct GNode *centurion;
358 358
359 /* Last time (sequence number) we tried to make this node */ 359 /* Last time (sequence number) we tried to make this node */
360 unsigned int checked_seqno; 360 unsigned int checked_seqno;
361 361
362 /* The "local" variables that are specific to this target and this target 362 /* The "local" variables that are specific to this target and this target
363 * only, such as $@, $<, $?. 363 * only, such as $@, $<, $?.
364 * 364 *
365 * Also used for the global variable scopes VAR_GLOBAL, VAR_CMDLINE, 365 * Also used for the global variable scopes VAR_GLOBAL, VAR_CMDLINE,
366 * VAR_INTERNAL, which contain variables with arbitrary names. */ 366 * VAR_INTERNAL, which contain variables with arbitrary names. */
367 HashTable context; 367 HashTable /* of Var pointer */ context;
368 368
369 /* The commands to be given to a shell to create this target. */ 369 /* The commands to be given to a shell to create this target. */
370 StringList *commands; 370 StringList *commands;
371 371
372 /* Suffix for the node (determined by Suff_FindDeps and opaque to everyone 372 /* Suffix for the node (determined by Suff_FindDeps and opaque to everyone
373 * but the Suff module) */ 373 * but the Suff module) */
374 struct Suff *suffix; 374 struct Suff *suffix;
375 375
376 /* filename where the GNode got defined */ 376 /* filename where the GNode got defined */
377 const char *fname; 377 const char *fname;
378 /* line number where the GNode got defined */ 378 /* line number where the GNode got defined */
379 int lineno; 379 int lineno;
380} GNode; 380} GNode;
381 381
382/* 382/*
383 * Error levels for parsing. PARSE_FATAL means the process cannot continue 383 * Error levels for parsing. PARSE_FATAL means the process cannot continue
384 * once the top-level makefile has been parsed. PARSE_WARNING and PARSE_INFO 384 * once the top-level makefile has been parsed. PARSE_WARNING and PARSE_INFO
385 * mean it can. 385 * mean it can.
386 */ 386 */
387typedef enum ParseErrorLevel { 387typedef enum ParseErrorLevel {
388 PARSE_FATAL = 1, 388 PARSE_FATAL = 1,
389 PARSE_WARNING, 389 PARSE_WARNING,
390 PARSE_INFO 390 PARSE_INFO
391} ParseErrorLevel; 391} ParseErrorLevel;
392 392
393/* 393/*
394 * Values returned by Cond_EvalLine and Cond_EvalCondition. 394 * Values returned by Cond_EvalLine and Cond_EvalCondition.
395 */ 395 */
396typedef enum CondEvalResult { 396typedef enum CondEvalResult {
397 COND_PARSE, /* Parse the next lines */ 397 COND_PARSE, /* Parse the next lines */
398 COND_SKIP, /* Skip the next lines */ 398 COND_SKIP, /* Skip the next lines */
399 COND_INVALID /* Not a conditional statement */ 399 COND_INVALID /* Not a conditional statement */
400} CondEvalResult; 400} CondEvalResult;
401 401
402/* 402/*
403 * Definitions for the "local" variables. Used only for clarity. 403 * Definitions for the "local" variables. Used only for clarity.
404 */ 404 */
405#define TARGET "@" /* Target of dependency */ 405#define TARGET "@" /* Target of dependency */
406#define OODATE "?" /* All out-of-date sources */ 406#define OODATE "?" /* All out-of-date sources */
407#define ALLSRC ">" /* All sources */ 407#define ALLSRC ">" /* All sources */
408#define IMPSRC "<" /* Source implied by transformation */ 408#define IMPSRC "<" /* Source implied by transformation */
409#define PREFIX "*" /* Common prefix */ 409#define PREFIX "*" /* Common prefix */
410#define ARCHIVE "!" /* Archive in "archive(member)" syntax */ 410#define ARCHIVE "!" /* Archive in "archive(member)" syntax */
411#define MEMBER "%" /* Member in "archive(member)" syntax */ 411#define MEMBER "%" /* Member in "archive(member)" syntax */
412 412
413#define FTARGET "@F" /* file part of TARGET */ 413#define FTARGET "@F" /* file part of TARGET */
414#define DTARGET "@D" /* directory part of TARGET */ 414#define DTARGET "@D" /* directory part of TARGET */
415#define FIMPSRC "<F" /* file part of IMPSRC */ 415#define FIMPSRC "<F" /* file part of IMPSRC */
416#define DIMPSRC "<D" /* directory part of IMPSRC */ 416#define DIMPSRC "<D" /* directory part of IMPSRC */
417#define FPREFIX "*F" /* file part of PREFIX */ 417#define FPREFIX "*F" /* file part of PREFIX */
418#define DPREFIX "*D" /* directory part of PREFIX */ 418#define DPREFIX "*D" /* directory part of PREFIX */
419 419
420/* 420/*
421 * Global Variables 421 * Global Variables
422 */ 422 */
423extern SearchPath *dirSearchPath; 423extern SearchPath *dirSearchPath;
424 /* The list of directories to search when 424 /* The list of directories to search when
425 * looking for targets */ 425 * looking for targets */
426extern Boolean allPrecious; /* True if every target is precious */ 426extern Boolean allPrecious; /* True if every target is precious */
427extern Boolean deleteOnError; /* True if failed targets should be deleted */ 427extern Boolean deleteOnError; /* True if failed targets should be deleted */
428extern Boolean doing_depend; /* TRUE if processing .depend */ 428extern Boolean doing_depend; /* TRUE if processing .depend */
429 429
430extern GNode *DEFAULT; /* .DEFAULT rule */ 430extern GNode *DEFAULT; /* .DEFAULT rule */
431 431
432extern GNode *VAR_INTERNAL; /* Variables defined internally by make 432extern GNode *VAR_INTERNAL; /* Variables defined internally by make
433 * which should not override those set by 433 * which should not override those set by
434 * makefiles. 434 * makefiles.
435 */ 435 */
436extern GNode *VAR_GLOBAL; /* Variables defined in a global context, e.g 436extern GNode *VAR_GLOBAL; /* Variables defined in a global context, e.g
437 * in the Makefile itself */ 437 * in the Makefile itself */
438extern GNode *VAR_CMDLINE; /* Variables defined on the command line */ 438extern GNode *VAR_CMDLINE; /* Variables defined on the command line */
439extern char var_Error[]; /* Value returned by Var_Parse when an error 439extern char var_Error[]; /* Value returned by Var_Parse when an error
440 * is encountered. It actually points to 440 * is encountered. It actually points to
441 * an empty string, so naive callers needn't 441 * an empty string, so naive callers needn't
442 * worry about it. */ 442 * worry about it. */
443 443
444extern time_t now; /* The time at the start of this whole 444extern time_t now; /* The time at the start of this whole
445 * process */ 445 * process */
446 446
447extern Boolean oldVars; /* Do old-style variable substitution */ 447extern Boolean oldVars; /* Do old-style variable substitution */
448 448
449extern SearchPath *sysIncPath; /* The system include path. */ 449extern SearchPath *sysIncPath; /* The system include path. */
450extern SearchPath *defSysIncPath; /* The default system include path. */ 450extern SearchPath *defSysIncPath; /* The default system include path. */
451 451
452extern char curdir[]; /* Startup directory */ 452extern char curdir[]; /* Startup directory */
453extern char *progname; /* The program name */ 453extern char *progname; /* The program name */
454extern char *makeDependfile; /* .depend */ 454extern char *makeDependfile; /* .depend */
455extern char **savedEnv; /* if we replaced environ this will be non-NULL */ 455extern char **savedEnv; /* if we replaced environ this will be non-NULL */
456 456
457extern int makelevel; 457extern int makelevel;
458 458
459/* 459/*
460 * We cannot vfork() in a child of vfork(). 460 * We cannot vfork() in a child of vfork().
461 * Most systems do not enforce this but some do. 461 * Most systems do not enforce this but some do.
462 */ 462 */
463#define vFork() ((getpid() == myPid) ? vfork() : fork()) 463#define vFork() ((getpid() == myPid) ? vfork() : fork())
464extern pid_t myPid; 464extern pid_t myPid;
465 465
466#define MAKEFLAGS ".MAKEFLAGS" 466#define MAKEFLAGS ".MAKEFLAGS"
467#define MAKEOVERRIDES ".MAKEOVERRIDES" 467#define MAKEOVERRIDES ".MAKEOVERRIDES"
468#define MAKE_JOB_PREFIX ".MAKE.JOB.PREFIX" /* prefix for job target output */ 468#define MAKE_JOB_PREFIX ".MAKE.JOB.PREFIX" /* prefix for job target output */
469#define MAKE_EXPORTED ".MAKE.EXPORTED" /* variables we export */ 469#define MAKE_EXPORTED ".MAKE.EXPORTED" /* variables we export */
470#define MAKE_MAKEFILES ".MAKE.MAKEFILES" /* all makefiles already loaded */ 470#define MAKE_MAKEFILES ".MAKE.MAKEFILES" /* all makefiles already loaded */
471#define MAKE_LEVEL ".MAKE.LEVEL" /* recursion level */ 471#define MAKE_LEVEL ".MAKE.LEVEL" /* recursion level */
472#define MAKEFILE_PREFERENCE ".MAKE.MAKEFILE_PREFERENCE" 472#define MAKEFILE_PREFERENCE ".MAKE.MAKEFILE_PREFERENCE"
473#define MAKE_DEPENDFILE ".MAKE.DEPENDFILE" /* .depend */ 473#define MAKE_DEPENDFILE ".MAKE.DEPENDFILE" /* .depend */
474#define MAKE_MODE ".MAKE.MODE" 474#define MAKE_MODE ".MAKE.MODE"
475#ifndef MAKE_LEVEL_ENV 475#ifndef MAKE_LEVEL_ENV
476# define MAKE_LEVEL_ENV "MAKELEVEL" 476# define MAKE_LEVEL_ENV "MAKELEVEL"
477#endif 477#endif
478 478
479typedef enum DebugFlags { 479typedef enum DebugFlags {
480 DEBUG_ARCH = 1 << 0, 480 DEBUG_ARCH = 1 << 0,
481 DEBUG_COND = 1 << 1, 481 DEBUG_COND = 1 << 1,
482 DEBUG_DIR = 1 << 2, 482 DEBUG_DIR = 1 << 2,
483 DEBUG_GRAPH1 = 1 << 3, 483 DEBUG_GRAPH1 = 1 << 3,
484 DEBUG_GRAPH2 = 1 << 4, 484 DEBUG_GRAPH2 = 1 << 4,
485 DEBUG_JOB = 1 << 5, 485 DEBUG_JOB = 1 << 5,
486 DEBUG_MAKE = 1 << 6, 486 DEBUG_MAKE = 1 << 6,
487 DEBUG_SUFF = 1 << 7, 487 DEBUG_SUFF = 1 << 7,
488 DEBUG_TARG = 1 << 8, 488 DEBUG_TARG = 1 << 8,
489 DEBUG_VAR = 1 << 9, 489 DEBUG_VAR = 1 << 9,
490 DEBUG_FOR = 1 << 10, 490 DEBUG_FOR = 1 << 10,
491 DEBUG_SHELL = 1 << 11, 491 DEBUG_SHELL = 1 << 11,
492 DEBUG_ERROR = 1 << 12, 492 DEBUG_ERROR = 1 << 12,
493 DEBUG_LOUD = 1 << 13, 493 DEBUG_LOUD = 1 << 13,
494 DEBUG_META = 1 << 14, 494 DEBUG_META = 1 << 14,
495 DEBUG_HASH = 1 << 15, 495 DEBUG_HASH = 1 << 15,
496 496
497 DEBUG_GRAPH3 = 1 << 16, 497 DEBUG_GRAPH3 = 1 << 16,
498 DEBUG_SCRIPT = 1 << 17, 498 DEBUG_SCRIPT = 1 << 17,
499 DEBUG_PARSE = 1 << 18, 499 DEBUG_PARSE = 1 << 18,
500 DEBUG_CWD = 1 << 19, 500 DEBUG_CWD = 1 << 19,
501 501
502 DEBUG_LINT = 1 << 20 502 DEBUG_LINT = 1 << 20
503} DebugFlags; 503} DebugFlags;
504 504
505#define CONCAT(a,b) a##b 505#define CONCAT(a,b) a##b
506 506
507#define DEBUG(module) (opts.debug & CONCAT(DEBUG_,module)) 507#define DEBUG(module) (opts.debug & CONCAT(DEBUG_,module))
508 508
509void debug_printf(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2); 509void debug_printf(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2);
510 510
511#define DEBUG0(module, text) \ 511#define DEBUG0(module, text) \
512 if (!DEBUG(module)) (void)0; \ 512 if (!DEBUG(module)) (void)0; \
513 else debug_printf("%s", text) 513 else debug_printf("%s", text)
514 514
515#define DEBUG1(module, fmt, arg1) \ 515#define DEBUG1(module, fmt, arg1) \
516 if (!DEBUG(module)) (void)0; \ 516 if (!DEBUG(module)) (void)0; \
517 else debug_printf(fmt, arg1) 517 else debug_printf(fmt, arg1)
518 518
519#define DEBUG2(module, fmt, arg1, arg2) \ 519#define DEBUG2(module, fmt, arg1, arg2) \
520 if (!DEBUG(module)) (void)0; \ 520 if (!DEBUG(module)) (void)0; \
521 else debug_printf(fmt, arg1, arg2) 521 else debug_printf(fmt, arg1, arg2)
522 522
523#define DEBUG3(module, fmt, arg1, arg2, arg3) \ 523#define DEBUG3(module, fmt, arg1, arg2, arg3) \
524 if (!DEBUG(module)) (void)0; \ 524 if (!DEBUG(module)) (void)0; \
525 else debug_printf(fmt, arg1, arg2, arg3) 525 else debug_printf(fmt, arg1, arg2, arg3)
526 526
527#define DEBUG4(module, fmt, arg1, arg2, arg3, arg4) \ 527#define DEBUG4(module, fmt, arg1, arg2, arg3, arg4) \
528 if (!DEBUG(module)) (void)0; \ 528 if (!DEBUG(module)) (void)0; \
529 else debug_printf(fmt, arg1, arg2, arg3, arg4) 529 else debug_printf(fmt, arg1, arg2, arg3, arg4)
530 530
531#define DEBUG5(module, fmt, arg1, arg2, arg3, arg4, arg5) \ 531#define DEBUG5(module, fmt, arg1, arg2, arg3, arg4, arg5) \
532 if (!DEBUG(module)) (void)0; \ 532 if (!DEBUG(module)) (void)0; \
533 else debug_printf(fmt, arg1, arg2, arg3, arg4, arg5) 533 else debug_printf(fmt, arg1, arg2, arg3, arg4, arg5)
534 534
535typedef enum PrintVarsMode { 535typedef enum PrintVarsMode {
536 COMPAT_VARS = 1, 536 COMPAT_VARS = 1,
537 EXPAND_VARS 537 EXPAND_VARS
538} PrintVarsMode; 538} PrintVarsMode;
539 539
540/* Command line options */ 540/* Command line options */
541typedef struct CmdOpts { 541typedef struct CmdOpts {
542 /* -B: whether we are make compatible */ 542 /* -B: whether we are make compatible */
543 Boolean compatMake; 543 Boolean compatMake;
544 544
545 /* -d: debug control: There is one bit per module. It is up to the 545 /* -d: debug control: There is one bit per module. It is up to the
546 * module what debug information to print. */ 546 * module what debug information to print. */
547 DebugFlags debug; 547 DebugFlags debug;
548 548
549 /* -df: debug output is written here - default stderr */ 549 /* -df: debug output is written here - default stderr */
550 FILE *debug_file; 550 FILE *debug_file;
551 551
552 /* -dV: for the -V option, print unexpanded variable values */ 552 /* -dV: for the -V option, print unexpanded variable values */
553 Boolean debugVflag; 553 Boolean debugVflag;
554 554
555 /* -e: check environment variables before global variables */ 555 /* -e: check environment variables before global variables */
556 Boolean checkEnvFirst; 556 Boolean checkEnvFirst;
557 557
558 /* -f: the makefiles to read */ 558 /* -f: the makefiles to read */
559 StringList *makefiles; 559 StringList *makefiles;
560 560
561 /* -i: if true, ignore all errors from shell commands */ 561 /* -i: if true, ignore all errors from shell commands */
562 Boolean ignoreErrors; 562 Boolean ignoreErrors;
563 563
564 /* -j: the maximum number of jobs that can run in parallel; 564 /* -j: the maximum number of jobs that can run in parallel;
565 * this is coordinated with the submakes */ 565 * this is coordinated with the submakes */
566 int maxJobs; 566 int maxJobs;
567 567
568 /* -k: if true, continue on unaffected portions of the graph when an 568 /* -k: if true, continue on unaffected portions of the graph when an
569 * error occurs in one portion */ 569 * error occurs in one portion */
570 Boolean keepgoing; 570 Boolean keepgoing;
571 571
572 /* -N: execute no commands from the targets */ 572 /* -N: execute no commands from the targets */
573 Boolean noRecursiveExecute; 573 Boolean noRecursiveExecute;
574 574
575 /* -n: execute almost no commands from the targets */ 575 /* -n: execute almost no commands from the targets */
576 Boolean noExecute; 576 Boolean noExecute;
577 577
578 /* -q: if true, we aren't supposed to really make anything, just see if 578 /* -q: if true, we aren't supposed to really make anything, just see if
579 * the targets are out-of-date */ 579 * the targets are out-of-date */
580 Boolean queryFlag; 580 Boolean queryFlag;
581 581
582 /* -r: raw mode, without loading the builtin rules. */ 582 /* -r: raw mode, without loading the builtin rules. */
583 Boolean noBuiltins; 583 Boolean noBuiltins;
584 584
585 /* -s: don't echo the shell commands before executing them */ 585 /* -s: don't echo the shell commands before executing them */
586 Boolean beSilent; 586 Boolean beSilent;
587 587
588 /* -t: touch the targets if they are out-of-date, but don't actually 588 /* -t: touch the targets if they are out-of-date, but don't actually
589 * make them */ 589 * make them */
590 Boolean touchFlag; 590 Boolean touchFlag;
591 591
592 /* -[Vv]: print expanded or unexpanded selected variables */ 592 /* -[Vv]: print expanded or unexpanded selected variables */
593 PrintVarsMode printVars; 593 PrintVarsMode printVars;
594 /* -[Vv]: the variables to print */ 594 /* -[Vv]: the variables to print */
595 StringList *variables; 595 StringList *variables;
596 596
597 /* -W: if true, makefile parsing warnings are treated as errors */ 597 /* -W: if true, makefile parsing warnings are treated as errors */
598 Boolean parseWarnFatal; 598 Boolean parseWarnFatal;
599 599
600 /* -w: print Entering and Leaving for submakes */ 600 /* -w: print Entering and Leaving for submakes */
601 Boolean enterFlag; 601 Boolean enterFlag;
602 602
603 /* -X: if true, do not export variables set on the command line to the 603 /* -X: if true, do not export variables set on the command line to the
604 * environment. */ 604 * environment. */
605 Boolean varNoExportEnv; 605 Boolean varNoExportEnv;
606 606
607 /* The target names specified on the command line. 607 /* The target names specified on the command line.
608 * Used to resolve .if make(...) statements. */ 608 * Used to resolve .if make(...) statements. */
609 StringList *create; 609 StringList *create;
610 610
611} CmdOpts; 611} CmdOpts;
612 612
613extern CmdOpts opts; 613extern CmdOpts opts;
614 614
615#include "nonints.h" 615#include "nonints.h"
616 616
617void Make_TimeStamp(GNode *, GNode *); 617void Make_TimeStamp(GNode *, GNode *);
618Boolean Make_OODate(GNode *); 618Boolean Make_OODate(GNode *);
619void Make_ExpandUse(GNodeList *); 619void Make_ExpandUse(GNodeList *);
620time_t Make_Recheck(GNode *); 620time_t Make_Recheck(GNode *);
621void Make_HandleUse(GNode *, GNode *); 621void Make_HandleUse(GNode *, GNode *);
622void Make_Update(GNode *); 622void Make_Update(GNode *);
623void Make_DoAllVar(GNode *); 623void Make_DoAllVar(GNode *);
624Boolean Make_Run(GNodeList *); 624Boolean Make_Run(GNodeList *);
625int dieQuietly(GNode *, int); 625int dieQuietly(GNode *, int);
626void PrintOnError(GNode *, const char *); 626void PrintOnError(GNode *, const char *);
627void Main_ExportMAKEFLAGS(Boolean); 627void Main_ExportMAKEFLAGS(Boolean);
628Boolean Main_SetObjdir(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2); 628Boolean Main_SetObjdir(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2);
629int mkTempFile(const char *, char **); 629int mkTempFile(const char *, char **);
630int str2Lst_Append(StringList *, char *, const char *); 630int str2Lst_Append(StringList *, char *, const char *);
631void GNode_FprintDetails(FILE *, const char *, const GNode *, const char *); 631void GNode_FprintDetails(FILE *, const char *, const GNode *, const char *);
632Boolean NoExecute(GNode *gn); 632Boolean NoExecute(GNode *gn);
633 633
634/* See if the node was seen on the left-hand side of a dependency operator. */ 634/* See if the node was seen on the left-hand side of a dependency operator. */
635static MAKE_ATTR_UNUSED Boolean 635static MAKE_ATTR_UNUSED Boolean
636GNode_IsTarget(const GNode *gn) 636GNode_IsTarget(const GNode *gn)
637{ 637{
638 return (gn->type & OP_OPMASK) != 0; 638 return (gn->type & OP_OPMASK) != 0;
639} 639}
640 640
641static MAKE_ATTR_UNUSED const char * 641static MAKE_ATTR_UNUSED const char *
642GNode_Path(const GNode *gn) 642GNode_Path(const GNode *gn)
643{ 643{
644 return gn->path != NULL ? gn->path : gn->name; 644 return gn->path != NULL ? gn->path : gn->name;
645} 645}
646 646
647#ifdef __GNUC__ 647#ifdef __GNUC__
648#define UNCONST(ptr) ({ \ 648#define UNCONST(ptr) ({ \
649 union __unconst { \ 649 union __unconst { \
650 const void *__cp; \ 650 const void *__cp; \
651 void *__p; \ 651 void *__p; \
652 } __d; \ 652 } __d; \
653 __d.__cp = ptr, __d.__p; }) 653 __d.__cp = ptr, __d.__p; })
654#else 654#else
655#define UNCONST(ptr) (void *)(ptr) 655#define UNCONST(ptr) (void *)(ptr)
656#endif 656#endif
657 657
658/* At least GNU/Hurd systems lack hardcoded MAXPATHLEN/PATH_MAX */ 658/* At least GNU/Hurd systems lack hardcoded MAXPATHLEN/PATH_MAX */
659#include <limits.h> 659#include <limits.h>
660#ifndef MAXPATHLEN 660#ifndef MAXPATHLEN
661#define MAXPATHLEN 4096 661#define MAXPATHLEN 4096
662#endif 662#endif
663#ifndef PATH_MAX 663#ifndef PATH_MAX
664#define PATH_MAX MAXPATHLEN 664#define PATH_MAX MAXPATHLEN
665#endif 665#endif
666 666
667#if defined(SYSV) 667#if defined(SYSV)
668#define KILLPG(pid, sig) kill(-(pid), (sig)) 668#define KILLPG(pid, sig) kill(-(pid), (sig))
669#else 669#else
670#define KILLPG(pid, sig) killpg((pid), (sig)) 670#define KILLPG(pid, sig) killpg((pid), (sig))
671#endif 671#endif
672 672
673static inline MAKE_ATTR_UNUSED Boolean ch_isalnum(char ch) 673static inline MAKE_ATTR_UNUSED Boolean ch_isalnum(char ch)
674{ return isalnum((unsigned char)ch) != 0; } 674{ return isalnum((unsigned char)ch) != 0; }
675static inline MAKE_ATTR_UNUSED Boolean ch_isalpha(char ch) 675static inline MAKE_ATTR_UNUSED Boolean ch_isalpha(char ch)
676{ return isalpha((unsigned char)ch) != 0; } 676{ return isalpha((unsigned char)ch) != 0; }
677static inline MAKE_ATTR_UNUSED Boolean ch_isdigit(char ch) 677static inline MAKE_ATTR_UNUSED Boolean ch_isdigit(char ch)
678{ return isdigit((unsigned char)ch) != 0; } 678{ return isdigit((unsigned char)ch) != 0; }
679static inline MAKE_ATTR_UNUSED Boolean ch_isspace(char ch) 679static inline MAKE_ATTR_UNUSED Boolean ch_isspace(char ch)
680{ return isspace((unsigned char)ch) != 0; } 680{ return isspace((unsigned char)ch) != 0; }
681static inline MAKE_ATTR_UNUSED Boolean ch_isupper(char ch) 681static inline MAKE_ATTR_UNUSED Boolean ch_isupper(char ch)
682{ return isupper((unsigned char)ch) != 0; } 682{ return isupper((unsigned char)ch) != 0; }
683static inline MAKE_ATTR_UNUSED char ch_tolower(char ch) 683static inline MAKE_ATTR_UNUSED char ch_tolower(char ch)
684{ return (char)tolower((unsigned char)ch); } 684{ return (char)tolower((unsigned char)ch); }
685static inline MAKE_ATTR_UNUSED char ch_toupper(char ch) 685static inline MAKE_ATTR_UNUSED char ch_toupper(char ch)
686{ return (char)toupper((unsigned char)ch); } 686{ return (char)toupper((unsigned char)ch); }
687 687
688static inline MAKE_ATTR_UNUSED void 688static inline MAKE_ATTR_UNUSED void
689cpp_skip_whitespace(const char **pp) 689cpp_skip_whitespace(const char **pp)
690{ 690{
691 while (ch_isspace(**pp)) 691 while (ch_isspace(**pp))
692 (*pp)++; 692 (*pp)++;
693} 693}
694 694
695static inline MAKE_ATTR_UNUSED void 695static inline MAKE_ATTR_UNUSED void
696pp_skip_whitespace(char **pp) 696pp_skip_whitespace(char **pp)
697{ 697{
698 while (ch_isspace(**pp)) 698 while (ch_isspace(**pp))
699 (*pp)++; 699 (*pp)++;
700} 700}
701 701
702#ifdef MAKE_NATIVE 702#ifdef MAKE_NATIVE
703# include <sys/cdefs.h> 703# include <sys/cdefs.h>
704# ifndef lint 704# ifndef lint
705# define MAKE_RCSID(id) __RCSID(id) 705# define MAKE_RCSID(id) __RCSID(id)
706# endif 706# endif
707#else 707#else
708# define MAKE_RCSID(id) static volatile char rcsid[] = id 708# define MAKE_RCSID(id) static volatile char rcsid[] = id
709#endif 709#endif
710 710
711#endif /* MAKE_MAKE_H */ 711#endif /* MAKE_MAKE_H */

cvs diff -r1.604 -r1.605 src/usr.bin/make/var.c (switch to unified diff)

--- src/usr.bin/make/var.c 2020/10/30 16:54:38 1.604
+++ src/usr.bin/make/var.c 2020/10/30 17:10:48 1.605
@@ -1,1582 +1,1574 @@ @@ -1,1582 +1,1574 @@
1/* $NetBSD: var.c,v 1.604 2020/10/30 16:54:38 rillig Exp $ */ 1/* $NetBSD: var.c,v 1.605 2020/10/30 17:10:48 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.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors 18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software 19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission. 20 * without specific prior written permission.
21 * 21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE. 32 * SUCH DAMAGE.
33 */ 33 */
34 34
35/* 35/*
36 * Copyright (c) 1989 by Berkeley Softworks 36 * Copyright (c) 1989 by Berkeley Softworks
37 * All rights reserved. 37 * All rights reserved.
38 * 38 *
39 * This code is derived from software contributed to Berkeley by 39 * This code is derived from software contributed to Berkeley by
40 * Adam de Boor. 40 * Adam de Boor.
41 * 41 *
42 * Redistribution and use in source and binary forms, with or without 42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions 43 * modification, are permitted provided that the following conditions
44 * are met: 44 * are met:
45 * 1. Redistributions of source code must retain the above copyright 45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer. 46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright 47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the 48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution. 49 * documentation and/or other materials provided with the distribution.
50 * 3. All advertising materials mentioning features or use of this software 50 * 3. All advertising materials mentioning features or use of this software
51 * must display the following acknowledgement: 51 * must display the following acknowledgement:
52 * This product includes software developed by the University of 52 * This product includes software developed by the University of
53 * California, Berkeley and its contributors. 53 * California, Berkeley and its contributors.
54 * 4. Neither the name of the University nor the names of its contributors 54 * 4. Neither the name of the University nor the names of its contributors
55 * may be used to endorse or promote products derived from this software 55 * may be used to endorse or promote products derived from this software
56 * without specific prior written permission. 56 * without specific prior written permission.
57 * 57 *
58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
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/* 71/*
72 * Handling of variables and the expressions formed from them. 72 * Handling of variables and the expressions formed from them.
73 * 73 *
74 * Variables are set using lines of the form VAR=value. Both the variable 74 * Variables are set using lines of the form VAR=value. Both the variable
75 * name and the value can contain references to other variables, by using 75 * name and the value can contain references to other variables, by using
76 * expressions like ${VAR}, ${VAR:Modifiers}, ${${VARNAME}} or ${VAR:${MODS}}. 76 * expressions like ${VAR}, ${VAR:Modifiers}, ${${VARNAME}} or ${VAR:${MODS}}.
77 * 77 *
78 * Interface: 78 * Interface:
79 * Var_Init Initialize this module. 79 * Var_Init Initialize this module.
80 * 80 *
81 * Var_End Clean up the module. 81 * Var_End Clean up the module.
82 * 82 *
83 * Var_Set Set the value of the variable, creating it if 83 * Var_Set Set the value of the variable, creating it if
84 * necessary. 84 * necessary.
85 * 85 *
86 * Var_Append Append more characters to the variable, creating it if 86 * Var_Append Append more characters to the variable, creating it if
87 * necessary. A space is placed between the old value and 87 * necessary. A space is placed between the old value and
88 * the new one. 88 * the new one.
89 * 89 *
90 * Var_Exists See if a variable exists. 90 * Var_Exists See if a variable exists.
91 * 91 *
92 * Var_Value Return the unexpanded value of a variable, or NULL if 92 * Var_Value Return the unexpanded value of a variable, or NULL if
93 * the variable is undefined. 93 * the variable is undefined.
94 * 94 *
95 * Var_Subst Substitute all variable expressions in a string. 95 * Var_Subst Substitute all variable expressions in a string.
96 * 96 *
97 * Var_Parse Parse a variable expression such as ${VAR:Mpattern}. 97 * Var_Parse Parse a variable expression such as ${VAR:Mpattern}.
98 * 98 *
99 * Var_Delete Delete a variable. 99 * Var_Delete Delete a variable.
100 * 100 *
101 * Var_ExportVars Export some or even all variables to the environment 101 * Var_ExportVars Export some or even all variables to the environment
102 * of this process and its child processes. 102 * of this process and its child processes.
103 * 103 *
104 * Var_Export Export the variable to the environment of this process 104 * Var_Export Export the variable to the environment of this process
105 * and its child processes. 105 * and its child processes.
106 * 106 *
107 * Var_UnExport Don't export the variable anymore. 107 * Var_UnExport Don't export the variable anymore.
108 * 108 *
109 * Debugging: 109 * Debugging:
110 * Var_Stats Print out hashing statistics if in -dh mode. 110 * Var_Stats Print out hashing statistics if in -dh mode.
111 * 111 *
112 * Var_Dump Print out all variables defined in the given context. 112 * Var_Dump Print out all variables defined in the given context.
113 * 113 *
114 * XXX: There's a lot of duplication in these functions. 114 * XXX: There's a lot of duplication in these functions.
115 */ 115 */
116 116
117#include <sys/stat.h> 117#include <sys/stat.h>
118#ifndef NO_REGEX 118#ifndef NO_REGEX
119#include <sys/types.h> 119#include <sys/types.h>
120#include <regex.h> 120#include <regex.h>
121#endif 121#endif
122#include <inttypes.h> 122#include <inttypes.h>
123#include <limits.h> 123#include <limits.h>
124#include <time.h> 124#include <time.h>
125 125
126#include "make.h" 126#include "make.h"
127#include "dir.h" 127#include "dir.h"
128#include "job.h" 128#include "job.h"
129#include "metachar.h" 129#include "metachar.h"
130 130
131/* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ 131/* "@(#)var.c 8.3 (Berkeley) 3/19/94" */
132MAKE_RCSID("$NetBSD: var.c,v 1.604 2020/10/30 16:54:38 rillig Exp $"); 132MAKE_RCSID("$NetBSD: var.c,v 1.605 2020/10/30 17:10:48 rillig Exp $");
133 133
134#define VAR_DEBUG1(fmt, arg1) DEBUG1(VAR, fmt, arg1) 134#define VAR_DEBUG1(fmt, arg1) DEBUG1(VAR, fmt, arg1)
135#define VAR_DEBUG2(fmt, arg1, arg2) DEBUG2(VAR, fmt, arg1, arg2) 135#define VAR_DEBUG2(fmt, arg1, arg2) DEBUG2(VAR, fmt, arg1, arg2)
136#define VAR_DEBUG3(fmt, arg1, arg2, arg3) DEBUG3(VAR, fmt, arg1, arg2, arg3) 136#define VAR_DEBUG3(fmt, arg1, arg2, arg3) DEBUG3(VAR, fmt, arg1, arg2, arg3)
137#define VAR_DEBUG4(fmt, arg1, arg2, arg3, arg4) DEBUG4(VAR, fmt, arg1, arg2, arg3, arg4) 137#define VAR_DEBUG4(fmt, arg1, arg2, arg3, arg4) DEBUG4(VAR, fmt, arg1, arg2, arg3, arg4)
138 138
139ENUM_FLAGS_RTTI_3(VarEvalFlags, 139ENUM_FLAGS_RTTI_3(VarEvalFlags,
140 VARE_UNDEFERR, VARE_WANTRES, VARE_ASSIGN); 140 VARE_UNDEFERR, VARE_WANTRES, VARE_ASSIGN);
141 141
142/* 142/*
143 * This lets us tell if we have replaced the original environ 143 * This lets us tell if we have replaced the original environ
144 * (which we cannot free). 144 * (which we cannot free).
145 */ 145 */
146char **savedEnv = NULL; 146char **savedEnv = NULL;
147 147
148/* Special return value for Var_Parse, indicating a parse error. It may be 148/* Special return value for Var_Parse, indicating a parse error. It may be
149 * caused by an undefined variable, a syntax error in a modifier or 149 * caused by an undefined variable, a syntax error in a modifier or
150 * something entirely different. */ 150 * something entirely different. */
151char var_Error[] = ""; 151char var_Error[] = "";
152 152
153/* Special return value for Var_Parse, indicating an undefined variable in 153/* Special return value for Var_Parse, indicating an undefined variable in
154 * a case where VARE_UNDEFERR is not set. This undefined variable is 154 * a case where VARE_UNDEFERR is not set. This undefined variable is
155 * typically a dynamic variable such as ${.TARGET}, whose expansion needs to 155 * typically a dynamic variable such as ${.TARGET}, whose expansion needs to
156 * be deferred until it is defined in an actual target. */ 156 * be deferred until it is defined in an actual target. */
157static char varUndefined[] = ""; 157static char varUndefined[] = "";
158 158
159/* Special return value for Var_Parse, just to avoid allocating empty strings. 159/* Special return value for Var_Parse, just to avoid allocating empty strings.
160 * In contrast to var_Error and varUndefined, this is not an error marker but 160 * In contrast to var_Error and varUndefined, this is not an error marker but
161 * just an ordinary successful return value. */ 161 * just an ordinary successful return value. */
162static char emptyString[] = ""; 162static char emptyString[] = "";
163 163
164/* 164/*
165 * Traditionally this make consumed $$ during := like any other expansion. 165 * Traditionally this make consumed $$ during := like any other expansion.
166 * Other make's do not, and this make follows straight since 2016-01-09. 166 * Other make's do not, and this make follows straight since 2016-01-09.
167 * 167 *
168 * This knob allows controlling the behavior. 168 * This knob allows controlling the behavior.
169 * FALSE to consume $$ during := assignment. 169 * FALSE to consume $$ during := assignment.
170 * TRUE to preserve $$ during := assignment. 170 * TRUE to preserve $$ during := assignment.
171 */ 171 */
172#define MAKE_SAVE_DOLLARS ".MAKE.SAVE_DOLLARS" 172#define MAKE_SAVE_DOLLARS ".MAKE.SAVE_DOLLARS"
173static Boolean save_dollars = TRUE; 173static Boolean save_dollars = TRUE;
174 174
175/* 175/*
176 * Internally, variables are contained in four different contexts. 176 * Internally, variables are contained in four different contexts.
177 * 1) the environment. They cannot be changed. If an environment 177 * 1) the environment. They cannot be changed. If an environment
178 * variable is appended to, the result is placed in the global 178 * variable is appended to, the result is placed in the global
179 * context. 179 * context.
180 * 2) the global context. Variables set in the makefiles are located 180 * 2) the global context. Variables set in the makefiles are located
181 * here. 181 * here.
182 * 3) the command-line context. All variables set on the command line 182 * 3) the command-line context. All variables set on the command line
183 * are placed in this context. 183 * are placed in this context.
184 * 4) the local context. Each target has associated with it a context 184 * 4) the local context. Each target has associated with it a context
185 * list. On this list are located the structures describing such 185 * list. On this list are located the structures describing such
186 * local variables as $(@) and $(*) 186 * local variables as $(@) and $(*)
187 * The four contexts are searched in the reverse order from which they are 187 * The four contexts are searched in the reverse order from which they are
188 * listed (but see opts.checkEnvFirst). 188 * listed (but see opts.checkEnvFirst).
189 */ 189 */
190GNode *VAR_INTERNAL; /* variables from make itself */ 190GNode *VAR_INTERNAL; /* variables from make itself */
191GNode *VAR_GLOBAL; /* variables from the makefile */ 191GNode *VAR_GLOBAL; /* variables from the makefile */
192GNode *VAR_CMDLINE; /* variables defined on the command-line */ 192GNode *VAR_CMDLINE; /* variables defined on the command-line */
193 193
194typedef enum VarFlags { 194typedef enum VarFlags {
195 195
196 /* The variable's value is currently being used by Var_Parse or Var_Subst. 196 /* The variable's value is currently being used by Var_Parse or Var_Subst.
197 * This marker is used to avoid endless recursion. */ 197 * This marker is used to avoid endless recursion. */
198 VAR_IN_USE = 0x01, 198 VAR_IN_USE = 0x01,
199 199
200 /* The variable comes from the environment. 200 /* The variable comes from the environment.
201 * These variables are not registered in any GNode, therefore they must 201 * These variables are not registered in any GNode, therefore they must
202 * be freed as soon as they are not used anymore. */ 202 * be freed as soon as they are not used anymore. */
203 VAR_FROM_ENV = 0x02, 203 VAR_FROM_ENV = 0x02,
204 204
205 /* The variable is exported to the environment, to be used by child 205 /* The variable is exported to the environment, to be used by child
206 * processes. */ 206 * processes. */
207 VAR_EXPORTED = 0x10, 207 VAR_EXPORTED = 0x10,
208 208
209 /* At the point where this variable was exported, it contained an 209 /* At the point where this variable was exported, it contained an
210 * unresolved reference to another variable. Before any child process is 210 * unresolved reference to another variable. Before any child process is
211 * started, it needs to be exported again, in the hope that the referenced 211 * started, it needs to be exported again, in the hope that the referenced
212 * variable can then be resolved. */ 212 * variable can then be resolved. */
213 VAR_REEXPORT = 0x20, 213 VAR_REEXPORT = 0x20,
214 214
215 /* The variable came from the command line. */ 215 /* The variable came from the command line. */
216 VAR_FROM_CMD = 0x40, 216 VAR_FROM_CMD = 0x40,
217 217
218 /* The variable value cannot be changed anymore, and the variable cannot 218 /* The variable value cannot be changed anymore, and the variable cannot
219 * be deleted. Any attempts to do so are ignored. */ 219 * be deleted. Any attempts to do so are ignored. */
220 VAR_READONLY = 0x80 220 VAR_READONLY = 0x80
221} VarFlags; 221} VarFlags;
222 222
223ENUM_FLAGS_RTTI_6(VarFlags, 223ENUM_FLAGS_RTTI_6(VarFlags,
224 VAR_IN_USE, VAR_FROM_ENV, 224 VAR_IN_USE, VAR_FROM_ENV,
225 VAR_EXPORTED, VAR_REEXPORT, VAR_FROM_CMD, VAR_READONLY); 225 VAR_EXPORTED, VAR_REEXPORT, VAR_FROM_CMD, VAR_READONLY);
226 226
227/* Variables are defined using one of the VAR=value assignments. Their 227/* Variables are defined using one of the VAR=value assignments. Their
228 * value can be queried by expressions such as $V, ${VAR}, or with modifiers 228 * value can be queried by expressions such as $V, ${VAR}, or with modifiers
229 * such as ${VAR:S,from,to,g:Q}. 229 * such as ${VAR:S,from,to,g:Q}.
230 * 230 *
231 * There are 3 kinds of variables: context variables, environment variables, 231 * There are 3 kinds of variables: context variables, environment variables,
232 * undefined variables. 232 * undefined variables.
233 * 233 *
234 * Context variables are stored in a GNode.context. The only way to undefine 234 * Context variables are stored in a GNode.context. The only way to undefine
235 * a context variable is using the .undef directive. In particular, it must 235 * a context variable is using the .undef directive. In particular, it must
236 * not be possible to undefine a variable during the evaluation of an 236 * not be possible to undefine a variable during the evaluation of an
237 * expression, or Var.name might point nowhere. 237 * expression, or Var.name might point nowhere.
238 * 238 *
239 * Environment variables are temporary. They are returned by VarFind, and 239 * Environment variables are temporary. They are returned by VarFind, and
240 * after using them, they must be freed using VarFreeEnv. 240 * after using them, they must be freed using VarFreeEnv.
241 * 241 *
242 * Undefined variables occur during evaluation of variable expressions such 242 * Undefined variables occur during evaluation of variable expressions such
243 * as ${UNDEF:Ufallback} in Var_Parse and ApplyModifiers. 243 * as ${UNDEF:Ufallback} in Var_Parse and ApplyModifiers.
244 */ 244 */
245typedef struct Var { 245typedef struct Var {
246 /* The name of the variable, once set, doesn't change anymore. 246 /* The name of the variable, once set, doesn't change anymore.
247 * For context variables, it aliases the corresponding HashEntry name. 247 * For context variables, it aliases the corresponding HashEntry name.
248 * For environment and undefined variables, it is allocated. */ 248 * For environment and undefined variables, it is allocated. */
249 const char *name; 249 const char *name;
250 void *name_freeIt; 250 void *name_freeIt;
251 251
252 Buffer val; /* its value */ 252 Buffer val; /* its value */
253 VarFlags flags; /* miscellaneous status flags */ 253 VarFlags flags; /* miscellaneous status flags */
254} Var; 254} Var;
255 255
256/* 256/*
257 * Exporting vars is expensive so skip it if we can 257 * Exporting vars is expensive so skip it if we can
258 */ 258 */
259typedef enum VarExportedMode { 259typedef enum VarExportedMode {
260 VAR_EXPORTED_NONE, 260 VAR_EXPORTED_NONE,
261 VAR_EXPORTED_SOME, 261 VAR_EXPORTED_SOME,
262 VAR_EXPORTED_ALL 262 VAR_EXPORTED_ALL
263} VarExportedMode; 263} VarExportedMode;
264 264
265static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE; 265static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE;
266 266
267typedef enum VarExportFlags { 267typedef enum VarExportFlags {
268 /* 268 /*
269 * We pass this to Var_Export when doing the initial export 269 * We pass this to Var_Export when doing the initial export
270 * or after updating an exported var. 270 * or after updating an exported var.
271 */ 271 */
272 VAR_EXPORT_PARENT = 0x01, 272 VAR_EXPORT_PARENT = 0x01,
273 /* 273 /*
274 * We pass this to Var_Export1 to tell it to leave the value alone. 274 * We pass this to Var_Export1 to tell it to leave the value alone.
275 */ 275 */
276 VAR_EXPORT_LITERAL = 0x02 276 VAR_EXPORT_LITERAL = 0x02
277} VarExportFlags; 277} VarExportFlags;
278 278
279/* Flags for pattern matching in the :S and :C modifiers */ 279/* Flags for pattern matching in the :S and :C modifiers */
280typedef enum VarPatternFlags { 280typedef enum VarPatternFlags {
281 VARP_SUB_GLOBAL = 0x01, /* Replace as often as possible ('g') */ 281 VARP_SUB_GLOBAL = 0x01, /* Replace as often as possible ('g') */
282 VARP_SUB_ONE = 0x02, /* Replace only once ('1') */ 282 VARP_SUB_ONE = 0x02, /* Replace only once ('1') */
283 VARP_ANCHOR_START = 0x04, /* Match at start of word ('^') */ 283 VARP_ANCHOR_START = 0x04, /* Match at start of word ('^') */
284 VARP_ANCHOR_END = 0x08 /* Match at end of word ('$') */ 284 VARP_ANCHOR_END = 0x08 /* Match at end of word ('$') */
285} VarPatternFlags; 285} VarPatternFlags;
286 286
287static Var * 287static Var *
288VarNew(const char *name, void *name_freeIt, const char *value, VarFlags flags) 288VarNew(const char *name, void *name_freeIt, const char *value, VarFlags flags)
289{ 289{
290 size_t value_len = strlen(value); 290 size_t value_len = strlen(value);
291 Var *var = bmake_malloc(sizeof *var); 291 Var *var = bmake_malloc(sizeof *var);
292 var->name = name; 292 var->name = name;
293 var->name_freeIt = name_freeIt; 293 var->name_freeIt = name_freeIt;
294 Buf_Init(&var->val, value_len + 1); 294 Buf_Init(&var->val, value_len + 1);
295 Buf_AddBytes(&var->val, value, value_len); 295 Buf_AddBytes(&var->val, value, value_len);
296 var->flags = flags; 296 var->flags = flags;
297 return var; 297 return var;
298} 298}
299 299
300static const char * 300static const char *
301CanonicalVarname(const char *name) 301CanonicalVarname(const char *name)
302{ 302{
303 if (*name == '.' && ch_isupper(name[1])) { 303 if (*name == '.' && ch_isupper(name[1])) {
304 switch (name[1]) { 304 switch (name[1]) {
305 case 'A': 305 case 'A':
306 if (strcmp(name, ".ALLSRC") == 0) 306 if (strcmp(name, ".ALLSRC") == 0)
307 name = ALLSRC; 307 name = ALLSRC;
308 if (strcmp(name, ".ARCHIVE") == 0) 308 if (strcmp(name, ".ARCHIVE") == 0)
309 name = ARCHIVE; 309 name = ARCHIVE;
310 break; 310 break;
311 case 'I': 311 case 'I':
312 if (strcmp(name, ".IMPSRC") == 0) 312 if (strcmp(name, ".IMPSRC") == 0)
313 name = IMPSRC; 313 name = IMPSRC;
314 break; 314 break;
315 case 'M': 315 case 'M':
316 if (strcmp(name, ".MEMBER") == 0) 316 if (strcmp(name, ".MEMBER") == 0)
317 name = MEMBER; 317 name = MEMBER;
318 break; 318 break;
319 case 'O': 319 case 'O':
320 if (strcmp(name, ".OODATE") == 0) 320 if (strcmp(name, ".OODATE") == 0)
321 name = OODATE; 321 name = OODATE;
322 break; 322 break;
323 case 'P': 323 case 'P':
324 if (strcmp(name, ".PREFIX") == 0) 324 if (strcmp(name, ".PREFIX") == 0)
325 name = PREFIX; 325 name = PREFIX;
326 break; 326 break;
327 case 'S': 327 case 'S':
328 if (strcmp(name, ".SHELL") == 0) { 328 if (strcmp(name, ".SHELL") == 0) {
329 if (!shellPath) 329 if (!shellPath)
330 Shell_Init(); 330 Shell_Init();
331 } 331 }
332 break; 332 break;
333 case 'T': 333 case 'T':
334 if (strcmp(name, ".TARGET") == 0) 334 if (strcmp(name, ".TARGET") == 0)
335 name = TARGET; 335 name = TARGET;
336 break; 336 break;
337 } 337 }
338 } 338 }
339 339
340 /* GNU make has an additional alias $^ == ${.ALLSRC}. */ 340 /* GNU make has an additional alias $^ == ${.ALLSRC}. */
341 341
342 return name; 342 return name;
343} 343}
344 344
345static Var * 345static Var *
346GNode_FindVar(GNode *ctxt, const char *varname, unsigned int hash) 346GNode_FindVar(GNode *ctxt, const char *varname, unsigned int hash)
347{ 347{
348 return HashTable_FindValueHash(&ctxt->context, varname, hash); 348 return HashTable_FindValueHash(&ctxt->context, varname, hash);
349} 349}
350 350
351/*- 351/* Find the variable in the context, and maybe in other contexts as well.
352 *----------------------------------------------------------------------- 
353 * VarFind -- 
354 * Find the given variable in the given context and any other contexts 
355 * indicated. 
356 * 352 *
357 * Input: 353 * Input:
358 * name name to find 354 * name name to find
359 * ctxt context in which to find it 355 * ctxt context in which to look first
360 * elsewhere to look in other contexts as well 356 * elsewhere TRUE to look in other contexts as well
361 * 357 *
362 * Results: 358 * Results:
363 * A pointer to the structure describing the desired variable or 359 * The found variable, or NULL if the variable does not exist.
364 * NULL if the variable does not exist. 360 * If the variable is an environment variable, it must be freed using
365 *----------------------------------------------------------------------- 361 * VarFreeEnv after use.
366 */ 362 */
367static Var * 363static Var *
368VarFind(const char *name, GNode *ctxt, Boolean elsewhere) 364VarFind(const char *name, GNode *ctxt, Boolean elsewhere)
369{ 365{
370 Var *var; 366 Var *var;
371 unsigned int nameHash; 367 unsigned int nameHash;
372 368
373 /* 369 /*
374 * If the variable name begins with a '.', it could very well be one of 370 * If the variable name begins with a '.', it could very well be one of
375 * the local ones. We check the name against all the local variables 371 * the local ones. We check the name against all the local variables
376 * and substitute the short version in for 'name' if it matches one of 372 * and substitute the short version in for 'name' if it matches one of
377 * them. 373 * them.
378 */ 374 */
379 name = CanonicalVarname(name); 375 name = CanonicalVarname(name);
380 nameHash = Hash_Hash(name); 376 nameHash = Hash_Hash(name);
381 377
382 /* 378 /* First look for the variable in the given context. */
383 * First look for the variable in the given context. If it's not there, 
384 * look for it in VAR_CMDLINE, VAR_GLOBAL and the environment, in that order, 
385 * depending on the FIND_* flags in 'flags' 
386 */ 
387 var = GNode_FindVar(ctxt, name, nameHash); 379 var = GNode_FindVar(ctxt, name, nameHash);
388 if (!elsewhere) 380 if (!elsewhere)
389 return var; 381 return var;
390 382
 383 /* The variable was not found in the given context. Now look for it in
 384 * the other contexts as well. */
391 if (var == NULL && ctxt != VAR_CMDLINE) 385 if (var == NULL && ctxt != VAR_CMDLINE)
392 var = GNode_FindVar(VAR_CMDLINE, name, nameHash); 386 var = GNode_FindVar(VAR_CMDLINE, name, nameHash);
393 387
394 if (!opts.checkEnvFirst && var == NULL && ctxt != VAR_GLOBAL) { 388 if (!opts.checkEnvFirst && var == NULL && ctxt != VAR_GLOBAL) {
395 var = GNode_FindVar(VAR_GLOBAL, name, nameHash); 389 var = GNode_FindVar(VAR_GLOBAL, name, nameHash);
396 if (var == NULL && ctxt != VAR_INTERNAL) { 390 if (var == NULL && ctxt != VAR_INTERNAL) {
397 /* VAR_INTERNAL is subordinate to VAR_GLOBAL */ 391 /* VAR_INTERNAL is subordinate to VAR_GLOBAL */
398 var = GNode_FindVar(VAR_INTERNAL, name, nameHash); 392 var = GNode_FindVar(VAR_INTERNAL, name, nameHash);
399 } 393 }
400 } 394 }
401 395
402 if (var == NULL) { 396 if (var == NULL) {
403 char *env; 397 char *env;
404 398
405 if ((env = getenv(name)) != NULL) { 399 if ((env = getenv(name)) != NULL) {
406 char *varname = bmake_strdup(name); 400 char *varname = bmake_strdup(name);
407 return VarNew(varname, varname, env, VAR_FROM_ENV); 401 return VarNew(varname, varname, env, VAR_FROM_ENV);
408 } 402 }
409 403
410 if (opts.checkEnvFirst && ctxt != VAR_GLOBAL) { 404 if (opts.checkEnvFirst && ctxt != VAR_GLOBAL) {
411 var = GNode_FindVar(VAR_GLOBAL, name, nameHash); 405 var = GNode_FindVar(VAR_GLOBAL, name, nameHash);
412 if (var == NULL && ctxt != VAR_INTERNAL) 406 if (var == NULL && ctxt != VAR_INTERNAL)
413 var = GNode_FindVar(VAR_INTERNAL, name, nameHash); 407 var = GNode_FindVar(VAR_INTERNAL, name, nameHash);
414 return var; 408 return var;
415 } 409 }
416 410
417 return NULL; 411 return NULL;
418 } 412 }
419 413
420 return var; 414 return var;
421} 415}
422 416
423/*- 417/* If the variable is an environment variable, free it.
424 *----------------------------------------------------------------------- 
425 * VarFreeEnv -- 
426 * If the variable is an environment variable, free it 
427 * 418 *
428 * Input: 419 * Input:
429 * v the variable 420 * v the variable
430 * destroy true if the value buffer should be destroyed. 421 * freeValue true if the variable value should be freed as well
431 * 422 *
432 * Results: 423 * Results:
433 * TRUE if it is an environment variable, FALSE otherwise. 424 * TRUE if it is an environment variable, FALSE otherwise.
434 *----------------------------------------------------------------------- 
435 */ 425 */
436static Boolean 426static Boolean
437VarFreeEnv(Var *v, Boolean destroy) 427VarFreeEnv(Var *v, Boolean freeValue)
438{ 428{
439 if (!(v->flags & VAR_FROM_ENV)) 429 if (!(v->flags & VAR_FROM_ENV))
440 return FALSE; 430 return FALSE;
 431
441 free(v->name_freeIt); 432 free(v->name_freeIt);
442 Buf_Destroy(&v->val, destroy); 433 Buf_Destroy(&v->val, freeValue);
443 free(v); 434 free(v);
444 return TRUE; 435 return TRUE;
445} 436}
446 437
447/* Add a new variable of the given name and value to the given context. 438/* Add a new variable of the given name and value to the given context.
448 * The name and val arguments are duplicated so they may safely be freed. */ 439 * The name and val arguments are duplicated so they may safely be freed. */
449static void 440static void
450VarAdd(const char *name, const char *val, GNode *ctxt, VarSet_Flags flags) 441VarAdd(const char *name, const char *val, GNode *ctxt, VarSet_Flags flags)
451{ 442{
452 HashEntry *he = HashTable_CreateEntry(&ctxt->context, name, NULL); 443 HashEntry *he = HashTable_CreateEntry(&ctxt->context, name, NULL);
453 Var *v = VarNew(he->key, NULL, val, 444 Var *v = VarNew(he->key /* aliased */, NULL, val,
454 flags & VAR_SET_READONLY ? VAR_READONLY : 0); 445 flags & VAR_SET_READONLY ? VAR_READONLY : 0);
455 HashEntry_Set(he, v); 446 HashEntry_Set(he, v);
456 if (!(ctxt->flags & INTERNAL)) { 447 if (!(ctxt->flags & INTERNAL)) {
457 VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val); 448 VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val);
458 } 449 }
459} 450}
460 451
461/* Remove a variable from a context, freeing the Var structure as well. */ 452/* Remove a variable from a context, freeing all related memory as well. */
462void 453void
463Var_Delete(const char *name, GNode *ctxt) 454Var_Delete(const char *name, GNode *ctxt)
464{ 455{
465 char *name_freeIt = NULL; 456 char *name_freeIt = NULL;
466 HashEntry *he; 457 HashEntry *he;
467 458
468 if (strchr(name, '$') != NULL) { 459 if (strchr(name, '$') != NULL) {
469 (void)Var_Subst(name, VAR_GLOBAL, VARE_WANTRES, &name_freeIt); 460 (void)Var_Subst(name, VAR_GLOBAL, VARE_WANTRES, &name_freeIt);
470 /* TODO: handle errors */ 461 /* TODO: handle errors */
471 name = name_freeIt; 462 name = name_freeIt;
472 } 463 }
473 he = HashTable_FindEntry(&ctxt->context, name); 464 he = HashTable_FindEntry(&ctxt->context, name);
474 VAR_DEBUG3("%s:delete %s%s\n", 465 VAR_DEBUG3("%s:delete %s%s\n",
475 ctxt->name, name, he != NULL ? "" : " (not found)"); 466 ctxt->name, name, he != NULL ? "" : " (not found)");
476 free(name_freeIt); 467 free(name_freeIt);
477 468
478 if (he != NULL) { 469 if (he != NULL) {
479 Var *v = HashEntry_Get(he); 470 Var *v = HashEntry_Get(he);
480 if (v->flags & VAR_EXPORTED) 471 if (v->flags & VAR_EXPORTED)
481 unsetenv(v->name); 472 unsetenv(v->name);
482 if (strcmp(v->name, MAKE_EXPORTED) == 0) 473 if (strcmp(v->name, MAKE_EXPORTED) == 0)
483 var_exportedVars = VAR_EXPORTED_NONE; 474 var_exportedVars = VAR_EXPORTED_NONE;
484 assert(v->name_freeIt == NULL); 475 assert(v->name_freeIt == NULL);
485 HashTable_DeleteEntry(&ctxt->context, he); 476 HashTable_DeleteEntry(&ctxt->context, he);
486 Buf_Destroy(&v->val, TRUE); 477 Buf_Destroy(&v->val, TRUE);
487 free(v); 478 free(v);
488 } 479 }
489} 480}
490 481
491static Boolean 482static Boolean
492MayExport(const char *name) 483MayExport(const char *name)
493{ 484{
494 if (name[0] == '.') 485 if (name[0] == '.')
495 return FALSE; /* skip internals */ 486 return FALSE; /* skip internals */
496 if (name[0] == '-') 487 if (name[0] == '-')
497 return FALSE; /* skip misnamed variables */ 488 return FALSE; /* skip misnamed variables */
498 if (name[1] == '\0') { 489 if (name[1] == '\0') {
499 /* 490 /*
500 * A single char. 491 * A single char.
501 * If it is one of the vars that should only appear in 492 * If it is one of the vars that should only appear in
502 * local context, skip it, else we can get Var_Subst 493 * local context, skip it, else we can get Var_Subst
503 * into a loop. 494 * into a loop.
504 */ 495 */
505 switch (name[0]) { 496 switch (name[0]) {
506 case '@': 497 case '@':
507 case '%': 498 case '%':
508 case '*': 499 case '*':
509 case '!': 500 case '!':
510 return FALSE; 501 return FALSE;
511 } 502 }
512 } 503 }
513 return TRUE; 504 return TRUE;
514} 505}
515 506
516/* 507/*
517 * Export a single variable. 508 * Export a single variable.
518 * We ignore make internal variables (those which start with '.'). 509 * We ignore make internal variables (those which start with '.').
519 * Also we jump through some hoops to avoid calling setenv 510 * Also we jump through some hoops to avoid calling setenv
520 * more than necessary since it can leak. 511 * more than necessary since it can leak.
521 * We only manipulate flags of vars if 'parent' is set. 512 * We only manipulate flags of vars if 'parent' is set.
522 */ 513 */
523static Boolean 514static Boolean
524Var_Export1(const char *name, VarExportFlags flags) 515Var_Export1(const char *name, VarExportFlags flags)
525{ 516{
526 VarExportFlags parent = flags & VAR_EXPORT_PARENT; 517 VarExportFlags parent = flags & VAR_EXPORT_PARENT;
527 Var *v; 518 Var *v;
528 char *val; 519 char *val;
529 520
530 if (!MayExport(name)) 521 if (!MayExport(name))
531 return FALSE; 522 return FALSE;
532 523
533 v = VarFind(name, VAR_GLOBAL, 0); 524 v = VarFind(name, VAR_GLOBAL, 0);
534 if (v == NULL) 525 if (v == NULL)
535 return FALSE; 526 return FALSE;
536 527
537 if (!parent && (v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT)) 528 if (!parent && (v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT))
538 return FALSE; /* nothing to do */ 529 return FALSE; /* nothing to do */
539 530
540 val = Buf_GetAll(&v->val, NULL); 531 val = Buf_GetAll(&v->val, NULL);
541 if (!(flags & VAR_EXPORT_LITERAL) && strchr(val, '$') != NULL) { 532 if (!(flags & VAR_EXPORT_LITERAL) && strchr(val, '$') != NULL) {
542 char *expr; 533 char *expr;
543 534
544 if (parent) { 535 if (parent) {
545 /* 536 /*
546 * Flag this as something we need to re-export. 537 * Flag the variable as something we need to re-export.
547 * No point actually exporting it now though, 538 * No point actually exporting it now though,
548 * the child can do it at the last minute. 539 * the child process can do it at the last minute.
549 */ 540 */
550 v->flags |= VAR_EXPORTED | VAR_REEXPORT; 541 v->flags |= VAR_EXPORTED | VAR_REEXPORT;
551 return TRUE; 542 return TRUE;
552 } 543 }
553 if (v->flags & VAR_IN_USE) { 544 if (v->flags & VAR_IN_USE) {
554 /* 545 /*
555 * We recursed while exporting in a child. 546 * We recursed while exporting in a child.
556 * This isn't going to end well, just skip it. 547 * This isn't going to end well, just skip it.
557 */ 548 */
558 return FALSE; 549 return FALSE;
559 } 550 }
560 551
561 expr = str_concat3("${", name, "}"); 552 expr = str_concat3("${", name, "}");
562 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &val); 553 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &val);
563 /* TODO: handle errors */ 554 /* TODO: handle errors */
564 setenv(name, val, 1); 555 setenv(name, val, 1);
565 free(val); 556 free(val);
566 free(expr); 557 free(expr);
567 } else { 558 } else {
568 if (parent) 559 if (parent)
569 v->flags &= ~(unsigned)VAR_REEXPORT; /* once will do */ 560 v->flags &= ~(unsigned)VAR_REEXPORT; /* once will do */
570 if (parent || !(v->flags & VAR_EXPORTED)) 561 if (parent || !(v->flags & VAR_EXPORTED))
571 setenv(name, val, 1); 562 setenv(name, val, 1);
572 } 563 }
 564
573 /* 565 /*
574 * This is so Var_Set knows to call Var_Export again... 566 * This is so Var_Set knows to call Var_Export again...
575 */ 567 */
576 if (parent) { 568 if (parent) {
577 v->flags |= VAR_EXPORTED; 569 v->flags |= VAR_EXPORTED;
578 } 570 }
579 return TRUE; 571 return TRUE;
580} 572}
581 573
582/* 574/*
583 * This gets called from our children. 575 * This gets called from our child processes.
584 */ 576 */
585void 577void
586Var_ExportVars(void) 578Var_ExportVars(void)
587{ 579{
588 char *val; 580 char *val;
589 581
590 /* 582 /*
591 * Several make's support this sort of mechanism for tracking 583 * Several make's support this sort of mechanism for tracking
592 * recursion - but each uses a different name. 584 * recursion - but each uses a different name.
593 * We allow the makefiles to update MAKELEVEL and ensure 585 * We allow the makefiles to update MAKELEVEL and ensure
594 * children see a correctly incremented value. 586 * children see a correctly incremented value.
595 */ 587 */
596 char tmp[BUFSIZ]; 588 char tmp[BUFSIZ];
597 snprintf(tmp, sizeof(tmp), "%d", makelevel + 1); 589 snprintf(tmp, sizeof(tmp), "%d", makelevel + 1);
598 setenv(MAKE_LEVEL_ENV, tmp, 1); 590 setenv(MAKE_LEVEL_ENV, tmp, 1);
599 591
600 if (var_exportedVars == VAR_EXPORTED_NONE) 592 if (var_exportedVars == VAR_EXPORTED_NONE)
601 return; 593 return;
602 594
603 if (var_exportedVars == VAR_EXPORTED_ALL) { 595 if (var_exportedVars == VAR_EXPORTED_ALL) {
604 HashIter hi; 596 HashIter hi;
605 597
606 /* Ouch! Exporting all variables at once is crazy... */ 598 /* Ouch! Exporting all variables at once is crazy... */
607 HashIter_Init(&hi, &VAR_GLOBAL->context); 599 HashIter_Init(&hi, &VAR_GLOBAL->context);
608 while (HashIter_Next(&hi) != NULL) { 600 while (HashIter_Next(&hi) != NULL) {
609 Var *var = hi.entry->value; 601 Var *var = hi.entry->value;
610 Var_Export1(var->name, 0); 602 Var_Export1(var->name, 0);
611 } 603 }
612 return; 604 return;
613 } 605 }
614 606
615 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES, &val); 607 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES, &val);
616 /* TODO: handle errors */ 608 /* TODO: handle errors */
617 if (*val) { 609 if (*val) {
618 Words words = Str_Words(val, FALSE); 610 Words words = Str_Words(val, FALSE);
619 size_t i; 611 size_t i;
620 612
621 for (i = 0; i < words.len; i++) 613 for (i = 0; i < words.len; i++)
622 Var_Export1(words.words[i], 0); 614 Var_Export1(words.words[i], 0);
623 Words_Free(words); 615 Words_Free(words);
624 } 616 }
625 free(val); 617 free(val);
626} 618}
627 619
628/* 620/*
629 * This is called when .export is seen or .MAKE.EXPORTED is modified. 621 * This is called when .export is seen or .MAKE.EXPORTED is modified.
630 * 622 *
631 * It is also called when any exported variable is modified. 623 * It is also called when any exported variable is modified.
632 * XXX: Is it really? 624 * XXX: Is it really?
633 * 625 *
634 * str has the format "[-env|-literal] varname...". 626 * str has the format "[-env|-literal] varname...".
635 */ 627 */
636void 628void
637Var_Export(const char *str, Boolean isExport) 629Var_Export(const char *str, Boolean isExport)
638{ 630{
639 VarExportFlags flags; 631 VarExportFlags flags;
640 char *val; 632 char *val;
641 633
642 if (isExport && str[0] == '\0') { 634 if (isExport && str[0] == '\0') {
643 var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */ 635 var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */
644 return; 636 return;
645 } 637 }
646 638
647 if (isExport && strncmp(str, "-env", 4) == 0) { 639 if (isExport && strncmp(str, "-env", 4) == 0) {
648 str += 4; 640 str += 4;
649 flags = 0; 641 flags = 0;
650 } else if (isExport && strncmp(str, "-literal", 8) == 0) { 642 } else if (isExport && strncmp(str, "-literal", 8) == 0) {
651 str += 8; 643 str += 8;
652 flags = VAR_EXPORT_LITERAL; 644 flags = VAR_EXPORT_LITERAL;
653 } else { 645 } else {
654 flags = VAR_EXPORT_PARENT; 646 flags = VAR_EXPORT_PARENT;
655 } 647 }
656 648
657 (void)Var_Subst(str, VAR_GLOBAL, VARE_WANTRES, &val); 649 (void)Var_Subst(str, VAR_GLOBAL, VARE_WANTRES, &val);
658 /* TODO: handle errors */ 650 /* TODO: handle errors */
659 if (val[0] != '\0') { 651 if (val[0] != '\0') {
660 Words words = Str_Words(val, FALSE); 652 Words words = Str_Words(val, FALSE);
661 653
662 size_t i; 654 size_t i;
663 for (i = 0; i < words.len; i++) { 655 for (i = 0; i < words.len; i++) {
664 const char *name = words.words[i]; 656 const char *name = words.words[i];
665 if (Var_Export1(name, flags)) { 657 if (Var_Export1(name, flags)) {
666 if (var_exportedVars == VAR_EXPORTED_NONE) 658 if (var_exportedVars == VAR_EXPORTED_NONE)
667 var_exportedVars = VAR_EXPORTED_SOME; 659 var_exportedVars = VAR_EXPORTED_SOME;
668 if (isExport && (flags & VAR_EXPORT_PARENT)) { 660 if (isExport && (flags & VAR_EXPORT_PARENT)) {
669 Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL); 661 Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL);
670 } 662 }
671 } 663 }
672 } 664 }
673 Words_Free(words); 665 Words_Free(words);
674 } 666 }
675 free(val); 667 free(val);
676} 668}
677 669
678 670
679extern char **environ; 671extern char **environ;
680 672
681/* 673/*
682 * This is called when .unexport[-env] is seen. 674 * This is called when .unexport[-env] is seen.
683 * 675 *
684 * str must have the form "unexport[-env] varname...". 676 * str must have the form "unexport[-env] varname...".
685 */ 677 */
686void 678void
687Var_UnExport(const char *str) 679Var_UnExport(const char *str)
688{ 680{
689 const char *varnames; 681 const char *varnames;
690 char *varnames_freeIt; 682 char *varnames_freeIt;
691 Boolean unexport_env; 683 Boolean unexport_env;
692 684
693 varnames = NULL; 685 varnames = NULL;
694 varnames_freeIt = NULL; 686 varnames_freeIt = NULL;
695 687
696 str += strlen("unexport"); 688 str += strlen("unexport");
697 unexport_env = strncmp(str, "-env", 4) == 0; 689 unexport_env = strncmp(str, "-env", 4) == 0;
698 if (unexport_env) { 690 if (unexport_env) {
699 const char *cp; 691 const char *cp;
700 char **newenv; 692 char **newenv;
701 693
702 cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */ 694 cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */
703 if (environ == savedEnv) { 695 if (environ == savedEnv) {
704 /* we have been here before! */ 696 /* we have been here before! */
705 newenv = bmake_realloc(environ, 2 * sizeof(char *)); 697 newenv = bmake_realloc(environ, 2 * sizeof(char *));
706 } else { 698 } else {
707 if (savedEnv) { 699 if (savedEnv) {
708 free(savedEnv); 700 free(savedEnv);
709 savedEnv = NULL; 701 savedEnv = NULL;
710 } 702 }
711 newenv = bmake_malloc(2 * sizeof(char *)); 703 newenv = bmake_malloc(2 * sizeof(char *));
712 } 704 }
713 705
714 /* Note: we cannot safely free() the original environ. */ 706 /* Note: we cannot safely free() the original environ. */
715 environ = savedEnv = newenv; 707 environ = savedEnv = newenv;
716 newenv[0] = NULL; 708 newenv[0] = NULL;
717 newenv[1] = NULL; 709 newenv[1] = NULL;
718 if (cp && *cp) 710 if (cp && *cp)
719 setenv(MAKE_LEVEL_ENV, cp, 1); 711 setenv(MAKE_LEVEL_ENV, cp, 1);
720 } else { 712 } else {
721 cpp_skip_whitespace(&str); 713 cpp_skip_whitespace(&str);
722 if (str[0] != '\0') 714 if (str[0] != '\0')
723 varnames = str; 715 varnames = str;
724 } 716 }
725 717
726 if (varnames == NULL) { 718 if (varnames == NULL) {
727 /* Using .MAKE.EXPORTED */ 719 /* Using .MAKE.EXPORTED */
728 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES, 720 (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", VAR_GLOBAL, VARE_WANTRES,
729 &varnames_freeIt); 721 &varnames_freeIt);
730 /* TODO: handle errors */ 722 /* TODO: handle errors */
731 varnames = varnames_freeIt; 723 varnames = varnames_freeIt;
732 } 724 }
733 725
734 { 726 {
735 Var *v; 727 Var *v;
736 size_t i; 728 size_t i;
737 729
738 Words words = Str_Words(varnames, FALSE); 730 Words words = Str_Words(varnames, FALSE);
739 for (i = 0; i < words.len; i++) { 731 for (i = 0; i < words.len; i++) {
740 const char *varname = words.words[i]; 732 const char *varname = words.words[i];
741 v = VarFind(varname, VAR_GLOBAL, 0); 733 v = VarFind(varname, VAR_GLOBAL, 0);
742 if (v == NULL) { 734 if (v == NULL) {
743 VAR_DEBUG1("Not unexporting \"%s\" (not found)\n", varname); 735 VAR_DEBUG1("Not unexporting \"%s\" (not found)\n", varname);
744 continue; 736 continue;
745 } 737 }
746 738
747 VAR_DEBUG1("Unexporting \"%s\"\n", varname); 739 VAR_DEBUG1("Unexporting \"%s\"\n", varname);
748 if (!unexport_env && (v->flags & VAR_EXPORTED) && 740 if (!unexport_env && (v->flags & VAR_EXPORTED) &&
749 !(v->flags & VAR_REEXPORT)) 741 !(v->flags & VAR_REEXPORT))
750 unsetenv(v->name); 742 unsetenv(v->name);
751 v->flags &= ~(unsigned)(VAR_EXPORTED | VAR_REEXPORT); 743 v->flags &= ~(unsigned)(VAR_EXPORTED | VAR_REEXPORT);
752 744
753 /* 745 /*
754 * If we are unexporting a list, 746 * If we are unexporting a list,
755 * remove each one from .MAKE.EXPORTED. 747 * remove each one from .MAKE.EXPORTED.
756 * If we are removing them all, 748 * If we are removing them all,
757 * just delete .MAKE.EXPORTED below. 749 * just delete .MAKE.EXPORTED below.
758 */ 750 */
759 if (varnames == str) { 751 if (varnames == str) {
760 char *expr = str_concat3("${" MAKE_EXPORTED ":N", v->name, "}"); 752 char *expr = str_concat3("${" MAKE_EXPORTED ":N", v->name, "}");
761 char *cp; 753 char *cp;
762 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &cp); 754 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &cp);
763 /* TODO: handle errors */ 755 /* TODO: handle errors */
764 Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL); 756 Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL);
765 free(cp); 757 free(cp);
766 free(expr); 758 free(expr);
767 } 759 }
768 } 760 }
769 Words_Free(words); 761 Words_Free(words);
770 if (varnames != str) { 762 if (varnames != str) {
771 Var_Delete(MAKE_EXPORTED, VAR_GLOBAL); 763 Var_Delete(MAKE_EXPORTED, VAR_GLOBAL);
772 free(varnames_freeIt); 764 free(varnames_freeIt);
773 } 765 }
774 } 766 }
775} 767}
776 768
777/* See Var_Set for documentation. */ 769/* See Var_Set for documentation. */
778void 770void
779Var_Set_with_flags(const char *name, const char *val, GNode *ctxt, 771Var_Set_with_flags(const char *name, const char *val, GNode *ctxt,
780 VarSet_Flags flags) 772 VarSet_Flags flags)
781{ 773{
782 const char *unexpanded_name = name; 774 const char *unexpanded_name = name;
783 char *name_freeIt = NULL; 775 char *name_freeIt = NULL;
784 Var *v; 776 Var *v;
785 777
786 assert(val != NULL); 778 assert(val != NULL);
787 779
788 if (strchr(name, '$') != NULL) { 780 if (strchr(name, '$') != NULL) {
789 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt); 781 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt);
790 /* TODO: handle errors */ 782 /* TODO: handle errors */
791 name = name_freeIt; 783 name = name_freeIt;
792 } 784 }
793 785
794 if (name[0] == '\0') { 786 if (name[0] == '\0') {
795 VAR_DEBUG2("Var_Set(\"%s\", \"%s\", ...) " 787 VAR_DEBUG2("Var_Set(\"%s\", \"%s\", ...) "
796 "name expands to empty string - ignored\n", 788 "name expands to empty string - ignored\n",
797 unexpanded_name, val); 789 unexpanded_name, val);
798 free(name_freeIt); 790 free(name_freeIt);
799 return; 791 return;
800 } 792 }
801 793
802 if (ctxt == VAR_GLOBAL) { 794 if (ctxt == VAR_GLOBAL) {
803 v = VarFind(name, VAR_CMDLINE, 0); 795 v = VarFind(name, VAR_CMDLINE, 0);
804 if (v != NULL) { 796 if (v != NULL) {
805 if (v->flags & VAR_FROM_CMD) { 797 if (v->flags & VAR_FROM_CMD) {
806 VAR_DEBUG3("%s:%s = %s ignored!\n", ctxt->name, name, val); 798 VAR_DEBUG3("%s:%s = %s ignored!\n", ctxt->name, name, val);
807 goto out; 799 goto out;
808 } 800 }
809 VarFreeEnv(v, TRUE); 801 VarFreeEnv(v, TRUE);
810 } 802 }
811 } 803 }
812 804
813 /* 805 /*
814 * We only look for a variable in the given context since anything set 806 * We only look for a variable in the given context since anything set
815 * here will override anything in a lower context, so there's not much 807 * here will override anything in a lower context, so there's not much
816 * point in searching them all just to save a bit of memory... 808 * point in searching them all just to save a bit of memory...
817 */ 809 */
818 v = VarFind(name, ctxt, 0); 810 v = VarFind(name, ctxt, 0);
819 if (v == NULL) { 811 if (v == NULL) {
820 if (ctxt == VAR_CMDLINE && !(flags & VAR_NO_EXPORT)) { 812 if (ctxt == VAR_CMDLINE && !(flags & VAR_NO_EXPORT)) {
821 /* 813 /*
822 * This var would normally prevent the same name being added 814 * This var would normally prevent the same name being added
823 * to VAR_GLOBAL, so delete it from there if needed. 815 * to VAR_GLOBAL, so delete it from there if needed.
824 * Otherwise -V name may show the wrong value. 816 * Otherwise -V name may show the wrong value.
825 */ 817 */
826 Var_Delete(name, VAR_GLOBAL); 818 Var_Delete(name, VAR_GLOBAL);
827 } 819 }
828 VarAdd(name, val, ctxt, flags); 820 VarAdd(name, val, ctxt, flags);
829 } else { 821 } else {
830 if ((v->flags & VAR_READONLY) && !(flags & VAR_SET_READONLY)) { 822 if ((v->flags & VAR_READONLY) && !(flags & VAR_SET_READONLY)) {
831 VAR_DEBUG3("%s:%s = %s ignored (read-only)\n", 823 VAR_DEBUG3("%s:%s = %s ignored (read-only)\n",
832 ctxt->name, name, val); 824 ctxt->name, name, val);
833 goto out; 825 goto out;
834 } 826 }
835 Buf_Empty(&v->val); 827 Buf_Empty(&v->val);
836 if (val) 828 if (val)
837 Buf_AddStr(&v->val, val); 829 Buf_AddStr(&v->val, val);
838 830
839 VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val); 831 VAR_DEBUG3("%s:%s = %s\n", ctxt->name, name, val);
840 if (v->flags & VAR_EXPORTED) { 832 if (v->flags & VAR_EXPORTED) {
841 Var_Export1(name, VAR_EXPORT_PARENT); 833 Var_Export1(name, VAR_EXPORT_PARENT);
842 } 834 }
843 } 835 }
844 /* 836 /*
845 * Any variables given on the command line are automatically exported 837 * Any variables given on the command line are automatically exported
846 * to the environment (as per POSIX standard) 838 * to the environment (as per POSIX standard)
847 * Other than internals. 839 * Other than internals.
848 */ 840 */
849 if (ctxt == VAR_CMDLINE && !(flags & VAR_NO_EXPORT) && name[0] != '.') { 841 if (ctxt == VAR_CMDLINE && !(flags & VAR_NO_EXPORT) && name[0] != '.') {
850 if (v == NULL) { 842 if (v == NULL) {
851 /* we just added it */ 843 /* we just added it */
852 v = VarFind(name, ctxt, 0); 844 v = VarFind(name, ctxt, 0);
853 } 845 }
854 if (v != NULL) 846 if (v != NULL)
855 v->flags |= VAR_FROM_CMD; 847 v->flags |= VAR_FROM_CMD;
856 /* 848 /*
857 * If requested, don't export these in the environment 849 * If requested, don't export these in the environment
858 * individually. We still put them in MAKEOVERRIDES so 850 * individually. We still put them in MAKEOVERRIDES so
859 * that the command-line settings continue to override 851 * that the command-line settings continue to override
860 * Makefile settings. 852 * Makefile settings.
861 */ 853 */
862 if (!opts.varNoExportEnv) 854 if (!opts.varNoExportEnv)
863 setenv(name, val ? val : "", 1); 855 setenv(name, val ? val : "", 1);
864 856
865 Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL); 857 Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL);
866 } 858 }
867 if (name[0] == '.' && strcmp(name, MAKE_SAVE_DOLLARS) == 0) 859 if (name[0] == '.' && strcmp(name, MAKE_SAVE_DOLLARS) == 0)
868 save_dollars = s2Boolean(val, save_dollars); 860 save_dollars = s2Boolean(val, save_dollars);
869 861
870out: 862out:
871 free(name_freeIt); 863 free(name_freeIt);
872 if (v != NULL) 864 if (v != NULL)
873 VarFreeEnv(v, TRUE); 865 VarFreeEnv(v, TRUE);
874} 866}
875 867
876/*- 868/*-
877 *----------------------------------------------------------------------- 869 *-----------------------------------------------------------------------
878 * Var_Set -- 870 * Var_Set --
879 * Set the variable name to the value val in the given context. 871 * Set the variable name to the value val in the given context.
880 * 872 *
881 * If the variable doesn't yet exist, it is created. 873 * If the variable doesn't yet exist, it is created.
882 * Otherwise the new value overwrites and replaces the old value. 874 * Otherwise the new value overwrites and replaces the old value.
883 * 875 *
884 * Input: 876 * Input:
885 * name name of variable to set 877 * name name of variable to set
886 * val value to give to the variable 878 * val value to give to the variable
887 * ctxt context in which to set it 879 * ctxt context in which to set it
888 * 880 *
889 * Notes: 881 * Notes:
890 * The variable is searched for only in its context before being 882 * The variable is searched for only in its context before being
891 * created in that context. I.e. if the context is VAR_GLOBAL, 883 * created in that context. I.e. if the context is VAR_GLOBAL,
892 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMDLINE, 884 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMDLINE,
893 * only VAR_CMDLINE->context is searched. This is done to avoid the 885 * only VAR_CMDLINE->context is searched. This is done to avoid the
894 * literally thousands of unnecessary strcmp's that used to be done to 886 * literally thousands of unnecessary strcmp's that used to be done to
895 * set, say, $(@) or $(<). 887 * set, say, $(@) or $(<).
896 * If the context is VAR_GLOBAL though, we check if the variable 888 * If the context is VAR_GLOBAL though, we check if the variable
897 * was set in VAR_CMDLINE from the command line and skip it if so. 889 * was set in VAR_CMDLINE from the command line and skip it if so.
898 *----------------------------------------------------------------------- 890 *-----------------------------------------------------------------------
899 */ 891 */
900void 892void
901Var_Set(const char *name, const char *val, GNode *ctxt) 893Var_Set(const char *name, const char *val, GNode *ctxt)
902{ 894{
903 Var_Set_with_flags(name, val, ctxt, 0); 895 Var_Set_with_flags(name, val, ctxt, 0);
904} 896}
905 897
906/*- 898/*-
907 *----------------------------------------------------------------------- 899 *-----------------------------------------------------------------------
908 * Var_Append -- 900 * Var_Append --
909 * The variable of the given name has the given value appended to it in 901 * The variable of the given name has the given value appended to it in
910 * the given context. 902 * the given context.
911 * 903 *
912 * If the variable doesn't exist, it is created. Otherwise the strings 904 * If the variable doesn't exist, it is created. Otherwise the strings
913 * are concatenated, with a space in between. 905 * are concatenated, with a space in between.
914 * 906 *
915 * Input: 907 * Input:
916 * name name of variable to modify 908 * name name of variable to modify
917 * val string to append to it 909 * val string to append to it
918 * ctxt context in which this should occur 910 * ctxt context in which this should occur
919 * 911 *
920 * Notes: 912 * Notes:
921 * Only if the variable is being sought in the global context is the 913 * Only if the variable is being sought in the global context is the
922 * environment searched. 914 * environment searched.
923 * XXX: Knows its calling circumstances in that if called with ctxt 915 * XXX: Knows its calling circumstances in that if called with ctxt
924 * an actual target, it will only search that context since only 916 * an actual target, it will only search that context since only
925 * a local variable could be being appended to. This is actually 917 * a local variable could be being appended to. This is actually
926 * a big win and must be tolerated. 918 * a big win and must be tolerated.
927 *----------------------------------------------------------------------- 919 *-----------------------------------------------------------------------
928 */ 920 */
929void 921void
930Var_Append(const char *name, const char *val, GNode *ctxt) 922Var_Append(const char *name, const char *val, GNode *ctxt)
931{ 923{
932 char *name_freeIt = NULL; 924 char *name_freeIt = NULL;
933 Var *v; 925 Var *v;
934 926
935 assert(val != NULL); 927 assert(val != NULL);
936 928
937 if (strchr(name, '$') != NULL) { 929 if (strchr(name, '$') != NULL) {
938 const char *unexpanded_name = name; 930 const char *unexpanded_name = name;
939 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt); 931 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt);
940 /* TODO: handle errors */ 932 /* TODO: handle errors */
941 name = name_freeIt; 933 name = name_freeIt;
942 if (name[0] == '\0') { 934 if (name[0] == '\0') {
943 VAR_DEBUG2("Var_Append(\"%s\", \"%s\", ...) " 935 VAR_DEBUG2("Var_Append(\"%s\", \"%s\", ...) "
944 "name expands to empty string - ignored\n", 936 "name expands to empty string - ignored\n",
945 unexpanded_name, val); 937 unexpanded_name, val);
946 free(name_freeIt); 938 free(name_freeIt);
947 return; 939 return;
948 } 940 }
949 } 941 }
950 942
951 v = VarFind(name, ctxt, ctxt == VAR_GLOBAL); 943 v = VarFind(name, ctxt, ctxt == VAR_GLOBAL);
952 944
953 if (v == NULL) { 945 if (v == NULL) {
954 Var_Set(name, val, ctxt); 946 Var_Set(name, val, ctxt);
955 } else if (v->flags & VAR_READONLY) { 947 } else if (v->flags & VAR_READONLY) {
956 VAR_DEBUG1("Ignoring append to %s since it is read-only\n", name); 948 VAR_DEBUG1("Ignoring append to %s since it is read-only\n", name);
957 } else if (ctxt == VAR_CMDLINE || !(v->flags & VAR_FROM_CMD)) { 949 } else if (ctxt == VAR_CMDLINE || !(v->flags & VAR_FROM_CMD)) {
958 Buf_AddByte(&v->val, ' '); 950 Buf_AddByte(&v->val, ' ');
959 Buf_AddStr(&v->val, val); 951 Buf_AddStr(&v->val, val);
960 952
961 VAR_DEBUG3("%s:%s = %s\n", 953 VAR_DEBUG3("%s:%s = %s\n",
962 ctxt->name, name, Buf_GetAll(&v->val, NULL)); 954 ctxt->name, name, Buf_GetAll(&v->val, NULL));
963 955
964 if (v->flags & VAR_FROM_ENV) { 956 if (v->flags & VAR_FROM_ENV) {
965 HashEntry *h; 957 HashEntry *h;
966 958
967 /* 959 /*
968 * If the original variable came from the environment, we 960 * If the original variable came from the environment, we
969 * have to install it in the global context (we could place 961 * have to install it in the global context (we could place
970 * it in the environment, but then we should provide a way to 962 * it in the environment, but then we should provide a way to
971 * export other variables...) 963 * export other variables...)
972 */ 964 */
973 v->flags &= ~(unsigned)VAR_FROM_ENV; 965 v->flags &= ~(unsigned)VAR_FROM_ENV;
974 h = HashTable_CreateEntry(&ctxt->context, name, NULL); 966 h = HashTable_CreateEntry(&ctxt->context, name, NULL);
975 HashEntry_Set(h, v); 967 HashEntry_Set(h, v);
976 } 968 }
977 } 969 }
978 free(name_freeIt); 970 free(name_freeIt);
979} 971}
980 972
981/* See if the given variable exists, in the given context or in other 973/* See if the given variable exists, in the given context or in other
982 * fallback contexts. 974 * fallback contexts.
983 * 975 *
984 * Input: 976 * Input:
985 * name Variable to find 977 * name Variable to find
986 * ctxt Context in which to start search 978 * ctxt Context in which to start search
987 */ 979 */
988Boolean 980Boolean
989Var_Exists(const char *name, GNode *ctxt) 981Var_Exists(const char *name, GNode *ctxt)
990{ 982{
991 char *name_freeIt = NULL; 983 char *name_freeIt = NULL;
992 Var *v; 984 Var *v;
993 985
994 if (strchr(name, '$') != NULL) { 986 if (strchr(name, '$') != NULL) {
995 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt); 987 (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt);
996 /* TODO: handle errors */ 988 /* TODO: handle errors */
997 name = name_freeIt; 989 name = name_freeIt;
998 } 990 }
999 991
1000 v = VarFind(name, ctxt, TRUE); 992 v = VarFind(name, ctxt, TRUE);
1001 free(name_freeIt); 993 free(name_freeIt);
1002 if (v == NULL) 994 if (v == NULL)
1003 return FALSE; 995 return FALSE;
1004 996
1005 (void)VarFreeEnv(v, TRUE); 997 (void)VarFreeEnv(v, TRUE);
1006 return TRUE; 998 return TRUE;
1007} 999}
1008 1000
1009/*- 1001/*-
1010 *----------------------------------------------------------------------- 1002 *-----------------------------------------------------------------------
1011 * Var_Value -- 1003 * Var_Value --
1012 * Return the unexpanded value of the given variable in the given 1004 * Return the unexpanded value of the given variable in the given
1013 * context, or the usual contexts. 1005 * context, or the usual contexts.
1014 * 1006 *
1015 * Input: 1007 * Input:
1016 * name name to find 1008 * name name to find
1017 * ctxt context in which to search for it 1009 * ctxt context in which to search for it
1018 * 1010 *
1019 * Results: 1011 * Results:
1020 * The value if the variable exists, NULL if it doesn't. 1012 * The value if the variable exists, NULL if it doesn't.
1021 * If the returned value is not NULL, the caller must free *freeIt 1013 * If the returned value is not NULL, the caller must free *freeIt
1022 * as soon as the returned value is no longer needed. 1014 * as soon as the returned value is no longer needed.
1023 *----------------------------------------------------------------------- 1015 *-----------------------------------------------------------------------
1024 */ 1016 */
1025const char * 1017const char *
1026Var_Value(const char *name, GNode *ctxt, char **freeIt) 1018Var_Value(const char *name, GNode *ctxt, char **freeIt)
1027{ 1019{
1028 Var *v = VarFind(name, ctxt, TRUE); 1020 Var *v = VarFind(name, ctxt, TRUE);
1029 char *p; 1021 char *p;
1030 1022
1031 *freeIt = NULL; 1023 *freeIt = NULL;
1032 if (v == NULL) 1024 if (v == NULL)
1033 return NULL; 1025 return NULL;
1034 1026
1035 p = Buf_GetAll(&v->val, NULL); 1027 p = Buf_GetAll(&v->val, NULL);
1036 if (VarFreeEnv(v, FALSE)) 1028 if (VarFreeEnv(v, FALSE))
1037 *freeIt = p; 1029 *freeIt = p;
1038 return p; 1030 return p;
1039} 1031}
1040 1032
1041 1033
1042/* SepBuf is a string being built from "words", interleaved with separators. */ 1034/* SepBuf is a string being built from "words", interleaved with separators. */
1043typedef struct SepBuf { 1035typedef struct SepBuf {
1044 Buffer buf; 1036 Buffer buf;
1045 Boolean needSep; 1037 Boolean needSep;
1046 char sep; /* usually ' ', but see the :ts modifier */ 1038 char sep; /* usually ' ', but see the :ts modifier */
1047} SepBuf; 1039} SepBuf;
1048 1040
1049static void 1041static void
1050SepBuf_Init(SepBuf *buf, char sep) 1042SepBuf_Init(SepBuf *buf, char sep)
1051{ 1043{
1052 Buf_Init(&buf->buf, 32 /* bytes */); 1044 Buf_Init(&buf->buf, 32 /* bytes */);
1053 buf->needSep = FALSE; 1045 buf->needSep = FALSE;
1054 buf->sep = sep; 1046 buf->sep = sep;
1055} 1047}
1056 1048
1057static void 1049static void
1058SepBuf_Sep(SepBuf *buf) 1050SepBuf_Sep(SepBuf *buf)
1059{ 1051{
1060 buf->needSep = TRUE; 1052 buf->needSep = TRUE;
1061} 1053}
1062 1054
1063static void 1055static void
1064SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size) 1056SepBuf_AddBytes(SepBuf *buf, const char *mem, size_t mem_size)
1065{ 1057{
1066 if (mem_size == 0) 1058 if (mem_size == 0)
1067 return; 1059 return;
1068 if (buf->needSep && buf->sep != '\0') { 1060 if (buf->needSep && buf->sep != '\0') {
1069 Buf_AddByte(&buf->buf, buf->sep); 1061 Buf_AddByte(&buf->buf, buf->sep);
1070 buf->needSep = FALSE; 1062 buf->needSep = FALSE;
1071 } 1063 }
1072 Buf_AddBytes(&buf->buf, mem, mem_size); 1064 Buf_AddBytes(&buf->buf, mem, mem_size);
1073} 1065}
1074 1066
1075static void 1067static void
1076SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end) 1068SepBuf_AddBytesBetween(SepBuf *buf, const char *start, const char *end)
1077{ 1069{
1078 SepBuf_AddBytes(buf, start, (size_t)(end - start)); 1070 SepBuf_AddBytes(buf, start, (size_t)(end - start));
1079} 1071}
1080 1072
1081static void 1073static void
1082SepBuf_AddStr(SepBuf *buf, const char *str) 1074SepBuf_AddStr(SepBuf *buf, const char *str)
1083{ 1075{
1084 SepBuf_AddBytes(buf, str, strlen(str)); 1076 SepBuf_AddBytes(buf, str, strlen(str));
1085} 1077}
1086 1078
1087static char * 1079static char *
1088SepBuf_Destroy(SepBuf *buf, Boolean free_buf) 1080SepBuf_Destroy(SepBuf *buf, Boolean free_buf)
1089{ 1081{
1090 return Buf_Destroy(&buf->buf, free_buf); 1082 return Buf_Destroy(&buf->buf, free_buf);
1091} 1083}
1092 1084
1093 1085
1094/* This callback for ModifyWords gets a single word from an expression and 1086/* This callback for ModifyWords gets a single word from an expression and
1095 * typically adds a modification of this word to the buffer. It may also do 1087 * typically adds a modification of this word to the buffer. It may also do
1096 * nothing or add several words. */ 1088 * nothing or add several words. */
1097typedef void (*ModifyWordsCallback)(const char *word, SepBuf *buf, void *data); 1089typedef void (*ModifyWordsCallback)(const char *word, SepBuf *buf, void *data);
1098 1090
1099 1091
1100/* Callback for ModifyWords to implement the :H modifier. 1092/* Callback for ModifyWords to implement the :H modifier.
1101 * Add the dirname of the given word to the buffer. */ 1093 * Add the dirname of the given word to the buffer. */
1102static void 1094static void
1103ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1095ModifyWord_Head(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1104{ 1096{
1105 const char *slash = strrchr(word, '/'); 1097 const char *slash = strrchr(word, '/');
1106 if (slash != NULL) 1098 if (slash != NULL)
1107 SepBuf_AddBytesBetween(buf, word, slash); 1099 SepBuf_AddBytesBetween(buf, word, slash);
1108 else 1100 else
1109 SepBuf_AddStr(buf, "."); 1101 SepBuf_AddStr(buf, ".");
1110} 1102}
1111 1103
1112/* Callback for ModifyWords to implement the :T modifier. 1104/* Callback for ModifyWords to implement the :T modifier.
1113 * Add the basename of the given word to the buffer. */ 1105 * Add the basename of the given word to the buffer. */
1114static void 1106static void
1115ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1107ModifyWord_Tail(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1116{ 1108{
1117 const char *slash = strrchr(word, '/'); 1109 const char *slash = strrchr(word, '/');
1118 const char *base = slash != NULL ? slash + 1 : word; 1110 const char *base = slash != NULL ? slash + 1 : word;
1119 SepBuf_AddStr(buf, base); 1111 SepBuf_AddStr(buf, base);
1120} 1112}
1121 1113
1122/* Callback for ModifyWords to implement the :E modifier. 1114/* Callback for ModifyWords to implement the :E modifier.
1123 * Add the filename suffix of the given word to the buffer, if it exists. */ 1115 * Add the filename suffix of the given word to the buffer, if it exists. */
1124static void 1116static void
1125ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1117ModifyWord_Suffix(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1126{ 1118{
1127 const char *dot = strrchr(word, '.'); 1119 const char *dot = strrchr(word, '.');
1128 if (dot != NULL) 1120 if (dot != NULL)
1129 SepBuf_AddStr(buf, dot + 1); 1121 SepBuf_AddStr(buf, dot + 1);
1130} 1122}
1131 1123
1132/* Callback for ModifyWords to implement the :R modifier. 1124/* Callback for ModifyWords to implement the :R modifier.
1133 * Add the basename of the given word to the buffer. */ 1125 * Add the basename of the given word to the buffer. */
1134static void 1126static void
1135ModifyWord_Root(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED) 1127ModifyWord_Root(const char *word, SepBuf *buf, void *dummy MAKE_ATTR_UNUSED)
1136{ 1128{
1137 const char *dot = strrchr(word, '.'); 1129 const char *dot = strrchr(word, '.');
1138 size_t len = dot != NULL ? (size_t)(dot - word) : strlen(word); 1130 size_t len = dot != NULL ? (size_t)(dot - word) : strlen(word);
1139 SepBuf_AddBytes(buf, word, len); 1131 SepBuf_AddBytes(buf, word, len);
1140} 1132}
1141 1133
1142/* Callback for ModifyWords to implement the :M modifier. 1134/* Callback for ModifyWords to implement the :M modifier.
1143 * Place the word in the buffer if it matches the given pattern. */ 1135 * Place the word in the buffer if it matches the given pattern. */
1144static void 1136static void
1145ModifyWord_Match(const char *word, SepBuf *buf, void *data) 1137ModifyWord_Match(const char *word, SepBuf *buf, void *data)
1146{ 1138{
1147 const char *pattern = data; 1139 const char *pattern = data;
1148 VAR_DEBUG2("VarMatch [%s] [%s]\n", word, pattern); 1140 VAR_DEBUG2("VarMatch [%s] [%s]\n", word, pattern);
1149 if (Str_Match(word, pattern)) 1141 if (Str_Match(word, pattern))
1150 SepBuf_AddStr(buf, word); 1142 SepBuf_AddStr(buf, word);
1151} 1143}
1152 1144
1153/* Callback for ModifyWords to implement the :N modifier. 1145/* Callback for ModifyWords to implement the :N modifier.
1154 * Place the word in the buffer if it doesn't match the given pattern. */ 1146 * Place the word in the buffer if it doesn't match the given pattern. */
1155static void 1147static void
1156ModifyWord_NoMatch(const char *word, SepBuf *buf, void *data) 1148ModifyWord_NoMatch(const char *word, SepBuf *buf, void *data)
1157{ 1149{
1158 const char *pattern = data; 1150 const char *pattern = data;
1159 if (!Str_Match(word, pattern)) 1151 if (!Str_Match(word, pattern))
1160 SepBuf_AddStr(buf, word); 1152 SepBuf_AddStr(buf, word);
1161} 1153}
1162 1154
1163#ifdef SYSVVARSUB 1155#ifdef SYSVVARSUB
1164/*- 1156/*-
1165 *----------------------------------------------------------------------- 1157 *-----------------------------------------------------------------------
1166 * Str_SYSVMatch -- 1158 * Str_SYSVMatch --
1167 * Check word against pattern for a match (% is wild), 1159 * Check word against pattern for a match (% is wild),
1168 * 1160 *
1169 * Input: 1161 * Input:
1170 * word Word to examine 1162 * word Word to examine
1171 * pattern Pattern to examine against 1163 * pattern Pattern to examine against
1172 * 1164 *
1173 * Results: 1165 * Results:
1174 * Returns the start of the match, or NULL. 1166 * Returns the start of the match, or NULL.
1175 * *match_len returns the length of the match, if any. 1167 * *match_len returns the length of the match, if any.
1176 * *hasPercent returns whether the pattern contains a percent. 1168 * *hasPercent returns whether the pattern contains a percent.
1177 *----------------------------------------------------------------------- 1169 *-----------------------------------------------------------------------
1178 */ 1170 */
1179static const char * 1171static const char *
1180Str_SYSVMatch(const char *word, const char *pattern, size_t *match_len, 1172Str_SYSVMatch(const char *word, const char *pattern, size_t *match_len,
1181 Boolean *hasPercent) 1173 Boolean *hasPercent)
1182{ 1174{
1183 const char *p = pattern; 1175 const char *p = pattern;
1184 const char *w = word; 1176 const char *w = word;
1185 const char *percent; 1177 const char *percent;
1186 size_t w_len; 1178 size_t w_len;
1187 size_t p_len; 1179 size_t p_len;
1188 const char *w_tail; 1180 const char *w_tail;
1189 1181
1190 *hasPercent = FALSE; 1182 *hasPercent = FALSE;
1191 if (*p == '\0') { /* ${VAR:=suffix} */ 1183 if (*p == '\0') { /* ${VAR:=suffix} */
1192 *match_len = strlen(w); /* Null pattern is the whole string */ 1184 *match_len = strlen(w); /* Null pattern is the whole string */
1193 return w; 1185 return w;
1194 } 1186 }
1195 1187
1196 percent = strchr(p, '%'); 1188 percent = strchr(p, '%');
1197 if (percent != NULL) { /* ${VAR:...%...=...} */ 1189 if (percent != NULL) { /* ${VAR:...%...=...} */
1198 *hasPercent = TRUE; 1190 *hasPercent = TRUE;
1199 if (*w == '\0') 1191 if (*w == '\0')
1200 return NULL; /* empty word does not match pattern */ 1192 return NULL; /* empty word does not match pattern */
1201 1193
1202 /* check that the prefix matches */ 1194 /* check that the prefix matches */
1203 for (; p != percent && *w != '\0' && *w == *p; w++, p++) 1195 for (; p != percent && *w != '\0' && *w == *p; w++, p++)
1204 continue; 1196 continue;
1205 if (p != percent) 1197 if (p != percent)
1206 return NULL; /* No match */ 1198 return NULL; /* No match */
1207 1199
1208 p++; /* Skip the percent */ 1200 p++; /* Skip the percent */
1209 if (*p == '\0') { 1201 if (*p == '\0') {
1210 /* No more pattern, return the rest of the string */ 1202 /* No more pattern, return the rest of the string */
1211 *match_len = strlen(w); 1203 *match_len = strlen(w);
1212 return w; 1204 return w;
1213 } 1205 }
1214 } 1206 }
1215 1207
1216 /* Test whether the tail matches */ 1208 /* Test whether the tail matches */
1217 w_len = strlen(w); 1209 w_len = strlen(w);
1218 p_len = strlen(p); 1210 p_len = strlen(p);
1219 if (w_len < p_len) 1211 if (w_len < p_len)
1220 return NULL; 1212 return NULL;
1221 1213
1222 w_tail = w + w_len - p_len; 1214 w_tail = w + w_len - p_len;
1223 if (memcmp(p, w_tail, p_len) != 0) 1215 if (memcmp(p, w_tail, p_len) != 0)
1224 return NULL; 1216 return NULL;
1225 1217
1226 *match_len = (size_t)(w_tail - w); 1218 *match_len = (size_t)(w_tail - w);
1227 return w; 1219 return w;
1228} 1220}
1229 1221
1230struct ModifyWord_SYSVSubstArgs { 1222struct ModifyWord_SYSVSubstArgs {
1231 GNode *ctx; 1223 GNode *ctx;
1232 const char *lhs; 1224 const char *lhs;
1233 const char *rhs; 1225 const char *rhs;
1234}; 1226};
1235 1227
1236/* Callback for ModifyWords to implement the :%.from=%.to modifier. */ 1228/* Callback for ModifyWords to implement the :%.from=%.to modifier. */
1237static void 1229static void
1238ModifyWord_SYSVSubst(const char *word, SepBuf *buf, void *data) 1230ModifyWord_SYSVSubst(const char *word, SepBuf *buf, void *data)
1239{ 1231{
1240 const struct ModifyWord_SYSVSubstArgs *args = data; 1232 const struct ModifyWord_SYSVSubstArgs *args = data;
1241 char *rhs_expanded; 1233 char *rhs_expanded;
1242 const char *rhs; 1234 const char *rhs;
1243 const char *percent; 1235 const char *percent;
1244 1236
1245 size_t match_len; 1237 size_t match_len;
1246 Boolean lhsPercent; 1238 Boolean lhsPercent;
1247 const char *match = Str_SYSVMatch(word, args->lhs, &match_len, &lhsPercent); 1239 const char *match = Str_SYSVMatch(word, args->lhs, &match_len, &lhsPercent);
1248 if (match == NULL) { 1240 if (match == NULL) {
1249 SepBuf_AddStr(buf, word); 1241 SepBuf_AddStr(buf, word);
1250 return; 1242 return;
1251 } 1243 }
1252 1244
1253 /* Append rhs to the buffer, substituting the first '%' with the 1245 /* Append rhs to the buffer, substituting the first '%' with the
1254 * match, but only if the lhs had a '%' as well. */ 1246 * match, but only if the lhs had a '%' as well. */
1255 1247
1256 (void)Var_Subst(args->rhs, args->ctx, VARE_WANTRES, &rhs_expanded); 1248 (void)Var_Subst(args->rhs, args->ctx, VARE_WANTRES, &rhs_expanded);
1257 /* TODO: handle errors */ 1249 /* TODO: handle errors */
1258 1250
1259 rhs = rhs_expanded; 1251 rhs = rhs_expanded;
1260 percent = strchr(rhs, '%'); 1252 percent = strchr(rhs, '%');
1261 1253
1262 if (percent != NULL && lhsPercent) { 1254 if (percent != NULL && lhsPercent) {
1263 /* Copy the prefix of the replacement pattern */ 1255 /* Copy the prefix of the replacement pattern */
1264 SepBuf_AddBytesBetween(buf, rhs, percent); 1256 SepBuf_AddBytesBetween(buf, rhs, percent);
1265 rhs = percent + 1; 1257 rhs = percent + 1;
1266 } 1258 }
1267 if (percent != NULL || !lhsPercent) 1259 if (percent != NULL || !lhsPercent)
1268 SepBuf_AddBytes(buf, match, match_len); 1260 SepBuf_AddBytes(buf, match, match_len);
1269 1261
1270 /* Append the suffix of the replacement pattern */ 1262 /* Append the suffix of the replacement pattern */
1271 SepBuf_AddStr(buf, rhs); 1263 SepBuf_AddStr(buf, rhs);
1272 1264
1273 free(rhs_expanded); 1265 free(rhs_expanded);
1274} 1266}
1275#endif 1267#endif
1276 1268
1277 1269
1278struct ModifyWord_SubstArgs { 1270struct ModifyWord_SubstArgs {
1279 const char *lhs; 1271 const char *lhs;
1280 size_t lhsLen; 1272 size_t lhsLen;
1281 const char *rhs; 1273 const char *rhs;
1282 size_t rhsLen; 1274 size_t rhsLen;
1283 VarPatternFlags pflags; 1275 VarPatternFlags pflags;
1284 Boolean matched; 1276 Boolean matched;
1285}; 1277};
1286 1278
1287/* Callback for ModifyWords to implement the :S,from,to, modifier. 1279/* Callback for ModifyWords to implement the :S,from,to, modifier.
1288 * Perform a string substitution on the given word. */ 1280 * Perform a string substitution on the given word. */
1289static void 1281static void
1290ModifyWord_Subst(const char *word, SepBuf *buf, void *data) 1282ModifyWord_Subst(const char *word, SepBuf *buf, void *data)
1291{ 1283{
1292 size_t wordLen = strlen(word); 1284 size_t wordLen = strlen(word);
1293 struct ModifyWord_SubstArgs *args = data; 1285 struct ModifyWord_SubstArgs *args = data;
1294 const char *match; 1286 const char *match;
1295 1287
1296 if ((args->pflags & VARP_SUB_ONE) && args->matched) 1288 if ((args->pflags & VARP_SUB_ONE) && args->matched)
1297 goto nosub; 1289 goto nosub;
1298 1290
1299 if (args->pflags & VARP_ANCHOR_START) { 1291 if (args->pflags & VARP_ANCHOR_START) {
1300 if (wordLen < args->lhsLen || 1292 if (wordLen < args->lhsLen ||
1301 memcmp(word, args->lhs, args->lhsLen) != 0) 1293 memcmp(word, args->lhs, args->lhsLen) != 0)
1302 goto nosub; 1294 goto nosub;
1303 1295
1304 if (args->pflags & VARP_ANCHOR_END) { 1296 if (args->pflags & VARP_ANCHOR_END) {
1305 if (wordLen != args->lhsLen) 1297 if (wordLen != args->lhsLen)
1306 goto nosub; 1298 goto nosub;
1307 1299
1308 /* :S,^whole$,replacement, */ 1300 /* :S,^whole$,replacement, */
1309 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1301 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1310 args->matched = TRUE; 1302 args->matched = TRUE;
1311 } else { 1303 } else {
1312 /* :S,^prefix,replacement, */ 1304 /* :S,^prefix,replacement, */
1313 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1305 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1314 SepBuf_AddBytes(buf, word + args->lhsLen, wordLen - args->lhsLen); 1306 SepBuf_AddBytes(buf, word + args->lhsLen, wordLen - args->lhsLen);
1315 args->matched = TRUE; 1307 args->matched = TRUE;
1316 } 1308 }
1317 return; 1309 return;
1318 } 1310 }
1319 1311
1320 if (args->pflags & VARP_ANCHOR_END) { 1312 if (args->pflags & VARP_ANCHOR_END) {
1321 const char *start; 1313 const char *start;
1322 1314
1323 if (wordLen < args->lhsLen) 1315 if (wordLen < args->lhsLen)
1324 goto nosub; 1316 goto nosub;
1325 1317
1326 start = word + (wordLen - args->lhsLen); 1318 start = word + (wordLen - args->lhsLen);
1327 if (memcmp(start, args->lhs, args->lhsLen) != 0) 1319 if (memcmp(start, args->lhs, args->lhsLen) != 0)
1328 goto nosub; 1320 goto nosub;
1329 1321
1330 /* :S,suffix$,replacement, */ 1322 /* :S,suffix$,replacement, */
1331 SepBuf_AddBytesBetween(buf, word, start); 1323 SepBuf_AddBytesBetween(buf, word, start);
1332 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1324 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1333 args->matched = TRUE; 1325 args->matched = TRUE;
1334 return; 1326 return;
1335 } 1327 }
1336 1328
1337 if (args->lhs[0] == '\0') 1329 if (args->lhs[0] == '\0')
1338 goto nosub; 1330 goto nosub;
1339 1331
1340 /* unanchored case, may match more than once */ 1332 /* unanchored case, may match more than once */
1341 while ((match = strstr(word, args->lhs)) != NULL) { 1333 while ((match = strstr(word, args->lhs)) != NULL) {
1342 SepBuf_AddBytesBetween(buf, word, match); 1334 SepBuf_AddBytesBetween(buf, word, match);
1343 SepBuf_AddBytes(buf, args->rhs, args->rhsLen); 1335 SepBuf_AddBytes(buf, args->rhs, args->rhsLen);
1344 args->matched = TRUE; 1336 args->matched = TRUE;
1345 wordLen -= (size_t)(match - word) + args->lhsLen; 1337 wordLen -= (size_t)(match - word) + args->lhsLen;
1346 word += (size_t)(match - word) + args->lhsLen; 1338 word += (size_t)(match - word) + args->lhsLen;
1347 if (wordLen == 0 || !(args->pflags & VARP_SUB_GLOBAL)) 1339 if (wordLen == 0 || !(args->pflags & VARP_SUB_GLOBAL))
1348 break; 1340 break;
1349 } 1341 }
1350nosub: 1342nosub:
1351 SepBuf_AddBytes(buf, word, wordLen); 1343 SepBuf_AddBytes(buf, word, wordLen);
1352} 1344}
1353 1345
1354#ifndef NO_REGEX 1346#ifndef NO_REGEX
1355/* Print the error caused by a regcomp or regexec call. */ 1347/* Print the error caused by a regcomp or regexec call. */
1356static void 1348static void
1357VarREError(int reerr, regex_t *pat, const char *str) 1349VarREError(int reerr, regex_t *pat, const char *str)
1358{ 1350{
1359 size_t errlen = regerror(reerr, pat, 0, 0); 1351 size_t errlen = regerror(reerr, pat, 0, 0);
1360 char *errbuf = bmake_malloc(errlen); 1352 char *errbuf = bmake_malloc(errlen);
1361 regerror(reerr, pat, errbuf, errlen); 1353 regerror(reerr, pat, errbuf, errlen);
1362 Error("%s: %s", str, errbuf); 1354 Error("%s: %s", str, errbuf);
1363 free(errbuf); 1355 free(errbuf);
1364} 1356}
1365 1357
1366struct ModifyWord_SubstRegexArgs { 1358struct ModifyWord_SubstRegexArgs {
1367 regex_t re; 1359 regex_t re;
1368 size_t nsub; 1360 size_t nsub;
1369 char *replace; 1361 char *replace;
1370 VarPatternFlags pflags; 1362 VarPatternFlags pflags;
1371 Boolean matched; 1363 Boolean matched;
1372}; 1364};
1373 1365
1374/* Callback for ModifyWords to implement the :C/from/to/ modifier. 1366/* Callback for ModifyWords to implement the :C/from/to/ modifier.
1375 * Perform a regex substitution on the given word. */ 1367 * Perform a regex substitution on the given word. */
1376static void 1368static void
1377ModifyWord_SubstRegex(const char *word, SepBuf *buf, void *data) 1369ModifyWord_SubstRegex(const char *word, SepBuf *buf, void *data)
1378{ 1370{
1379 struct ModifyWord_SubstRegexArgs *args = data; 1371 struct ModifyWord_SubstRegexArgs *args = data;
1380 int xrv; 1372 int xrv;
1381 const char *wp = word; 1373 const char *wp = word;
1382 char *rp; 1374 char *rp;
1383 int flags = 0; 1375 int flags = 0;
1384 regmatch_t m[10]; 1376 regmatch_t m[10];
1385 1377
1386 if ((args->pflags & VARP_SUB_ONE) && args->matched) 1378 if ((args->pflags & VARP_SUB_ONE) && args->matched)
1387 goto nosub; 1379 goto nosub;
1388 1380
1389tryagain: 1381tryagain:
1390 xrv = regexec(&args->re, wp, args->nsub, m, flags); 1382 xrv = regexec(&args->re, wp, args->nsub, m, flags);
1391 1383
1392 switch (xrv) { 1384 switch (xrv) {
1393 case 0: 1385 case 0:
1394 args->matched = TRUE; 1386 args->matched = TRUE;
1395 SepBuf_AddBytes(buf, wp, (size_t)m[0].rm_so); 1387 SepBuf_AddBytes(buf, wp, (size_t)m[0].rm_so);
1396 1388
1397 for (rp = args->replace; *rp; rp++) { 1389 for (rp = args->replace; *rp; rp++) {
1398 if (*rp == '\\' && (rp[1] == '&' || rp[1] == '\\')) { 1390 if (*rp == '\\' && (rp[1] == '&' || rp[1] == '\\')) {
1399 SepBuf_AddBytes(buf, rp + 1, 1); 1391 SepBuf_AddBytes(buf, rp + 1, 1);
1400 rp++; 1392 rp++;
1401 continue; 1393 continue;
1402 } 1394 }
1403 1395
1404 if (*rp == '&') { 1396 if (*rp == '&') {
1405 SepBuf_AddBytesBetween(buf, wp + m[0].rm_so, wp + m[0].rm_eo); 1397 SepBuf_AddBytesBetween(buf, wp + m[0].rm_so, wp + m[0].rm_eo);
1406 continue; 1398 continue;
1407 } 1399 }
1408 1400
1409 if (*rp != '\\' || !ch_isdigit(rp[1])) { 1401 if (*rp != '\\' || !ch_isdigit(rp[1])) {
1410 SepBuf_AddBytes(buf, rp, 1); 1402 SepBuf_AddBytes(buf, rp, 1);
1411 continue; 1403 continue;
1412 } 1404 }
1413 1405
1414 { /* \0 to \9 backreference */ 1406 { /* \0 to \9 backreference */
1415 size_t n = (size_t)(rp[1] - '0'); 1407 size_t n = (size_t)(rp[1] - '0');
1416 rp++; 1408 rp++;
1417 1409
1418 if (n >= args->nsub) { 1410 if (n >= args->nsub) {
1419 Error("No subexpression \\%zu", n); 1411 Error("No subexpression \\%zu", n);
1420 } else if (m[n].rm_so == -1 && m[n].rm_eo == -1) { 1412 } else if (m[n].rm_so == -1 && m[n].rm_eo == -1) {
1421 Error("No match for subexpression \\%zu", n); 1413 Error("No match for subexpression \\%zu", n);
1422 } else { 1414 } else {
1423 SepBuf_AddBytesBetween(buf, wp + m[n].rm_so, 1415 SepBuf_AddBytesBetween(buf, wp + m[n].rm_so,
1424 wp + m[n].rm_eo); 1416 wp + m[n].rm_eo);
1425 } 1417 }
1426 } 1418 }
1427 } 1419 }
1428 1420
1429 wp += m[0].rm_eo; 1421 wp += m[0].rm_eo;
1430 if (args->pflags & VARP_SUB_GLOBAL) { 1422 if (args->pflags & VARP_SUB_GLOBAL) {
1431 flags |= REG_NOTBOL; 1423 flags |= REG_NOTBOL;
1432 if (m[0].rm_so == 0 && m[0].rm_eo == 0) { 1424 if (m[0].rm_so == 0 && m[0].rm_eo == 0) {
1433 SepBuf_AddBytes(buf, wp, 1); 1425 SepBuf_AddBytes(buf, wp, 1);
1434 wp++; 1426 wp++;
1435 } 1427 }
1436 if (*wp) 1428 if (*wp)
1437 goto tryagain; 1429 goto tryagain;
1438 } 1430 }
1439 if (*wp) { 1431 if (*wp) {
1440 SepBuf_AddStr(buf, wp); 1432 SepBuf_AddStr(buf, wp);
1441 } 1433 }
1442 break; 1434 break;
1443 default: 1435 default:
1444 VarREError(xrv, &args->re, "Unexpected regex error"); 1436 VarREError(xrv, &args->re, "Unexpected regex error");
1445 /* FALLTHROUGH */ 1437 /* FALLTHROUGH */
1446 case REG_NOMATCH: 1438 case REG_NOMATCH:
1447 nosub: 1439 nosub:
1448 SepBuf_AddStr(buf, wp); 1440 SepBuf_AddStr(buf, wp);
1449 break; 1441 break;
1450 } 1442 }
1451} 1443}
1452#endif 1444#endif
1453 1445
1454 1446
1455struct ModifyWord_LoopArgs { 1447struct ModifyWord_LoopArgs {
1456 GNode *ctx; 1448 GNode *ctx;
1457 char *tvar; /* name of temporary variable */ 1449 char *tvar; /* name of temporary variable */
1458 char *str; /* string to expand */ 1450 char *str; /* string to expand */
1459 VarEvalFlags eflags; 1451 VarEvalFlags eflags;
1460}; 1452};
1461 1453
1462/* Callback for ModifyWords to implement the :@var@...@ modifier of ODE make. */ 1454/* Callback for ModifyWords to implement the :@var@...@ modifier of ODE make. */
1463static void 1455static void
1464ModifyWord_Loop(const char *word, SepBuf *buf, void *data) 1456ModifyWord_Loop(const char *word, SepBuf *buf, void *data)
1465{ 1457{
1466 const struct ModifyWord_LoopArgs *args; 1458 const struct ModifyWord_LoopArgs *args;
1467 char *s; 1459 char *s;
1468 1460
1469 if (word[0] == '\0') 1461 if (word[0] == '\0')
1470 return; 1462 return;
1471 1463
1472 args = data; 1464 args = data;
1473 Var_Set_with_flags(args->tvar, word, args->ctx, VAR_NO_EXPORT); 1465 Var_Set_with_flags(args->tvar, word, args->ctx, VAR_NO_EXPORT);
1474 (void)Var_Subst(args->str, args->ctx, args->eflags, &s); 1466 (void)Var_Subst(args->str, args->ctx, args->eflags, &s);
1475 /* TODO: handle errors */ 1467 /* TODO: handle errors */
1476 1468
1477 VAR_DEBUG4("ModifyWord_Loop: in \"%s\", replace \"%s\" with \"%s\" " 1469 VAR_DEBUG4("ModifyWord_Loop: in \"%s\", replace \"%s\" with \"%s\" "
1478 "to \"%s\"\n", 1470 "to \"%s\"\n",
1479 word, args->tvar, args->str, s); 1471 word, args->tvar, args->str, s);
1480 1472
1481 if (s[0] == '\n' || Buf_EndsWith(&buf->buf, '\n')) 1473 if (s[0] == '\n' || Buf_EndsWith(&buf->buf, '\n'))
1482 buf->needSep = FALSE; 1474 buf->needSep = FALSE;
1483 SepBuf_AddStr(buf, s); 1475 SepBuf_AddStr(buf, s);
1484 free(s); 1476 free(s);
1485} 1477}
1486 1478
1487 1479
1488/*- 1480/*-
1489 * Implements the :[first..last] modifier. 1481 * Implements the :[first..last] modifier.
1490 * This is a special case of ModifyWords since we want to be able 1482 * This is a special case of ModifyWords since we want to be able
1491 * to scan the list backwards if first > last. 1483 * to scan the list backwards if first > last.
1492 */ 1484 */
1493static char * 1485static char *
1494VarSelectWords(char sep, Boolean oneBigWord, const char *str, int first, 1486VarSelectWords(char sep, Boolean oneBigWord, const char *str, int first,
1495 int last) 1487 int last)
1496{ 1488{
1497 Words words; 1489 Words words;
1498 int len, start, end, step; 1490 int len, start, end, step;
1499 int i; 1491 int i;
1500 1492
1501 SepBuf buf; 1493 SepBuf buf;
1502 SepBuf_Init(&buf, sep); 1494 SepBuf_Init(&buf, sep);
1503 1495
1504 if (oneBigWord) { 1496 if (oneBigWord) {
1505 /* fake what Str_Words() would do if there were only one word */ 1497 /* fake what Str_Words() would do if there were only one word */
1506 words.len = 1; 1498 words.len = 1;
1507 words.words = bmake_malloc((words.len + 1) * sizeof(char *)); 1499 words.words = bmake_malloc((words.len + 1) * sizeof(char *));
1508 words.freeIt = bmake_strdup(str); 1500 words.freeIt = bmake_strdup(str);
1509 words.words[0] = words.freeIt; 1501 words.words[0] = words.freeIt;
1510 words.words[1] = NULL; 1502 words.words[1] = NULL;
1511 } else { 1503 } else {
1512 words = Str_Words(str, FALSE); 1504 words = Str_Words(str, FALSE);
1513 } 1505 }
1514 1506
1515 /* 1507 /*
1516 * Now sanitize the given range. 1508 * Now sanitize the given range.
1517 * If first or last are negative, convert them to the positive equivalents 1509 * If first or last are negative, convert them to the positive equivalents
1518 * (-1 gets converted to ac, -2 gets converted to (ac - 1), etc.). 1510 * (-1 gets converted to ac, -2 gets converted to (ac - 1), etc.).
1519 */ 1511 */
1520 len = (int)words.len; 1512 len = (int)words.len;
1521 if (first < 0) 1513 if (first < 0)
1522 first += len + 1; 1514 first += len + 1;
1523 if (last < 0) 1515 if (last < 0)
1524 last += len + 1; 1516 last += len + 1;
1525 1517
1526 /* 1518 /*
1527 * We avoid scanning more of the list than we need to. 1519 * We avoid scanning more of the list than we need to.
1528 */ 1520 */
1529 if (first > last) { 1521 if (first > last) {
1530 start = (first > len ? len : first) - 1; 1522 start = (first > len ? len : first) - 1;
1531 end = last < 1 ? 0 : last - 1; 1523 end = last < 1 ? 0 : last - 1;
1532 step = -1; 1524 step = -1;
1533 } else { 1525 } else {
1534 start = first < 1 ? 0 : first - 1; 1526 start = first < 1 ? 0 : first - 1;
1535 end = last > len ? len : last; 1527 end = last > len ? len : last;
1536 step = 1; 1528 step = 1;
1537 } 1529 }
1538 1530
1539 for (i = start; (step < 0) == (i >= end); i += step) { 1531 for (i = start; (step < 0) == (i >= end); i += step) {
1540 SepBuf_AddStr(&buf, words.words[i]); 1532 SepBuf_AddStr(&buf, words.words[i]);
1541 SepBuf_Sep(&buf); 1533 SepBuf_Sep(&buf);
1542 } 1534 }
1543 1535
1544 Words_Free(words); 1536 Words_Free(words);
1545 1537
1546 return SepBuf_Destroy(&buf, FALSE); 1538 return SepBuf_Destroy(&buf, FALSE);
1547} 1539}
1548 1540
1549 1541
1550/* Callback for ModifyWords to implement the :tA modifier. 1542/* Callback for ModifyWords to implement the :tA modifier.
1551 * Replace each word with the result of realpath() if successful. */ 1543 * Replace each word with the result of realpath() if successful. */
1552static void 1544static void
1553ModifyWord_Realpath(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) 1545ModifyWord_Realpath(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED)
1554{ 1546{
1555 struct stat st; 1547 struct stat st;
1556 char rbuf[MAXPATHLEN]; 1548 char rbuf[MAXPATHLEN];
1557 1549
1558 const char *rp = cached_realpath(word, rbuf); 1550 const char *rp = cached_realpath(word, rbuf);
1559 if (rp != NULL && *rp == '/' && stat(rp, &st) == 0) 1551 if (rp != NULL && *rp == '/' && stat(rp, &st) == 0)
1560 word = rp; 1552 word = rp;
1561 1553
1562 SepBuf_AddStr(buf, word); 1554 SepBuf_AddStr(buf, word);
1563} 1555}
1564 1556
1565/*- 1557/*-
1566 *----------------------------------------------------------------------- 1558 *-----------------------------------------------------------------------
1567 * Modify each of the words of the passed string using the given function. 1559 * Modify each of the words of the passed string using the given function.
1568 * 1560 *
1569 * Input: 1561 * Input:
1570 * str String whose words should be modified 1562 * str String whose words should be modified
1571 * modifyWord Function that modifies a single word 1563 * modifyWord Function that modifies a single word
1572 * modifyWord_args Custom arguments for modifyWord 1564 * modifyWord_args Custom arguments for modifyWord
1573 * 1565 *
1574 * Results: 1566 * Results:
1575 * A string of all the words modified appropriately. 1567 * A string of all the words modified appropriately.
1576 *----------------------------------------------------------------------- 1568 *-----------------------------------------------------------------------
1577 */ 1569 */
1578static char * 1570static char *
1579ModifyWords(GNode *ctx, char sep, Boolean oneBigWord, const char *str, 1571ModifyWords(GNode *ctx, char sep, Boolean oneBigWord, const char *str,
1580 ModifyWordsCallback modifyWord, void *modifyWord_args) 1572 ModifyWordsCallback modifyWord, void *modifyWord_args)
1581{ 1573{
1582 SepBuf result; 1574 SepBuf result;