| @@ -1,2088 +1,2087 @@ | | | @@ -1,2088 +1,2087 @@ |
1 | /* $NetBSD: parse.c,v 1.518 2020/12/27 11:47:04 rillig Exp $ */ | | 1 | /* $NetBSD: parse.c,v 1.519 2020/12/27 18:22:28 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 | * Parsing of makefiles. | | 72 | * Parsing of makefiles. |
73 | * | | 73 | * |
74 | * Parse_File is the main entry point and controls most of the other | | 74 | * Parse_File is the main entry point and controls most of the other |
75 | * functions in this module. | | 75 | * functions in this module. |
76 | * | | 76 | * |
77 | * The directories for the .include "..." directive are kept in | | 77 | * The directories for the .include "..." directive are kept in |
78 | * 'parseIncPath', while those for .include <...> are kept in 'sysIncPath'. | | 78 | * 'parseIncPath', while those for .include <...> are kept in 'sysIncPath'. |
79 | * The targets currently being defined are kept in 'targets'. | | 79 | * The targets currently being defined are kept in 'targets'. |
80 | * | | 80 | * |
81 | * Interface: | | 81 | * Interface: |
82 | * Parse_Init Initialize the module | | 82 | * Parse_Init Initialize the module |
83 | * | | 83 | * |
84 | * Parse_End Clean up the module | | 84 | * Parse_End Clean up the module |
85 | * | | 85 | * |
86 | * Parse_File Parse a top-level makefile. Included files are | | 86 | * Parse_File Parse a top-level makefile. Included files are |
87 | * handled by Parse_include_file though. | | 87 | * handled by Parse_include_file though. |
88 | * | | 88 | * |
89 | * Parse_IsVar Return TRUE if the given line is a variable | | 89 | * Parse_IsVar Return TRUE if the given line is a variable |
90 | * assignment. Used by MainParseArgs to determine if | | 90 | * assignment. Used by MainParseArgs to determine if |
91 | * an argument is a target or a variable assignment. | | 91 | * an argument is a target or a variable assignment. |
92 | * Used internally for pretty much the same thing. | | 92 | * Used internally for pretty much the same thing. |
93 | * | | 93 | * |
94 | * Parse_Error Report a parse error, a warning or an informational | | 94 | * Parse_Error Report a parse error, a warning or an informational |
95 | * message. | | 95 | * message. |
96 | * | | 96 | * |
97 | * Parse_MainName Returns a list of the main target to create. | | 97 | * Parse_MainName Returns a list of the main target to create. |
98 | */ | | 98 | */ |
99 | | | 99 | |
100 | #include <sys/types.h> | | 100 | #include <sys/types.h> |
101 | #include <sys/mman.h> | | 101 | #include <sys/mman.h> |
102 | #include <sys/stat.h> | | 102 | #include <sys/stat.h> |
103 | #include <errno.h> | | 103 | #include <errno.h> |
104 | #include <stdarg.h> | | 104 | #include <stdarg.h> |
105 | #include <stdint.h> | | 105 | #include <stdint.h> |
106 | | | 106 | |
107 | #ifndef MAP_FILE | | 107 | #ifndef MAP_FILE |
108 | #define MAP_FILE 0 | | 108 | #define MAP_FILE 0 |
109 | #endif | | 109 | #endif |
110 | #ifndef MAP_COPY | | 110 | #ifndef MAP_COPY |
111 | #define MAP_COPY MAP_PRIVATE | | 111 | #define MAP_COPY MAP_PRIVATE |
112 | #endif | | 112 | #endif |
113 | | | 113 | |
114 | #include "make.h" | | 114 | #include "make.h" |
115 | #include "dir.h" | | 115 | #include "dir.h" |
116 | #include "job.h" | | 116 | #include "job.h" |
117 | #include "pathnames.h" | | 117 | #include "pathnames.h" |
118 | | | 118 | |
119 | /* "@(#)parse.c 8.3 (Berkeley) 3/19/94" */ | | 119 | /* "@(#)parse.c 8.3 (Berkeley) 3/19/94" */ |
120 | MAKE_RCSID("$NetBSD: parse.c,v 1.518 2020/12/27 11:47:04 rillig Exp $"); | | 120 | MAKE_RCSID("$NetBSD: parse.c,v 1.519 2020/12/27 18:22:28 rillig Exp $"); |
121 | | | 121 | |
122 | /* types and constants */ | | 122 | /* types and constants */ |
123 | | | 123 | |
124 | /* | | 124 | /* |
125 | * Structure for a file being read ("included file") | | 125 | * Structure for a file being read ("included file") |
126 | */ | | 126 | */ |
127 | typedef struct IFile { | | 127 | typedef struct IFile { |
128 | char *fname; /* name of file (relative? absolute?) */ | | 128 | char *fname; /* name of file (relative? absolute?) */ |
129 | Boolean fromForLoop; /* simulated .include by the .for loop */ | | 129 | Boolean fromForLoop; /* simulated .include by the .for loop */ |
130 | int lineno; /* current line number in file */ | | 130 | int lineno; /* current line number in file */ |
131 | int first_lineno; /* line number of start of text */ | | 131 | int first_lineno; /* line number of start of text */ |
132 | unsigned int cond_depth; /* 'if' nesting when file opened */ | | 132 | unsigned int cond_depth; /* 'if' nesting when file opened */ |
133 | Boolean depending; /* state of doing_depend on EOF */ | | 133 | Boolean depending; /* state of doing_depend on EOF */ |
134 | | | 134 | |
135 | /* The buffer from which the file's content is read. */ | | 135 | /* The buffer from which the file's content is read. */ |
136 | char *buf_freeIt; | | 136 | char *buf_freeIt; |
137 | char *buf_ptr; /* next char to be read */ | | 137 | char *buf_ptr; /* next char to be read */ |
138 | char *buf_end; | | 138 | char *buf_end; |
139 | | | 139 | |
140 | /* Function to read more data, with a single opaque argument. */ | | 140 | /* Function to read more data, with a single opaque argument. */ |
141 | ReadMoreProc readMore; | | 141 | ReadMoreProc readMore; |
142 | void *readMoreArg; | | 142 | void *readMoreArg; |
143 | | | 143 | |
144 | struct loadedfile *lf; /* loadedfile object, if any */ | | 144 | struct loadedfile *lf; /* loadedfile object, if any */ |
145 | } IFile; | | 145 | } IFile; |
146 | | | 146 | |
147 | /* | | 147 | /* |
148 | * Tokens for target attributes | | 148 | * Tokens for target attributes |
149 | */ | | 149 | */ |
150 | typedef enum ParseSpecial { | | 150 | typedef enum ParseSpecial { |
151 | SP_ATTRIBUTE, /* Generic attribute */ | | 151 | SP_ATTRIBUTE, /* Generic attribute */ |
152 | SP_BEGIN, /* .BEGIN */ | | 152 | SP_BEGIN, /* .BEGIN */ |
153 | SP_DEFAULT, /* .DEFAULT */ | | 153 | SP_DEFAULT, /* .DEFAULT */ |
154 | SP_DELETE_ON_ERROR, /* .DELETE_ON_ERROR */ | | 154 | SP_DELETE_ON_ERROR, /* .DELETE_ON_ERROR */ |
155 | SP_END, /* .END */ | | 155 | SP_END, /* .END */ |
156 | SP_ERROR, /* .ERROR */ | | 156 | SP_ERROR, /* .ERROR */ |
157 | SP_IGNORE, /* .IGNORE */ | | 157 | SP_IGNORE, /* .IGNORE */ |
158 | SP_INCLUDES, /* .INCLUDES; not mentioned in the manual page */ | | 158 | SP_INCLUDES, /* .INCLUDES; not mentioned in the manual page */ |
159 | SP_INTERRUPT, /* .INTERRUPT */ | | 159 | SP_INTERRUPT, /* .INTERRUPT */ |
160 | SP_LIBS, /* .LIBS; not mentioned in the manual page */ | | 160 | SP_LIBS, /* .LIBS; not mentioned in the manual page */ |
161 | /* .MAIN and we don't have anything user-specified to make */ | | 161 | /* .MAIN and we don't have anything user-specified to make */ |
162 | SP_MAIN, | | 162 | SP_MAIN, |
163 | SP_META, /* .META */ | | 163 | SP_META, /* .META */ |
164 | SP_MFLAGS, /* .MFLAGS or .MAKEFLAGS */ | | 164 | SP_MFLAGS, /* .MFLAGS or .MAKEFLAGS */ |
165 | SP_NOMETA, /* .NOMETA */ | | 165 | SP_NOMETA, /* .NOMETA */ |
166 | SP_NOMETA_CMP, /* .NOMETA_CMP */ | | 166 | SP_NOMETA_CMP, /* .NOMETA_CMP */ |
167 | SP_NOPATH, /* .NOPATH */ | | 167 | SP_NOPATH, /* .NOPATH */ |
168 | SP_NOT, /* Not special */ | | 168 | SP_NOT, /* Not special */ |
169 | SP_NOTPARALLEL, /* .NOTPARALLEL or .NO_PARALLEL */ | | 169 | SP_NOTPARALLEL, /* .NOTPARALLEL or .NO_PARALLEL */ |
170 | SP_NULL, /* .NULL; not mentioned in the manual page */ | | 170 | SP_NULL, /* .NULL; not mentioned in the manual page */ |
171 | SP_OBJDIR, /* .OBJDIR */ | | 171 | SP_OBJDIR, /* .OBJDIR */ |
172 | SP_ORDER, /* .ORDER */ | | 172 | SP_ORDER, /* .ORDER */ |
173 | SP_PARALLEL, /* .PARALLEL; not mentioned in the manual page */ | | 173 | SP_PARALLEL, /* .PARALLEL; not mentioned in the manual page */ |
174 | SP_PATH, /* .PATH or .PATH.suffix */ | | 174 | SP_PATH, /* .PATH or .PATH.suffix */ |
175 | SP_PHONY, /* .PHONY */ | | 175 | SP_PHONY, /* .PHONY */ |
176 | #ifdef POSIX | | 176 | #ifdef POSIX |
177 | SP_POSIX, /* .POSIX; not mentioned in the manual page */ | | 177 | SP_POSIX, /* .POSIX; not mentioned in the manual page */ |
178 | #endif | | 178 | #endif |
179 | SP_PRECIOUS, /* .PRECIOUS */ | | 179 | SP_PRECIOUS, /* .PRECIOUS */ |
180 | SP_SHELL, /* .SHELL */ | | 180 | SP_SHELL, /* .SHELL */ |
181 | SP_SILENT, /* .SILENT */ | | 181 | SP_SILENT, /* .SILENT */ |
182 | SP_SINGLESHELL, /* .SINGLESHELL; not mentioned in the manual page */ | | 182 | SP_SINGLESHELL, /* .SINGLESHELL; not mentioned in the manual page */ |
183 | SP_STALE, /* .STALE */ | | 183 | SP_STALE, /* .STALE */ |
184 | SP_SUFFIXES, /* .SUFFIXES */ | | 184 | SP_SUFFIXES, /* .SUFFIXES */ |
185 | SP_WAIT /* .WAIT */ | | 185 | SP_WAIT /* .WAIT */ |
186 | } ParseSpecial; | | 186 | } ParseSpecial; |
187 | | | 187 | |
188 | typedef List SearchPathList; | | 188 | typedef List SearchPathList; |
189 | typedef ListNode SearchPathListNode; | | 189 | typedef ListNode SearchPathListNode; |
190 | | | 190 | |
191 | /* result data */ | | 191 | /* result data */ |
192 | | | 192 | |
193 | /* | | 193 | /* |
194 | * The main target to create. This is the first target on the first | | 194 | * The main target to create. This is the first target on the first |
195 | * dependency line in the first makefile. | | 195 | * dependency line in the first makefile. |
196 | */ | | 196 | */ |
197 | static GNode *mainNode; | | 197 | static GNode *mainNode; |
198 | | | 198 | |
199 | /* eval state */ | | 199 | /* eval state */ |
200 | | | 200 | |
201 | /* During parsing, the targets from the left-hand side of the currently | | 201 | /* During parsing, the targets from the left-hand side of the currently |
202 | * active dependency line, or NULL if the current line does not belong to a | | 202 | * active dependency line, or NULL if the current line does not belong to a |
203 | * dependency line, for example because it is a variable assignment. | | 203 | * dependency line, for example because it is a variable assignment. |
204 | * | | 204 | * |
205 | * See unit-tests/deptgt.mk, keyword "parse.c:targets". */ | | 205 | * See unit-tests/deptgt.mk, keyword "parse.c:targets". */ |
206 | static GNodeList *targets; | | 206 | static GNodeList *targets; |
207 | | | 207 | |
208 | #ifdef CLEANUP | | 208 | #ifdef CLEANUP |
209 | /* All shell commands for all targets, in no particular order and possibly | | 209 | /* All shell commands for all targets, in no particular order and possibly |
210 | * with duplicates. Kept in a separate list since the commands from .USE or | | 210 | * with duplicates. Kept in a separate list since the commands from .USE or |
211 | * .USEBEFORE nodes are shared with other GNodes, thereby giving up the | | 211 | * .USEBEFORE nodes are shared with other GNodes, thereby giving up the |
212 | * easily understandable ownership over the allocated strings. */ | | 212 | * easily understandable ownership over the allocated strings. */ |
213 | static StringList targCmds = LST_INIT; | | 213 | static StringList targCmds = LST_INIT; |
214 | #endif | | 214 | #endif |
215 | | | 215 | |
216 | /* | | 216 | /* |
217 | * Predecessor node for handling .ORDER. Initialized to NULL when .ORDER | | 217 | * Predecessor node for handling .ORDER. Initialized to NULL when .ORDER |
218 | * seen, then set to each successive source on the line. | | 218 | * seen, then set to each successive source on the line. |
219 | */ | | 219 | */ |
220 | static GNode *order_pred; | | 220 | static GNode *order_pred; |
221 | | | 221 | |
222 | /* parser state */ | | 222 | /* parser state */ |
223 | | | 223 | |
224 | /* number of fatal errors */ | | 224 | /* number of fatal errors */ |
225 | static int fatals = 0; | | 225 | static int fatals = 0; |
226 | | | 226 | |
227 | /* | | 227 | /* |
228 | * Variables for doing includes | | 228 | * Variables for doing includes |
229 | */ | | 229 | */ |
230 | | | 230 | |
231 | /* The include chain of makefiles. At the bottom is the top-level makefile | | 231 | /* The include chain of makefiles. At the bottom is the top-level makefile |
232 | * from the command line, and on top of that, there are the included files or | | 232 | * from the command line, and on top of that, there are the included files or |
233 | * .for loops, up to and including the current file. | | 233 | * .for loops, up to and including the current file. |
234 | * | | 234 | * |
235 | * This data could be used to print stack traces on parse errors. As of | | 235 | * This data could be used to print stack traces on parse errors. As of |
236 | * 2020-09-14, this is not done though. It seems quite simple to print the | | 236 | * 2020-09-14, this is not done though. It seems quite simple to print the |
237 | * tuples (fname:lineno:fromForLoop), from top to bottom. This simple idea is | | 237 | * tuples (fname:lineno:fromForLoop), from top to bottom. This simple idea is |
238 | * made complicated by the fact that the .for loops also use this stack for | | 238 | * made complicated by the fact that the .for loops also use this stack for |
239 | * storing information. | | 239 | * storing information. |
240 | * | | 240 | * |
241 | * The lineno fields of the IFiles with fromForLoop == TRUE look confusing, | | 241 | * The lineno fields of the IFiles with fromForLoop == TRUE look confusing, |
242 | * which is demonstrated by the test 'include-main.mk'. They seem sorted | | 242 | * which is demonstrated by the test 'include-main.mk'. They seem sorted |
243 | * backwards since they tell the number of completely parsed lines, which for | | 243 | * backwards since they tell the number of completely parsed lines, which for |
244 | * a .for loop is right after the terminating .endfor. To compensate for this | | 244 | * a .for loop is right after the terminating .endfor. To compensate for this |
245 | * confusion, there is another field first_lineno pointing at the start of the | | 245 | * confusion, there is another field first_lineno pointing at the start of the |
246 | * .for loop, 1-based for human consumption. | | 246 | * .for loop, 1-based for human consumption. |
247 | * | | 247 | * |
248 | * To make the stack trace intuitive, the entry below the first .for loop must | | 248 | * To make the stack trace intuitive, the entry below the first .for loop must |
249 | * be ignored completely since neither its lineno nor its first_lineno is | | 249 | * be ignored completely since neither its lineno nor its first_lineno is |
250 | * useful. Instead, the topmost of each chain of .for loop needs to be | | 250 | * useful. Instead, the topmost of each chain of .for loop needs to be |
251 | * printed twice, once with its first_lineno and once with its lineno. | | 251 | * printed twice, once with its first_lineno and once with its lineno. |
252 | * | | 252 | * |
253 | * As of 2020-10-28, using the above rules, the stack trace for the .info line | | 253 | * As of 2020-10-28, using the above rules, the stack trace for the .info line |
254 | * in include-subsub.mk would be: | | 254 | * in include-subsub.mk would be: |
255 | * | | 255 | * |
256 | * includes[5]: include-subsub.mk:4 | | 256 | * includes[5]: include-subsub.mk:4 |
257 | * (lineno, from an .include) | | 257 | * (lineno, from an .include) |
258 | * includes[4]: include-sub.mk:32 | | 258 | * includes[4]: include-sub.mk:32 |
259 | * (lineno, from a .for loop below an .include) | | 259 | * (lineno, from a .for loop below an .include) |
260 | * includes[4]: include-sub.mk:31 | | 260 | * includes[4]: include-sub.mk:31 |
261 | * (first_lineno, from a .for loop, lineno == 32) | | 261 | * (first_lineno, from a .for loop, lineno == 32) |
262 | * includes[3]: include-sub.mk:30 | | 262 | * includes[3]: include-sub.mk:30 |
263 | * (first_lineno, from a .for loop, lineno == 33) | | 263 | * (first_lineno, from a .for loop, lineno == 33) |
264 | * includes[2]: include-sub.mk:29 | | 264 | * includes[2]: include-sub.mk:29 |
265 | * (first_lineno, from a .for loop, lineno == 34) | | 265 | * (first_lineno, from a .for loop, lineno == 34) |
266 | * includes[1]: include-sub.mk:35 | | 266 | * includes[1]: include-sub.mk:35 |
267 | * (not printed since it is below a .for loop) | | 267 | * (not printed since it is below a .for loop) |
268 | * includes[0]: include-main.mk:27 | | 268 | * includes[0]: include-main.mk:27 |
269 | */ | | 269 | */ |
270 | static Vector /* of IFile */ includes; | | 270 | static Vector /* of IFile */ includes; |
271 | | | 271 | |
272 | static IFile * | | 272 | static IFile * |
273 | GetInclude(size_t i) | | 273 | GetInclude(size_t i) |
274 | { | | 274 | { |
275 | return Vector_Get(&includes, i); | | 275 | return Vector_Get(&includes, i); |
276 | } | | 276 | } |
277 | | | 277 | |
278 | /* The file that is currently being read. */ | | 278 | /* The file that is currently being read. */ |
279 | static IFile * | | 279 | static IFile * |
280 | CurFile(void) | | 280 | CurFile(void) |
281 | { | | 281 | { |
282 | return GetInclude(includes.len - 1); | | 282 | return GetInclude(includes.len - 1); |
283 | } | | 283 | } |
284 | | | 284 | |
285 | /* include paths */ | | 285 | /* include paths */ |
286 | SearchPath *parseIncPath; /* dirs for "..." includes */ | | 286 | SearchPath *parseIncPath; /* dirs for "..." includes */ |
287 | SearchPath *sysIncPath; /* dirs for <...> includes */ | | 287 | SearchPath *sysIncPath; /* dirs for <...> includes */ |
288 | SearchPath *defSysIncPath; /* default for sysIncPath */ | | 288 | SearchPath *defSysIncPath; /* default for sysIncPath */ |
289 | | | 289 | |
290 | /* parser tables */ | | 290 | /* parser tables */ |
291 | | | 291 | |
292 | /* | | 292 | /* |
293 | * The parseKeywords table is searched using binary search when deciding | | 293 | * The parseKeywords table is searched using binary search when deciding |
294 | * if a target or source is special. The 'spec' field is the ParseSpecial | | 294 | * if a target or source is special. The 'spec' field is the ParseSpecial |
295 | * type of the keyword (SP_NOT if the keyword isn't special as a target) while | | 295 | * type of the keyword (SP_NOT if the keyword isn't special as a target) while |
296 | * the 'op' field is the operator to apply to the list of targets if the | | 296 | * the 'op' field is the operator to apply to the list of targets if the |
297 | * keyword is used as a source ("0" if the keyword isn't special as a source) | | 297 | * keyword is used as a source ("0" if the keyword isn't special as a source) |
298 | */ | | 298 | */ |
299 | static const struct { | | 299 | static const struct { |
300 | const char *name; /* Name of keyword */ | | 300 | const char *name; /* Name of keyword */ |
301 | ParseSpecial spec; /* Type when used as a target */ | | 301 | ParseSpecial spec; /* Type when used as a target */ |
302 | GNodeType op; /* Operator when used as a source */ | | 302 | GNodeType op; /* Operator when used as a source */ |
303 | } parseKeywords[] = { | | 303 | } parseKeywords[] = { |
304 | { ".BEGIN", SP_BEGIN, OP_NONE }, | | 304 | { ".BEGIN", SP_BEGIN, OP_NONE }, |
305 | { ".DEFAULT", SP_DEFAULT, OP_NONE }, | | 305 | { ".DEFAULT", SP_DEFAULT, OP_NONE }, |
306 | { ".DELETE_ON_ERROR", SP_DELETE_ON_ERROR, OP_NONE }, | | 306 | { ".DELETE_ON_ERROR", SP_DELETE_ON_ERROR, OP_NONE }, |
307 | { ".END", SP_END, OP_NONE }, | | 307 | { ".END", SP_END, OP_NONE }, |
308 | { ".ERROR", SP_ERROR, OP_NONE }, | | 308 | { ".ERROR", SP_ERROR, OP_NONE }, |
309 | { ".EXEC", SP_ATTRIBUTE, OP_EXEC }, | | 309 | { ".EXEC", SP_ATTRIBUTE, OP_EXEC }, |
310 | { ".IGNORE", SP_IGNORE, OP_IGNORE }, | | 310 | { ".IGNORE", SP_IGNORE, OP_IGNORE }, |
311 | { ".INCLUDES", SP_INCLUDES, OP_NONE }, | | 311 | { ".INCLUDES", SP_INCLUDES, OP_NONE }, |
312 | { ".INTERRUPT", SP_INTERRUPT, OP_NONE }, | | 312 | { ".INTERRUPT", SP_INTERRUPT, OP_NONE }, |
313 | { ".INVISIBLE", SP_ATTRIBUTE, OP_INVISIBLE }, | | 313 | { ".INVISIBLE", SP_ATTRIBUTE, OP_INVISIBLE }, |
314 | { ".JOIN", SP_ATTRIBUTE, OP_JOIN }, | | 314 | { ".JOIN", SP_ATTRIBUTE, OP_JOIN }, |
315 | { ".LIBS", SP_LIBS, OP_NONE }, | | 315 | { ".LIBS", SP_LIBS, OP_NONE }, |
316 | { ".MADE", SP_ATTRIBUTE, OP_MADE }, | | 316 | { ".MADE", SP_ATTRIBUTE, OP_MADE }, |
317 | { ".MAIN", SP_MAIN, OP_NONE }, | | 317 | { ".MAIN", SP_MAIN, OP_NONE }, |
318 | { ".MAKE", SP_ATTRIBUTE, OP_MAKE }, | | 318 | { ".MAKE", SP_ATTRIBUTE, OP_MAKE }, |
319 | { ".MAKEFLAGS", SP_MFLAGS, OP_NONE }, | | 319 | { ".MAKEFLAGS", SP_MFLAGS, OP_NONE }, |
320 | { ".META", SP_META, OP_META }, | | 320 | { ".META", SP_META, OP_META }, |
321 | { ".MFLAGS", SP_MFLAGS, OP_NONE }, | | 321 | { ".MFLAGS", SP_MFLAGS, OP_NONE }, |
322 | { ".NOMETA", SP_NOMETA, OP_NOMETA }, | | 322 | { ".NOMETA", SP_NOMETA, OP_NOMETA }, |
323 | { ".NOMETA_CMP", SP_NOMETA_CMP, OP_NOMETA_CMP }, | | 323 | { ".NOMETA_CMP", SP_NOMETA_CMP, OP_NOMETA_CMP }, |
324 | { ".NOPATH", SP_NOPATH, OP_NOPATH }, | | 324 | { ".NOPATH", SP_NOPATH, OP_NOPATH }, |
325 | { ".NOTMAIN", SP_ATTRIBUTE, OP_NOTMAIN }, | | 325 | { ".NOTMAIN", SP_ATTRIBUTE, OP_NOTMAIN }, |
326 | { ".NOTPARALLEL", SP_NOTPARALLEL, OP_NONE }, | | 326 | { ".NOTPARALLEL", SP_NOTPARALLEL, OP_NONE }, |
327 | { ".NO_PARALLEL", SP_NOTPARALLEL, OP_NONE }, | | 327 | { ".NO_PARALLEL", SP_NOTPARALLEL, OP_NONE }, |
328 | { ".NULL", SP_NULL, OP_NONE }, | | 328 | { ".NULL", SP_NULL, OP_NONE }, |
329 | { ".OBJDIR", SP_OBJDIR, OP_NONE }, | | 329 | { ".OBJDIR", SP_OBJDIR, OP_NONE }, |
330 | { ".OPTIONAL", SP_ATTRIBUTE, OP_OPTIONAL }, | | 330 | { ".OPTIONAL", SP_ATTRIBUTE, OP_OPTIONAL }, |
331 | { ".ORDER", SP_ORDER, OP_NONE }, | | 331 | { ".ORDER", SP_ORDER, OP_NONE }, |
332 | { ".PARALLEL", SP_PARALLEL, OP_NONE }, | | 332 | { ".PARALLEL", SP_PARALLEL, OP_NONE }, |
333 | { ".PATH", SP_PATH, OP_NONE }, | | 333 | { ".PATH", SP_PATH, OP_NONE }, |
334 | { ".PHONY", SP_PHONY, OP_PHONY }, | | 334 | { ".PHONY", SP_PHONY, OP_PHONY }, |
335 | #ifdef POSIX | | 335 | #ifdef POSIX |
336 | { ".POSIX", SP_POSIX, OP_NONE }, | | 336 | { ".POSIX", SP_POSIX, OP_NONE }, |
337 | #endif | | 337 | #endif |
338 | { ".PRECIOUS", SP_PRECIOUS, OP_PRECIOUS }, | | 338 | { ".PRECIOUS", SP_PRECIOUS, OP_PRECIOUS }, |
339 | { ".RECURSIVE", SP_ATTRIBUTE, OP_MAKE }, | | 339 | { ".RECURSIVE", SP_ATTRIBUTE, OP_MAKE }, |
340 | { ".SHELL", SP_SHELL, OP_NONE }, | | 340 | { ".SHELL", SP_SHELL, OP_NONE }, |
341 | { ".SILENT", SP_SILENT, OP_SILENT }, | | 341 | { ".SILENT", SP_SILENT, OP_SILENT }, |
342 | { ".SINGLESHELL", SP_SINGLESHELL, OP_NONE }, | | 342 | { ".SINGLESHELL", SP_SINGLESHELL, OP_NONE }, |
343 | { ".STALE", SP_STALE, OP_NONE }, | | 343 | { ".STALE", SP_STALE, OP_NONE }, |
344 | { ".SUFFIXES", SP_SUFFIXES, OP_NONE }, | | 344 | { ".SUFFIXES", SP_SUFFIXES, OP_NONE }, |
345 | { ".USE", SP_ATTRIBUTE, OP_USE }, | | 345 | { ".USE", SP_ATTRIBUTE, OP_USE }, |
346 | { ".USEBEFORE", SP_ATTRIBUTE, OP_USEBEFORE }, | | 346 | { ".USEBEFORE", SP_ATTRIBUTE, OP_USEBEFORE }, |
347 | { ".WAIT", SP_WAIT, OP_NONE }, | | 347 | { ".WAIT", SP_WAIT, OP_NONE }, |
348 | }; | | 348 | }; |
349 | | | 349 | |
350 | /* file loader */ | | 350 | /* file loader */ |
351 | | | 351 | |
352 | struct loadedfile { | | 352 | struct loadedfile { |
353 | /* XXX: What is the lifetime of this path? Who manages the memory? */ | | 353 | /* XXX: What is the lifetime of this path? Who manages the memory? */ |
354 | const char *path; /* name, for error reports */ | | 354 | const char *path; /* name, for error reports */ |
355 | char *buf; /* contents buffer */ | | 355 | char *buf; /* contents buffer */ |
356 | size_t len; /* length of contents */ | | 356 | size_t len; /* length of contents */ |
357 | size_t maplen; /* length of mmap area, or 0 */ | | 357 | size_t maplen; /* length of mmap area, or 0 */ |
358 | Boolean used; /* XXX: have we used the data yet */ | | 358 | Boolean used; /* XXX: have we used the data yet */ |
359 | }; | | 359 | }; |
360 | | | 360 | |
361 | /* XXX: What is the lifetime of the path? Who manages the memory? */ | | 361 | /* XXX: What is the lifetime of the path? Who manages the memory? */ |
362 | static struct loadedfile * | | 362 | static struct loadedfile * |
363 | loadedfile_create(const char *path) | | 363 | loadedfile_create(const char *path) |
364 | { | | 364 | { |
365 | struct loadedfile *lf; | | 365 | struct loadedfile *lf; |
366 | | | 366 | |
367 | lf = bmake_malloc(sizeof *lf); | | 367 | lf = bmake_malloc(sizeof *lf); |
368 | lf->path = path == NULL ? "(stdin)" : path; | | 368 | lf->path = path == NULL ? "(stdin)" : path; |
369 | lf->buf = NULL; | | 369 | lf->buf = NULL; |
370 | lf->len = 0; | | 370 | lf->len = 0; |
371 | lf->maplen = 0; | | 371 | lf->maplen = 0; |
372 | lf->used = FALSE; | | 372 | lf->used = FALSE; |
373 | return lf; | | 373 | return lf; |
374 | } | | 374 | } |
375 | | | 375 | |
376 | static void | | 376 | static void |
377 | loadedfile_destroy(struct loadedfile *lf) | | 377 | loadedfile_destroy(struct loadedfile *lf) |
378 | { | | 378 | { |
379 | if (lf->buf != NULL) { | | 379 | if (lf->buf != NULL) { |
380 | if (lf->maplen > 0) | | 380 | if (lf->maplen > 0) |
381 | munmap(lf->buf, lf->maplen); | | 381 | munmap(lf->buf, lf->maplen); |
382 | else | | 382 | else |
383 | free(lf->buf); | | 383 | free(lf->buf); |
384 | } | | 384 | } |
385 | free(lf); | | 385 | free(lf); |
386 | } | | 386 | } |
387 | | | 387 | |
388 | /* | | 388 | /* |
389 | * readMore() operation for loadedfile, as needed by the weird and twisted | | 389 | * readMore() operation for loadedfile, as needed by the weird and twisted |
390 | * logic below. Once that's cleaned up, we can get rid of lf->used. | | 390 | * logic below. Once that's cleaned up, we can get rid of lf->used. |
391 | */ | | 391 | */ |
392 | static char * | | 392 | static char * |
393 | loadedfile_readMore(void *x, size_t *len) | | 393 | loadedfile_readMore(void *x, size_t *len) |
394 | { | | 394 | { |
395 | struct loadedfile *lf = x; | | 395 | struct loadedfile *lf = x; |
396 | | | 396 | |
397 | if (lf->used) | | 397 | if (lf->used) |
398 | return NULL; | | 398 | return NULL; |
399 | | | 399 | |
400 | lf->used = TRUE; | | 400 | lf->used = TRUE; |
401 | *len = lf->len; | | 401 | *len = lf->len; |
402 | return lf->buf; | | 402 | return lf->buf; |
403 | } | | 403 | } |
404 | | | 404 | |
405 | /* | | 405 | /* |
406 | * Try to get the size of a file. | | 406 | * Try to get the size of a file. |
407 | */ | | 407 | */ |
408 | static Boolean | | 408 | static Boolean |
409 | load_getsize(int fd, size_t *ret) | | 409 | load_getsize(int fd, size_t *ret) |
410 | { | | 410 | { |
411 | struct stat st; | | 411 | struct stat st; |
412 | | | 412 | |
413 | if (fstat(fd, &st) < 0) | | 413 | if (fstat(fd, &st) < 0) |
414 | return FALSE; | | 414 | return FALSE; |
415 | | | 415 | |
416 | if (!S_ISREG(st.st_mode)) | | 416 | if (!S_ISREG(st.st_mode)) |
417 | return FALSE; | | 417 | return FALSE; |
418 | | | 418 | |
419 | /* | | 419 | /* |
420 | * st_size is an off_t, which is 64 bits signed; *ret is | | 420 | * st_size is an off_t, which is 64 bits signed; *ret is |
421 | * size_t, which might be 32 bits unsigned or 64 bits | | 421 | * size_t, which might be 32 bits unsigned or 64 bits |
422 | * unsigned. Rather than being elaborate, just punt on | | 422 | * unsigned. Rather than being elaborate, just punt on |
423 | * files that are more than 2^31 bytes. We should never | | 423 | * files that are more than 2^31 bytes. We should never |
424 | * see a makefile that size in practice... | | 424 | * see a makefile that size in practice... |
425 | * | | 425 | * |
426 | * While we're at it reject negative sizes too, just in case. | | 426 | * While we're at it reject negative sizes too, just in case. |
427 | */ | | 427 | */ |
428 | if (st.st_size < 0 || st.st_size > 0x7fffffff) | | 428 | if (st.st_size < 0 || st.st_size > 0x7fffffff) |
429 | return FALSE; | | 429 | return FALSE; |
430 | | | 430 | |
431 | *ret = (size_t)st.st_size; | | 431 | *ret = (size_t)st.st_size; |
432 | return TRUE; | | 432 | return TRUE; |
433 | } | | 433 | } |
434 | | | 434 | |
435 | static Boolean | | 435 | static Boolean |
436 | loadedfile_mmap(struct loadedfile *lf, int fd) | | 436 | loadedfile_mmap(struct loadedfile *lf, int fd) |
437 | { | | 437 | { |
438 | static unsigned long pagesize = 0; | | 438 | static unsigned long pagesize = 0; |
439 | | | 439 | |
440 | if (!load_getsize(fd, &lf->len)) | | 440 | if (!load_getsize(fd, &lf->len)) |
441 | return FALSE; | | 441 | return FALSE; |
442 | | | 442 | |
443 | /* found a size, try mmap */ | | 443 | /* found a size, try mmap */ |
444 | if (pagesize == 0) | | 444 | if (pagesize == 0) |
445 | pagesize = (unsigned long)sysconf(_SC_PAGESIZE); | | 445 | pagesize = (unsigned long)sysconf(_SC_PAGESIZE); |
446 | if (pagesize == 0 || pagesize == (unsigned long)-1) | | 446 | if (pagesize == 0 || pagesize == (unsigned long)-1) |
447 | pagesize = 0x1000; | | 447 | pagesize = 0x1000; |
448 | | | 448 | |
449 | /* round size up to a page */ | | 449 | /* round size up to a page */ |
450 | lf->maplen = pagesize * ((lf->len + pagesize - 1) / pagesize); | | 450 | lf->maplen = pagesize * ((lf->len + pagesize - 1) / pagesize); |
451 | | | 451 | |
452 | /* | | 452 | /* |
453 | * XXX hack for dealing with empty files; remove when | | 453 | * XXX hack for dealing with empty files; remove when |
454 | * we're no longer limited by interfacing to the old | | 454 | * we're no longer limited by interfacing to the old |
455 | * logic elsewhere in this file. | | 455 | * logic elsewhere in this file. |
456 | */ | | 456 | */ |
457 | if (lf->maplen == 0) | | 457 | if (lf->maplen == 0) |
458 | lf->maplen = pagesize; | | 458 | lf->maplen = pagesize; |
459 | | | 459 | |
460 | /* | | 460 | /* |
461 | * FUTURE: remove PROT_WRITE when the parser no longer | | 461 | * FUTURE: remove PROT_WRITE when the parser no longer |
462 | * needs to scribble on the input. | | 462 | * needs to scribble on the input. |
463 | */ | | 463 | */ |
464 | lf->buf = mmap(NULL, lf->maplen, PROT_READ | PROT_WRITE, | | 464 | lf->buf = mmap(NULL, lf->maplen, PROT_READ | PROT_WRITE, |
465 | MAP_FILE | MAP_COPY, fd, 0); | | 465 | MAP_FILE | MAP_COPY, fd, 0); |
466 | if (lf->buf == MAP_FAILED) | | 466 | if (lf->buf == MAP_FAILED) |
467 | return FALSE; | | 467 | return FALSE; |
468 | | | 468 | |
469 | if (lf->len > 0 && lf->buf[lf->len - 1] != '\n') { | | 469 | if (lf->len > 0 && lf->buf[lf->len - 1] != '\n') { |
470 | if (lf->len == lf->maplen) { | | 470 | if (lf->len == lf->maplen) { |
471 | char *b = bmake_malloc(lf->len + 1); | | 471 | char *b = bmake_malloc(lf->len + 1); |
472 | memcpy(b, lf->buf, lf->len); | | 472 | memcpy(b, lf->buf, lf->len); |
473 | munmap(lf->buf, lf->maplen); | | 473 | munmap(lf->buf, lf->maplen); |
474 | lf->maplen = 0; | | 474 | lf->maplen = 0; |
475 | } | | 475 | } |
476 | lf->buf[lf->len++] = '\n'; | | 476 | lf->buf[lf->len++] = '\n'; |
477 | } | | 477 | } |
478 | | | 478 | |
479 | return TRUE; | | 479 | return TRUE; |
480 | } | | 480 | } |
481 | | | 481 | |
482 | /* | | 482 | /* |
483 | * Read in a file. | | 483 | * Read in a file. |
484 | * | | 484 | * |
485 | * Until the path search logic can be moved under here instead of | | 485 | * Until the path search logic can be moved under here instead of |
486 | * being in the caller in another source file, we need to have the fd | | 486 | * being in the caller in another source file, we need to have the fd |
487 | * passed in already open. Bleh. | | 487 | * passed in already open. Bleh. |
488 | * | | 488 | * |
489 | * If the path is NULL, use stdin. | | 489 | * If the path is NULL, use stdin. |
490 | */ | | 490 | */ |
491 | static struct loadedfile * | | 491 | static struct loadedfile * |
492 | loadfile(const char *path, int fd) | | 492 | loadfile(const char *path, int fd) |
493 | { | | 493 | { |
494 | struct loadedfile *lf; | | 494 | struct loadedfile *lf; |
495 | ssize_t result; | | 495 | ssize_t result; |
496 | size_t bufpos; | | 496 | size_t bufpos; |
497 | | | 497 | |
498 | lf = loadedfile_create(path); | | 498 | lf = loadedfile_create(path); |
499 | | | 499 | |
500 | if (path == NULL) { | | 500 | if (path == NULL) { |
501 | assert(fd == -1); | | 501 | assert(fd == -1); |
502 | fd = STDIN_FILENO; | | 502 | fd = STDIN_FILENO; |
503 | } else { | | 503 | } else { |
504 | #if 0 /* notyet */ | | 504 | #if 0 /* notyet */ |
505 | fd = open(path, O_RDONLY); | | 505 | fd = open(path, O_RDONLY); |
506 | if (fd < 0) { | | 506 | if (fd < 0) { |
507 | ... | | 507 | ... |
508 | Error("%s: %s", path, strerror(errno)); | | 508 | Error("%s: %s", path, strerror(errno)); |
509 | exit(1); | | 509 | exit(1); |
510 | } | | 510 | } |
511 | #endif | | 511 | #endif |
512 | } | | 512 | } |
513 | | | 513 | |
514 | if (loadedfile_mmap(lf, fd)) | | 514 | if (loadedfile_mmap(lf, fd)) |
515 | goto done; | | 515 | goto done; |
516 | | | 516 | |
517 | /* cannot mmap; load the traditional way */ | | 517 | /* cannot mmap; load the traditional way */ |
518 | | | 518 | |
519 | lf->maplen = 0; | | 519 | lf->maplen = 0; |
520 | lf->len = 1024; | | 520 | lf->len = 1024; |
521 | lf->buf = bmake_malloc(lf->len); | | 521 | lf->buf = bmake_malloc(lf->len); |
522 | | | 522 | |
523 | bufpos = 0; | | 523 | bufpos = 0; |
524 | for (;;) { | | 524 | for (;;) { |
525 | assert(bufpos <= lf->len); | | 525 | assert(bufpos <= lf->len); |
526 | if (bufpos == lf->len) { | | 526 | if (bufpos == lf->len) { |
527 | if (lf->len > SIZE_MAX / 2) { | | 527 | if (lf->len > SIZE_MAX / 2) { |
528 | errno = EFBIG; | | 528 | errno = EFBIG; |
529 | Error("%s: file too large", path); | | 529 | Error("%s: file too large", path); |
530 | exit(2); /* Not 1 so -q can distinguish error */ | | 530 | exit(2); /* Not 1 so -q can distinguish error */ |
531 | } | | 531 | } |
532 | lf->len *= 2; | | 532 | lf->len *= 2; |
533 | lf->buf = bmake_realloc(lf->buf, lf->len); | | 533 | lf->buf = bmake_realloc(lf->buf, lf->len); |
534 | } | | 534 | } |
535 | assert(bufpos < lf->len); | | 535 | assert(bufpos < lf->len); |
536 | result = read(fd, lf->buf + bufpos, lf->len - bufpos); | | 536 | result = read(fd, lf->buf + bufpos, lf->len - bufpos); |
537 | if (result < 0) { | | 537 | if (result < 0) { |
538 | Error("%s: read error: %s", path, strerror(errno)); | | 538 | Error("%s: read error: %s", path, strerror(errno)); |
539 | exit(2); /* Not 1 so -q can distinguish error */ | | 539 | exit(2); /* Not 1 so -q can distinguish error */ |
540 | } | | 540 | } |
541 | if (result == 0) | | 541 | if (result == 0) |
542 | break; | | 542 | break; |
543 | | | 543 | |
544 | bufpos += (size_t)result; | | 544 | bufpos += (size_t)result; |
545 | } | | 545 | } |
546 | assert(bufpos <= lf->len); | | 546 | assert(bufpos <= lf->len); |
547 | lf->len = bufpos; | | 547 | lf->len = bufpos; |
548 | | | 548 | |
549 | /* truncate malloc region to actual length (maybe not useful) */ | | 549 | /* truncate malloc region to actual length (maybe not useful) */ |
550 | if (lf->len > 0) { | | 550 | if (lf->len > 0) { |
551 | /* as for mmap case, ensure trailing \n */ | | 551 | /* as for mmap case, ensure trailing \n */ |
552 | if (lf->buf[lf->len - 1] != '\n') | | 552 | if (lf->buf[lf->len - 1] != '\n') |
553 | lf->len++; | | 553 | lf->len++; |
554 | lf->buf = bmake_realloc(lf->buf, lf->len); | | 554 | lf->buf = bmake_realloc(lf->buf, lf->len); |
555 | lf->buf[lf->len - 1] = '\n'; | | 555 | lf->buf[lf->len - 1] = '\n'; |
556 | } | | 556 | } |
557 | | | 557 | |
558 | done: | | 558 | done: |
559 | if (path != NULL) | | 559 | if (path != NULL) |
560 | close(fd); | | 560 | close(fd); |
561 | | | 561 | |
562 | return lf; | | 562 | return lf; |
563 | } | | 563 | } |
564 | | | 564 | |
565 | /* old code */ | | 565 | /* old code */ |
566 | | | 566 | |
567 | /* Check if the current character is escaped on the current line. */ | | 567 | /* Check if the current character is escaped on the current line. */ |
568 | static Boolean | | 568 | static Boolean |
569 | ParseIsEscaped(const char *line, const char *c) | | 569 | ParseIsEscaped(const char *line, const char *c) |
570 | { | | 570 | { |
571 | Boolean active = FALSE; | | 571 | Boolean active = FALSE; |
572 | for (;;) { | | 572 | for (;;) { |
573 | if (line == c) | | 573 | if (line == c) |
574 | return active; | | 574 | return active; |
575 | if (*--c != '\\') | | 575 | if (*--c != '\\') |
576 | return active; | | 576 | return active; |
577 | active = !active; | | 577 | active = !active; |
578 | } | | 578 | } |
579 | } | | 579 | } |
580 | | | 580 | |
581 | /* Add the filename and lineno to the GNode so that we remember where it | | 581 | /* Add the filename and lineno to the GNode so that we remember where it |
582 | * was first defined. */ | | 582 | * was first defined. */ |
583 | static void | | 583 | static void |
584 | ParseMark(GNode *gn) | | 584 | ParseMark(GNode *gn) |
585 | { | | 585 | { |
586 | IFile *curFile = CurFile(); | | 586 | IFile *curFile = CurFile(); |
587 | gn->fname = curFile->fname; | | 587 | gn->fname = curFile->fname; |
588 | gn->lineno = curFile->lineno; | | 588 | gn->lineno = curFile->lineno; |
589 | } | | 589 | } |
590 | | | 590 | |
591 | /* Look in the table of keywords for one matching the given string. | | 591 | /* Look in the table of keywords for one matching the given string. |
592 | * Return the index of the keyword, or -1 if it isn't there. */ | | 592 | * Return the index of the keyword, or -1 if it isn't there. */ |
593 | static int | | 593 | static int |
594 | ParseFindKeyword(const char *str) | | 594 | ParseFindKeyword(const char *str) |
595 | { | | 595 | { |
596 | int start = 0; | | 596 | int start = 0; |
597 | int end = sizeof parseKeywords / sizeof parseKeywords[0] - 1; | | 597 | int end = sizeof parseKeywords / sizeof parseKeywords[0] - 1; |
598 | | | 598 | |
599 | do { | | 599 | do { |
600 | int curr = start + (end - start) / 2; | | 600 | int curr = start + (end - start) / 2; |
601 | int diff = strcmp(str, parseKeywords[curr].name); | | 601 | int diff = strcmp(str, parseKeywords[curr].name); |
602 | | | 602 | |
603 | if (diff == 0) | | 603 | if (diff == 0) |
604 | return curr; | | 604 | return curr; |
605 | if (diff < 0) | | 605 | if (diff < 0) |
606 | end = curr - 1; | | 606 | end = curr - 1; |
607 | else | | 607 | else |
608 | start = curr + 1; | | 608 | start = curr + 1; |
609 | } while (start <= end); | | 609 | } while (start <= end); |
610 | | | 610 | |
611 | return -1; | | 611 | return -1; |
612 | } | | 612 | } |
613 | | | 613 | |
614 | static void | | 614 | static void |
615 | PrintLocation(FILE *f, const char *fname, size_t lineno) | | 615 | PrintLocation(FILE *f, const char *fname, size_t lineno) |
616 | { | | 616 | { |
617 | char dirbuf[MAXPATHLEN + 1]; | | 617 | char dirbuf[MAXPATHLEN + 1]; |
618 | FStr dir, base; | | 618 | FStr dir, base; |
619 | | | 619 | |
620 | if (*fname == '/' || strcmp(fname, "(stdin)") == 0) { | | 620 | if (*fname == '/' || strcmp(fname, "(stdin)") == 0) { |
621 | (void)fprintf(f, "\"%s\" line %u: ", fname, (unsigned)lineno); | | 621 | (void)fprintf(f, "\"%s\" line %u: ", fname, (unsigned)lineno); |
622 | return; | | 622 | return; |
623 | } | | 623 | } |
624 | | | 624 | |
625 | /* Find out which makefile is the culprit. | | 625 | /* Find out which makefile is the culprit. |
626 | * We try ${.PARSEDIR} and apply realpath(3) if not absolute. */ | | 626 | * We try ${.PARSEDIR} and apply realpath(3) if not absolute. */ |
627 | | | 627 | |
628 | dir = Var_Value(".PARSEDIR", VAR_GLOBAL); | | 628 | dir = Var_Value(".PARSEDIR", VAR_GLOBAL); |
629 | if (dir.str == NULL) | | 629 | if (dir.str == NULL) |
630 | dir.str = "."; | | 630 | dir.str = "."; |
631 | if (dir.str[0] != '/') | | 631 | if (dir.str[0] != '/') |
632 | dir.str = realpath(dir.str, dirbuf); | | 632 | dir.str = realpath(dir.str, dirbuf); |
633 | | | 633 | |
634 | base = Var_Value(".PARSEFILE", VAR_GLOBAL); | | 634 | base = Var_Value(".PARSEFILE", VAR_GLOBAL); |
635 | if (base.str == NULL) | | 635 | if (base.str == NULL) |
636 | base.str = str_basename(fname); | | 636 | base.str = str_basename(fname); |
637 | | | 637 | |
638 | (void)fprintf(f, "\"%s/%s\" line %u: ", | | 638 | (void)fprintf(f, "\"%s/%s\" line %u: ", |
639 | dir.str, base.str, (unsigned)lineno); | | 639 | dir.str, base.str, (unsigned)lineno); |
640 | | | 640 | |
641 | FStr_Done(&base); | | 641 | FStr_Done(&base); |
642 | FStr_Done(&dir); | | 642 | FStr_Done(&dir); |
643 | } | | 643 | } |
644 | | | 644 | |
645 | static void | | 645 | static void |
646 | ParseVErrorInternal(FILE *f, const char *fname, size_t lineno, | | 646 | ParseVErrorInternal(FILE *f, const char *fname, size_t lineno, |
647 | ParseErrorLevel type, const char *fmt, va_list ap) | | 647 | ParseErrorLevel type, const char *fmt, va_list ap) |
648 | { | | 648 | { |
649 | static Boolean fatal_warning_error_printed = FALSE; | | 649 | static Boolean fatal_warning_error_printed = FALSE; |
650 | | | 650 | |
651 | (void)fprintf(f, "%s: ", progname); | | 651 | (void)fprintf(f, "%s: ", progname); |
652 | | | 652 | |
653 | if (fname != NULL) | | 653 | if (fname != NULL) |
654 | PrintLocation(f, fname, lineno); | | 654 | PrintLocation(f, fname, lineno); |
655 | if (type == PARSE_WARNING) | | 655 | if (type == PARSE_WARNING) |
656 | (void)fprintf(f, "warning: "); | | 656 | (void)fprintf(f, "warning: "); |
657 | (void)vfprintf(f, fmt, ap); | | 657 | (void)vfprintf(f, fmt, ap); |
658 | (void)fprintf(f, "\n"); | | 658 | (void)fprintf(f, "\n"); |
659 | (void)fflush(f); | | 659 | (void)fflush(f); |
660 | | | 660 | |
661 | if (type == PARSE_INFO) | | 661 | if (type == PARSE_INFO) |
662 | return; | | 662 | return; |
663 | if (type == PARSE_FATAL || opts.parseWarnFatal) | | 663 | if (type == PARSE_FATAL || opts.parseWarnFatal) |
664 | fatals++; | | 664 | fatals++; |
665 | if (opts.parseWarnFatal && !fatal_warning_error_printed) { | | 665 | if (opts.parseWarnFatal && !fatal_warning_error_printed) { |
666 | Error("parsing warnings being treated as errors"); | | 666 | Error("parsing warnings being treated as errors"); |
667 | fatal_warning_error_printed = TRUE; | | 667 | fatal_warning_error_printed = TRUE; |
668 | } | | 668 | } |
669 | } | | 669 | } |
670 | | | 670 | |
671 | static void | | 671 | static void |
672 | ParseErrorInternal(const char *fname, size_t lineno, | | 672 | ParseErrorInternal(const char *fname, size_t lineno, |
673 | ParseErrorLevel type, const char *fmt, ...) | | 673 | ParseErrorLevel type, const char *fmt, ...) |
674 | { | | 674 | { |
675 | va_list ap; | | 675 | va_list ap; |
676 | | | 676 | |
677 | (void)fflush(stdout); | | 677 | (void)fflush(stdout); |
678 | va_start(ap, fmt); | | 678 | va_start(ap, fmt); |
679 | ParseVErrorInternal(stderr, fname, lineno, type, fmt, ap); | | 679 | ParseVErrorInternal(stderr, fname, lineno, type, fmt, ap); |
680 | va_end(ap); | | 680 | va_end(ap); |
681 | | | 681 | |
682 | if (opts.debug_file != stderr && opts.debug_file != stdout) { | | 682 | if (opts.debug_file != stderr && opts.debug_file != stdout) { |
683 | va_start(ap, fmt); | | 683 | va_start(ap, fmt); |
684 | ParseVErrorInternal(opts.debug_file, fname, lineno, type, | | 684 | ParseVErrorInternal(opts.debug_file, fname, lineno, type, |
685 | fmt, ap); | | 685 | fmt, ap); |
686 | va_end(ap); | | 686 | va_end(ap); |
687 | } | | 687 | } |
688 | } | | 688 | } |
689 | | | 689 | |
690 | /* Print a parse error message, including location information. | | 690 | /* Print a parse error message, including location information. |
691 | * | | 691 | * |
692 | * If the level is PARSE_FATAL, continue parsing until the end of the | | 692 | * If the level is PARSE_FATAL, continue parsing until the end of the |
693 | * current top-level makefile, then exit (see Parse_File). | | 693 | * current top-level makefile, then exit (see Parse_File). |
694 | * | | 694 | * |
695 | * Fmt is given without a trailing newline. */ | | 695 | * Fmt is given without a trailing newline. */ |
696 | void | | 696 | void |
697 | Parse_Error(ParseErrorLevel type, const char *fmt, ...) | | 697 | Parse_Error(ParseErrorLevel type, const char *fmt, ...) |
698 | { | | 698 | { |
699 | va_list ap; | | 699 | va_list ap; |
700 | const char *fname; | | 700 | const char *fname; |
701 | size_t lineno; | | 701 | size_t lineno; |
702 | | | 702 | |
703 | if (includes.len == 0) { | | 703 | if (includes.len == 0) { |
704 | fname = NULL; | | 704 | fname = NULL; |
705 | lineno = 0; | | 705 | lineno = 0; |
706 | } else { | | 706 | } else { |
707 | IFile *curFile = CurFile(); | | 707 | IFile *curFile = CurFile(); |
708 | fname = curFile->fname; | | 708 | fname = curFile->fname; |
709 | lineno = (size_t)curFile->lineno; | | 709 | lineno = (size_t)curFile->lineno; |
710 | } | | 710 | } |
711 | | | 711 | |
712 | va_start(ap, fmt); | | 712 | va_start(ap, fmt); |
713 | (void)fflush(stdout); | | 713 | (void)fflush(stdout); |
714 | ParseVErrorInternal(stderr, fname, lineno, type, fmt, ap); | | 714 | ParseVErrorInternal(stderr, fname, lineno, type, fmt, ap); |
715 | va_end(ap); | | 715 | va_end(ap); |
716 | | | 716 | |
717 | if (opts.debug_file != stderr && opts.debug_file != stdout) { | | 717 | if (opts.debug_file != stderr && opts.debug_file != stdout) { |
718 | va_start(ap, fmt); | | 718 | va_start(ap, fmt); |
719 | ParseVErrorInternal(opts.debug_file, fname, lineno, type, | | 719 | ParseVErrorInternal(opts.debug_file, fname, lineno, type, |
720 | fmt, ap); | | 720 | fmt, ap); |
721 | va_end(ap); | | 721 | va_end(ap); |
722 | } | | 722 | } |
723 | } | | 723 | } |
724 | | | 724 | |
725 | | | 725 | |
726 | /* Parse and handle a .info, .warning or .error directive. | | 726 | /* Parse and handle a .info, .warning or .error directive. |
727 | * For an .error directive, immediately exit. */ | | 727 | * For an .error directive, immediately exit. */ |
728 | static void | | 728 | static void |
729 | ParseMessage(ParseErrorLevel level, const char *levelName, const char *umsg) | | 729 | ParseMessage(ParseErrorLevel level, const char *levelName, const char *umsg) |
730 | { | | 730 | { |
731 | char *xmsg; | | 731 | char *xmsg; |
732 | | | 732 | |
733 | if (umsg[0] == '\0') { | | 733 | if (umsg[0] == '\0') { |
734 | Parse_Error(PARSE_FATAL, "Missing argument for \".%s\"", | | 734 | Parse_Error(PARSE_FATAL, "Missing argument for \".%s\"", |
735 | levelName); | | 735 | levelName); |
736 | return; | | 736 | return; |
737 | } | | 737 | } |
738 | | | 738 | |
739 | (void)Var_Subst(umsg, VAR_CMDLINE, VARE_WANTRES, &xmsg); | | 739 | (void)Var_Subst(umsg, VAR_CMDLINE, VARE_WANTRES, &xmsg); |
740 | /* TODO: handle errors */ | | 740 | /* TODO: handle errors */ |
741 | | | 741 | |
742 | Parse_Error(level, "%s", xmsg); | | 742 | Parse_Error(level, "%s", xmsg); |
743 | free(xmsg); | | 743 | free(xmsg); |
744 | | | 744 | |
745 | if (level == PARSE_FATAL) { | | 745 | if (level == PARSE_FATAL) { |
746 | PrintOnError(NULL, NULL); | | 746 | PrintOnError(NULL, NULL); |
747 | exit(1); | | 747 | exit(1); |
748 | } | | 748 | } |
749 | } | | 749 | } |
750 | | | 750 | |
751 | /* Add the child to the parent's children. | | 751 | /* Add the child to the parent's children. |
752 | * | | 752 | * |
753 | * Additionally, add the parent to the child's parents, but only if the | | 753 | * Additionally, add the parent to the child's parents, but only if the |
754 | * target is not special. An example for such a special target is .END, | | 754 | * target is not special. An example for such a special target is .END, |
755 | * which does not need to be informed once the child target has been made. */ | | 755 | * which does not need to be informed once the child target has been made. */ |
756 | static void | | 756 | static void |
757 | LinkSource(GNode *pgn, GNode *cgn, Boolean isSpecial) | | 757 | LinkSource(GNode *pgn, GNode *cgn, Boolean isSpecial) |
758 | { | | 758 | { |
759 | if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty(&pgn->cohorts)) | | 759 | if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty(&pgn->cohorts)) |
760 | pgn = pgn->cohorts.last->datum; | | 760 | pgn = pgn->cohorts.last->datum; |
761 | | | 761 | |
762 | Lst_Append(&pgn->children, cgn); | | 762 | Lst_Append(&pgn->children, cgn); |
763 | pgn->unmade++; | | 763 | pgn->unmade++; |
764 | | | 764 | |
765 | /* Special targets like .END don't need any children. */ | | 765 | /* Special targets like .END don't need any children. */ |
766 | if (!isSpecial) | | 766 | if (!isSpecial) |
767 | Lst_Append(&cgn->parents, pgn); | | 767 | Lst_Append(&cgn->parents, pgn); |
768 | | | 768 | |
769 | if (DEBUG(PARSE)) { | | 769 | if (DEBUG(PARSE)) { |
770 | debug_printf("# %s: added child %s - %s\n", | | 770 | debug_printf("# %s: added child %s - %s\n", |
771 | __func__, pgn->name, cgn->name); | | 771 | __func__, pgn->name, cgn->name); |
772 | Targ_PrintNode(pgn, 0); | | 772 | Targ_PrintNode(pgn, 0); |
773 | Targ_PrintNode(cgn, 0); | | 773 | Targ_PrintNode(cgn, 0); |
774 | } | | 774 | } |
775 | } | | 775 | } |
776 | | | 776 | |
777 | /* Add the node to each target from the current dependency group. */ | | 777 | /* Add the node to each target from the current dependency group. */ |
778 | static void | | 778 | static void |
779 | LinkToTargets(GNode *gn, Boolean isSpecial) | | 779 | LinkToTargets(GNode *gn, Boolean isSpecial) |
780 | { | | 780 | { |
781 | GNodeListNode *ln; | | 781 | GNodeListNode *ln; |
782 | | | 782 | |
783 | for (ln = targets->first; ln != NULL; ln = ln->next) | | 783 | for (ln = targets->first; ln != NULL; ln = ln->next) |
784 | LinkSource(ln->datum, gn, isSpecial); | | 784 | LinkSource(ln->datum, gn, isSpecial); |
785 | } | | 785 | } |
786 | | | 786 | |
787 | static Boolean | | 787 | static Boolean |
788 | TryApplyDependencyOperator(GNode *gn, GNodeType op) | | 788 | TryApplyDependencyOperator(GNode *gn, GNodeType op) |
789 | { | | 789 | { |
790 | /* | | 790 | /* |
791 | * If the node occurred on the left-hand side of a dependency and the | | 791 | * If the node occurred on the left-hand side of a dependency and the |
792 | * operator also defines a dependency, they must match. | | 792 | * operator also defines a dependency, they must match. |
793 | */ | | 793 | */ |
794 | if ((op & OP_OPMASK) && (gn->type & OP_OPMASK) && | | 794 | if ((op & OP_OPMASK) && (gn->type & OP_OPMASK) && |
795 | ((op & OP_OPMASK) != (gn->type & OP_OPMASK))) { | | 795 | ((op & OP_OPMASK) != (gn->type & OP_OPMASK))) { |
796 | Parse_Error(PARSE_FATAL, "Inconsistent operator for %s", | | 796 | Parse_Error(PARSE_FATAL, "Inconsistent operator for %s", |
797 | gn->name); | | 797 | gn->name); |
798 | return FALSE; | | 798 | return FALSE; |
799 | } | | 799 | } |
800 | | | 800 | |
801 | if (op == OP_DOUBLEDEP && (gn->type & OP_OPMASK) == OP_DOUBLEDEP) { | | 801 | if (op == OP_DOUBLEDEP && (gn->type & OP_OPMASK) == OP_DOUBLEDEP) { |
802 | /* | | 802 | /* |
803 | * If the node was of the left-hand side of a '::' operator, | | 803 | * If the node was of the left-hand side of a '::' operator, |
804 | * we need to create a new instance of it for the children | | 804 | * we need to create a new instance of it for the children |
805 | * and commands on this dependency line since each of these | | 805 | * and commands on this dependency line since each of these |
806 | * dependency groups has its own attributes and commands, | | 806 | * dependency groups has its own attributes and commands, |
807 | * separate from the others. | | 807 | * separate from the others. |
808 | * | | 808 | * |
809 | * The new instance is placed on the 'cohorts' list of the | | 809 | * The new instance is placed on the 'cohorts' list of the |
810 | * initial one (note the initial one is not on its own | | 810 | * initial one (note the initial one is not on its own |
811 | * cohorts list) and the new instance is linked to all | | 811 | * cohorts list) and the new instance is linked to all |
812 | * parents of the initial instance. | | 812 | * parents of the initial instance. |
813 | */ | | 813 | */ |
814 | GNode *cohort; | | 814 | GNode *cohort; |
815 | | | 815 | |
816 | /* | | 816 | /* |
817 | * Propagate copied bits to the initial node. They'll be | | 817 | * Propagate copied bits to the initial node. They'll be |
818 | * propagated back to the rest of the cohorts later. | | 818 | * propagated back to the rest of the cohorts later. |
819 | */ | | 819 | */ |
820 | gn->type |= op & ~OP_OPMASK; | | 820 | gn->type |= op & ~OP_OPMASK; |
821 | | | 821 | |
822 | cohort = Targ_NewInternalNode(gn->name); | | 822 | cohort = Targ_NewInternalNode(gn->name); |
823 | if (doing_depend) | | 823 | if (doing_depend) |
824 | ParseMark(cohort); | | 824 | ParseMark(cohort); |
825 | /* | | 825 | /* |
826 | * Make the cohort invisible as well to avoid duplicating it | | 826 | * Make the cohort invisible as well to avoid duplicating it |
827 | * into other variables. True, parents of this target won't | | 827 | * into other variables. True, parents of this target won't |
828 | * tend to do anything with their local variables, but better | | 828 | * tend to do anything with their local variables, but better |
829 | * safe than sorry. | | 829 | * safe than sorry. |
830 | * | | 830 | * |
831 | * (I think this is pointless now, since the relevant list | | 831 | * (I think this is pointless now, since the relevant list |
832 | * traversals will no longer see this node anyway. -mycroft) | | 832 | * traversals will no longer see this node anyway. -mycroft) |
833 | */ | | 833 | */ |
834 | cohort->type = op | OP_INVISIBLE; | | 834 | cohort->type = op | OP_INVISIBLE; |
835 | Lst_Append(&gn->cohorts, cohort); | | 835 | Lst_Append(&gn->cohorts, cohort); |
836 | cohort->centurion = gn; | | 836 | cohort->centurion = gn; |
837 | gn->unmade_cohorts++; | | 837 | gn->unmade_cohorts++; |
838 | snprintf(cohort->cohort_num, sizeof cohort->cohort_num, "#%d", | | 838 | snprintf(cohort->cohort_num, sizeof cohort->cohort_num, "#%d", |
839 | (unsigned int)gn->unmade_cohorts % 1000000); | | 839 | (unsigned int)gn->unmade_cohorts % 1000000); |
840 | } else { | | 840 | } else { |
841 | /* | | 841 | /* |
842 | * We don't want to nuke any previous flags (whatever they | | 842 | * We don't want to nuke any previous flags (whatever they |
843 | * were) so we just OR the new operator into the old. | | 843 | * were) so we just OR the new operator into the old. |
844 | */ | | 844 | */ |
845 | gn->type |= op; | | 845 | gn->type |= op; |
846 | } | | 846 | } |
847 | | | 847 | |
848 | return TRUE; | | 848 | return TRUE; |
849 | } | | 849 | } |
850 | | | 850 | |
851 | static void | | 851 | static void |
852 | ApplyDependencyOperator(GNodeType op) | | 852 | ApplyDependencyOperator(GNodeType op) |
853 | { | | 853 | { |
854 | GNodeListNode *ln; | | 854 | GNodeListNode *ln; |
855 | | | 855 | |
856 | for (ln = targets->first; ln != NULL; ln = ln->next) | | 856 | for (ln = targets->first; ln != NULL; ln = ln->next) |
857 | if (!TryApplyDependencyOperator(ln->datum, op)) | | 857 | if (!TryApplyDependencyOperator(ln->datum, op)) |
858 | break; | | 858 | break; |
859 | } | | 859 | } |
860 | | | 860 | |
861 | /* | | 861 | /* |
862 | * We add a .WAIT node in the dependency list. After any dynamic dependencies | | 862 | * We add a .WAIT node in the dependency list. After any dynamic dependencies |
863 | * (and filename globbing) have happened, it is given a dependency on each | | 863 | * (and filename globbing) have happened, it is given a dependency on each |
864 | * previous child, back until the previous .WAIT node. The next child won't | | 864 | * previous child, back until the previous .WAIT node. The next child won't |
865 | * be scheduled until the .WAIT node is built. | | 865 | * be scheduled until the .WAIT node is built. |
866 | * | | 866 | * |
867 | * We give each .WAIT node a unique name (mainly for diagnostics). | | 867 | * We give each .WAIT node a unique name (mainly for diagnostics). |
868 | */ | | 868 | */ |
869 | static void | | 869 | static void |
870 | ParseDependencySourceWait(Boolean isSpecial) | | 870 | ParseDependencySourceWait(Boolean isSpecial) |
871 | { | | 871 | { |
872 | static int wait_number = 0; | | 872 | static int wait_number = 0; |
873 | char wait_src[16]; | | 873 | char wait_src[16]; |
874 | GNode *gn; | | 874 | GNode *gn; |
875 | | | 875 | |
876 | snprintf(wait_src, sizeof wait_src, ".WAIT_%u", ++wait_number); | | 876 | snprintf(wait_src, sizeof wait_src, ".WAIT_%u", ++wait_number); |
877 | gn = Targ_NewInternalNode(wait_src); | | 877 | gn = Targ_NewInternalNode(wait_src); |
878 | if (doing_depend) | | 878 | if (doing_depend) |
879 | ParseMark(gn); | | 879 | ParseMark(gn); |
880 | gn->type = OP_WAIT | OP_PHONY | OP_DEPENDS | OP_NOTMAIN; | | 880 | gn->type = OP_WAIT | OP_PHONY | OP_DEPENDS | OP_NOTMAIN; |
881 | LinkToTargets(gn, isSpecial); | | 881 | LinkToTargets(gn, isSpecial); |
882 | | | 882 | |
883 | } | | 883 | } |
884 | | | 884 | |
885 | static Boolean | | 885 | static Boolean |
886 | ParseDependencySourceKeyword(const char *src, ParseSpecial specType) | | 886 | ParseDependencySourceKeyword(const char *src, ParseSpecial specType) |
887 | { | | 887 | { |
888 | int keywd; | | 888 | int keywd; |
889 | GNodeType op; | | 889 | GNodeType op; |
890 | | | 890 | |
891 | if (*src != '.' || !ch_isupper(src[1])) | | 891 | if (*src != '.' || !ch_isupper(src[1])) |
892 | return FALSE; | | 892 | return FALSE; |
893 | | | 893 | |
894 | keywd = ParseFindKeyword(src); | | 894 | keywd = ParseFindKeyword(src); |
895 | if (keywd == -1) | | 895 | if (keywd == -1) |
896 | return FALSE; | | 896 | return FALSE; |
897 | | | 897 | |
898 | op = parseKeywords[keywd].op; | | 898 | op = parseKeywords[keywd].op; |
899 | if (op != OP_NONE) { | | 899 | if (op != OP_NONE) { |
900 | ApplyDependencyOperator(op); | | 900 | ApplyDependencyOperator(op); |
901 | return TRUE; | | 901 | return TRUE; |
902 | } | | 902 | } |
903 | if (parseKeywords[keywd].spec == SP_WAIT) { | | 903 | if (parseKeywords[keywd].spec == SP_WAIT) { |
904 | ParseDependencySourceWait(specType != SP_NOT); | | 904 | ParseDependencySourceWait(specType != SP_NOT); |
905 | return TRUE; | | 905 | return TRUE; |
906 | } | | 906 | } |
907 | return FALSE; | | 907 | return FALSE; |
908 | } | | 908 | } |
909 | | | 909 | |
910 | static void | | 910 | static void |
911 | ParseDependencySourceMain(const char *src) | | 911 | ParseDependencySourceMain(const char *src) |
912 | { | | 912 | { |
913 | /* | | 913 | /* |
914 | * In a line like ".MAIN: source1 source2", it means we need to add | | 914 | * In a line like ".MAIN: source1 source2", it means we need to add |
915 | * the sources of said target to the list of things to create. | | 915 | * the sources of said target to the list of things to create. |
916 | * | | 916 | * |
917 | * Note that this will only be invoked if the user didn't specify a | | 917 | * Note that this will only be invoked if the user didn't specify a |
918 | * target on the command line and the .MAIN occurs for the first time. | | 918 | * target on the command line and the .MAIN occurs for the first time. |
919 | * | | 919 | * |
920 | * See ParseDoDependencyTargetSpecial, branch SP_MAIN. | | 920 | * See ParseDoDependencyTargetSpecial, branch SP_MAIN. |
921 | * See unit-tests/cond-func-make-main.mk. | | 921 | * See unit-tests/cond-func-make-main.mk. |
922 | */ | | 922 | */ |
923 | Lst_Append(&opts.create, bmake_strdup(src)); | | 923 | Lst_Append(&opts.create, bmake_strdup(src)); |
924 | /* | | 924 | /* |
925 | * Add the name to the .TARGETS variable as well, so the user can | | 925 | * Add the name to the .TARGETS variable as well, so the user can |
926 | * employ that, if desired. | | 926 | * employ that, if desired. |
927 | */ | | 927 | */ |
928 | Var_Append(".TARGETS", src, VAR_GLOBAL); | | 928 | Var_Append(".TARGETS", src, VAR_GLOBAL); |
929 | } | | 929 | } |
930 | | | 930 | |
931 | static void | | 931 | static void |
932 | ParseDependencySourceOrder(const char *src) | | 932 | ParseDependencySourceOrder(const char *src) |
933 | { | | 933 | { |
934 | GNode *gn; | | 934 | GNode *gn; |
935 | /* | | 935 | /* |
936 | * Create proper predecessor/successor links between the previous | | 936 | * Create proper predecessor/successor links between the previous |
937 | * source and the current one. | | 937 | * source and the current one. |
938 | */ | | 938 | */ |
939 | gn = Targ_GetNode(src); | | 939 | gn = Targ_GetNode(src); |
940 | if (doing_depend) | | 940 | if (doing_depend) |
941 | ParseMark(gn); | | 941 | ParseMark(gn); |
942 | if (order_pred != NULL) { | | 942 | if (order_pred != NULL) { |
943 | Lst_Append(&order_pred->order_succ, gn); | | 943 | Lst_Append(&order_pred->order_succ, gn); |
944 | Lst_Append(&gn->order_pred, order_pred); | | 944 | Lst_Append(&gn->order_pred, order_pred); |
945 | if (DEBUG(PARSE)) { | | 945 | if (DEBUG(PARSE)) { |
946 | debug_printf("# %s: added Order dependency %s - %s\n", | | 946 | debug_printf("# %s: added Order dependency %s - %s\n", |
947 | __func__, order_pred->name, gn->name); | | 947 | __func__, order_pred->name, gn->name); |
948 | Targ_PrintNode(order_pred, 0); | | 948 | Targ_PrintNode(order_pred, 0); |
949 | Targ_PrintNode(gn, 0); | | 949 | Targ_PrintNode(gn, 0); |
950 | } | | 950 | } |
951 | } | | 951 | } |
952 | /* | | 952 | /* |
953 | * The current source now becomes the predecessor for the next one. | | 953 | * The current source now becomes the predecessor for the next one. |
954 | */ | | 954 | */ |
955 | order_pred = gn; | | 955 | order_pred = gn; |
956 | } | | 956 | } |
957 | | | 957 | |
958 | static void | | 958 | static void |
959 | ParseDependencySourceOther(const char *src, GNodeType tOp, | | 959 | ParseDependencySourceOther(const char *src, GNodeType tOp, |
960 | ParseSpecial specType) | | 960 | ParseSpecial specType) |
961 | { | | 961 | { |
962 | GNode *gn; | | 962 | GNode *gn; |
963 | | | 963 | |
964 | /* | | 964 | /* |
965 | * If the source is not an attribute, we need to find/create | | 965 | * If the source is not an attribute, we need to find/create |
966 | * a node for it. After that we can apply any operator to it | | 966 | * a node for it. After that we can apply any operator to it |
967 | * from a special target or link it to its parents, as | | 967 | * from a special target or link it to its parents, as |
968 | * appropriate. | | 968 | * appropriate. |
969 | * | | 969 | * |
970 | * In the case of a source that was the object of a :: operator, | | 970 | * In the case of a source that was the object of a :: operator, |
971 | * the attribute is applied to all of its instances (as kept in | | 971 | * the attribute is applied to all of its instances (as kept in |
972 | * the 'cohorts' list of the node) or all the cohorts are linked | | 972 | * the 'cohorts' list of the node) or all the cohorts are linked |
973 | * to all the targets. | | 973 | * to all the targets. |
974 | */ | | 974 | */ |
975 | | | 975 | |
976 | /* Find/create the 'src' node and attach to all targets */ | | 976 | /* Find/create the 'src' node and attach to all targets */ |
977 | gn = Targ_GetNode(src); | | 977 | gn = Targ_GetNode(src); |
978 | if (doing_depend) | | 978 | if (doing_depend) |
979 | ParseMark(gn); | | 979 | ParseMark(gn); |
980 | if (tOp != OP_NONE) | | 980 | if (tOp != OP_NONE) |
981 | gn->type |= tOp; | | 981 | gn->type |= tOp; |
982 | else | | 982 | else |
983 | LinkToTargets(gn, specType != SP_NOT); | | 983 | LinkToTargets(gn, specType != SP_NOT); |
984 | } | | 984 | } |
985 | | | 985 | |
986 | /* | | 986 | /* |
987 | * Given the name of a source in a dependency line, figure out if it is an | | 987 | * Given the name of a source in a dependency line, figure out if it is an |
988 | * attribute (such as .SILENT) and apply it to the targets if it is. Else | | 988 | * attribute (such as .SILENT) and apply it to the targets if it is. Else |
989 | * decide if there is some attribute which should be applied *to* the source | | 989 | * decide if there is some attribute which should be applied *to* the source |
990 | * because of some special target (such as .PHONY) and apply it if so. | | 990 | * because of some special target (such as .PHONY) and apply it if so. |
991 | * Otherwise, make the source a child of the targets in the list 'targets'. | | 991 | * Otherwise, make the source a child of the targets in the list 'targets'. |
992 | * | | 992 | * |
993 | * Input: | | 993 | * Input: |
994 | * tOp operator (if any) from special targets | | 994 | * tOp operator (if any) from special targets |
995 | * src name of the source to handle | | 995 | * src name of the source to handle |
996 | */ | | 996 | */ |
997 | static void | | 997 | static void |
998 | ParseDependencySource(GNodeType tOp, const char *src, ParseSpecial specType) | | 998 | ParseDependencySource(GNodeType tOp, const char *src, ParseSpecial specType) |
999 | { | | 999 | { |
1000 | if (ParseDependencySourceKeyword(src, specType)) | | 1000 | if (ParseDependencySourceKeyword(src, specType)) |
1001 | return; | | 1001 | return; |
1002 | | | 1002 | |
1003 | if (specType == SP_MAIN) | | 1003 | if (specType == SP_MAIN) |
1004 | ParseDependencySourceMain(src); | | 1004 | ParseDependencySourceMain(src); |
1005 | else if (specType == SP_ORDER) | | 1005 | else if (specType == SP_ORDER) |
1006 | ParseDependencySourceOrder(src); | | 1006 | ParseDependencySourceOrder(src); |
1007 | else | | 1007 | else |
1008 | ParseDependencySourceOther(src, tOp, specType); | | 1008 | ParseDependencySourceOther(src, tOp, specType); |
1009 | } | | 1009 | } |
1010 | | | 1010 | |
1011 | /* | | 1011 | /* |
1012 | * If we have yet to decide on a main target to make, in the absence of any | | 1012 | * If we have yet to decide on a main target to make, in the absence of any |
1013 | * user input, we want the first target on the first dependency line that is | | 1013 | * user input, we want the first target on the first dependency line that is |
1014 | * actually a real target (i.e. isn't a .USE or .EXEC rule) to be made. | | 1014 | * actually a real target (i.e. isn't a .USE or .EXEC rule) to be made. |
1015 | */ | | 1015 | */ |
1016 | static void | | 1016 | static void |
1017 | FindMainTarget(void) | | 1017 | FindMainTarget(void) |
1018 | { | | 1018 | { |
1019 | GNodeListNode *ln; | | 1019 | GNodeListNode *ln; |
1020 | | | 1020 | |
1021 | if (mainNode != NULL) | | 1021 | if (mainNode != NULL) |
1022 | return; | | 1022 | return; |
1023 | | | 1023 | |
1024 | for (ln = targets->first; ln != NULL; ln = ln->next) { | | 1024 | for (ln = targets->first; ln != NULL; ln = ln->next) { |
1025 | GNode *gn = ln->datum; | | 1025 | GNode *gn = ln->datum; |
1026 | if (!(gn->type & OP_NOTARGET)) { | | 1026 | if (!(gn->type & OP_NOTARGET)) { |
1027 | DEBUG1(MAKE, "Setting main node to \"%s\"\n", gn->name); | | 1027 | DEBUG1(MAKE, "Setting main node to \"%s\"\n", gn->name); |
1028 | mainNode = gn; | | 1028 | mainNode = gn; |
1029 | Targ_SetMain(gn); | | 1029 | Targ_SetMain(gn); |
1030 | return; | | 1030 | return; |
1031 | } | | 1031 | } |
1032 | } | | 1032 | } |
1033 | } | | 1033 | } |
1034 | | | 1034 | |
1035 | /* | | 1035 | /* |
1036 | * We got to the end of the line while we were still looking at targets. | | 1036 | * We got to the end of the line while we were still looking at targets. |
1037 | * | | 1037 | * |
1038 | * Ending a dependency line without an operator is a Bozo no-no. As a | | 1038 | * Ending a dependency line without an operator is a Bozo no-no. As a |
1039 | * heuristic, this is also often triggered by undetected conflicts from | | 1039 | * heuristic, this is also often triggered by undetected conflicts from |
1040 | * cvs/rcs merges. | | 1040 | * cvs/rcs merges. |
1041 | */ | | 1041 | */ |
1042 | static void | | 1042 | static void |
1043 | ParseErrorNoDependency(const char *lstart) | | 1043 | ParseErrorNoDependency(const char *lstart) |
1044 | { | | 1044 | { |
1045 | if ((strncmp(lstart, "<<<<<<", 6) == 0) || | | 1045 | if ((strncmp(lstart, "<<<<<<", 6) == 0) || |
1046 | (strncmp(lstart, "======", 6) == 0) || | | 1046 | (strncmp(lstart, "======", 6) == 0) || |
1047 | (strncmp(lstart, ">>>>>>", 6) == 0)) | | 1047 | (strncmp(lstart, ">>>>>>", 6) == 0)) |
1048 | Parse_Error(PARSE_FATAL, | | 1048 | Parse_Error(PARSE_FATAL, |
1049 | "Makefile appears to contain unresolved cvs/rcs/??? merge conflicts"); | | 1049 | "Makefile appears to contain unresolved cvs/rcs/??? merge conflicts"); |
1050 | else if (lstart[0] == '.') { | | 1050 | else if (lstart[0] == '.') { |
1051 | const char *dirstart = lstart + 1; | | 1051 | const char *dirstart = lstart + 1; |
1052 | const char *dirend; | | 1052 | const char *dirend; |
1053 | cpp_skip_whitespace(&dirstart); | | 1053 | cpp_skip_whitespace(&dirstart); |
1054 | dirend = dirstart; | | 1054 | dirend = dirstart; |
1055 | while (ch_isalnum(*dirend) || *dirend == '-') | | 1055 | while (ch_isalnum(*dirend) || *dirend == '-') |
1056 | dirend++; | | 1056 | dirend++; |
1057 | Parse_Error(PARSE_FATAL, "Unknown directive \"%.*s\"", | | 1057 | Parse_Error(PARSE_FATAL, "Unknown directive \"%.*s\"", |
1058 | (int)(dirend - dirstart), dirstart); | | 1058 | (int)(dirend - dirstart), dirstart); |
1059 | } else | | 1059 | } else |
1060 | Parse_Error(PARSE_FATAL, "Need an operator"); | | 1060 | Parse_Error(PARSE_FATAL, "Need an operator"); |
1061 | } | | 1061 | } |
1062 | | | 1062 | |
1063 | static void | | 1063 | static void |
1064 | ParseDependencyTargetWord(const char **pp, const char *lstart) | | 1064 | ParseDependencyTargetWord(const char **pp, const char *lstart) |
1065 | { | | 1065 | { |
1066 | const char *cp = *pp; | | 1066 | const char *cp = *pp; |
1067 | | | 1067 | |
1068 | while (*cp != '\0') { | | 1068 | while (*cp != '\0') { |
1069 | if ((ch_isspace(*cp) || *cp == '!' || *cp == ':' || | | 1069 | if ((ch_isspace(*cp) || *cp == '!' || *cp == ':' || |
1070 | *cp == '(') && | | 1070 | *cp == '(') && |
1071 | !ParseIsEscaped(lstart, cp)) | | 1071 | !ParseIsEscaped(lstart, cp)) |
1072 | break; | | 1072 | break; |
1073 | | | 1073 | |
1074 | if (*cp == '$') { | | 1074 | if (*cp == '$') { |
1075 | /* | | 1075 | /* |
1076 | * Must be a dynamic source (would have been expanded | | 1076 | * Must be a dynamic source (would have been expanded |
1077 | * otherwise), so call the Var module to parse the | | 1077 | * otherwise), so call the Var module to parse the |
1078 | * puppy so we can safely advance beyond it. | | 1078 | * puppy so we can safely advance beyond it. |
1079 | * | | 1079 | * |
1080 | * There should be no errors in this, as they would | | 1080 | * There should be no errors in this, as they would |
1081 | * have been discovered in the initial Var_Subst and | | 1081 | * have been discovered in the initial Var_Subst and |
1082 | * we wouldn't be here. | | 1082 | * we wouldn't be here. |
1083 | */ | | 1083 | */ |
1084 | const char *nested_p = cp; | | 1084 | const char *nested_p = cp; |
1085 | FStr nested_val; | | 1085 | FStr nested_val; |
1086 | | | 1086 | |
1087 | /* XXX: Why VARE_WANTRES? */ | | 1087 | (void)Var_Parse(&nested_p, VAR_CMDLINE, VARE_NONE, |
1088 | (void)Var_Parse(&nested_p, VAR_CMDLINE, | | 1088 | &nested_val); |
1089 | VARE_WANTRES | VARE_UNDEFERR, &nested_val); | | | |
1090 | /* TODO: handle errors */ | | 1089 | /* TODO: handle errors */ |
1091 | FStr_Done(&nested_val); | | 1090 | FStr_Done(&nested_val); |
1092 | cp += nested_p - cp; | | 1091 | cp += nested_p - cp; |
1093 | } else | | 1092 | } else |
1094 | cp++; | | 1093 | cp++; |
1095 | } | | 1094 | } |
1096 | | | 1095 | |
1097 | *pp = cp; | | 1096 | *pp = cp; |
1098 | } | | 1097 | } |
1099 | | | 1098 | |
1100 | /* Handle special targets like .PATH, .DEFAULT, .BEGIN, .ORDER. */ | | 1099 | /* Handle special targets like .PATH, .DEFAULT, .BEGIN, .ORDER. */ |
1101 | static void | | 1100 | static void |
1102 | ParseDoDependencyTargetSpecial(ParseSpecial *inout_specType, | | 1101 | ParseDoDependencyTargetSpecial(ParseSpecial *inout_specType, |
1103 | const char *line, /* XXX: bad name */ | | 1102 | const char *line, /* XXX: bad name */ |
1104 | SearchPathList **inout_paths) | | 1103 | SearchPathList **inout_paths) |
1105 | { | | 1104 | { |
1106 | switch (*inout_specType) { | | 1105 | switch (*inout_specType) { |
1107 | case SP_PATH: | | 1106 | case SP_PATH: |
1108 | if (*inout_paths == NULL) | | 1107 | if (*inout_paths == NULL) |
1109 | *inout_paths = Lst_New(); | | 1108 | *inout_paths = Lst_New(); |
1110 | Lst_Append(*inout_paths, &dirSearchPath); | | 1109 | Lst_Append(*inout_paths, &dirSearchPath); |
1111 | break; | | 1110 | break; |
1112 | case SP_MAIN: | | 1111 | case SP_MAIN: |
1113 | /* | | 1112 | /* |
1114 | * Allow targets from the command line to override the | | 1113 | * Allow targets from the command line to override the |
1115 | * .MAIN node. | | 1114 | * .MAIN node. |
1116 | */ | | 1115 | */ |
1117 | if (!Lst_IsEmpty(&opts.create)) | | 1116 | if (!Lst_IsEmpty(&opts.create)) |
1118 | *inout_specType = SP_NOT; | | 1117 | *inout_specType = SP_NOT; |
1119 | break; | | 1118 | break; |
1120 | case SP_BEGIN: | | 1119 | case SP_BEGIN: |
1121 | case SP_END: | | 1120 | case SP_END: |
1122 | case SP_STALE: | | 1121 | case SP_STALE: |
1123 | case SP_ERROR: | | 1122 | case SP_ERROR: |
1124 | case SP_INTERRUPT: { | | 1123 | case SP_INTERRUPT: { |
1125 | GNode *gn = Targ_GetNode(line); | | 1124 | GNode *gn = Targ_GetNode(line); |
1126 | if (doing_depend) | | 1125 | if (doing_depend) |
1127 | ParseMark(gn); | | 1126 | ParseMark(gn); |
1128 | gn->type |= OP_NOTMAIN | OP_SPECIAL; | | 1127 | gn->type |= OP_NOTMAIN | OP_SPECIAL; |
1129 | Lst_Append(targets, gn); | | 1128 | Lst_Append(targets, gn); |
1130 | break; | | 1129 | break; |
1131 | } | | 1130 | } |
1132 | case SP_DEFAULT: { | | 1131 | case SP_DEFAULT: { |
1133 | /* | | 1132 | /* |
1134 | * Need to create a node to hang commands on, but we don't | | 1133 | * Need to create a node to hang commands on, but we don't |
1135 | * want it in the graph, nor do we want it to be the Main | | 1134 | * want it in the graph, nor do we want it to be the Main |
1136 | * Target. We claim the node is a transformation rule to make | | 1135 | * Target. We claim the node is a transformation rule to make |
1137 | * life easier later, when we'll use Make_HandleUse to | | 1136 | * life easier later, when we'll use Make_HandleUse to |
1138 | * actually apply the .DEFAULT commands. | | 1137 | * actually apply the .DEFAULT commands. |
1139 | */ | | 1138 | */ |
1140 | GNode *gn = GNode_New(".DEFAULT"); | | 1139 | GNode *gn = GNode_New(".DEFAULT"); |
1141 | gn->type |= OP_NOTMAIN | OP_TRANSFORM; | | 1140 | gn->type |= OP_NOTMAIN | OP_TRANSFORM; |
1142 | Lst_Append(targets, gn); | | 1141 | Lst_Append(targets, gn); |
1143 | defaultNode = gn; | | 1142 | defaultNode = gn; |
1144 | break; | | 1143 | break; |
1145 | } | | 1144 | } |
1146 | case SP_DELETE_ON_ERROR: | | 1145 | case SP_DELETE_ON_ERROR: |
1147 | deleteOnError = TRUE; | | 1146 | deleteOnError = TRUE; |
1148 | break; | | 1147 | break; |
1149 | case SP_NOTPARALLEL: | | 1148 | case SP_NOTPARALLEL: |
1150 | opts.maxJobs = 1; | | 1149 | opts.maxJobs = 1; |
1151 | break; | | 1150 | break; |
1152 | case SP_SINGLESHELL: | | 1151 | case SP_SINGLESHELL: |
1153 | opts.compatMake = TRUE; | | 1152 | opts.compatMake = TRUE; |
1154 | break; | | 1153 | break; |
1155 | case SP_ORDER: | | 1154 | case SP_ORDER: |
1156 | order_pred = NULL; | | 1155 | order_pred = NULL; |
1157 | break; | | 1156 | break; |
1158 | default: | | 1157 | default: |
1159 | break; | | 1158 | break; |
1160 | } | | 1159 | } |
1161 | } | | 1160 | } |
1162 | | | 1161 | |
1163 | /* | | 1162 | /* |
1164 | * .PATH<suffix> has to be handled specially. | | 1163 | * .PATH<suffix> has to be handled specially. |
1165 | * Call on the suffix module to give us a path to modify. | | 1164 | * Call on the suffix module to give us a path to modify. |
1166 | */ | | 1165 | */ |
1167 | static Boolean | | 1166 | static Boolean |
1168 | ParseDoDependencyTargetPath(const char *line, /* XXX: bad name */ | | 1167 | ParseDoDependencyTargetPath(const char *line, /* XXX: bad name */ |
1169 | SearchPathList **inout_paths) | | 1168 | SearchPathList **inout_paths) |
1170 | { | | 1169 | { |
1171 | SearchPath *path; | | 1170 | SearchPath *path; |
1172 | | | 1171 | |
1173 | path = Suff_GetPath(&line[5]); | | 1172 | path = Suff_GetPath(&line[5]); |
1174 | if (path == NULL) { | | 1173 | if (path == NULL) { |
1175 | Parse_Error(PARSE_FATAL, | | 1174 | Parse_Error(PARSE_FATAL, |
1176 | "Suffix '%s' not defined (yet)", &line[5]); | | 1175 | "Suffix '%s' not defined (yet)", &line[5]); |
1177 | return FALSE; | | 1176 | return FALSE; |
1178 | } | | 1177 | } |
1179 | | | 1178 | |
1180 | if (*inout_paths == NULL) | | 1179 | if (*inout_paths == NULL) |
1181 | *inout_paths = Lst_New(); | | 1180 | *inout_paths = Lst_New(); |
1182 | Lst_Append(*inout_paths, path); | | 1181 | Lst_Append(*inout_paths, path); |
1183 | | | 1182 | |
1184 | return TRUE; | | 1183 | return TRUE; |
1185 | } | | 1184 | } |
1186 | | | 1185 | |
1187 | /* | | 1186 | /* |
1188 | * See if it's a special target and if so set specType to match it. | | 1187 | * See if it's a special target and if so set specType to match it. |
1189 | */ | | 1188 | */ |
1190 | static Boolean | | 1189 | static Boolean |
1191 | ParseDoDependencyTarget(const char *line, /* XXX: bad name */ | | 1190 | ParseDoDependencyTarget(const char *line, /* XXX: bad name */ |
1192 | ParseSpecial *inout_specType, | | 1191 | ParseSpecial *inout_specType, |
1193 | GNodeType *out_tOp, SearchPathList **inout_paths) | | 1192 | GNodeType *out_tOp, SearchPathList **inout_paths) |
1194 | { | | 1193 | { |
1195 | int keywd; | | 1194 | int keywd; |
1196 | | | 1195 | |
1197 | if (!(line[0] == '.' && ch_isupper(line[1]))) | | 1196 | if (!(line[0] == '.' && ch_isupper(line[1]))) |
1198 | return TRUE; | | 1197 | return TRUE; |
1199 | | | 1198 | |
1200 | /* | | 1199 | /* |
1201 | * See if the target is a special target that must have it | | 1200 | * See if the target is a special target that must have it |
1202 | * or its sources handled specially. | | 1201 | * or its sources handled specially. |
1203 | */ | | 1202 | */ |
1204 | keywd = ParseFindKeyword(line); | | 1203 | keywd = ParseFindKeyword(line); |
1205 | if (keywd != -1) { | | 1204 | if (keywd != -1) { |
1206 | if (*inout_specType == SP_PATH && | | 1205 | if (*inout_specType == SP_PATH && |
1207 | parseKeywords[keywd].spec != SP_PATH) { | | 1206 | parseKeywords[keywd].spec != SP_PATH) { |
1208 | Parse_Error(PARSE_FATAL, "Mismatched special targets"); | | 1207 | Parse_Error(PARSE_FATAL, "Mismatched special targets"); |
1209 | return FALSE; | | 1208 | return FALSE; |
1210 | } | | 1209 | } |
1211 | | | 1210 | |
1212 | *inout_specType = parseKeywords[keywd].spec; | | 1211 | *inout_specType = parseKeywords[keywd].spec; |
1213 | *out_tOp = parseKeywords[keywd].op; | | 1212 | *out_tOp = parseKeywords[keywd].op; |
1214 | | | 1213 | |
1215 | ParseDoDependencyTargetSpecial(inout_specType, line, | | 1214 | ParseDoDependencyTargetSpecial(inout_specType, line, |
1216 | inout_paths); | | 1215 | inout_paths); |
1217 | | | 1216 | |
1218 | } else if (strncmp(line, ".PATH", 5) == 0) { | | 1217 | } else if (strncmp(line, ".PATH", 5) == 0) { |
1219 | *inout_specType = SP_PATH; | | 1218 | *inout_specType = SP_PATH; |
1220 | if (!ParseDoDependencyTargetPath(line, inout_paths)) | | 1219 | if (!ParseDoDependencyTargetPath(line, inout_paths)) |
1221 | return FALSE; | | 1220 | return FALSE; |
1222 | } | | 1221 | } |
1223 | return TRUE; | | 1222 | return TRUE; |
1224 | } | | 1223 | } |
1225 | | | 1224 | |
1226 | static void | | 1225 | static void |
1227 | ParseDoDependencyTargetMundane(char *line, /* XXX: bad name */ | | 1226 | ParseDoDependencyTargetMundane(char *line, /* XXX: bad name */ |
1228 | StringList *curTargs) | | 1227 | StringList *curTargs) |
1229 | { | | 1228 | { |
1230 | if (Dir_HasWildcards(line)) { | | 1229 | if (Dir_HasWildcards(line)) { |
1231 | /* | | 1230 | /* |
1232 | * Targets are to be sought only in the current directory, | | 1231 | * Targets are to be sought only in the current directory, |
1233 | * so create an empty path for the thing. Note we need to | | 1232 | * so create an empty path for the thing. Note we need to |
1234 | * use Dir_Destroy in the destruction of the path as the | | 1233 | * use Dir_Destroy in the destruction of the path as the |
1235 | * Dir module could have added a directory to the path... | | 1234 | * Dir module could have added a directory to the path... |
1236 | */ | | 1235 | */ |
1237 | SearchPath *emptyPath = SearchPath_New(); | | 1236 | SearchPath *emptyPath = SearchPath_New(); |
1238 | | | 1237 | |
1239 | Dir_Expand(line, emptyPath, curTargs); | | 1238 | Dir_Expand(line, emptyPath, curTargs); |
1240 | | | 1239 | |
1241 | SearchPath_Free(emptyPath); | | 1240 | SearchPath_Free(emptyPath); |
1242 | } else { | | 1241 | } else { |
1243 | /* | | 1242 | /* |
1244 | * No wildcards, but we want to avoid code duplication, | | 1243 | * No wildcards, but we want to avoid code duplication, |
1245 | * so create a list with the word on it. | | 1244 | * so create a list with the word on it. |
1246 | */ | | 1245 | */ |
1247 | Lst_Append(curTargs, line); | | 1246 | Lst_Append(curTargs, line); |
1248 | } | | 1247 | } |
1249 | | | 1248 | |
1250 | /* Apply the targets. */ | | 1249 | /* Apply the targets. */ |
1251 | | | 1250 | |
1252 | while (!Lst_IsEmpty(curTargs)) { | | 1251 | while (!Lst_IsEmpty(curTargs)) { |
1253 | char *targName = Lst_Dequeue(curTargs); | | 1252 | char *targName = Lst_Dequeue(curTargs); |
1254 | GNode *gn = Suff_IsTransform(targName) | | 1253 | GNode *gn = Suff_IsTransform(targName) |
1255 | ? Suff_AddTransform(targName) | | 1254 | ? Suff_AddTransform(targName) |
1256 | : Targ_GetNode(targName); | | 1255 | : Targ_GetNode(targName); |
1257 | if (doing_depend) | | 1256 | if (doing_depend) |
1258 | ParseMark(gn); | | 1257 | ParseMark(gn); |
1259 | | | 1258 | |
1260 | Lst_Append(targets, gn); | | 1259 | Lst_Append(targets, gn); |
1261 | } | | 1260 | } |
1262 | } | | 1261 | } |
1263 | | | 1262 | |
1264 | static void | | 1263 | static void |
1265 | ParseDoDependencyTargetExtraWarn(char **pp, const char *lstart) | | 1264 | ParseDoDependencyTargetExtraWarn(char **pp, const char *lstart) |
1266 | { | | 1265 | { |
1267 | Boolean warning = FALSE; | | 1266 | Boolean warning = FALSE; |
1268 | char *cp = *pp; | | 1267 | char *cp = *pp; |
1269 | | | 1268 | |
1270 | while (*cp != '\0') { | | 1269 | while (*cp != '\0') { |
1271 | if (!ParseIsEscaped(lstart, cp) && (*cp == '!' || *cp == ':')) | | 1270 | if (!ParseIsEscaped(lstart, cp) && (*cp == '!' || *cp == ':')) |
1272 | break; | | 1271 | break; |
1273 | if (ParseIsEscaped(lstart, cp) || (*cp != ' ' && *cp != '\t')) | | 1272 | if (ParseIsEscaped(lstart, cp) || (*cp != ' ' && *cp != '\t')) |
1274 | warning = TRUE; | | 1273 | warning = TRUE; |
1275 | cp++; | | 1274 | cp++; |
1276 | } | | 1275 | } |
1277 | if (warning) | | 1276 | if (warning) |
1278 | Parse_Error(PARSE_WARNING, "Extra target ignored"); | | 1277 | Parse_Error(PARSE_WARNING, "Extra target ignored"); |
1279 | | | 1278 | |
1280 | *pp = cp; | | 1279 | *pp = cp; |
1281 | } | | 1280 | } |
1282 | | | 1281 | |
1283 | static void | | 1282 | static void |
1284 | ParseDoDependencyCheckSpec(ParseSpecial specType) | | 1283 | ParseDoDependencyCheckSpec(ParseSpecial specType) |
1285 | { | | 1284 | { |
1286 | switch (specType) { | | 1285 | switch (specType) { |
1287 | default: | | 1286 | default: |
1288 | Parse_Error(PARSE_WARNING, | | 1287 | Parse_Error(PARSE_WARNING, |
1289 | "Special and mundane targets don't mix. " | | 1288 | "Special and mundane targets don't mix. " |
1290 | "Mundane ones ignored"); | | 1289 | "Mundane ones ignored"); |
1291 | break; | | 1290 | break; |
1292 | case SP_DEFAULT: | | 1291 | case SP_DEFAULT: |
1293 | case SP_STALE: | | 1292 | case SP_STALE: |
1294 | case SP_BEGIN: | | 1293 | case SP_BEGIN: |
1295 | case SP_END: | | 1294 | case SP_END: |
1296 | case SP_ERROR: | | 1295 | case SP_ERROR: |
1297 | case SP_INTERRUPT: | | 1296 | case SP_INTERRUPT: |
1298 | /* | | 1297 | /* |
1299 | * These create nodes on which to hang commands, so targets | | 1298 | * These create nodes on which to hang commands, so targets |
1300 | * shouldn't be empty. | | 1299 | * shouldn't be empty. |
1301 | */ | | 1300 | */ |
1302 | case SP_NOT: | | 1301 | case SP_NOT: |
1303 | /* Nothing special here -- targets can be empty if it wants. */ | | 1302 | /* Nothing special here -- targets can be empty if it wants. */ |
1304 | break; | | 1303 | break; |
1305 | } | | 1304 | } |
1306 | } | | 1305 | } |
1307 | | | 1306 | |
1308 | static Boolean | | 1307 | static Boolean |
1309 | ParseDoDependencyParseOp(char **pp, const char *lstart, GNodeType *out_op) | | 1308 | ParseDoDependencyParseOp(char **pp, const char *lstart, GNodeType *out_op) |
1310 | { | | 1309 | { |
1311 | const char *cp = *pp; | | 1310 | const char *cp = *pp; |
1312 | | | 1311 | |
1313 | if (*cp == '!') { | | 1312 | if (*cp == '!') { |
1314 | *out_op = OP_FORCE; | | 1313 | *out_op = OP_FORCE; |
1315 | (*pp)++; | | 1314 | (*pp)++; |
1316 | return TRUE; | | 1315 | return TRUE; |
1317 | } | | 1316 | } |
1318 | | | 1317 | |
1319 | if (*cp == ':') { | | 1318 | if (*cp == ':') { |
1320 | if (cp[1] == ':') { | | 1319 | if (cp[1] == ':') { |
1321 | *out_op = OP_DOUBLEDEP; | | 1320 | *out_op = OP_DOUBLEDEP; |
1322 | (*pp) += 2; | | 1321 | (*pp) += 2; |
1323 | } else { | | 1322 | } else { |
1324 | *out_op = OP_DEPENDS; | | 1323 | *out_op = OP_DEPENDS; |
1325 | (*pp)++; | | 1324 | (*pp)++; |
1326 | } | | 1325 | } |
1327 | return TRUE; | | 1326 | return TRUE; |
1328 | } | | 1327 | } |
1329 | | | 1328 | |
1330 | { | | 1329 | { |
1331 | const char *msg = lstart[0] == '.' | | 1330 | const char *msg = lstart[0] == '.' |
1332 | ? "Unknown directive" : "Missing dependency operator"; | | 1331 | ? "Unknown directive" : "Missing dependency operator"; |
1333 | Parse_Error(PARSE_FATAL, "%s", msg); | | 1332 | Parse_Error(PARSE_FATAL, "%s", msg); |
1334 | return FALSE; | | 1333 | return FALSE; |
1335 | } | | 1334 | } |
1336 | } | | 1335 | } |
1337 | | | 1336 | |
1338 | static void | | 1337 | static void |
1339 | ClearPaths(SearchPathList *paths) | | 1338 | ClearPaths(SearchPathList *paths) |
1340 | { | | 1339 | { |
1341 | if (paths != NULL) { | | 1340 | if (paths != NULL) { |
1342 | SearchPathListNode *ln; | | 1341 | SearchPathListNode *ln; |
1343 | for (ln = paths->first; ln != NULL; ln = ln->next) | | 1342 | for (ln = paths->first; ln != NULL; ln = ln->next) |
1344 | SearchPath_Clear(ln->datum); | | 1343 | SearchPath_Clear(ln->datum); |
1345 | } | | 1344 | } |
1346 | | | 1345 | |
1347 | Dir_SetPATH(); | | 1346 | Dir_SetPATH(); |
1348 | } | | 1347 | } |
1349 | | | 1348 | |
1350 | static void | | 1349 | static void |
1351 | ParseDoDependencySourcesEmpty(ParseSpecial specType, SearchPathList *paths) | | 1350 | ParseDoDependencySourcesEmpty(ParseSpecial specType, SearchPathList *paths) |
1352 | { | | 1351 | { |
1353 | switch (specType) { | | 1352 | switch (specType) { |
1354 | case SP_SUFFIXES: | | 1353 | case SP_SUFFIXES: |
1355 | Suff_ClearSuffixes(); | | 1354 | Suff_ClearSuffixes(); |
1356 | break; | | 1355 | break; |
1357 | case SP_PRECIOUS: | | 1356 | case SP_PRECIOUS: |
1358 | allPrecious = TRUE; | | 1357 | allPrecious = TRUE; |
1359 | break; | | 1358 | break; |
1360 | case SP_IGNORE: | | 1359 | case SP_IGNORE: |
1361 | opts.ignoreErrors = TRUE; | | 1360 | opts.ignoreErrors = TRUE; |
1362 | break; | | 1361 | break; |
1363 | case SP_SILENT: | | 1362 | case SP_SILENT: |
1364 | opts.beSilent = TRUE; | | 1363 | opts.beSilent = TRUE; |
1365 | break; | | 1364 | break; |
1366 | case SP_PATH: | | 1365 | case SP_PATH: |
1367 | ClearPaths(paths); | | 1366 | ClearPaths(paths); |
1368 | break; | | 1367 | break; |
1369 | #ifdef POSIX | | 1368 | #ifdef POSIX |
1370 | case SP_POSIX: | | 1369 | case SP_POSIX: |
1371 | Var_Set("%POSIX", "1003.2", VAR_GLOBAL); | | 1370 | Var_Set("%POSIX", "1003.2", VAR_GLOBAL); |
1372 | break; | | 1371 | break; |
1373 | #endif | | 1372 | #endif |
1374 | default: | | 1373 | default: |
1375 | break; | | 1374 | break; |
1376 | } | | 1375 | } |
1377 | } | | 1376 | } |
1378 | | | 1377 | |
1379 | static void | | 1378 | static void |
1380 | AddToPaths(const char *dir, SearchPathList *paths) | | 1379 | AddToPaths(const char *dir, SearchPathList *paths) |
1381 | { | | 1380 | { |
1382 | if (paths != NULL) { | | 1381 | if (paths != NULL) { |
1383 | SearchPathListNode *ln; | | 1382 | SearchPathListNode *ln; |
1384 | for (ln = paths->first; ln != NULL; ln = ln->next) | | 1383 | for (ln = paths->first; ln != NULL; ln = ln->next) |
1385 | (void)Dir_AddDir(ln->datum, dir); | | 1384 | (void)Dir_AddDir(ln->datum, dir); |
1386 | } | | 1385 | } |
1387 | } | | 1386 | } |
1388 | | | 1387 | |
1389 | /* | | 1388 | /* |
1390 | * If the target was one that doesn't take files as its sources | | 1389 | * If the target was one that doesn't take files as its sources |
1391 | * but takes something like suffixes, we take each | | 1390 | * but takes something like suffixes, we take each |
1392 | * space-separated word on the line as a something and deal | | 1391 | * space-separated word on the line as a something and deal |
1393 | * with it accordingly. | | 1392 | * with it accordingly. |
1394 | * | | 1393 | * |
1395 | * If the target was .SUFFIXES, we take each source as a | | 1394 | * If the target was .SUFFIXES, we take each source as a |
1396 | * suffix and add it to the list of suffixes maintained by the | | 1395 | * suffix and add it to the list of suffixes maintained by the |
1397 | * Suff module. | | 1396 | * Suff module. |
1398 | * | | 1397 | * |
1399 | * If the target was a .PATH, we add the source as a directory | | 1398 | * If the target was a .PATH, we add the source as a directory |
1400 | * to search on the search path. | | 1399 | * to search on the search path. |
1401 | * | | 1400 | * |
1402 | * If it was .INCLUDES, the source is taken to be the suffix of | | 1401 | * If it was .INCLUDES, the source is taken to be the suffix of |
1403 | * files which will be #included and whose search path should | | 1402 | * files which will be #included and whose search path should |
1404 | * be present in the .INCLUDES variable. | | 1403 | * be present in the .INCLUDES variable. |
1405 | * | | 1404 | * |
1406 | * If it was .LIBS, the source is taken to be the suffix of | | 1405 | * If it was .LIBS, the source is taken to be the suffix of |
1407 | * files which are considered libraries and whose search path | | 1406 | * files which are considered libraries and whose search path |
1408 | * should be present in the .LIBS variable. | | 1407 | * should be present in the .LIBS variable. |
1409 | * | | 1408 | * |
1410 | * If it was .NULL, the source is the suffix to use when a file | | 1409 | * If it was .NULL, the source is the suffix to use when a file |
1411 | * has no valid suffix. | | 1410 | * has no valid suffix. |
1412 | * | | 1411 | * |
1413 | * If it was .OBJDIR, the source is a new definition for .OBJDIR, | | 1412 | * If it was .OBJDIR, the source is a new definition for .OBJDIR, |
1414 | * and will cause make to do a new chdir to that path. | | 1413 | * and will cause make to do a new chdir to that path. |
1415 | */ | | 1414 | */ |
1416 | static void | | 1415 | static void |
1417 | ParseDoDependencySourceSpecial(ParseSpecial specType, char *word, | | 1416 | ParseDoDependencySourceSpecial(ParseSpecial specType, char *word, |
1418 | SearchPathList *paths) | | 1417 | SearchPathList *paths) |
1419 | { | | 1418 | { |
1420 | switch (specType) { | | 1419 | switch (specType) { |
1421 | case SP_SUFFIXES: | | 1420 | case SP_SUFFIXES: |
1422 | Suff_AddSuffix(word, &mainNode); | | 1421 | Suff_AddSuffix(word, &mainNode); |
1423 | break; | | 1422 | break; |
1424 | case SP_PATH: | | 1423 | case SP_PATH: |
1425 | AddToPaths(word, paths); | | 1424 | AddToPaths(word, paths); |
1426 | break; | | 1425 | break; |
1427 | case SP_INCLUDES: | | 1426 | case SP_INCLUDES: |
1428 | Suff_AddInclude(word); | | 1427 | Suff_AddInclude(word); |
1429 | break; | | 1428 | break; |
1430 | case SP_LIBS: | | 1429 | case SP_LIBS: |
1431 | Suff_AddLib(word); | | 1430 | Suff_AddLib(word); |
1432 | break; | | 1431 | break; |
1433 | case SP_NULL: | | 1432 | case SP_NULL: |
1434 | Suff_SetNull(word); | | 1433 | Suff_SetNull(word); |
1435 | break; | | 1434 | break; |
1436 | case SP_OBJDIR: | | 1435 | case SP_OBJDIR: |
1437 | Main_SetObjdir(FALSE, "%s", word); | | 1436 | Main_SetObjdir(FALSE, "%s", word); |
1438 | break; | | 1437 | break; |
1439 | default: | | 1438 | default: |
1440 | break; | | 1439 | break; |
1441 | } | | 1440 | } |
1442 | } | | 1441 | } |
1443 | | | 1442 | |
1444 | static Boolean | | 1443 | static Boolean |
1445 | ParseDoDependencyTargets(char **inout_cp, | | 1444 | ParseDoDependencyTargets(char **inout_cp, |
1446 | char **inout_line, | | 1445 | char **inout_line, |
1447 | const char *lstart, | | 1446 | const char *lstart, |
1448 | ParseSpecial *inout_specType, | | 1447 | ParseSpecial *inout_specType, |
1449 | GNodeType *inout_tOp, | | 1448 | GNodeType *inout_tOp, |
1450 | SearchPathList **inout_paths, | | 1449 | SearchPathList **inout_paths, |
1451 | StringList *curTargs) | | 1450 | StringList *curTargs) |
1452 | { | | 1451 | { |
1453 | char *cp; | | 1452 | char *cp; |
1454 | char *tgt = *inout_line; | | 1453 | char *tgt = *inout_line; |
1455 | char savec; | | 1454 | char savec; |
1456 | const char *p; | | 1455 | const char *p; |
1457 | | | 1456 | |
1458 | for (;;) { | | 1457 | for (;;) { |
1459 | /* | | 1458 | /* |
1460 | * Here LINE points to the beginning of the next word, and | | 1459 | * Here LINE points to the beginning of the next word, and |
1461 | * LSTART points to the actual beginning of the line. | | 1460 | * LSTART points to the actual beginning of the line. |
1462 | */ | | 1461 | */ |
1463 | | | 1462 | |
1464 | /* Find the end of the next word. */ | | 1463 | /* Find the end of the next word. */ |
1465 | cp = tgt; | | 1464 | cp = tgt; |
1466 | p = cp; | | 1465 | p = cp; |
1467 | ParseDependencyTargetWord(&p, lstart); | | 1466 | ParseDependencyTargetWord(&p, lstart); |
1468 | cp += p - cp; | | 1467 | cp += p - cp; |
1469 | | | 1468 | |
1470 | /* | | 1469 | /* |
1471 | * If the word is followed by a left parenthesis, it's the | | 1470 | * If the word is followed by a left parenthesis, it's the |
1472 | * name of an object file inside an archive (ar file). | | 1471 | * name of an object file inside an archive (ar file). |
1473 | */ | | 1472 | */ |
1474 | if (!ParseIsEscaped(lstart, cp) && *cp == '(') { | | 1473 | if (!ParseIsEscaped(lstart, cp) && *cp == '(') { |
1475 | /* | | 1474 | /* |
1476 | * Archives must be handled specially to make sure the | | 1475 | * Archives must be handled specially to make sure the |
1477 | * OP_ARCHV flag is set in their 'type' field, for one | | 1476 | * OP_ARCHV flag is set in their 'type' field, for one |
1478 | * thing, and because things like "archive(file1.o | | 1477 | * thing, and because things like "archive(file1.o |
1479 | * file2.o file3.o)" are permissible. | | 1478 | * file2.o file3.o)" are permissible. |
1480 | * | | 1479 | * |
1481 | * Arch_ParseArchive will set 'line' to be the first | | 1480 | * Arch_ParseArchive will set 'line' to be the first |
1482 | * non-blank after the archive-spec. It creates/finds | | 1481 | * non-blank after the archive-spec. It creates/finds |
1483 | * nodes for the members and places them on the given | | 1482 | * nodes for the members and places them on the given |
1484 | * list, returning TRUE if all went well and FALSE if | | 1483 | * list, returning TRUE if all went well and FALSE if |
1485 | * there was an error in the specification. On error, | | 1484 | * there was an error in the specification. On error, |
1486 | * line should remain untouched. | | 1485 | * line should remain untouched. |
1487 | */ | | 1486 | */ |
1488 | if (!Arch_ParseArchive(&tgt, targets, VAR_CMDLINE)) { | | 1487 | if (!Arch_ParseArchive(&tgt, targets, VAR_CMDLINE)) { |
1489 | Parse_Error(PARSE_FATAL, | | 1488 | Parse_Error(PARSE_FATAL, |
1490 | "Error in archive specification: \"%s\"", | | 1489 | "Error in archive specification: \"%s\"", |
1491 | tgt); | | 1490 | tgt); |
1492 | return FALSE; | | 1491 | return FALSE; |
1493 | } | | 1492 | } |
1494 | | | 1493 | |
1495 | cp = tgt; | | 1494 | cp = tgt; |
1496 | continue; | | 1495 | continue; |
1497 | } | | 1496 | } |
1498 | | | 1497 | |
1499 | if (*cp == '\0') { | | 1498 | if (*cp == '\0') { |
1500 | ParseErrorNoDependency(lstart); | | 1499 | ParseErrorNoDependency(lstart); |
1501 | return FALSE; | | 1500 | return FALSE; |
1502 | } | | 1501 | } |
1503 | | | 1502 | |
1504 | /* Insert a null terminator. */ | | 1503 | /* Insert a null terminator. */ |
1505 | savec = *cp; | | 1504 | savec = *cp; |
1506 | *cp = '\0'; | | 1505 | *cp = '\0'; |
1507 | | | 1506 | |
1508 | if (!ParseDoDependencyTarget(tgt, inout_specType, inout_tOp, | | 1507 | if (!ParseDoDependencyTarget(tgt, inout_specType, inout_tOp, |
1509 | inout_paths)) | | 1508 | inout_paths)) |
1510 | return FALSE; | | 1509 | return FALSE; |
1511 | | | 1510 | |
1512 | /* | | 1511 | /* |
1513 | * Have word in line. Get or create its node and stick it at | | 1512 | * Have word in line. Get or create its node and stick it at |
1514 | * the end of the targets list | | 1513 | * the end of the targets list |
1515 | */ | | 1514 | */ |
1516 | if (*inout_specType == SP_NOT && *tgt != '\0') | | 1515 | if (*inout_specType == SP_NOT && *tgt != '\0') |
1517 | ParseDoDependencyTargetMundane(tgt, curTargs); | | 1516 | ParseDoDependencyTargetMundane(tgt, curTargs); |
1518 | else if (*inout_specType == SP_PATH && *tgt != '.' && | | 1517 | else if (*inout_specType == SP_PATH && *tgt != '.' && |
1519 | *tgt != '\0') | | 1518 | *tgt != '\0') |
1520 | Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", | | 1519 | Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", |
1521 | tgt); | | 1520 | tgt); |
1522 | | | 1521 | |
1523 | /* Don't need the inserted null terminator any more. */ | | 1522 | /* Don't need the inserted null terminator any more. */ |
1524 | *cp = savec; | | 1523 | *cp = savec; |
1525 | | | 1524 | |
1526 | /* | | 1525 | /* |
1527 | * If it is a special type and not .PATH, it's the only target | | 1526 | * If it is a special type and not .PATH, it's the only target |
1528 | * we allow on this line. | | 1527 | * we allow on this line. |
1529 | */ | | 1528 | */ |
1530 | if (*inout_specType != SP_NOT && *inout_specType != SP_PATH) | | 1529 | if (*inout_specType != SP_NOT && *inout_specType != SP_PATH) |
1531 | ParseDoDependencyTargetExtraWarn(&cp, lstart); | | 1530 | ParseDoDependencyTargetExtraWarn(&cp, lstart); |
1532 | else | | 1531 | else |
1533 | pp_skip_whitespace(&cp); | | 1532 | pp_skip_whitespace(&cp); |
1534 | | | 1533 | |
1535 | tgt = cp; | | 1534 | tgt = cp; |
1536 | if (*tgt == '\0') | | 1535 | if (*tgt == '\0') |
1537 | break; | | 1536 | break; |
1538 | if ((*tgt == '!' || *tgt == ':') && | | 1537 | if ((*tgt == '!' || *tgt == ':') && |
1539 | !ParseIsEscaped(lstart, tgt)) | | 1538 | !ParseIsEscaped(lstart, tgt)) |
1540 | break; | | 1539 | break; |
1541 | } | | 1540 | } |
1542 | | | 1541 | |
1543 | *inout_cp = cp; | | 1542 | *inout_cp = cp; |
1544 | *inout_line = tgt; | | 1543 | *inout_line = tgt; |
1545 | return TRUE; | | 1544 | return TRUE; |
1546 | } | | 1545 | } |
1547 | | | 1546 | |
1548 | static void | | 1547 | static void |
1549 | ParseDoDependencySourcesSpecial(char *start, char *end, | | 1548 | ParseDoDependencySourcesSpecial(char *start, char *end, |
1550 | ParseSpecial specType, SearchPathList *paths) | | 1549 | ParseSpecial specType, SearchPathList *paths) |
1551 | { | | 1550 | { |
1552 | char savec; | | 1551 | char savec; |
1553 | | | 1552 | |
1554 | while (*start != '\0') { | | 1553 | while (*start != '\0') { |
1555 | while (*end != '\0' && !ch_isspace(*end)) | | 1554 | while (*end != '\0' && !ch_isspace(*end)) |
1556 | end++; | | 1555 | end++; |
1557 | savec = *end; | | 1556 | savec = *end; |
1558 | *end = '\0'; | | 1557 | *end = '\0'; |
1559 | ParseDoDependencySourceSpecial(specType, start, paths); | | 1558 | ParseDoDependencySourceSpecial(specType, start, paths); |
1560 | *end = savec; | | 1559 | *end = savec; |
1561 | if (savec != '\0') | | 1560 | if (savec != '\0') |
1562 | end++; | | 1561 | end++; |
1563 | pp_skip_whitespace(&end); | | 1562 | pp_skip_whitespace(&end); |
1564 | start = end; | | 1563 | start = end; |
1565 | } | | 1564 | } |
1566 | } | | 1565 | } |
1567 | | | 1566 | |
1568 | static Boolean | | 1567 | static Boolean |
1569 | ParseDoDependencySourcesMundane(char *start, char *end, | | 1568 | ParseDoDependencySourcesMundane(char *start, char *end, |
1570 | ParseSpecial specType, GNodeType tOp) | | 1569 | ParseSpecial specType, GNodeType tOp) |
1571 | { | | 1570 | { |
1572 | while (*start != '\0') { | | 1571 | while (*start != '\0') { |
1573 | /* | | 1572 | /* |
1574 | * The targets take real sources, so we must beware of archive | | 1573 | * The targets take real sources, so we must beware of archive |
1575 | * specifications (i.e. things with left parentheses in them) | | 1574 | * specifications (i.e. things with left parentheses in them) |
1576 | * and handle them accordingly. | | 1575 | * and handle them accordingly. |
1577 | */ | | 1576 | */ |
1578 | for (; *end != '\0' && !ch_isspace(*end); end++) { | | 1577 | for (; *end != '\0' && !ch_isspace(*end); end++) { |
1579 | if (*end == '(' && end > start && end[-1] != '$') { | | 1578 | if (*end == '(' && end > start && end[-1] != '$') { |
1580 | /* | | 1579 | /* |
1581 | * Only stop for a left parenthesis if it | | 1580 | * Only stop for a left parenthesis if it |
1582 | * isn't at the start of a word (that'll be | | 1581 | * isn't at the start of a word (that'll be |
1583 | * for variable changes later) and isn't | | 1582 | * for variable changes later) and isn't |
1584 | * preceded by a dollar sign (a dynamic | | 1583 | * preceded by a dollar sign (a dynamic |
1585 | * source). | | 1584 | * source). |
1586 | */ | | 1585 | */ |
1587 | break; | | 1586 | break; |
1588 | } | | 1587 | } |
1589 | } | | 1588 | } |
1590 | | | 1589 | |
1591 | if (*end == '(') { | | 1590 | if (*end == '(') { |
1592 | GNodeList sources = LST_INIT; | | 1591 | GNodeList sources = LST_INIT; |
1593 | if (!Arch_ParseArchive(&start, &sources, VAR_CMDLINE)) { | | 1592 | if (!Arch_ParseArchive(&start, &sources, VAR_CMDLINE)) { |
1594 | Parse_Error(PARSE_FATAL, | | 1593 | Parse_Error(PARSE_FATAL, |
1595 | "Error in source archive spec \"%s\"", | | 1594 | "Error in source archive spec \"%s\"", |
1596 | start); | | 1595 | start); |
1597 | return FALSE; | | 1596 | return FALSE; |
1598 | } | | 1597 | } |
1599 | | | 1598 | |
1600 | while (!Lst_IsEmpty(&sources)) { | | 1599 | while (!Lst_IsEmpty(&sources)) { |
1601 | GNode *gn = Lst_Dequeue(&sources); | | 1600 | GNode *gn = Lst_Dequeue(&sources); |
1602 | ParseDependencySource(tOp, gn->name, specType); | | 1601 | ParseDependencySource(tOp, gn->name, specType); |
1603 | } | | 1602 | } |
1604 | Lst_Done(&sources); | | 1603 | Lst_Done(&sources); |
1605 | end = start; | | 1604 | end = start; |
1606 | } else { | | 1605 | } else { |
1607 | if (*end != '\0') { | | 1606 | if (*end != '\0') { |
1608 | *end = '\0'; | | 1607 | *end = '\0'; |
1609 | end++; | | 1608 | end++; |
1610 | } | | 1609 | } |
1611 | | | 1610 | |
1612 | ParseDependencySource(tOp, start, specType); | | 1611 | ParseDependencySource(tOp, start, specType); |
1613 | } | | 1612 | } |
1614 | pp_skip_whitespace(&end); | | 1613 | pp_skip_whitespace(&end); |
1615 | start = end; | | 1614 | start = end; |
1616 | } | | 1615 | } |
1617 | return TRUE; | | 1616 | return TRUE; |
1618 | } | | 1617 | } |
1619 | | | 1618 | |
1620 | /* Parse a dependency line consisting of targets, followed by a dependency | | 1619 | /* Parse a dependency line consisting of targets, followed by a dependency |
1621 | * operator, optionally followed by sources. | | 1620 | * operator, optionally followed by sources. |
1622 | * | | 1621 | * |
1623 | * The nodes of the sources are linked as children to the nodes of the | | 1622 | * The nodes of the sources are linked as children to the nodes of the |
1624 | * targets. Nodes are created as necessary. | | 1623 | * targets. Nodes are created as necessary. |
1625 | * | | 1624 | * |
1626 | * The operator is applied to each node in the global 'targets' list, | | 1625 | * The operator is applied to each node in the global 'targets' list, |
1627 | * which is where the nodes found for the targets are kept, by means of | | 1626 | * which is where the nodes found for the targets are kept, by means of |
1628 | * the ParseDoOp function. | | 1627 | * the ParseDoOp function. |
1629 | * | | 1628 | * |
1630 | * The sources are parsed in much the same way as the targets, except | | 1629 | * The sources are parsed in much the same way as the targets, except |
1631 | * that they are expanded using the wildcarding scheme of the C-Shell, | | 1630 | * that they are expanded using the wildcarding scheme of the C-Shell, |
1632 | * and a target is created for each expanded word. Each of the resulting | | 1631 | * and a target is created for each expanded word. Each of the resulting |
1633 | * nodes is then linked to each of the targets as one of its children. | | 1632 | * nodes is then linked to each of the targets as one of its children. |
1634 | * | | 1633 | * |
1635 | * Certain targets and sources such as .PHONY or .PRECIOUS are handled | | 1634 | * Certain targets and sources such as .PHONY or .PRECIOUS are handled |
1636 | * specially. These are the ones detailed by the specType variable. | | 1635 | * specially. These are the ones detailed by the specType variable. |
1637 | * | | 1636 | * |
1638 | * The storing of transformation rules such as '.c.o' is also taken care of | | 1637 | * The storing of transformation rules such as '.c.o' is also taken care of |
1639 | * here. A target is recognized as a transformation rule by calling | | 1638 | * here. A target is recognized as a transformation rule by calling |
1640 | * Suff_IsTransform. If it is a transformation rule, its node is gotten | | 1639 | * Suff_IsTransform. If it is a transformation rule, its node is gotten |
1641 | * from the suffix module via Suff_AddTransform rather than the standard | | 1640 | * from the suffix module via Suff_AddTransform rather than the standard |
1642 | * Targ_FindNode in the target module. | | 1641 | * Targ_FindNode in the target module. |
1643 | * | | 1642 | * |
1644 | * Upon return, the value of the line is unspecified. | | 1643 | * Upon return, the value of the line is unspecified. |
1645 | */ | | 1644 | */ |
1646 | static void | | 1645 | static void |
1647 | ParseDoDependency(char *line) | | 1646 | ParseDoDependency(char *line) |
1648 | { | | 1647 | { |
1649 | char *cp; /* our current position */ | | 1648 | char *cp; /* our current position */ |
1650 | GNodeType op; /* the operator on the line */ | | 1649 | GNodeType op; /* the operator on the line */ |
1651 | SearchPathList *paths; /* search paths to alter when parsing | | 1650 | SearchPathList *paths; /* search paths to alter when parsing |
1652 | * a list of .PATH targets */ | | 1651 | * a list of .PATH targets */ |
1653 | GNodeType tOp; /* operator from special target */ | | 1652 | GNodeType tOp; /* operator from special target */ |
1654 | /* target names to be found and added to the targets list */ | | 1653 | /* target names to be found and added to the targets list */ |
1655 | StringList curTargs = LST_INIT; | | 1654 | StringList curTargs = LST_INIT; |
1656 | char *lstart = line; | | 1655 | char *lstart = line; |
1657 | | | 1656 | |
1658 | /* | | 1657 | /* |
1659 | * specType contains the SPECial TYPE of the current target. It is | | 1658 | * specType contains the SPECial TYPE of the current target. It is |
1660 | * SP_NOT if the target is unspecial. If it *is* special, however, the | | 1659 | * SP_NOT if the target is unspecial. If it *is* special, however, the |
1661 | * children are linked as children of the parent but not vice versa. | | 1660 | * children are linked as children of the parent but not vice versa. |
1662 | */ | | 1661 | */ |
1663 | ParseSpecial specType = SP_NOT; | | 1662 | ParseSpecial specType = SP_NOT; |
1664 | | | 1663 | |
1665 | DEBUG1(PARSE, "ParseDoDependency(%s)\n", line); | | 1664 | DEBUG1(PARSE, "ParseDoDependency(%s)\n", line); |
1666 | tOp = OP_NONE; | | 1665 | tOp = OP_NONE; |
1667 | | | 1666 | |
1668 | paths = NULL; | | 1667 | paths = NULL; |
1669 | | | 1668 | |
1670 | /* | | 1669 | /* |
1671 | * First, grind through the targets. | | 1670 | * First, grind through the targets. |
1672 | */ | | 1671 | */ |
1673 | /* XXX: don't use line as an iterator variable */ | | 1672 | /* XXX: don't use line as an iterator variable */ |
1674 | if (!ParseDoDependencyTargets(&cp, &line, lstart, &specType, &tOp, | | 1673 | if (!ParseDoDependencyTargets(&cp, &line, lstart, &specType, &tOp, |
1675 | &paths, &curTargs)) | | 1674 | &paths, &curTargs)) |
1676 | goto out; | | 1675 | goto out; |
1677 | | | 1676 | |
1678 | /* | | 1677 | /* |
1679 | * Don't need the list of target names anymore. | | 1678 | * Don't need the list of target names anymore. |
1680 | * The targets themselves are now in the global variable 'targets'. | | 1679 | * The targets themselves are now in the global variable 'targets'. |
1681 | */ | | 1680 | */ |
1682 | Lst_Done(&curTargs); | | 1681 | Lst_Done(&curTargs); |
1683 | Lst_Init(&curTargs); | | 1682 | Lst_Init(&curTargs); |
1684 | | | 1683 | |
1685 | if (!Lst_IsEmpty(targets)) | | 1684 | if (!Lst_IsEmpty(targets)) |
1686 | ParseDoDependencyCheckSpec(specType); | | 1685 | ParseDoDependencyCheckSpec(specType); |
1687 | | | 1686 | |
1688 | /* | | 1687 | /* |
1689 | * Have now parsed all the target names. Must parse the operator next. | | 1688 | * Have now parsed all the target names. Must parse the operator next. |
1690 | */ | | 1689 | */ |
1691 | if (!ParseDoDependencyParseOp(&cp, lstart, &op)) | | 1690 | if (!ParseDoDependencyParseOp(&cp, lstart, &op)) |
1692 | goto out; | | 1691 | goto out; |
1693 | | | 1692 | |
1694 | /* | | 1693 | /* |
1695 | * Apply the operator to the target. This is how we remember which | | 1694 | * Apply the operator to the target. This is how we remember which |
1696 | * operator a target was defined with. It fails if the operator | | 1695 | * operator a target was defined with. It fails if the operator |
1697 | * used isn't consistent across all references. | | 1696 | * used isn't consistent across all references. |
1698 | */ | | 1697 | */ |
1699 | ApplyDependencyOperator(op); | | 1698 | ApplyDependencyOperator(op); |
1700 | | | 1699 | |
1701 | /* | | 1700 | /* |
1702 | * Onward to the sources. | | 1701 | * Onward to the sources. |
1703 | * | | 1702 | * |
1704 | * LINE will now point to the first source word, if any, or the | | 1703 | * LINE will now point to the first source word, if any, or the |
1705 | * end of the string if not. | | 1704 | * end of the string if not. |
1706 | */ | | 1705 | */ |
1707 | pp_skip_whitespace(&cp); | | 1706 | pp_skip_whitespace(&cp); |
1708 | line = cp; /* XXX: 'line' is an inappropriate name */ | | 1707 | line = cp; /* XXX: 'line' is an inappropriate name */ |
1709 | | | 1708 | |
1710 | /* | | 1709 | /* |
1711 | * Several special targets take different actions if present with no | | 1710 | * Several special targets take different actions if present with no |
1712 | * sources: | | 1711 | * sources: |
1713 | * a .SUFFIXES line with no sources clears out all old suffixes | | 1712 | * a .SUFFIXES line with no sources clears out all old suffixes |
1714 | * a .PRECIOUS line makes all targets precious | | 1713 | * a .PRECIOUS line makes all targets precious |
1715 | * a .IGNORE line ignores errors for all targets | | 1714 | * a .IGNORE line ignores errors for all targets |
1716 | * a .SILENT line creates silence when making all targets | | 1715 | * a .SILENT line creates silence when making all targets |
1717 | * a .PATH removes all directories from the search path(s). | | 1716 | * a .PATH removes all directories from the search path(s). |
1718 | */ | | 1717 | */ |
1719 | if (line[0] == '\0') { | | 1718 | if (line[0] == '\0') { |
1720 | ParseDoDependencySourcesEmpty(specType, paths); | | 1719 | ParseDoDependencySourcesEmpty(specType, paths); |
1721 | } else if (specType == SP_MFLAGS) { | | 1720 | } else if (specType == SP_MFLAGS) { |
1722 | /* | | 1721 | /* |
1723 | * Call on functions in main.c to deal with these arguments and | | 1722 | * Call on functions in main.c to deal with these arguments and |
1724 | * set the initial character to a null-character so the loop to | | 1723 | * set the initial character to a null-character so the loop to |
1725 | * get sources won't get anything | | 1724 | * get sources won't get anything |
1726 | */ | | 1725 | */ |
1727 | Main_ParseArgLine(line); | | 1726 | Main_ParseArgLine(line); |
1728 | *line = '\0'; | | 1727 | *line = '\0'; |
1729 | } else if (specType == SP_SHELL) { | | 1728 | } else if (specType == SP_SHELL) { |
1730 | if (!Job_ParseShell(line)) { | | 1729 | if (!Job_ParseShell(line)) { |
1731 | Parse_Error(PARSE_FATAL, | | 1730 | Parse_Error(PARSE_FATAL, |
1732 | "improper shell specification"); | | 1731 | "improper shell specification"); |
1733 | goto out; | | 1732 | goto out; |
1734 | } | | 1733 | } |
1735 | *line = '\0'; | | 1734 | *line = '\0'; |
1736 | } else if (specType == SP_NOTPARALLEL || specType == SP_SINGLESHELL || | | 1735 | } else if (specType == SP_NOTPARALLEL || specType == SP_SINGLESHELL || |
1737 | specType == SP_DELETE_ON_ERROR) { | | 1736 | specType == SP_DELETE_ON_ERROR) { |
1738 | *line = '\0'; | | 1737 | *line = '\0'; |
1739 | } | | 1738 | } |
1740 | | | 1739 | |
1741 | /* Now go for the sources. */ | | 1740 | /* Now go for the sources. */ |
1742 | if (specType == SP_SUFFIXES || specType == SP_PATH || | | 1741 | if (specType == SP_SUFFIXES || specType == SP_PATH || |
1743 | specType == SP_INCLUDES || specType == SP_LIBS || | | 1742 | specType == SP_INCLUDES || specType == SP_LIBS || |
1744 | specType == SP_NULL || specType == SP_OBJDIR) { | | 1743 | specType == SP_NULL || specType == SP_OBJDIR) { |
1745 | ParseDoDependencySourcesSpecial(line, cp, specType, paths); | | 1744 | ParseDoDependencySourcesSpecial(line, cp, specType, paths); |
1746 | if (paths != NULL) { | | 1745 | if (paths != NULL) { |
1747 | Lst_Free(paths); | | 1746 | Lst_Free(paths); |
1748 | paths = NULL; | | 1747 | paths = NULL; |
1749 | } | | 1748 | } |
1750 | if (specType == SP_PATH) | | 1749 | if (specType == SP_PATH) |
1751 | Dir_SetPATH(); | | 1750 | Dir_SetPATH(); |
1752 | } else { | | 1751 | } else { |
1753 | assert(paths == NULL); | | 1752 | assert(paths == NULL); |
1754 | if (!ParseDoDependencySourcesMundane(line, cp, specType, tOp)) | | 1753 | if (!ParseDoDependencySourcesMundane(line, cp, specType, tOp)) |
1755 | goto out; | | 1754 | goto out; |
1756 | } | | 1755 | } |
1757 | | | 1756 | |
1758 | FindMainTarget(); | | 1757 | FindMainTarget(); |
1759 | | | 1758 | |
1760 | out: | | 1759 | out: |
1761 | if (paths != NULL) | | 1760 | if (paths != NULL) |
1762 | Lst_Free(paths); | | 1761 | Lst_Free(paths); |
1763 | Lst_Done(&curTargs); | | 1762 | Lst_Done(&curTargs); |
1764 | } | | 1763 | } |
1765 | | | 1764 | |
1766 | typedef struct VarAssignParsed { | | 1765 | typedef struct VarAssignParsed { |
1767 | const char *nameStart; /* unexpanded */ | | 1766 | const char *nameStart; /* unexpanded */ |
1768 | const char *nameEnd; /* before operator adjustment */ | | 1767 | const char *nameEnd; /* before operator adjustment */ |
1769 | const char *eq; /* the '=' of the assignment operator */ | | 1768 | const char *eq; /* the '=' of the assignment operator */ |
1770 | } VarAssignParsed; | | 1769 | } VarAssignParsed; |
1771 | | | 1770 | |
1772 | /* | | 1771 | /* |
1773 | * Determine the assignment operator and adjust the end of the variable | | 1772 | * Determine the assignment operator and adjust the end of the variable |
1774 | * name accordingly. | | 1773 | * name accordingly. |
1775 | */ | | 1774 | */ |
1776 | static void | | 1775 | static void |
1777 | AdjustVarassignOp(const VarAssignParsed *pvar, const char *value, | | 1776 | AdjustVarassignOp(const VarAssignParsed *pvar, const char *value, |
1778 | VarAssign *out_var) | | 1777 | VarAssign *out_var) |
1779 | { | | 1778 | { |
1780 | const char *op = pvar->eq; | | 1779 | const char *op = pvar->eq; |
1781 | const char *const name = pvar->nameStart; | | 1780 | const char *const name = pvar->nameStart; |
1782 | VarAssignOp type; | | 1781 | VarAssignOp type; |
1783 | | | 1782 | |
1784 | if (op > name && op[-1] == '+') { | | 1783 | if (op > name && op[-1] == '+') { |
1785 | type = VAR_APPEND; | | 1784 | type = VAR_APPEND; |
1786 | op--; | | 1785 | op--; |
1787 | | | 1786 | |
1788 | } else if (op > name && op[-1] == '?') { | | 1787 | } else if (op > name && op[-1] == '?') { |
1789 | op--; | | 1788 | op--; |
1790 | type = VAR_DEFAULT; | | 1789 | type = VAR_DEFAULT; |
1791 | | | 1790 | |
1792 | } else if (op > name && op[-1] == ':') { | | 1791 | } else if (op > name && op[-1] == ':') { |
1793 | op--; | | 1792 | op--; |
1794 | type = VAR_SUBST; | | 1793 | type = VAR_SUBST; |
1795 | | | 1794 | |
1796 | } else if (op > name && op[-1] == '!') { | | 1795 | } else if (op > name && op[-1] == '!') { |
1797 | op--; | | 1796 | op--; |
1798 | type = VAR_SHELL; | | 1797 | type = VAR_SHELL; |
1799 | | | 1798 | |
1800 | } else { | | 1799 | } else { |
1801 | type = VAR_NORMAL; | | 1800 | type = VAR_NORMAL; |
1802 | #ifdef SUNSHCMD | | 1801 | #ifdef SUNSHCMD |
1803 | while (op > name && ch_isspace(op[-1])) | | 1802 | while (op > name && ch_isspace(op[-1])) |
1804 | op--; | | 1803 | op--; |
1805 | | | 1804 | |
1806 | if (op >= name + 3 && op[-3] == ':' && op[-2] == 's' && | | 1805 | if (op >= name + 3 && op[-3] == ':' && op[-2] == 's' && |
1807 | op[-1] == 'h') { | | 1806 | op[-1] == 'h') { |
1808 | type = VAR_SHELL; | | 1807 | type = VAR_SHELL; |
1809 | op -= 3; | | 1808 | op -= 3; |
1810 | } | | 1809 | } |
1811 | #endif | | 1810 | #endif |
1812 | } | | 1811 | } |
1813 | | | 1812 | |
1814 | { | | 1813 | { |
1815 | const char *nameEnd = pvar->nameEnd < op ? pvar->nameEnd : op; | | 1814 | const char *nameEnd = pvar->nameEnd < op ? pvar->nameEnd : op; |
1816 | out_var->varname = bmake_strsedup(pvar->nameStart, nameEnd); | | 1815 | out_var->varname = bmake_strsedup(pvar->nameStart, nameEnd); |
1817 | out_var->op = type; | | 1816 | out_var->op = type; |
1818 | out_var->value = value; | | 1817 | out_var->value = value; |
1819 | } | | 1818 | } |
1820 | } | | 1819 | } |
1821 | | | 1820 | |
1822 | /* | | 1821 | /* |
1823 | * Parse a variable assignment, consisting of a single-word variable name, | | 1822 | * Parse a variable assignment, consisting of a single-word variable name, |
1824 | * optional whitespace, an assignment operator, optional whitespace and the | | 1823 | * optional whitespace, an assignment operator, optional whitespace and the |
1825 | * variable value. | | 1824 | * variable value. |
1826 | * | | 1825 | * |
1827 | * Note: There is a lexical ambiguity with assignment modifier characters | | 1826 | * Note: There is a lexical ambiguity with assignment modifier characters |
1828 | * in variable names. This routine interprets the character before the = | | 1827 | * in variable names. This routine interprets the character before the = |
1829 | * as a modifier. Therefore, an assignment like | | 1828 | * as a modifier. Therefore, an assignment like |
1830 | * C++=/usr/bin/CC | | 1829 | * C++=/usr/bin/CC |
1831 | * is interpreted as "C+ +=" instead of "C++ =". | | 1830 | * is interpreted as "C+ +=" instead of "C++ =". |
1832 | * | | 1831 | * |
1833 | * Used for both lines in a file and command line arguments. | | 1832 | * Used for both lines in a file and command line arguments. |
1834 | */ | | 1833 | */ |
1835 | Boolean | | 1834 | Boolean |
1836 | Parse_IsVar(const char *p, VarAssign *out_var) | | 1835 | Parse_IsVar(const char *p, VarAssign *out_var) |
1837 | { | | 1836 | { |
1838 | VarAssignParsed pvar; | | 1837 | VarAssignParsed pvar; |
1839 | const char *firstSpace = NULL; | | 1838 | const char *firstSpace = NULL; |
1840 | int level = 0; | | 1839 | int level = 0; |
1841 | | | 1840 | |
1842 | cpp_skip_hspace(&p); /* Skip to variable name */ | | 1841 | cpp_skip_hspace(&p); /* Skip to variable name */ |
1843 | | | 1842 | |
1844 | /* | | 1843 | /* |
1845 | * During parsing, the '+' of the '+=' operator is initially parsed | | 1844 | * During parsing, the '+' of the '+=' operator is initially parsed |
1846 | * as part of the variable name. It is later corrected, as is the | | 1845 | * as part of the variable name. It is later corrected, as is the |
1847 | * ':sh' modifier. Of these two (nameEnd and op), the earlier one | | 1846 | * ':sh' modifier. Of these two (nameEnd and op), the earlier one |
1848 | * determines the actual end of the variable name. | | 1847 | * determines the actual end of the variable name. |
1849 | */ | | 1848 | */ |
1850 | pvar.nameStart = p; | | 1849 | pvar.nameStart = p; |
1851 | #ifdef CLEANUP | | 1850 | #ifdef CLEANUP |
1852 | pvar.nameEnd = NULL; | | 1851 | pvar.nameEnd = NULL; |
1853 | pvar.eq = NULL; | | 1852 | pvar.eq = NULL; |
1854 | #endif | | 1853 | #endif |
1855 | | | 1854 | |
1856 | /* | | 1855 | /* |
1857 | * Scan for one of the assignment operators outside a variable | | 1856 | * Scan for one of the assignment operators outside a variable |
1858 | * expansion. | | 1857 | * expansion. |
1859 | */ | | 1858 | */ |
1860 | while (*p != '\0') { | | 1859 | while (*p != '\0') { |
1861 | char ch = *p++; | | 1860 | char ch = *p++; |
1862 | if (ch == '(' || ch == '{') { | | 1861 | if (ch == '(' || ch == '{') { |
1863 | level++; | | 1862 | level++; |
1864 | continue; | | 1863 | continue; |
1865 | } | | 1864 | } |
1866 | if (ch == ')' || ch == '}') { | | 1865 | if (ch == ')' || ch == '}') { |
1867 | level--; | | 1866 | level--; |
1868 | continue; | | 1867 | continue; |
1869 | } | | 1868 | } |
1870 | | | 1869 | |
1871 | if (level != 0) | | 1870 | if (level != 0) |
1872 | continue; | | 1871 | continue; |
1873 | | | 1872 | |
1874 | if (ch == ' ' || ch == '\t') | | 1873 | if (ch == ' ' || ch == '\t') |
1875 | if (firstSpace == NULL) | | 1874 | if (firstSpace == NULL) |
1876 | firstSpace = p - 1; | | 1875 | firstSpace = p - 1; |
1877 | while (ch == ' ' || ch == '\t') | | 1876 | while (ch == ' ' || ch == '\t') |
1878 | ch = *p++; | | 1877 | ch = *p++; |
1879 | | | 1878 | |
1880 | #ifdef SUNSHCMD | | 1879 | #ifdef SUNSHCMD |
1881 | if (ch == ':' && p[0] == 's' && p[1] == 'h') { | | 1880 | if (ch == ':' && p[0] == 's' && p[1] == 'h') { |
1882 | p += 2; | | 1881 | p += 2; |
1883 | continue; | | 1882 | continue; |
1884 | } | | 1883 | } |
1885 | #endif | | 1884 | #endif |
1886 | if (ch == '=') { | | 1885 | if (ch == '=') { |
1887 | pvar.eq = p - 1; | | 1886 | pvar.eq = p - 1; |
1888 | pvar.nameEnd = firstSpace != NULL ? firstSpace : p - 1; | | 1887 | pvar.nameEnd = firstSpace != NULL ? firstSpace : p - 1; |
1889 | cpp_skip_whitespace(&p); | | 1888 | cpp_skip_whitespace(&p); |
1890 | AdjustVarassignOp(&pvar, p, out_var); | | 1889 | AdjustVarassignOp(&pvar, p, out_var); |
1891 | return TRUE; | | 1890 | return TRUE; |
1892 | } | | 1891 | } |
1893 | if (*p == '=' && | | 1892 | if (*p == '=' && |
1894 | (ch == '+' || ch == ':' || ch == '?' || ch == '!')) { | | 1893 | (ch == '+' || ch == ':' || ch == '?' || ch == '!')) { |
1895 | pvar.eq = p; | | 1894 | pvar.eq = p; |
1896 | pvar.nameEnd = firstSpace != NULL ? firstSpace : p; | | 1895 | pvar.nameEnd = firstSpace != NULL ? firstSpace : p; |
1897 | p++; | | 1896 | p++; |
1898 | cpp_skip_whitespace(&p); | | 1897 | cpp_skip_whitespace(&p); |
1899 | AdjustVarassignOp(&pvar, p, out_var); | | 1898 | AdjustVarassignOp(&pvar, p, out_var); |
1900 | return TRUE; | | 1899 | return TRUE; |
1901 | } | | 1900 | } |
1902 | if (firstSpace != NULL) | | 1901 | if (firstSpace != NULL) |
1903 | return FALSE; | | 1902 | return FALSE; |
1904 | } | | 1903 | } |
1905 | | | 1904 | |
1906 | return FALSE; | | 1905 | return FALSE; |
1907 | } | | 1906 | } |
1908 | | | 1907 | |
1909 | /* | | 1908 | /* |
1910 | * Check for syntax errors such as unclosed expressions or unknown modifiers. | | 1909 | * Check for syntax errors such as unclosed expressions or unknown modifiers. |
1911 | */ | | 1910 | */ |
1912 | static void | | 1911 | static void |
1913 | VarCheckSyntax(VarAssignOp type, const char *uvalue, GNode *ctxt) | | 1912 | VarCheckSyntax(VarAssignOp type, const char *uvalue, GNode *ctxt) |
1914 | { | | 1913 | { |
1915 | if (opts.strict) { | | 1914 | if (opts.strict) { |
1916 | if (type != VAR_SUBST && strchr(uvalue, '$') != NULL) { | | 1915 | if (type != VAR_SUBST && strchr(uvalue, '$') != NULL) { |
1917 | char *expandedValue; | | 1916 | char *expandedValue; |
1918 | | | 1917 | |
1919 | (void)Var_Subst(uvalue, ctxt, VARE_NONE, | | 1918 | (void)Var_Subst(uvalue, ctxt, VARE_NONE, |
1920 | &expandedValue); | | 1919 | &expandedValue); |
1921 | /* TODO: handle errors */ | | 1920 | /* TODO: handle errors */ |
1922 | free(expandedValue); | | 1921 | free(expandedValue); |
1923 | } | | 1922 | } |
1924 | } | | 1923 | } |
1925 | } | | 1924 | } |
1926 | | | 1925 | |
1927 | static void | | 1926 | static void |
1928 | VarAssign_EvalSubst(const char *name, const char *uvalue, GNode *ctxt, | | 1927 | VarAssign_EvalSubst(const char *name, const char *uvalue, GNode *ctxt, |
1929 | FStr *out_avalue) | | 1928 | FStr *out_avalue) |
1930 | { | | 1929 | { |
1931 | const char *avalue; | | 1930 | const char *avalue; |
1932 | char *evalue; | | 1931 | char *evalue; |
1933 | Boolean savedPreserveUndefined = preserveUndefined; | | 1932 | Boolean savedPreserveUndefined = preserveUndefined; |
1934 | | | 1933 | |
1935 | /* TODO: Can this assignment to preserveUndefined be moved further down | | 1934 | /* TODO: Can this assignment to preserveUndefined be moved further down |
1936 | * to the actually interesting Var_Subst call, without affecting any | | 1935 | * to the actually interesting Var_Subst call, without affecting any |
1937 | * edge cases? | | 1936 | * edge cases? |
1938 | * | | 1937 | * |
1939 | * It might affect the implicit expansion of the variable name in the | | 1938 | * It might affect the implicit expansion of the variable name in the |
1940 | * Var_Exists and Var_Set calls, even though it's unlikely that anyone | | 1939 | * Var_Exists and Var_Set calls, even though it's unlikely that anyone |
1941 | * cared about this edge case when adding this code. In addition, | | 1940 | * cared about this edge case when adding this code. In addition, |
1942 | * variable assignments should not refer to any undefined variables in | | 1941 | * variable assignments should not refer to any undefined variables in |
1943 | * the variable name. */ | | 1942 | * the variable name. */ |
1944 | preserveUndefined = TRUE; | | 1943 | preserveUndefined = TRUE; |
1945 | | | 1944 | |
1946 | /* | | 1945 | /* |
1947 | * make sure that we set the variable the first time to nothing | | 1946 | * make sure that we set the variable the first time to nothing |
1948 | * so that it gets substituted! | | 1947 | * so that it gets substituted! |
1949 | */ | | 1948 | */ |
1950 | if (!Var_Exists(name, ctxt)) | | 1949 | if (!Var_Exists(name, ctxt)) |
1951 | Var_Set(name, "", ctxt); | | 1950 | Var_Set(name, "", ctxt); |
1952 | | | 1951 | |
1953 | (void)Var_Subst(uvalue, ctxt, VARE_WANTRES | VARE_KEEP_DOLLAR, &evalue); | | 1952 | (void)Var_Subst(uvalue, ctxt, VARE_WANTRES | VARE_KEEP_DOLLAR, &evalue); |
1954 | /* TODO: handle errors */ | | 1953 | /* TODO: handle errors */ |
1955 | preserveUndefined = savedPreserveUndefined; | | 1954 | preserveUndefined = savedPreserveUndefined; |
1956 | avalue = evalue; | | 1955 | avalue = evalue; |
1957 | Var_Set(name, avalue, ctxt); | | 1956 | Var_Set(name, avalue, ctxt); |
1958 | | | 1957 | |
1959 | *out_avalue = (FStr){ avalue, evalue }; | | 1958 | *out_avalue = (FStr){ avalue, evalue }; |
1960 | } | | 1959 | } |
1961 | | | 1960 | |
1962 | static void | | 1961 | static void |
1963 | VarAssign_EvalShell(const char *name, const char *uvalue, GNode *ctxt, | | 1962 | VarAssign_EvalShell(const char *name, const char *uvalue, GNode *ctxt, |
1964 | FStr *out_avalue) | | 1963 | FStr *out_avalue) |
1965 | { | | 1964 | { |
1966 | FStr cmd; | | 1965 | FStr cmd; |
1967 | const char *errfmt; | | 1966 | const char *errfmt; |
1968 | char *cmdOut; | | 1967 | char *cmdOut; |
1969 | | | 1968 | |
1970 | cmd = FStr_InitRefer(uvalue); | | 1969 | cmd = FStr_InitRefer(uvalue); |
1971 | if (strchr(cmd.str, '$') != NULL) { | | 1970 | if (strchr(cmd.str, '$') != NULL) { |
1972 | char *expanded; | | 1971 | char *expanded; |
1973 | (void)Var_Subst(cmd.str, VAR_CMDLINE, | | 1972 | (void)Var_Subst(cmd.str, VAR_CMDLINE, |
1974 | VARE_WANTRES | VARE_UNDEFERR, &expanded); | | 1973 | VARE_WANTRES | VARE_UNDEFERR, &expanded); |
1975 | /* TODO: handle errors */ | | 1974 | /* TODO: handle errors */ |
1976 | cmd = FStr_InitOwn(expanded); | | 1975 | cmd = FStr_InitOwn(expanded); |
1977 | } | | 1976 | } |
1978 | | | 1977 | |
1979 | cmdOut = Cmd_Exec(cmd.str, &errfmt); | | 1978 | cmdOut = Cmd_Exec(cmd.str, &errfmt); |
1980 | Var_Set(name, cmdOut, ctxt); | | 1979 | Var_Set(name, cmdOut, ctxt); |
1981 | *out_avalue = FStr_InitOwn(cmdOut); | | 1980 | *out_avalue = FStr_InitOwn(cmdOut); |
1982 | | | 1981 | |
1983 | if (errfmt != NULL) | | 1982 | if (errfmt != NULL) |
1984 | Parse_Error(PARSE_WARNING, errfmt, cmd.str); | | 1983 | Parse_Error(PARSE_WARNING, errfmt, cmd.str); |
1985 | | | 1984 | |
1986 | FStr_Done(&cmd); | | 1985 | FStr_Done(&cmd); |
1987 | } | | 1986 | } |
1988 | | | 1987 | |
1989 | /* Perform a variable assignment. | | 1988 | /* Perform a variable assignment. |
1990 | * | | 1989 | * |
1991 | * The actual value of the variable is returned in *out_avalue and | | 1990 | * The actual value of the variable is returned in *out_avalue and |
1992 | * *out_avalue_freeIt. Especially for VAR_SUBST and VAR_SHELL this can differ | | 1991 | * *out_avalue_freeIt. Especially for VAR_SUBST and VAR_SHELL this can differ |
1993 | * from the literal value. | | 1992 | * from the literal value. |
1994 | * | | 1993 | * |
1995 | * Return whether the assignment was actually done. The assignment is only | | 1994 | * Return whether the assignment was actually done. The assignment is only |
1996 | * skipped if the operator is '?=' and the variable already exists. */ | | 1995 | * skipped if the operator is '?=' and the variable already exists. */ |
1997 | static Boolean | | 1996 | static Boolean |
1998 | VarAssign_Eval(const char *name, VarAssignOp op, const char *uvalue, | | 1997 | VarAssign_Eval(const char *name, VarAssignOp op, const char *uvalue, |
1999 | GNode *ctxt, FStr *out_TRUE_avalue) | | 1998 | GNode *ctxt, FStr *out_TRUE_avalue) |
2000 | { | | 1999 | { |
2001 | FStr avalue = FStr_InitRefer(uvalue); | | 2000 | FStr avalue = FStr_InitRefer(uvalue); |
2002 | | | 2001 | |
2003 | if (op == VAR_APPEND) | | 2002 | if (op == VAR_APPEND) |
2004 | Var_Append(name, uvalue, ctxt); | | 2003 | Var_Append(name, uvalue, ctxt); |
2005 | else if (op == VAR_SUBST) | | 2004 | else if (op == VAR_SUBST) |
2006 | VarAssign_EvalSubst(name, uvalue, ctxt, &avalue); | | 2005 | VarAssign_EvalSubst(name, uvalue, ctxt, &avalue); |
2007 | else if (op == VAR_SHELL) | | 2006 | else if (op == VAR_SHELL) |
2008 | VarAssign_EvalShell(name, uvalue, ctxt, &avalue); | | 2007 | VarAssign_EvalShell(name, uvalue, ctxt, &avalue); |
2009 | else { | | 2008 | else { |
2010 | if (op == VAR_DEFAULT && Var_Exists(name, ctxt)) | | 2009 | if (op == VAR_DEFAULT && Var_Exists(name, ctxt)) |
2011 | return FALSE; | | 2010 | return FALSE; |
2012 | | | 2011 | |
2013 | /* Normal assignment -- just do it. */ | | 2012 | /* Normal assignment -- just do it. */ |
2014 | Var_Set(name, uvalue, ctxt); | | 2013 | Var_Set(name, uvalue, ctxt); |
2015 | } | | 2014 | } |
2016 | | | 2015 | |
2017 | *out_TRUE_avalue = avalue; | | 2016 | *out_TRUE_avalue = avalue; |
2018 | return TRUE; | | 2017 | return TRUE; |
2019 | } | | 2018 | } |
2020 | | | 2019 | |
2021 | static void | | 2020 | static void |
2022 | VarAssignSpecial(const char *name, const char *avalue) | | 2021 | VarAssignSpecial(const char *name, const char *avalue) |
2023 | { | | 2022 | { |
2024 | if (strcmp(name, MAKEOVERRIDES) == 0) | | 2023 | if (strcmp(name, MAKEOVERRIDES) == 0) |
2025 | Main_ExportMAKEFLAGS(FALSE); /* re-export MAKEFLAGS */ | | 2024 | Main_ExportMAKEFLAGS(FALSE); /* re-export MAKEFLAGS */ |
2026 | else if (strcmp(name, ".CURDIR") == 0) { | | 2025 | else if (strcmp(name, ".CURDIR") == 0) { |
2027 | /* | | 2026 | /* |
2028 | * Someone is being (too?) clever... | | 2027 | * Someone is being (too?) clever... |
2029 | * Let's pretend they know what they are doing and | | 2028 | * Let's pretend they know what they are doing and |
2030 | * re-initialize the 'cur' CachedDir. | | 2029 | * re-initialize the 'cur' CachedDir. |
2031 | */ | | 2030 | */ |
2032 | Dir_InitCur(avalue); | | 2031 | Dir_InitCur(avalue); |
2033 | Dir_SetPATH(); | | 2032 | Dir_SetPATH(); |
2034 | } else if (strcmp(name, MAKE_JOB_PREFIX) == 0) | | 2033 | } else if (strcmp(name, MAKE_JOB_PREFIX) == 0) |
2035 | Job_SetPrefix(); | | 2034 | Job_SetPrefix(); |
2036 | else if (strcmp(name, MAKE_EXPORTED) == 0) | | 2035 | else if (strcmp(name, MAKE_EXPORTED) == 0) |
2037 | Var_ExportVars(avalue); | | 2036 | Var_ExportVars(avalue); |
2038 | } | | 2037 | } |
2039 | | | 2038 | |
2040 | /* Perform the variable variable assignment in the given context. */ | | 2039 | /* Perform the variable variable assignment in the given context. */ |
2041 | void | | 2040 | void |
2042 | Parse_DoVar(VarAssign *var, GNode *ctxt) | | 2041 | Parse_DoVar(VarAssign *var, GNode *ctxt) |
2043 | { | | 2042 | { |
2044 | FStr avalue; /* actual value (maybe expanded) */ | | 2043 | FStr avalue; /* actual value (maybe expanded) */ |
2045 | | | 2044 | |
2046 | VarCheckSyntax(var->op, var->value, ctxt); | | 2045 | VarCheckSyntax(var->op, var->value, ctxt); |
2047 | if (VarAssign_Eval(var->varname, var->op, var->value, ctxt, &avalue)) { | | 2046 | if (VarAssign_Eval(var->varname, var->op, var->value, ctxt, &avalue)) { |
2048 | VarAssignSpecial(var->varname, avalue.str); | | 2047 | VarAssignSpecial(var->varname, avalue.str); |
2049 | FStr_Done(&avalue); | | 2048 | FStr_Done(&avalue); |
2050 | } | | 2049 | } |
2051 | | | 2050 | |
2052 | free(var->varname); | | 2051 | free(var->varname); |
2053 | } | | 2052 | } |
2054 | | | 2053 | |
2055 | | | 2054 | |
2056 | /* See if the command possibly calls a sub-make by using the variable | | 2055 | /* See if the command possibly calls a sub-make by using the variable |
2057 | * expressions ${.MAKE}, ${MAKE} or the plain word "make". */ | | 2056 | * expressions ${.MAKE}, ${MAKE} or the plain word "make". */ |
2058 | static Boolean | | 2057 | static Boolean |
2059 | MaybeSubMake(const char *cmd) | | 2058 | MaybeSubMake(const char *cmd) |
2060 | { | | 2059 | { |
2061 | const char *start; | | 2060 | const char *start; |
2062 | | | 2061 | |
2063 | for (start = cmd; *start != '\0'; start++) { | | 2062 | for (start = cmd; *start != '\0'; start++) { |
2064 | const char *p = start; | | 2063 | const char *p = start; |
2065 | char endc; | | 2064 | char endc; |
2066 | | | 2065 | |
2067 | /* XXX: What if progname != "make"? */ | | 2066 | /* XXX: What if progname != "make"? */ |
2068 | if (p[0] == 'm' && p[1] == 'a' && p[2] == 'k' && p[3] == 'e') | | 2067 | if (p[0] == 'm' && p[1] == 'a' && p[2] == 'k' && p[3] == 'e') |
2069 | if (start == cmd || !ch_isalnum(p[-1])) | | 2068 | if (start == cmd || !ch_isalnum(p[-1])) |
2070 | if (!ch_isalnum(p[4])) | | 2069 | if (!ch_isalnum(p[4])) |
2071 | return TRUE; | | 2070 | return TRUE; |
2072 | | | 2071 | |
2073 | if (*p != '$') | | 2072 | if (*p != '$') |
2074 | continue; | | 2073 | continue; |
2075 | p++; | | 2074 | p++; |
2076 | | | 2075 | |
2077 | if (*p == '{') | | 2076 | if (*p == '{') |
2078 | endc = '}'; | | 2077 | endc = '}'; |
2079 | else if (*p == '(') | | 2078 | else if (*p == '(') |
2080 | endc = ')'; | | 2079 | endc = ')'; |
2081 | else | | 2080 | else |
2082 | continue; | | 2081 | continue; |
2083 | p++; | | 2082 | p++; |
2084 | | | 2083 | |
2085 | if (*p == '.') /* Accept either ${.MAKE} or ${MAKE}. */ | | 2084 | if (*p == '.') /* Accept either ${.MAKE} or ${MAKE}. */ |
2086 | p++; | | 2085 | p++; |
2087 | | | 2086 | |
2088 | if (p[0] == 'M' && p[1] == 'A' && p[2] == 'K' && p[3] == 'E') | | 2087 | if (p[0] == 'M' && p[1] == 'A' && p[2] == 'K' && p[3] == 'E') |