| @@ -1,1619 +1,1616 @@ | | | @@ -1,1619 +1,1616 @@ |
1 | /* $NetBSD: parse.c,v 1.532 2021/01/26 23:44:56 rillig Exp $ */ | | 1 | /* $NetBSD: parse.c,v 1.533 2021/01/27 00:02:38 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/stat.h> | | 101 | #include <sys/stat.h> |
102 | #include <errno.h> | | 102 | #include <errno.h> |
103 | #include <stdarg.h> | | 103 | #include <stdarg.h> |
104 | #include <stdint.h> | | 104 | #include <stdint.h> |
105 | | | 105 | |
106 | #include "make.h" | | 106 | #include "make.h" |
107 | #include "dir.h" | | 107 | #include "dir.h" |
108 | #include "job.h" | | 108 | #include "job.h" |
109 | #include "pathnames.h" | | 109 | #include "pathnames.h" |
110 | | | 110 | |
111 | /* "@(#)parse.c 8.3 (Berkeley) 3/19/94" */ | | 111 | /* "@(#)parse.c 8.3 (Berkeley) 3/19/94" */ |
112 | MAKE_RCSID("$NetBSD: parse.c,v 1.532 2021/01/26 23:44:56 rillig Exp $"); | | 112 | MAKE_RCSID("$NetBSD: parse.c,v 1.533 2021/01/27 00:02:38 rillig Exp $"); |
113 | | | 113 | |
114 | /* types and constants */ | | 114 | /* types and constants */ |
115 | | | 115 | |
116 | /* | | 116 | /* |
117 | * Structure for a file being read ("included file") | | 117 | * Structure for a file being read ("included file") |
118 | */ | | 118 | */ |
119 | typedef struct IFile { | | 119 | typedef struct IFile { |
120 | char *fname; /* name of file (relative? absolute?) */ | | 120 | char *fname; /* name of file (relative? absolute?) */ |
121 | Boolean fromForLoop; /* simulated .include by the .for loop */ | | 121 | Boolean fromForLoop; /* simulated .include by the .for loop */ |
122 | int lineno; /* current line number in file */ | | 122 | int lineno; /* current line number in file */ |
123 | int first_lineno; /* line number of start of text */ | | 123 | int first_lineno; /* line number of start of text */ |
124 | unsigned int cond_depth; /* 'if' nesting when file opened */ | | 124 | unsigned int cond_depth; /* 'if' nesting when file opened */ |
125 | Boolean depending; /* state of doing_depend on EOF */ | | 125 | Boolean depending; /* state of doing_depend on EOF */ |
126 | | | 126 | |
127 | /* The buffer from which the file's content is read. */ | | 127 | /* The buffer from which the file's content is read. */ |
128 | char *buf_freeIt; | | 128 | char *buf_freeIt; |
129 | char *buf_ptr; /* next char to be read */ | | 129 | char *buf_ptr; /* next char to be read */ |
130 | char *buf_end; | | 130 | char *buf_end; |
131 | | | 131 | |
132 | /* Function to read more data, with a single opaque argument. */ | | 132 | /* Function to read more data, with a single opaque argument. */ |
133 | ReadMoreProc readMore; | | 133 | ReadMoreProc readMore; |
134 | void *readMoreArg; | | 134 | void *readMoreArg; |
135 | | | 135 | |
136 | struct loadedfile *lf; /* loadedfile object, if any */ | | 136 | struct loadedfile *lf; /* loadedfile object, if any */ |
137 | } IFile; | | 137 | } IFile; |
138 | | | 138 | |
139 | /* | | 139 | /* |
140 | * Tokens for target attributes | | 140 | * Tokens for target attributes |
141 | */ | | 141 | */ |
142 | typedef enum ParseSpecial { | | 142 | typedef enum ParseSpecial { |
143 | SP_ATTRIBUTE, /* Generic attribute */ | | 143 | SP_ATTRIBUTE, /* Generic attribute */ |
144 | SP_BEGIN, /* .BEGIN */ | | 144 | SP_BEGIN, /* .BEGIN */ |
145 | SP_DEFAULT, /* .DEFAULT */ | | 145 | SP_DEFAULT, /* .DEFAULT */ |
146 | SP_DELETE_ON_ERROR, /* .DELETE_ON_ERROR */ | | 146 | SP_DELETE_ON_ERROR, /* .DELETE_ON_ERROR */ |
147 | SP_END, /* .END */ | | 147 | SP_END, /* .END */ |
148 | SP_ERROR, /* .ERROR */ | | 148 | SP_ERROR, /* .ERROR */ |
149 | SP_IGNORE, /* .IGNORE */ | | 149 | SP_IGNORE, /* .IGNORE */ |
150 | SP_INCLUDES, /* .INCLUDES; not mentioned in the manual page */ | | 150 | SP_INCLUDES, /* .INCLUDES; not mentioned in the manual page */ |
151 | SP_INTERRUPT, /* .INTERRUPT */ | | 151 | SP_INTERRUPT, /* .INTERRUPT */ |
152 | SP_LIBS, /* .LIBS; not mentioned in the manual page */ | | 152 | SP_LIBS, /* .LIBS; not mentioned in the manual page */ |
153 | /* .MAIN and we don't have anything user-specified to make */ | | 153 | /* .MAIN and we don't have anything user-specified to make */ |
154 | SP_MAIN, | | 154 | SP_MAIN, |
155 | SP_META, /* .META */ | | 155 | SP_META, /* .META */ |
156 | SP_MFLAGS, /* .MFLAGS or .MAKEFLAGS */ | | 156 | SP_MFLAGS, /* .MFLAGS or .MAKEFLAGS */ |
157 | SP_NOMETA, /* .NOMETA */ | | 157 | SP_NOMETA, /* .NOMETA */ |
158 | SP_NOMETA_CMP, /* .NOMETA_CMP */ | | 158 | SP_NOMETA_CMP, /* .NOMETA_CMP */ |
159 | SP_NOPATH, /* .NOPATH */ | | 159 | SP_NOPATH, /* .NOPATH */ |
160 | SP_NOT, /* Not special */ | | 160 | SP_NOT, /* Not special */ |
161 | SP_NOTPARALLEL, /* .NOTPARALLEL or .NO_PARALLEL */ | | 161 | SP_NOTPARALLEL, /* .NOTPARALLEL or .NO_PARALLEL */ |
162 | SP_NULL, /* .NULL; not mentioned in the manual page */ | | 162 | SP_NULL, /* .NULL; not mentioned in the manual page */ |
163 | SP_OBJDIR, /* .OBJDIR */ | | 163 | SP_OBJDIR, /* .OBJDIR */ |
164 | SP_ORDER, /* .ORDER */ | | 164 | SP_ORDER, /* .ORDER */ |
165 | SP_PARALLEL, /* .PARALLEL; not mentioned in the manual page */ | | 165 | SP_PARALLEL, /* .PARALLEL; not mentioned in the manual page */ |
166 | SP_PATH, /* .PATH or .PATH.suffix */ | | 166 | SP_PATH, /* .PATH or .PATH.suffix */ |
167 | SP_PHONY, /* .PHONY */ | | 167 | SP_PHONY, /* .PHONY */ |
168 | #ifdef POSIX | | 168 | #ifdef POSIX |
169 | SP_POSIX, /* .POSIX; not mentioned in the manual page */ | | 169 | SP_POSIX, /* .POSIX; not mentioned in the manual page */ |
170 | #endif | | 170 | #endif |
171 | SP_PRECIOUS, /* .PRECIOUS */ | | 171 | SP_PRECIOUS, /* .PRECIOUS */ |
172 | SP_SHELL, /* .SHELL */ | | 172 | SP_SHELL, /* .SHELL */ |
173 | SP_SILENT, /* .SILENT */ | | 173 | SP_SILENT, /* .SILENT */ |
174 | SP_SINGLESHELL, /* .SINGLESHELL; not mentioned in the manual page */ | | 174 | SP_SINGLESHELL, /* .SINGLESHELL; not mentioned in the manual page */ |
175 | SP_STALE, /* .STALE */ | | 175 | SP_STALE, /* .STALE */ |
176 | SP_SUFFIXES, /* .SUFFIXES */ | | 176 | SP_SUFFIXES, /* .SUFFIXES */ |
177 | SP_WAIT /* .WAIT */ | | 177 | SP_WAIT /* .WAIT */ |
178 | } ParseSpecial; | | 178 | } ParseSpecial; |
179 | | | 179 | |
180 | typedef List SearchPathList; | | 180 | typedef List SearchPathList; |
181 | typedef ListNode SearchPathListNode; | | 181 | typedef ListNode SearchPathListNode; |
182 | | | 182 | |
183 | /* result data */ | | 183 | /* result data */ |
184 | | | 184 | |
185 | /* | | 185 | /* |
186 | * The main target to create. This is the first target on the first | | 186 | * The main target to create. This is the first target on the first |
187 | * dependency line in the first makefile. | | 187 | * dependency line in the first makefile. |
188 | */ | | 188 | */ |
189 | static GNode *mainNode; | | 189 | static GNode *mainNode; |
190 | | | 190 | |
191 | /* eval state */ | | 191 | /* eval state */ |
192 | | | 192 | |
193 | /* | | 193 | /* |
194 | * During parsing, the targets from the left-hand side of the currently | | 194 | * During parsing, the targets from the left-hand side of the currently |
195 | * active dependency line, or NULL if the current line does not belong to a | | 195 | * active dependency line, or NULL if the current line does not belong to a |
196 | * dependency line, for example because it is a variable assignment. | | 196 | * dependency line, for example because it is a variable assignment. |
197 | * | | 197 | * |
198 | * See unit-tests/deptgt.mk, keyword "parse.c:targets". | | 198 | * See unit-tests/deptgt.mk, keyword "parse.c:targets". |
199 | */ | | 199 | */ |
200 | static GNodeList *targets; | | 200 | static GNodeList *targets; |
201 | | | 201 | |
202 | #ifdef CLEANUP | | 202 | #ifdef CLEANUP |
203 | /* | | 203 | /* |
204 | * All shell commands for all targets, in no particular order and possibly | | 204 | * All shell commands for all targets, in no particular order and possibly |
205 | * with duplicates. Kept in a separate list since the commands from .USE or | | 205 | * with duplicates. Kept in a separate list since the commands from .USE or |
206 | * .USEBEFORE nodes are shared with other GNodes, thereby giving up the | | 206 | * .USEBEFORE nodes are shared with other GNodes, thereby giving up the |
207 | * easily understandable ownership over the allocated strings. | | 207 | * easily understandable ownership over the allocated strings. |
208 | */ | | 208 | */ |
209 | static StringList targCmds = LST_INIT; | | 209 | static StringList targCmds = LST_INIT; |
210 | #endif | | 210 | #endif |
211 | | | 211 | |
212 | /* | | 212 | /* |
213 | * Predecessor node for handling .ORDER. Initialized to NULL when .ORDER | | 213 | * Predecessor node for handling .ORDER. Initialized to NULL when .ORDER |
214 | * seen, then set to each successive source on the line. | | 214 | * seen, then set to each successive source on the line. |
215 | */ | | 215 | */ |
216 | static GNode *order_pred; | | 216 | static GNode *order_pred; |
217 | | | 217 | |
218 | /* parser state */ | | 218 | /* parser state */ |
219 | | | 219 | |
220 | /* number of fatal errors */ | | 220 | /* number of fatal errors */ |
221 | static int fatals = 0; | | 221 | static int fatals = 0; |
222 | | | 222 | |
223 | /* | | 223 | /* |
224 | * Variables for doing includes | | 224 | * Variables for doing includes |
225 | */ | | 225 | */ |
226 | | | 226 | |
227 | /* | | 227 | /* |
228 | * The include chain of makefiles. At index 0 is the top-level makefile from | | 228 | * The include chain of makefiles. At index 0 is the top-level makefile from |
229 | * the command line, followed by the included files or .for loops, up to and | | 229 | * the command line, followed by the included files or .for loops, up to and |
230 | * including the current file. | | 230 | * including the current file. |
231 | * | | 231 | * |
232 | * See PrintStackTrace for how to interpret the data. | | 232 | * See PrintStackTrace for how to interpret the data. |
233 | */ | | 233 | */ |
234 | static Vector /* of IFile */ includes; | | 234 | static Vector /* of IFile */ includes; |
235 | | | 235 | |
236 | static IFile * | | 236 | static IFile * |
237 | GetInclude(size_t i) | | 237 | GetInclude(size_t i) |
238 | { | | 238 | { |
239 | return Vector_Get(&includes, i); | | 239 | return Vector_Get(&includes, i); |
240 | } | | 240 | } |
241 | | | 241 | |
242 | /* The file that is currently being read. */ | | 242 | /* The file that is currently being read. */ |
243 | static IFile * | | 243 | static IFile * |
244 | CurFile(void) | | 244 | CurFile(void) |
245 | { | | 245 | { |
246 | return GetInclude(includes.len - 1); | | 246 | return GetInclude(includes.len - 1); |
247 | } | | 247 | } |
248 | | | 248 | |
249 | /* include paths */ | | 249 | /* include paths */ |
250 | SearchPath *parseIncPath; /* dirs for "..." includes */ | | 250 | SearchPath *parseIncPath; /* dirs for "..." includes */ |
251 | SearchPath *sysIncPath; /* dirs for <...> includes */ | | 251 | SearchPath *sysIncPath; /* dirs for <...> includes */ |
252 | SearchPath *defSysIncPath; /* default for sysIncPath */ | | 252 | SearchPath *defSysIncPath; /* default for sysIncPath */ |
253 | | | 253 | |
254 | /* parser tables */ | | 254 | /* parser tables */ |
255 | | | 255 | |
256 | /* | | 256 | /* |
257 | * The parseKeywords table is searched using binary search when deciding | | 257 | * The parseKeywords table is searched using binary search when deciding |
258 | * if a target or source is special. The 'spec' field is the ParseSpecial | | 258 | * if a target or source is special. The 'spec' field is the ParseSpecial |
259 | * type of the keyword (SP_NOT if the keyword isn't special as a target) while | | 259 | * type of the keyword (SP_NOT if the keyword isn't special as a target) while |
260 | * the 'op' field is the operator to apply to the list of targets if the | | 260 | * the 'op' field is the operator to apply to the list of targets if the |
261 | * keyword is used as a source ("0" if the keyword isn't special as a source) | | 261 | * keyword is used as a source ("0" if the keyword isn't special as a source) |
262 | */ | | 262 | */ |
263 | static const struct { | | 263 | static const struct { |
264 | const char *name; /* Name of keyword */ | | 264 | const char *name; /* Name of keyword */ |
265 | ParseSpecial spec; /* Type when used as a target */ | | 265 | ParseSpecial spec; /* Type when used as a target */ |
266 | GNodeType op; /* Operator when used as a source */ | | 266 | GNodeType op; /* Operator when used as a source */ |
267 | } parseKeywords[] = { | | 267 | } parseKeywords[] = { |
268 | { ".BEGIN", SP_BEGIN, OP_NONE }, | | 268 | { ".BEGIN", SP_BEGIN, OP_NONE }, |
269 | { ".DEFAULT", SP_DEFAULT, OP_NONE }, | | 269 | { ".DEFAULT", SP_DEFAULT, OP_NONE }, |
270 | { ".DELETE_ON_ERROR", SP_DELETE_ON_ERROR, OP_NONE }, | | 270 | { ".DELETE_ON_ERROR", SP_DELETE_ON_ERROR, OP_NONE }, |
271 | { ".END", SP_END, OP_NONE }, | | 271 | { ".END", SP_END, OP_NONE }, |
272 | { ".ERROR", SP_ERROR, OP_NONE }, | | 272 | { ".ERROR", SP_ERROR, OP_NONE }, |
273 | { ".EXEC", SP_ATTRIBUTE, OP_EXEC }, | | 273 | { ".EXEC", SP_ATTRIBUTE, OP_EXEC }, |
274 | { ".IGNORE", SP_IGNORE, OP_IGNORE }, | | 274 | { ".IGNORE", SP_IGNORE, OP_IGNORE }, |
275 | { ".INCLUDES", SP_INCLUDES, OP_NONE }, | | 275 | { ".INCLUDES", SP_INCLUDES, OP_NONE }, |
276 | { ".INTERRUPT", SP_INTERRUPT, OP_NONE }, | | 276 | { ".INTERRUPT", SP_INTERRUPT, OP_NONE }, |
277 | { ".INVISIBLE", SP_ATTRIBUTE, OP_INVISIBLE }, | | 277 | { ".INVISIBLE", SP_ATTRIBUTE, OP_INVISIBLE }, |
278 | { ".JOIN", SP_ATTRIBUTE, OP_JOIN }, | | 278 | { ".JOIN", SP_ATTRIBUTE, OP_JOIN }, |
279 | { ".LIBS", SP_LIBS, OP_NONE }, | | 279 | { ".LIBS", SP_LIBS, OP_NONE }, |
280 | { ".MADE", SP_ATTRIBUTE, OP_MADE }, | | 280 | { ".MADE", SP_ATTRIBUTE, OP_MADE }, |
281 | { ".MAIN", SP_MAIN, OP_NONE }, | | 281 | { ".MAIN", SP_MAIN, OP_NONE }, |
282 | { ".MAKE", SP_ATTRIBUTE, OP_MAKE }, | | 282 | { ".MAKE", SP_ATTRIBUTE, OP_MAKE }, |
283 | { ".MAKEFLAGS", SP_MFLAGS, OP_NONE }, | | 283 | { ".MAKEFLAGS", SP_MFLAGS, OP_NONE }, |
284 | { ".META", SP_META, OP_META }, | | 284 | { ".META", SP_META, OP_META }, |
285 | { ".MFLAGS", SP_MFLAGS, OP_NONE }, | | 285 | { ".MFLAGS", SP_MFLAGS, OP_NONE }, |
286 | { ".NOMETA", SP_NOMETA, OP_NOMETA }, | | 286 | { ".NOMETA", SP_NOMETA, OP_NOMETA }, |
287 | { ".NOMETA_CMP", SP_NOMETA_CMP, OP_NOMETA_CMP }, | | 287 | { ".NOMETA_CMP", SP_NOMETA_CMP, OP_NOMETA_CMP }, |
288 | { ".NOPATH", SP_NOPATH, OP_NOPATH }, | | 288 | { ".NOPATH", SP_NOPATH, OP_NOPATH }, |
289 | { ".NOTMAIN", SP_ATTRIBUTE, OP_NOTMAIN }, | | 289 | { ".NOTMAIN", SP_ATTRIBUTE, OP_NOTMAIN }, |
290 | { ".NOTPARALLEL", SP_NOTPARALLEL, OP_NONE }, | | 290 | { ".NOTPARALLEL", SP_NOTPARALLEL, OP_NONE }, |
291 | { ".NO_PARALLEL", SP_NOTPARALLEL, OP_NONE }, | | 291 | { ".NO_PARALLEL", SP_NOTPARALLEL, OP_NONE }, |
292 | { ".NULL", SP_NULL, OP_NONE }, | | 292 | { ".NULL", SP_NULL, OP_NONE }, |
293 | { ".OBJDIR", SP_OBJDIR, OP_NONE }, | | 293 | { ".OBJDIR", SP_OBJDIR, OP_NONE }, |
294 | { ".OPTIONAL", SP_ATTRIBUTE, OP_OPTIONAL }, | | 294 | { ".OPTIONAL", SP_ATTRIBUTE, OP_OPTIONAL }, |
295 | { ".ORDER", SP_ORDER, OP_NONE }, | | 295 | { ".ORDER", SP_ORDER, OP_NONE }, |
296 | { ".PARALLEL", SP_PARALLEL, OP_NONE }, | | 296 | { ".PARALLEL", SP_PARALLEL, OP_NONE }, |
297 | { ".PATH", SP_PATH, OP_NONE }, | | 297 | { ".PATH", SP_PATH, OP_NONE }, |
298 | { ".PHONY", SP_PHONY, OP_PHONY }, | | 298 | { ".PHONY", SP_PHONY, OP_PHONY }, |
299 | #ifdef POSIX | | 299 | #ifdef POSIX |
300 | { ".POSIX", SP_POSIX, OP_NONE }, | | 300 | { ".POSIX", SP_POSIX, OP_NONE }, |
301 | #endif | | 301 | #endif |
302 | { ".PRECIOUS", SP_PRECIOUS, OP_PRECIOUS }, | | 302 | { ".PRECIOUS", SP_PRECIOUS, OP_PRECIOUS }, |
303 | { ".RECURSIVE", SP_ATTRIBUTE, OP_MAKE }, | | 303 | { ".RECURSIVE", SP_ATTRIBUTE, OP_MAKE }, |
304 | { ".SHELL", SP_SHELL, OP_NONE }, | | 304 | { ".SHELL", SP_SHELL, OP_NONE }, |
305 | { ".SILENT", SP_SILENT, OP_SILENT }, | | 305 | { ".SILENT", SP_SILENT, OP_SILENT }, |
306 | { ".SINGLESHELL", SP_SINGLESHELL, OP_NONE }, | | 306 | { ".SINGLESHELL", SP_SINGLESHELL, OP_NONE }, |
307 | { ".STALE", SP_STALE, OP_NONE }, | | 307 | { ".STALE", SP_STALE, OP_NONE }, |
308 | { ".SUFFIXES", SP_SUFFIXES, OP_NONE }, | | 308 | { ".SUFFIXES", SP_SUFFIXES, OP_NONE }, |
309 | { ".USE", SP_ATTRIBUTE, OP_USE }, | | 309 | { ".USE", SP_ATTRIBUTE, OP_USE }, |
310 | { ".USEBEFORE", SP_ATTRIBUTE, OP_USEBEFORE }, | | 310 | { ".USEBEFORE", SP_ATTRIBUTE, OP_USEBEFORE }, |
311 | { ".WAIT", SP_WAIT, OP_NONE }, | | 311 | { ".WAIT", SP_WAIT, OP_NONE }, |
312 | }; | | 312 | }; |
313 | | | 313 | |
314 | /* file loader */ | | 314 | /* file loader */ |
315 | | | 315 | |
316 | struct loadedfile { | | 316 | struct loadedfile { |
317 | /* XXX: What is the lifetime of this path? Who manages the memory? */ | | 317 | /* XXX: What is the lifetime of this path? Who manages the memory? */ |
318 | const char *path; /* name, for error reports */ | | 318 | const char *path; /* name, for error reports */ |
319 | char *buf; /* contents buffer */ | | 319 | char *buf; /* contents buffer */ |
320 | size_t len; /* length of contents */ | | 320 | size_t len; /* length of contents */ |
321 | Boolean used; /* XXX: have we used the data yet */ | | 321 | Boolean used; /* XXX: have we used the data yet */ |
322 | }; | | 322 | }; |
323 | | | 323 | |
324 | /* XXX: What is the lifetime of the path? Who manages the memory? */ | | 324 | /* XXX: What is the lifetime of the path? Who manages the memory? */ |
325 | static struct loadedfile * | | 325 | static struct loadedfile * |
326 | loadedfile_create(const char *path, char *buf, size_t buflen) | | 326 | loadedfile_create(const char *path, char *buf, size_t buflen) |
327 | { | | 327 | { |
328 | struct loadedfile *lf; | | 328 | struct loadedfile *lf; |
329 | | | 329 | |
330 | lf = bmake_malloc(sizeof *lf); | | 330 | lf = bmake_malloc(sizeof *lf); |
331 | lf->path = path == NULL ? "(stdin)" : path; | | 331 | lf->path = path == NULL ? "(stdin)" : path; |
332 | lf->buf = buf; | | 332 | lf->buf = buf; |
333 | lf->len = buflen; | | 333 | lf->len = buflen; |
334 | lf->used = FALSE; | | 334 | lf->used = FALSE; |
335 | return lf; | | 335 | return lf; |
336 | } | | 336 | } |
337 | | | 337 | |
338 | static void | | 338 | static void |
339 | loadedfile_destroy(struct loadedfile *lf) | | 339 | loadedfile_destroy(struct loadedfile *lf) |
340 | { | | 340 | { |
341 | free(lf->buf); | | 341 | free(lf->buf); |
342 | free(lf); | | 342 | free(lf); |
343 | } | | 343 | } |
344 | | | 344 | |
345 | /* | | 345 | /* |
346 | * readMore() operation for loadedfile, as needed by the weird and twisted | | 346 | * readMore() operation for loadedfile, as needed by the weird and twisted |
347 | * logic below. Once that's cleaned up, we can get rid of lf->used. | | 347 | * logic below. Once that's cleaned up, we can get rid of lf->used. |
348 | */ | | 348 | */ |
349 | static char * | | 349 | static char * |
350 | loadedfile_readMore(void *x, size_t *len) | | 350 | loadedfile_readMore(void *x, size_t *len) |
351 | { | | 351 | { |
352 | struct loadedfile *lf = x; | | 352 | struct loadedfile *lf = x; |
353 | | | 353 | |
354 | if (lf->used) | | 354 | if (lf->used) |
355 | return NULL; | | 355 | return NULL; |
356 | | | 356 | |
357 | lf->used = TRUE; | | 357 | lf->used = TRUE; |
358 | *len = lf->len; | | 358 | *len = lf->len; |
359 | return lf->buf; | | 359 | return lf->buf; |
360 | } | | 360 | } |
361 | | | 361 | |
362 | /* | | 362 | /* |
363 | * Try to get the size of a file. | | 363 | * Try to get the size of a file. |
364 | */ | | 364 | */ |
365 | static Boolean | | 365 | static Boolean |
366 | load_getsize(int fd, size_t *ret) | | 366 | load_getsize(int fd, size_t *ret) |
367 | { | | 367 | { |
368 | struct stat st; | | 368 | struct stat st; |
369 | | | 369 | |
370 | if (fstat(fd, &st) < 0) | | 370 | if (fstat(fd, &st) < 0) |
371 | return FALSE; | | 371 | return FALSE; |
372 | | | 372 | |
373 | if (!S_ISREG(st.st_mode)) | | 373 | if (!S_ISREG(st.st_mode)) |
374 | return FALSE; | | 374 | return FALSE; |
375 | | | 375 | |
376 | /* | | 376 | /* |
377 | * st_size is an off_t, which is 64 bits signed; *ret is | | 377 | * st_size is an off_t, which is 64 bits signed; *ret is |
378 | * size_t, which might be 32 bits unsigned or 64 bits | | 378 | * size_t, which might be 32 bits unsigned or 64 bits |
379 | * unsigned. Rather than being elaborate, just punt on | | 379 | * unsigned. Rather than being elaborate, just punt on |
380 | * files that are more than 1 GiB. We should never | | 380 | * files that are more than 1 GiB. We should never |
381 | * see a makefile that size in practice. | | 381 | * see a makefile that size in practice. |
382 | * | | 382 | * |
383 | * While we're at it reject negative sizes too, just in case. | | 383 | * While we're at it reject negative sizes too, just in case. |
384 | */ | | 384 | */ |
385 | if (st.st_size < 0 || st.st_size > 0x3fffffff) | | 385 | if (st.st_size < 0 || st.st_size > 0x3fffffff) |
386 | return FALSE; | | 386 | return FALSE; |
387 | | | 387 | |
388 | *ret = (size_t)st.st_size; | | 388 | *ret = (size_t)st.st_size; |
389 | return TRUE; | | 389 | return TRUE; |
390 | } | | 390 | } |
391 | | | 391 | |
392 | /* | | 392 | /* |
393 | * Read in a file. | | 393 | * Read in a file. |
394 | * | | 394 | * |
395 | * Until the path search logic can be moved under here instead of | | 395 | * Until the path search logic can be moved under here instead of |
396 | * being in the caller in another source file, we need to have the fd | | 396 | * being in the caller in another source file, we need to have the fd |
397 | * passed in already open. Bleh. | | 397 | * passed in already open. Bleh. |
398 | * | | 398 | * |
399 | * If the path is NULL, use stdin. | | 399 | * If the path is NULL, use stdin. |
400 | */ | | 400 | */ |
401 | static struct loadedfile * | | 401 | static struct loadedfile * |
402 | loadfile(const char *path, int fd) | | 402 | loadfile(const char *path, int fd) |
403 | { | | 403 | { |
404 | ssize_t n; | | 404 | ssize_t n; |
405 | Buffer buf; | | 405 | Buffer buf; |
406 | size_t filesize; | | 406 | size_t filesize; |
407 | | | 407 | |
408 | | | 408 | |
409 | if (path == NULL) { | | 409 | if (path == NULL) { |
410 | assert(fd == -1); | | 410 | assert(fd == -1); |
411 | fd = STDIN_FILENO; | | 411 | fd = STDIN_FILENO; |
412 | } | | 412 | } |
413 | | | 413 | |
414 | if (load_getsize(fd, &filesize)) { | | 414 | if (load_getsize(fd, &filesize)) { |
415 | /* | | 415 | /* |
416 | * Avoid resizing the buffer later for no reason. | | 416 | * Avoid resizing the buffer later for no reason. |
417 | * | | 417 | * |
418 | * At the same time leave space for adding a final '\n', | | 418 | * At the same time leave space for adding a final '\n', |
419 | * just in case it is missing in the file. | | 419 | * just in case it is missing in the file. |
420 | */ | | 420 | */ |
421 | filesize++; | | 421 | filesize++; |
422 | } else | | 422 | } else |
423 | filesize = 1024; | | 423 | filesize = 1024; |
424 | Buf_InitSize(&buf, filesize); | | 424 | Buf_InitSize(&buf, filesize); |
425 | | | 425 | |
426 | for (;;) { | | 426 | for (;;) { |
427 | assert(buf.len <= buf.cap); | | 427 | assert(buf.len <= buf.cap); |
428 | if (buf.len == buf.cap) { | | 428 | if (buf.len == buf.cap) { |
429 | if (buf.cap > 0x1fffffff) { | | 429 | if (buf.cap > 0x1fffffff) { |
430 | errno = EFBIG; | | 430 | errno = EFBIG; |
431 | Error("%s: file too large", path); | | 431 | Error("%s: file too large", path); |
432 | exit(2); /* Not 1 so -q can distinguish error */ | | 432 | exit(2); /* Not 1 so -q can distinguish error */ |
433 | } | | 433 | } |
434 | Buf_Expand(&buf); | | 434 | Buf_Expand(&buf); |
435 | } | | 435 | } |
436 | assert(buf.len < buf.cap); | | 436 | assert(buf.len < buf.cap); |
437 | n = read(fd, buf.data + buf.len, buf.cap - buf.len); | | 437 | n = read(fd, buf.data + buf.len, buf.cap - buf.len); |
438 | if (n < 0) { | | 438 | if (n < 0) { |
439 | Error("%s: read error: %s", path, strerror(errno)); | | 439 | Error("%s: read error: %s", path, strerror(errno)); |
440 | exit(2); /* Not 1 so -q can distinguish error */ | | 440 | exit(2); /* Not 1 so -q can distinguish error */ |
441 | } | | 441 | } |
442 | if (n == 0) | | 442 | if (n == 0) |
443 | break; | | 443 | break; |
444 | | | 444 | |
445 | buf.len += (size_t)n; | | 445 | buf.len += (size_t)n; |
446 | } | | 446 | } |
447 | assert(buf.len <= buf.cap); | | 447 | assert(buf.len <= buf.cap); |
448 | | | 448 | |
449 | if (!Buf_EndsWith(&buf, '\n')) | | 449 | if (!Buf_EndsWith(&buf, '\n')) |
450 | Buf_AddByte(&buf, '\n'); | | 450 | Buf_AddByte(&buf, '\n'); |
451 | | | 451 | |
452 | if (path != NULL) | | 452 | if (path != NULL) |
453 | close(fd); | | 453 | close(fd); |
454 | | | 454 | |
455 | { | | 455 | { |
456 | struct loadedfile *lf = loadedfile_create(path, | | 456 | struct loadedfile *lf = loadedfile_create(path, |
457 | buf.data, buf.len); | | 457 | buf.data, buf.len); |
458 | Buf_Destroy(&buf, FALSE); | | 458 | Buf_Destroy(&buf, FALSE); |
459 | return lf; | | 459 | return lf; |
460 | } | | 460 | } |
461 | } | | 461 | } |
462 | | | 462 | |
463 | static void | | 463 | static void |
464 | PrintStackTrace(void) | | 464 | PrintStackTrace(void) |
465 | { | | 465 | { |
466 | const IFile *entries; | | 466 | const IFile *entries; |
467 | size_t i, n; | | 467 | size_t i, n; |
468 | | | 468 | |
469 | if (!(DEBUG(PARSE))) | | 469 | if (!(DEBUG(PARSE))) |
470 | return; | | 470 | return; |
471 | | | 471 | |
472 | entries = GetInclude(0); | | 472 | entries = GetInclude(0); |
473 | n = includes.len; | | 473 | n = includes.len; |
474 | if (n == 0) | | 474 | if (n == 0) |
475 | return; | | 475 | return; |
476 | n--; /* This entry is already in the diagnostic. */ | | 476 | n--; /* This entry is already in the diagnostic. */ |
477 | | | 477 | |
478 | /* | | 478 | /* |
479 | * For the IFiles with fromForLoop, lineno seems to be sorted | | 479 | * For the IFiles with fromForLoop, lineno seems to be sorted |
480 | * backwards. This is because lineno is the number of completely | | 480 | * backwards. This is because lineno is the number of completely |
481 | * parsed lines, which for a .for loop is right after the | | 481 | * parsed lines, which for a .for loop is right after the |
482 | * corresponding .endfor. The intuitive line number comes from | | 482 | * corresponding .endfor. The intuitive line number comes from |
483 | * first_lineno instead, which points at the start of the .for loop. | | 483 | * first_lineno instead, which points at the start of the .for loop. |
484 | * | | 484 | * |
485 | * To make the stack trace intuitive, the entry below each chain of | | 485 | * To make the stack trace intuitive, the entry below each chain of |
486 | * .for loop entries must be ignored completely since neither its | | 486 | * .for loop entries must be ignored completely since neither its |
487 | * lineno nor its first_lineno is useful. Instead, the topmost of | | 487 | * lineno nor its first_lineno is useful. Instead, the topmost of |
488 | * each chain of .for loop entries needs to be printed twice, once | | 488 | * each chain of .for loop entries needs to be printed twice, once |
489 | * with its first_lineno and once with its lineno. | | 489 | * with its first_lineno and once with its lineno. |
490 | */ | | 490 | */ |
491 | | | 491 | |
492 | for (i = n; i-- > 0;) { | | 492 | for (i = n; i-- > 0;) { |
493 | const IFile *entry = entries + i; | | 493 | const IFile *entry = entries + i; |
494 | const char *fname = entry->fname; | | 494 | const char *fname = entry->fname; |
495 | Boolean printLineno; | | 495 | Boolean printLineno; |
496 | char dirbuf[MAXPATHLEN + 1]; | | 496 | char dirbuf[MAXPATHLEN + 1]; |
497 | | | 497 | |
498 | if (fname[0] != '/' && strcmp(fname, "(stdin)") != 0) | | 498 | if (fname[0] != '/' && strcmp(fname, "(stdin)") != 0) |
499 | fname = realpath(fname, dirbuf); | | 499 | fname = realpath(fname, dirbuf); |
500 | | | 500 | |
501 | printLineno = !entry->fromForLoop; | | 501 | printLineno = !entry->fromForLoop; |
502 | if (i + 1 < n && entries[i + 1].fromForLoop == printLineno) | | 502 | if (i + 1 < n && entries[i + 1].fromForLoop == printLineno) |
503 | printLineno = entry->fromForLoop; | | 503 | printLineno = entry->fromForLoop; |
504 | | | 504 | |
505 | if (printLineno) | | 505 | if (printLineno) |
506 | debug_printf("\tin .include from %s:%d\n", | | 506 | debug_printf("\tin .include from %s:%d\n", |
507 | fname, entry->lineno); | | 507 | fname, entry->lineno); |
508 | if (entry->fromForLoop) | | 508 | if (entry->fromForLoop) |
509 | debug_printf("\tin .for loop from %s:%d\n", | | 509 | debug_printf("\tin .for loop from %s:%d\n", |
510 | fname, entry->first_lineno); | | 510 | fname, entry->first_lineno); |
511 | } | | 511 | } |
512 | } | | 512 | } |
513 | | | 513 | |
514 | /* Check if the current character is escaped on the current line. */ | | 514 | /* Check if the current character is escaped on the current line. */ |
515 | static Boolean | | 515 | static Boolean |
516 | ParseIsEscaped(const char *line, const char *c) | | 516 | ParseIsEscaped(const char *line, const char *c) |
517 | { | | 517 | { |
518 | Boolean active = FALSE; | | 518 | Boolean active = FALSE; |
519 | for (;;) { | | 519 | for (;;) { |
520 | if (line == c) | | 520 | if (line == c) |
521 | return active; | | 521 | return active; |
522 | if (*--c != '\\') | | 522 | if (*--c != '\\') |
523 | return active; | | 523 | return active; |
524 | active = !active; | | 524 | active = !active; |
525 | } | | 525 | } |
526 | } | | 526 | } |
527 | | | 527 | |
528 | /* | | 528 | /* |
529 | * Add the filename and lineno to the GNode so that we remember where it | | 529 | * Add the filename and lineno to the GNode so that we remember where it |
530 | * was first defined. | | 530 | * was first defined. |
531 | */ | | 531 | */ |
532 | static void | | 532 | static void |
533 | ParseMark(GNode *gn) | | 533 | ParseMark(GNode *gn) |
534 | { | | 534 | { |
535 | IFile *curFile = CurFile(); | | 535 | IFile *curFile = CurFile(); |
536 | gn->fname = curFile->fname; | | 536 | gn->fname = curFile->fname; |
537 | gn->lineno = curFile->lineno; | | 537 | gn->lineno = curFile->lineno; |
538 | } | | 538 | } |
539 | | | 539 | |
540 | /* | | 540 | /* |
541 | * Look in the table of keywords for one matching the given string. | | 541 | * Look in the table of keywords for one matching the given string. |
542 | * Return the index of the keyword, or -1 if it isn't there. | | 542 | * Return the index of the keyword, or -1 if it isn't there. |
543 | */ | | 543 | */ |
544 | static int | | 544 | static int |
545 | ParseFindKeyword(const char *str) | | 545 | ParseFindKeyword(const char *str) |
546 | { | | 546 | { |
547 | int start = 0; | | 547 | int start = 0; |
548 | int end = sizeof parseKeywords / sizeof parseKeywords[0] - 1; | | 548 | int end = sizeof parseKeywords / sizeof parseKeywords[0] - 1; |
549 | | | 549 | |
550 | do { | | 550 | do { |
551 | int curr = start + (end - start) / 2; | | 551 | int curr = start + (end - start) / 2; |
552 | int diff = strcmp(str, parseKeywords[curr].name); | | 552 | int diff = strcmp(str, parseKeywords[curr].name); |
553 | | | 553 | |
554 | if (diff == 0) | | 554 | if (diff == 0) |
555 | return curr; | | 555 | return curr; |
556 | if (diff < 0) | | 556 | if (diff < 0) |
557 | end = curr - 1; | | 557 | end = curr - 1; |
558 | else | | 558 | else |
559 | start = curr + 1; | | 559 | start = curr + 1; |
560 | } while (start <= end); | | 560 | } while (start <= end); |
561 | | | 561 | |
562 | return -1; | | 562 | return -1; |
563 | } | | 563 | } |
564 | | | 564 | |
565 | static void | | 565 | static void |
566 | PrintLocation(FILE *f, const char *fname, size_t lineno) | | 566 | PrintLocation(FILE *f, const char *fname, size_t lineno) |
567 | { | | 567 | { |
568 | char dirbuf[MAXPATHLEN + 1]; | | 568 | char dirbuf[MAXPATHLEN + 1]; |
569 | FStr dir, base; | | 569 | FStr dir, base; |
570 | | | 570 | |
571 | if (*fname == '/' || strcmp(fname, "(stdin)") == 0) { | | 571 | if (*fname == '/' || strcmp(fname, "(stdin)") == 0) { |
572 | (void)fprintf(f, "\"%s\" line %u: ", fname, (unsigned)lineno); | | 572 | (void)fprintf(f, "\"%s\" line %u: ", fname, (unsigned)lineno); |
573 | return; | | 573 | return; |
574 | } | | 574 | } |
575 | | | 575 | |
576 | /* Find out which makefile is the culprit. | | 576 | /* Find out which makefile is the culprit. |
577 | * We try ${.PARSEDIR} and apply realpath(3) if not absolute. */ | | 577 | * We try ${.PARSEDIR} and apply realpath(3) if not absolute. */ |
578 | | | 578 | |
579 | dir = Var_Value(".PARSEDIR", VAR_GLOBAL); | | 579 | dir = Var_Value(".PARSEDIR", VAR_GLOBAL); |
580 | if (dir.str == NULL) | | 580 | if (dir.str == NULL) |
581 | dir.str = "."; | | 581 | dir.str = "."; |
582 | if (dir.str[0] != '/') | | 582 | if (dir.str[0] != '/') |
583 | dir.str = realpath(dir.str, dirbuf); | | 583 | dir.str = realpath(dir.str, dirbuf); |
584 | | | 584 | |
585 | base = Var_Value(".PARSEFILE", VAR_GLOBAL); | | 585 | base = Var_Value(".PARSEFILE", VAR_GLOBAL); |
586 | if (base.str == NULL) | | 586 | if (base.str == NULL) |
587 | base.str = str_basename(fname); | | 587 | base.str = str_basename(fname); |
588 | | | 588 | |
589 | (void)fprintf(f, "\"%s/%s\" line %u: ", | | 589 | (void)fprintf(f, "\"%s/%s\" line %u: ", |
590 | dir.str, base.str, (unsigned)lineno); | | 590 | dir.str, base.str, (unsigned)lineno); |
591 | | | 591 | |
592 | FStr_Done(&base); | | 592 | FStr_Done(&base); |
593 | FStr_Done(&dir); | | 593 | FStr_Done(&dir); |
594 | } | | 594 | } |
595 | | | 595 | |
596 | static void | | 596 | static void |
597 | ParseVErrorInternal(FILE *f, const char *fname, size_t lineno, | | 597 | ParseVErrorInternal(FILE *f, const char *fname, size_t lineno, |
598 | ParseErrorLevel type, const char *fmt, va_list ap) | | 598 | ParseErrorLevel type, const char *fmt, va_list ap) |
599 | { | | 599 | { |
600 | static Boolean fatal_warning_error_printed = FALSE; | | 600 | static Boolean fatal_warning_error_printed = FALSE; |
601 | | | 601 | |
602 | (void)fprintf(f, "%s: ", progname); | | 602 | (void)fprintf(f, "%s: ", progname); |
603 | | | 603 | |
604 | if (fname != NULL) | | 604 | if (fname != NULL) |
605 | PrintLocation(f, fname, lineno); | | 605 | PrintLocation(f, fname, lineno); |
606 | if (type == PARSE_WARNING) | | 606 | if (type == PARSE_WARNING) |
607 | (void)fprintf(f, "warning: "); | | 607 | (void)fprintf(f, "warning: "); |
608 | (void)vfprintf(f, fmt, ap); | | 608 | (void)vfprintf(f, fmt, ap); |
609 | (void)fprintf(f, "\n"); | | 609 | (void)fprintf(f, "\n"); |
610 | (void)fflush(f); | | 610 | (void)fflush(f); |
611 | | | 611 | |
612 | if (type == PARSE_INFO) | | 612 | if (type == PARSE_INFO) |
613 | goto print_stack_trace; | | 613 | goto print_stack_trace; |
614 | if (type == PARSE_FATAL || opts.parseWarnFatal) | | 614 | if (type == PARSE_WARNING && !opts.parseWarnFatal) |
615 | fatals++; | | 615 | goto print_stack_trace; |
616 | if (opts.parseWarnFatal && !fatal_warning_error_printed) { | | 616 | fatals++; |
617 | /* | | 617 | if (type == PARSE_WARNING && !fatal_warning_error_printed) { |
618 | * FIXME: Also gets printed on .error, even though it | | | |
619 | * doesn't apply to it. | | | |
620 | */ | | | |
621 | Error("parsing warnings being treated as errors"); | | 618 | Error("parsing warnings being treated as errors"); |
622 | fatal_warning_error_printed = TRUE; | | 619 | fatal_warning_error_printed = TRUE; |
623 | } | | 620 | } |
624 | | | 621 | |
625 | print_stack_trace: | | 622 | print_stack_trace: |
626 | PrintStackTrace(); | | 623 | PrintStackTrace(); |
627 | } | | 624 | } |
628 | | | 625 | |
629 | static void | | 626 | static void |
630 | ParseErrorInternal(const char *fname, size_t lineno, | | 627 | ParseErrorInternal(const char *fname, size_t lineno, |
631 | ParseErrorLevel type, const char *fmt, ...) | | 628 | ParseErrorLevel type, const char *fmt, ...) |
632 | { | | 629 | { |
633 | va_list ap; | | 630 | va_list ap; |
634 | | | 631 | |
635 | (void)fflush(stdout); | | 632 | (void)fflush(stdout); |
636 | va_start(ap, fmt); | | 633 | va_start(ap, fmt); |
637 | ParseVErrorInternal(stderr, fname, lineno, type, fmt, ap); | | 634 | ParseVErrorInternal(stderr, fname, lineno, type, fmt, ap); |
638 | va_end(ap); | | 635 | va_end(ap); |
639 | | | 636 | |
640 | if (opts.debug_file != stderr && opts.debug_file != stdout) { | | 637 | if (opts.debug_file != stderr && opts.debug_file != stdout) { |
641 | va_start(ap, fmt); | | 638 | va_start(ap, fmt); |
642 | ParseVErrorInternal(opts.debug_file, fname, lineno, type, | | 639 | ParseVErrorInternal(opts.debug_file, fname, lineno, type, |
643 | fmt, ap); | | 640 | fmt, ap); |
644 | va_end(ap); | | 641 | va_end(ap); |
645 | } | | 642 | } |
646 | } | | 643 | } |
647 | | | 644 | |
648 | /* | | 645 | /* |
649 | * Print a parse error message, including location information. | | 646 | * Print a parse error message, including location information. |
650 | * | | 647 | * |
651 | * If the level is PARSE_FATAL, continue parsing until the end of the | | 648 | * If the level is PARSE_FATAL, continue parsing until the end of the |
652 | * current top-level makefile, then exit (see Parse_File). | | 649 | * current top-level makefile, then exit (see Parse_File). |
653 | * | | 650 | * |
654 | * Fmt is given without a trailing newline. | | 651 | * Fmt is given without a trailing newline. |
655 | */ | | 652 | */ |
656 | void | | 653 | void |
657 | Parse_Error(ParseErrorLevel type, const char *fmt, ...) | | 654 | Parse_Error(ParseErrorLevel type, const char *fmt, ...) |
658 | { | | 655 | { |
659 | va_list ap; | | 656 | va_list ap; |
660 | const char *fname; | | 657 | const char *fname; |
661 | size_t lineno; | | 658 | size_t lineno; |
662 | | | 659 | |
663 | if (includes.len == 0) { | | 660 | if (includes.len == 0) { |
664 | fname = NULL; | | 661 | fname = NULL; |
665 | lineno = 0; | | 662 | lineno = 0; |
666 | } else { | | 663 | } else { |
667 | IFile *curFile = CurFile(); | | 664 | IFile *curFile = CurFile(); |
668 | fname = curFile->fname; | | 665 | fname = curFile->fname; |
669 | lineno = (size_t)curFile->lineno; | | 666 | lineno = (size_t)curFile->lineno; |
670 | } | | 667 | } |
671 | | | 668 | |
672 | va_start(ap, fmt); | | 669 | va_start(ap, fmt); |
673 | (void)fflush(stdout); | | 670 | (void)fflush(stdout); |
674 | ParseVErrorInternal(stderr, fname, lineno, type, fmt, ap); | | 671 | ParseVErrorInternal(stderr, fname, lineno, type, fmt, ap); |
675 | va_end(ap); | | 672 | va_end(ap); |
676 | | | 673 | |
677 | if (opts.debug_file != stderr && opts.debug_file != stdout) { | | 674 | if (opts.debug_file != stderr && opts.debug_file != stdout) { |
678 | va_start(ap, fmt); | | 675 | va_start(ap, fmt); |
679 | ParseVErrorInternal(opts.debug_file, fname, lineno, type, | | 676 | ParseVErrorInternal(opts.debug_file, fname, lineno, type, |
680 | fmt, ap); | | 677 | fmt, ap); |
681 | va_end(ap); | | 678 | va_end(ap); |
682 | } | | 679 | } |
683 | } | | 680 | } |
684 | | | 681 | |
685 | | | 682 | |
686 | /* | | 683 | /* |
687 | * Parse and handle a .info, .warning or .error directive. | | 684 | * Parse and handle a .info, .warning or .error directive. |
688 | * For an .error directive, immediately exit. | | 685 | * For an .error directive, immediately exit. |
689 | */ | | 686 | */ |
690 | static void | | 687 | static void |
691 | ParseMessage(ParseErrorLevel level, const char *levelName, const char *umsg) | | 688 | ParseMessage(ParseErrorLevel level, const char *levelName, const char *umsg) |
692 | { | | 689 | { |
693 | char *xmsg; | | 690 | char *xmsg; |
694 | | | 691 | |
695 | if (umsg[0] == '\0') { | | 692 | if (umsg[0] == '\0') { |
696 | Parse_Error(PARSE_FATAL, "Missing argument for \".%s\"", | | 693 | Parse_Error(PARSE_FATAL, "Missing argument for \".%s\"", |
697 | levelName); | | 694 | levelName); |
698 | return; | | 695 | return; |
699 | } | | 696 | } |
700 | | | 697 | |
701 | (void)Var_Subst(umsg, VAR_CMDLINE, VARE_WANTRES, &xmsg); | | 698 | (void)Var_Subst(umsg, VAR_CMDLINE, VARE_WANTRES, &xmsg); |
702 | /* TODO: handle errors */ | | 699 | /* TODO: handle errors */ |
703 | | | 700 | |
704 | Parse_Error(level, "%s", xmsg); | | 701 | Parse_Error(level, "%s", xmsg); |
705 | free(xmsg); | | 702 | free(xmsg); |
706 | | | 703 | |
707 | if (level == PARSE_FATAL) { | | 704 | if (level == PARSE_FATAL) { |
708 | PrintOnError(NULL, NULL); | | 705 | PrintOnError(NULL, NULL); |
709 | exit(1); | | 706 | exit(1); |
710 | } | | 707 | } |
711 | } | | 708 | } |
712 | | | 709 | |
713 | /* | | 710 | /* |
714 | * Add the child to the parent's children. | | 711 | * Add the child to the parent's children. |
715 | * | | 712 | * |
716 | * Additionally, add the parent to the child's parents, but only if the | | 713 | * Additionally, add the parent to the child's parents, but only if the |
717 | * target is not special. An example for such a special target is .END, | | 714 | * target is not special. An example for such a special target is .END, |
718 | * which does not need to be informed once the child target has been made. | | 715 | * which does not need to be informed once the child target has been made. |
719 | */ | | 716 | */ |
720 | static void | | 717 | static void |
721 | LinkSource(GNode *pgn, GNode *cgn, Boolean isSpecial) | | 718 | LinkSource(GNode *pgn, GNode *cgn, Boolean isSpecial) |
722 | { | | 719 | { |
723 | if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty(&pgn->cohorts)) | | 720 | if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty(&pgn->cohorts)) |
724 | pgn = pgn->cohorts.last->datum; | | 721 | pgn = pgn->cohorts.last->datum; |
725 | | | 722 | |
726 | Lst_Append(&pgn->children, cgn); | | 723 | Lst_Append(&pgn->children, cgn); |
727 | pgn->unmade++; | | 724 | pgn->unmade++; |
728 | | | 725 | |
729 | /* Special targets like .END don't need any children. */ | | 726 | /* Special targets like .END don't need any children. */ |
730 | if (!isSpecial) | | 727 | if (!isSpecial) |
731 | Lst_Append(&cgn->parents, pgn); | | 728 | Lst_Append(&cgn->parents, pgn); |
732 | | | 729 | |
733 | if (DEBUG(PARSE)) { | | 730 | if (DEBUG(PARSE)) { |
734 | debug_printf("# %s: added child %s - %s\n", | | 731 | debug_printf("# %s: added child %s - %s\n", |
735 | __func__, pgn->name, cgn->name); | | 732 | __func__, pgn->name, cgn->name); |
736 | Targ_PrintNode(pgn, 0); | | 733 | Targ_PrintNode(pgn, 0); |
737 | Targ_PrintNode(cgn, 0); | | 734 | Targ_PrintNode(cgn, 0); |
738 | } | | 735 | } |
739 | } | | 736 | } |
740 | | | 737 | |
741 | /* Add the node to each target from the current dependency group. */ | | 738 | /* Add the node to each target from the current dependency group. */ |
742 | static void | | 739 | static void |
743 | LinkToTargets(GNode *gn, Boolean isSpecial) | | 740 | LinkToTargets(GNode *gn, Boolean isSpecial) |
744 | { | | 741 | { |
745 | GNodeListNode *ln; | | 742 | GNodeListNode *ln; |
746 | | | 743 | |
747 | for (ln = targets->first; ln != NULL; ln = ln->next) | | 744 | for (ln = targets->first; ln != NULL; ln = ln->next) |
748 | LinkSource(ln->datum, gn, isSpecial); | | 745 | LinkSource(ln->datum, gn, isSpecial); |
749 | } | | 746 | } |
750 | | | 747 | |
751 | static Boolean | | 748 | static Boolean |
752 | TryApplyDependencyOperator(GNode *gn, GNodeType op) | | 749 | TryApplyDependencyOperator(GNode *gn, GNodeType op) |
753 | { | | 750 | { |
754 | /* | | 751 | /* |
755 | * If the node occurred on the left-hand side of a dependency and the | | 752 | * If the node occurred on the left-hand side of a dependency and the |
756 | * operator also defines a dependency, they must match. | | 753 | * operator also defines a dependency, they must match. |
757 | */ | | 754 | */ |
758 | if ((op & OP_OPMASK) && (gn->type & OP_OPMASK) && | | 755 | if ((op & OP_OPMASK) && (gn->type & OP_OPMASK) && |
759 | ((op & OP_OPMASK) != (gn->type & OP_OPMASK))) { | | 756 | ((op & OP_OPMASK) != (gn->type & OP_OPMASK))) { |
760 | Parse_Error(PARSE_FATAL, "Inconsistent operator for %s", | | 757 | Parse_Error(PARSE_FATAL, "Inconsistent operator for %s", |
761 | gn->name); | | 758 | gn->name); |
762 | return FALSE; | | 759 | return FALSE; |
763 | } | | 760 | } |
764 | | | 761 | |
765 | if (op == OP_DOUBLEDEP && (gn->type & OP_OPMASK) == OP_DOUBLEDEP) { | | 762 | if (op == OP_DOUBLEDEP && (gn->type & OP_OPMASK) == OP_DOUBLEDEP) { |
766 | /* | | 763 | /* |
767 | * If the node was of the left-hand side of a '::' operator, | | 764 | * If the node was of the left-hand side of a '::' operator, |
768 | * we need to create a new instance of it for the children | | 765 | * we need to create a new instance of it for the children |
769 | * and commands on this dependency line since each of these | | 766 | * and commands on this dependency line since each of these |
770 | * dependency groups has its own attributes and commands, | | 767 | * dependency groups has its own attributes and commands, |
771 | * separate from the others. | | 768 | * separate from the others. |
772 | * | | 769 | * |
773 | * The new instance is placed on the 'cohorts' list of the | | 770 | * The new instance is placed on the 'cohorts' list of the |
774 | * initial one (note the initial one is not on its own | | 771 | * initial one (note the initial one is not on its own |
775 | * cohorts list) and the new instance is linked to all | | 772 | * cohorts list) and the new instance is linked to all |
776 | * parents of the initial instance. | | 773 | * parents of the initial instance. |
777 | */ | | 774 | */ |
778 | GNode *cohort; | | 775 | GNode *cohort; |
779 | | | 776 | |
780 | /* | | 777 | /* |
781 | * Propagate copied bits to the initial node. They'll be | | 778 | * Propagate copied bits to the initial node. They'll be |
782 | * propagated back to the rest of the cohorts later. | | 779 | * propagated back to the rest of the cohorts later. |
783 | */ | | 780 | */ |
784 | gn->type |= op & ~OP_OPMASK; | | 781 | gn->type |= op & ~OP_OPMASK; |
785 | | | 782 | |
786 | cohort = Targ_NewInternalNode(gn->name); | | 783 | cohort = Targ_NewInternalNode(gn->name); |
787 | if (doing_depend) | | 784 | if (doing_depend) |
788 | ParseMark(cohort); | | 785 | ParseMark(cohort); |
789 | /* | | 786 | /* |
790 | * Make the cohort invisible as well to avoid duplicating it | | 787 | * Make the cohort invisible as well to avoid duplicating it |
791 | * into other variables. True, parents of this target won't | | 788 | * into other variables. True, parents of this target won't |
792 | * tend to do anything with their local variables, but better | | 789 | * tend to do anything with their local variables, but better |
793 | * safe than sorry. | | 790 | * safe than sorry. |
794 | * | | 791 | * |
795 | * (I think this is pointless now, since the relevant list | | 792 | * (I think this is pointless now, since the relevant list |
796 | * traversals will no longer see this node anyway. -mycroft) | | 793 | * traversals will no longer see this node anyway. -mycroft) |
797 | */ | | 794 | */ |
798 | cohort->type = op | OP_INVISIBLE; | | 795 | cohort->type = op | OP_INVISIBLE; |
799 | Lst_Append(&gn->cohorts, cohort); | | 796 | Lst_Append(&gn->cohorts, cohort); |
800 | cohort->centurion = gn; | | 797 | cohort->centurion = gn; |
801 | gn->unmade_cohorts++; | | 798 | gn->unmade_cohorts++; |
802 | snprintf(cohort->cohort_num, sizeof cohort->cohort_num, "#%d", | | 799 | snprintf(cohort->cohort_num, sizeof cohort->cohort_num, "#%d", |
803 | (unsigned int)gn->unmade_cohorts % 1000000); | | 800 | (unsigned int)gn->unmade_cohorts % 1000000); |
804 | } else { | | 801 | } else { |
805 | /* | | 802 | /* |
806 | * We don't want to nuke any previous flags (whatever they | | 803 | * We don't want to nuke any previous flags (whatever they |
807 | * were) so we just OR the new operator into the old. | | 804 | * were) so we just OR the new operator into the old. |
808 | */ | | 805 | */ |
809 | gn->type |= op; | | 806 | gn->type |= op; |
810 | } | | 807 | } |
811 | | | 808 | |
812 | return TRUE; | | 809 | return TRUE; |
813 | } | | 810 | } |
814 | | | 811 | |
815 | static void | | 812 | static void |
816 | ApplyDependencyOperator(GNodeType op) | | 813 | ApplyDependencyOperator(GNodeType op) |
817 | { | | 814 | { |
818 | GNodeListNode *ln; | | 815 | GNodeListNode *ln; |
819 | | | 816 | |
820 | for (ln = targets->first; ln != NULL; ln = ln->next) | | 817 | for (ln = targets->first; ln != NULL; ln = ln->next) |
821 | if (!TryApplyDependencyOperator(ln->datum, op)) | | 818 | if (!TryApplyDependencyOperator(ln->datum, op)) |
822 | break; | | 819 | break; |
823 | } | | 820 | } |
824 | | | 821 | |
825 | /* | | 822 | /* |
826 | * We add a .WAIT node in the dependency list. After any dynamic dependencies | | 823 | * We add a .WAIT node in the dependency list. After any dynamic dependencies |
827 | * (and filename globbing) have happened, it is given a dependency on each | | 824 | * (and filename globbing) have happened, it is given a dependency on each |
828 | * previous child, back until the previous .WAIT node. The next child won't | | 825 | * previous child, back until the previous .WAIT node. The next child won't |
829 | * be scheduled until the .WAIT node is built. | | 826 | * be scheduled until the .WAIT node is built. |
830 | * | | 827 | * |
831 | * We give each .WAIT node a unique name (mainly for diagnostics). | | 828 | * We give each .WAIT node a unique name (mainly for diagnostics). |
832 | */ | | 829 | */ |
833 | static void | | 830 | static void |
834 | ParseDependencySourceWait(Boolean isSpecial) | | 831 | ParseDependencySourceWait(Boolean isSpecial) |
835 | { | | 832 | { |
836 | static int wait_number = 0; | | 833 | static int wait_number = 0; |
837 | char wait_src[16]; | | 834 | char wait_src[16]; |
838 | GNode *gn; | | 835 | GNode *gn; |
839 | | | 836 | |
840 | snprintf(wait_src, sizeof wait_src, ".WAIT_%u", ++wait_number); | | 837 | snprintf(wait_src, sizeof wait_src, ".WAIT_%u", ++wait_number); |
841 | gn = Targ_NewInternalNode(wait_src); | | 838 | gn = Targ_NewInternalNode(wait_src); |
842 | if (doing_depend) | | 839 | if (doing_depend) |
843 | ParseMark(gn); | | 840 | ParseMark(gn); |
844 | gn->type = OP_WAIT | OP_PHONY | OP_DEPENDS | OP_NOTMAIN; | | 841 | gn->type = OP_WAIT | OP_PHONY | OP_DEPENDS | OP_NOTMAIN; |
845 | LinkToTargets(gn, isSpecial); | | 842 | LinkToTargets(gn, isSpecial); |
846 | | | 843 | |
847 | } | | 844 | } |
848 | | | 845 | |
849 | static Boolean | | 846 | static Boolean |
850 | ParseDependencySourceKeyword(const char *src, ParseSpecial specType) | | 847 | ParseDependencySourceKeyword(const char *src, ParseSpecial specType) |
851 | { | | 848 | { |
852 | int keywd; | | 849 | int keywd; |
853 | GNodeType op; | | 850 | GNodeType op; |
854 | | | 851 | |
855 | if (*src != '.' || !ch_isupper(src[1])) | | 852 | if (*src != '.' || !ch_isupper(src[1])) |
856 | return FALSE; | | 853 | return FALSE; |
857 | | | 854 | |
858 | keywd = ParseFindKeyword(src); | | 855 | keywd = ParseFindKeyword(src); |
859 | if (keywd == -1) | | 856 | if (keywd == -1) |
860 | return FALSE; | | 857 | return FALSE; |
861 | | | 858 | |
862 | op = parseKeywords[keywd].op; | | 859 | op = parseKeywords[keywd].op; |
863 | if (op != OP_NONE) { | | 860 | if (op != OP_NONE) { |
864 | ApplyDependencyOperator(op); | | 861 | ApplyDependencyOperator(op); |
865 | return TRUE; | | 862 | return TRUE; |
866 | } | | 863 | } |
867 | if (parseKeywords[keywd].spec == SP_WAIT) { | | 864 | if (parseKeywords[keywd].spec == SP_WAIT) { |
868 | ParseDependencySourceWait(specType != SP_NOT); | | 865 | ParseDependencySourceWait(specType != SP_NOT); |
869 | return TRUE; | | 866 | return TRUE; |
870 | } | | 867 | } |
871 | return FALSE; | | 868 | return FALSE; |
872 | } | | 869 | } |
873 | | | 870 | |
874 | static void | | 871 | static void |
875 | ParseDependencySourceMain(const char *src) | | 872 | ParseDependencySourceMain(const char *src) |
876 | { | | 873 | { |
877 | /* | | 874 | /* |
878 | * In a line like ".MAIN: source1 source2", it means we need to add | | 875 | * In a line like ".MAIN: source1 source2", it means we need to add |
879 | * the sources of said target to the list of things to create. | | 876 | * the sources of said target to the list of things to create. |
880 | * | | 877 | * |
881 | * Note that this will only be invoked if the user didn't specify a | | 878 | * Note that this will only be invoked if the user didn't specify a |
882 | * target on the command line and the .MAIN occurs for the first time. | | 879 | * target on the command line and the .MAIN occurs for the first time. |
883 | * | | 880 | * |
884 | * See ParseDoDependencyTargetSpecial, branch SP_MAIN. | | 881 | * See ParseDoDependencyTargetSpecial, branch SP_MAIN. |
885 | * See unit-tests/cond-func-make-main.mk. | | 882 | * See unit-tests/cond-func-make-main.mk. |
886 | */ | | 883 | */ |
887 | Lst_Append(&opts.create, bmake_strdup(src)); | | 884 | Lst_Append(&opts.create, bmake_strdup(src)); |
888 | /* | | 885 | /* |
889 | * Add the name to the .TARGETS variable as well, so the user can | | 886 | * Add the name to the .TARGETS variable as well, so the user can |
890 | * employ that, if desired. | | 887 | * employ that, if desired. |
891 | */ | | 888 | */ |
892 | Var_Append(".TARGETS", src, VAR_GLOBAL); | | 889 | Var_Append(".TARGETS", src, VAR_GLOBAL); |
893 | } | | 890 | } |
894 | | | 891 | |
895 | static void | | 892 | static void |
896 | ParseDependencySourceOrder(const char *src) | | 893 | ParseDependencySourceOrder(const char *src) |
897 | { | | 894 | { |
898 | GNode *gn; | | 895 | GNode *gn; |
899 | /* | | 896 | /* |
900 | * Create proper predecessor/successor links between the previous | | 897 | * Create proper predecessor/successor links between the previous |
901 | * source and the current one. | | 898 | * source and the current one. |
902 | */ | | 899 | */ |
903 | gn = Targ_GetNode(src); | | 900 | gn = Targ_GetNode(src); |
904 | if (doing_depend) | | 901 | if (doing_depend) |
905 | ParseMark(gn); | | 902 | ParseMark(gn); |
906 | if (order_pred != NULL) { | | 903 | if (order_pred != NULL) { |
907 | Lst_Append(&order_pred->order_succ, gn); | | 904 | Lst_Append(&order_pred->order_succ, gn); |
908 | Lst_Append(&gn->order_pred, order_pred); | | 905 | Lst_Append(&gn->order_pred, order_pred); |
909 | if (DEBUG(PARSE)) { | | 906 | if (DEBUG(PARSE)) { |
910 | debug_printf("# %s: added Order dependency %s - %s\n", | | 907 | debug_printf("# %s: added Order dependency %s - %s\n", |
911 | __func__, order_pred->name, gn->name); | | 908 | __func__, order_pred->name, gn->name); |
912 | Targ_PrintNode(order_pred, 0); | | 909 | Targ_PrintNode(order_pred, 0); |
913 | Targ_PrintNode(gn, 0); | | 910 | Targ_PrintNode(gn, 0); |
914 | } | | 911 | } |
915 | } | | 912 | } |
916 | /* | | 913 | /* |
917 | * The current source now becomes the predecessor for the next one. | | 914 | * The current source now becomes the predecessor for the next one. |
918 | */ | | 915 | */ |
919 | order_pred = gn; | | 916 | order_pred = gn; |
920 | } | | 917 | } |
921 | | | 918 | |
922 | static void | | 919 | static void |
923 | ParseDependencySourceOther(const char *src, GNodeType tOp, | | 920 | ParseDependencySourceOther(const char *src, GNodeType tOp, |
924 | ParseSpecial specType) | | 921 | ParseSpecial specType) |
925 | { | | 922 | { |
926 | GNode *gn; | | 923 | GNode *gn; |
927 | | | 924 | |
928 | /* | | 925 | /* |
929 | * If the source is not an attribute, we need to find/create | | 926 | * If the source is not an attribute, we need to find/create |
930 | * a node for it. After that we can apply any operator to it | | 927 | * a node for it. After that we can apply any operator to it |
931 | * from a special target or link it to its parents, as | | 928 | * from a special target or link it to its parents, as |
932 | * appropriate. | | 929 | * appropriate. |
933 | * | | 930 | * |
934 | * In the case of a source that was the object of a :: operator, | | 931 | * In the case of a source that was the object of a :: operator, |
935 | * the attribute is applied to all of its instances (as kept in | | 932 | * the attribute is applied to all of its instances (as kept in |
936 | * the 'cohorts' list of the node) or all the cohorts are linked | | 933 | * the 'cohorts' list of the node) or all the cohorts are linked |
937 | * to all the targets. | | 934 | * to all the targets. |
938 | */ | | 935 | */ |
939 | | | 936 | |
940 | /* Find/create the 'src' node and attach to all targets */ | | 937 | /* Find/create the 'src' node and attach to all targets */ |
941 | gn = Targ_GetNode(src); | | 938 | gn = Targ_GetNode(src); |
942 | if (doing_depend) | | 939 | if (doing_depend) |
943 | ParseMark(gn); | | 940 | ParseMark(gn); |
944 | if (tOp != OP_NONE) | | 941 | if (tOp != OP_NONE) |
945 | gn->type |= tOp; | | 942 | gn->type |= tOp; |
946 | else | | 943 | else |
947 | LinkToTargets(gn, specType != SP_NOT); | | 944 | LinkToTargets(gn, specType != SP_NOT); |
948 | } | | 945 | } |
949 | | | 946 | |
950 | /* | | 947 | /* |
951 | * Given the name of a source in a dependency line, figure out if it is an | | 948 | * Given the name of a source in a dependency line, figure out if it is an |
952 | * attribute (such as .SILENT) and apply it to the targets if it is. Else | | 949 | * attribute (such as .SILENT) and apply it to the targets if it is. Else |
953 | * decide if there is some attribute which should be applied *to* the source | | 950 | * decide if there is some attribute which should be applied *to* the source |
954 | * because of some special target (such as .PHONY) and apply it if so. | | 951 | * because of some special target (such as .PHONY) and apply it if so. |
955 | * Otherwise, make the source a child of the targets in the list 'targets'. | | 952 | * Otherwise, make the source a child of the targets in the list 'targets'. |
956 | * | | 953 | * |
957 | * Input: | | 954 | * Input: |
958 | * tOp operator (if any) from special targets | | 955 | * tOp operator (if any) from special targets |
959 | * src name of the source to handle | | 956 | * src name of the source to handle |
960 | */ | | 957 | */ |
961 | static void | | 958 | static void |
962 | ParseDependencySource(GNodeType tOp, const char *src, ParseSpecial specType) | | 959 | ParseDependencySource(GNodeType tOp, const char *src, ParseSpecial specType) |
963 | { | | 960 | { |
964 | if (ParseDependencySourceKeyword(src, specType)) | | 961 | if (ParseDependencySourceKeyword(src, specType)) |
965 | return; | | 962 | return; |
966 | | | 963 | |
967 | if (specType == SP_MAIN) | | 964 | if (specType == SP_MAIN) |
968 | ParseDependencySourceMain(src); | | 965 | ParseDependencySourceMain(src); |
969 | else if (specType == SP_ORDER) | | 966 | else if (specType == SP_ORDER) |
970 | ParseDependencySourceOrder(src); | | 967 | ParseDependencySourceOrder(src); |
971 | else | | 968 | else |
972 | ParseDependencySourceOther(src, tOp, specType); | | 969 | ParseDependencySourceOther(src, tOp, specType); |
973 | } | | 970 | } |
974 | | | 971 | |
975 | /* | | 972 | /* |
976 | * If we have yet to decide on a main target to make, in the absence of any | | 973 | * If we have yet to decide on a main target to make, in the absence of any |
977 | * user input, we want the first target on the first dependency line that is | | 974 | * user input, we want the first target on the first dependency line that is |
978 | * actually a real target (i.e. isn't a .USE or .EXEC rule) to be made. | | 975 | * actually a real target (i.e. isn't a .USE or .EXEC rule) to be made. |
979 | */ | | 976 | */ |
980 | static void | | 977 | static void |
981 | FindMainTarget(void) | | 978 | FindMainTarget(void) |
982 | { | | 979 | { |
983 | GNodeListNode *ln; | | 980 | GNodeListNode *ln; |
984 | | | 981 | |
985 | if (mainNode != NULL) | | 982 | if (mainNode != NULL) |
986 | return; | | 983 | return; |
987 | | | 984 | |
988 | for (ln = targets->first; ln != NULL; ln = ln->next) { | | 985 | for (ln = targets->first; ln != NULL; ln = ln->next) { |
989 | GNode *gn = ln->datum; | | 986 | GNode *gn = ln->datum; |
990 | if (!(gn->type & OP_NOTARGET)) { | | 987 | if (!(gn->type & OP_NOTARGET)) { |
991 | DEBUG1(MAKE, "Setting main node to \"%s\"\n", gn->name); | | 988 | DEBUG1(MAKE, "Setting main node to \"%s\"\n", gn->name); |
992 | mainNode = gn; | | 989 | mainNode = gn; |
993 | Targ_SetMain(gn); | | 990 | Targ_SetMain(gn); |
994 | return; | | 991 | return; |
995 | } | | 992 | } |
996 | } | | 993 | } |
997 | } | | 994 | } |
998 | | | 995 | |
999 | /* | | 996 | /* |
1000 | * We got to the end of the line while we were still looking at targets. | | 997 | * We got to the end of the line while we were still looking at targets. |
1001 | * | | 998 | * |
1002 | * Ending a dependency line without an operator is a Bozo no-no. As a | | 999 | * Ending a dependency line without an operator is a Bozo no-no. As a |
1003 | * heuristic, this is also often triggered by undetected conflicts from | | 1000 | * heuristic, this is also often triggered by undetected conflicts from |
1004 | * cvs/rcs merges. | | 1001 | * cvs/rcs merges. |
1005 | */ | | 1002 | */ |
1006 | static void | | 1003 | static void |
1007 | ParseErrorNoDependency(const char *lstart) | | 1004 | ParseErrorNoDependency(const char *lstart) |
1008 | { | | 1005 | { |
1009 | if ((strncmp(lstart, "<<<<<<", 6) == 0) || | | 1006 | if ((strncmp(lstart, "<<<<<<", 6) == 0) || |
1010 | (strncmp(lstart, "======", 6) == 0) || | | 1007 | (strncmp(lstart, "======", 6) == 0) || |
1011 | (strncmp(lstart, ">>>>>>", 6) == 0)) | | 1008 | (strncmp(lstart, ">>>>>>", 6) == 0)) |
1012 | Parse_Error(PARSE_FATAL, | | 1009 | Parse_Error(PARSE_FATAL, |
1013 | "Makefile appears to contain unresolved cvs/rcs/??? merge conflicts"); | | 1010 | "Makefile appears to contain unresolved cvs/rcs/??? merge conflicts"); |
1014 | else if (lstart[0] == '.') { | | 1011 | else if (lstart[0] == '.') { |
1015 | const char *dirstart = lstart + 1; | | 1012 | const char *dirstart = lstart + 1; |
1016 | const char *dirend; | | 1013 | const char *dirend; |
1017 | cpp_skip_whitespace(&dirstart); | | 1014 | cpp_skip_whitespace(&dirstart); |
1018 | dirend = dirstart; | | 1015 | dirend = dirstart; |
1019 | while (ch_isalnum(*dirend) || *dirend == '-') | | 1016 | while (ch_isalnum(*dirend) || *dirend == '-') |
1020 | dirend++; | | 1017 | dirend++; |
1021 | Parse_Error(PARSE_FATAL, "Unknown directive \"%.*s\"", | | 1018 | Parse_Error(PARSE_FATAL, "Unknown directive \"%.*s\"", |
1022 | (int)(dirend - dirstart), dirstart); | | 1019 | (int)(dirend - dirstart), dirstart); |
1023 | } else | | 1020 | } else |
1024 | Parse_Error(PARSE_FATAL, "Need an operator"); | | 1021 | Parse_Error(PARSE_FATAL, "Need an operator"); |
1025 | } | | 1022 | } |
1026 | | | 1023 | |
1027 | static void | | 1024 | static void |
1028 | ParseDependencyTargetWord(const char **pp, const char *lstart) | | 1025 | ParseDependencyTargetWord(const char **pp, const char *lstart) |
1029 | { | | 1026 | { |
1030 | const char *cp = *pp; | | 1027 | const char *cp = *pp; |
1031 | | | 1028 | |
1032 | while (*cp != '\0') { | | 1029 | while (*cp != '\0') { |
1033 | if ((ch_isspace(*cp) || *cp == '!' || *cp == ':' || | | 1030 | if ((ch_isspace(*cp) || *cp == '!' || *cp == ':' || |
1034 | *cp == '(') && | | 1031 | *cp == '(') && |
1035 | !ParseIsEscaped(lstart, cp)) | | 1032 | !ParseIsEscaped(lstart, cp)) |
1036 | break; | | 1033 | break; |
1037 | | | 1034 | |
1038 | if (*cp == '$') { | | 1035 | if (*cp == '$') { |
1039 | /* | | 1036 | /* |
1040 | * Must be a dynamic source (would have been expanded | | 1037 | * Must be a dynamic source (would have been expanded |
1041 | * otherwise), so call the Var module to parse the | | 1038 | * otherwise), so call the Var module to parse the |
1042 | * puppy so we can safely advance beyond it. | | 1039 | * puppy so we can safely advance beyond it. |
1043 | * | | 1040 | * |
1044 | * There should be no errors in this, as they would | | 1041 | * There should be no errors in this, as they would |
1045 | * have been discovered in the initial Var_Subst and | | 1042 | * have been discovered in the initial Var_Subst and |
1046 | * we wouldn't be here. | | 1043 | * we wouldn't be here. |
1047 | */ | | 1044 | */ |
1048 | const char *nested_p = cp; | | 1045 | const char *nested_p = cp; |
1049 | FStr nested_val; | | 1046 | FStr nested_val; |
1050 | | | 1047 | |
1051 | (void)Var_Parse(&nested_p, VAR_CMDLINE, VARE_NONE, | | 1048 | (void)Var_Parse(&nested_p, VAR_CMDLINE, VARE_NONE, |
1052 | &nested_val); | | 1049 | &nested_val); |
1053 | /* TODO: handle errors */ | | 1050 | /* TODO: handle errors */ |
1054 | FStr_Done(&nested_val); | | 1051 | FStr_Done(&nested_val); |
1055 | cp += nested_p - cp; | | 1052 | cp += nested_p - cp; |
1056 | } else | | 1053 | } else |
1057 | cp++; | | 1054 | cp++; |
1058 | } | | 1055 | } |
1059 | | | 1056 | |
1060 | *pp = cp; | | 1057 | *pp = cp; |
1061 | } | | 1058 | } |
1062 | | | 1059 | |
1063 | /* Handle special targets like .PATH, .DEFAULT, .BEGIN, .ORDER. */ | | 1060 | /* Handle special targets like .PATH, .DEFAULT, .BEGIN, .ORDER. */ |
1064 | static void | | 1061 | static void |
1065 | ParseDoDependencyTargetSpecial(ParseSpecial *inout_specType, | | 1062 | ParseDoDependencyTargetSpecial(ParseSpecial *inout_specType, |
1066 | const char *targetName, | | 1063 | const char *targetName, |
1067 | SearchPathList **inout_paths) | | 1064 | SearchPathList **inout_paths) |
1068 | { | | 1065 | { |
1069 | switch (*inout_specType) { | | 1066 | switch (*inout_specType) { |
1070 | case SP_PATH: | | 1067 | case SP_PATH: |
1071 | if (*inout_paths == NULL) | | 1068 | if (*inout_paths == NULL) |
1072 | *inout_paths = Lst_New(); | | 1069 | *inout_paths = Lst_New(); |
1073 | Lst_Append(*inout_paths, &dirSearchPath); | | 1070 | Lst_Append(*inout_paths, &dirSearchPath); |
1074 | break; | | 1071 | break; |
1075 | case SP_MAIN: | | 1072 | case SP_MAIN: |
1076 | /* | | 1073 | /* |
1077 | * Allow targets from the command line to override the | | 1074 | * Allow targets from the command line to override the |
1078 | * .MAIN node. | | 1075 | * .MAIN node. |
1079 | */ | | 1076 | */ |
1080 | if (!Lst_IsEmpty(&opts.create)) | | 1077 | if (!Lst_IsEmpty(&opts.create)) |
1081 | *inout_specType = SP_NOT; | | 1078 | *inout_specType = SP_NOT; |
1082 | break; | | 1079 | break; |
1083 | case SP_BEGIN: | | 1080 | case SP_BEGIN: |
1084 | case SP_END: | | 1081 | case SP_END: |
1085 | case SP_STALE: | | 1082 | case SP_STALE: |
1086 | case SP_ERROR: | | 1083 | case SP_ERROR: |
1087 | case SP_INTERRUPT: { | | 1084 | case SP_INTERRUPT: { |
1088 | GNode *gn = Targ_GetNode(targetName); | | 1085 | GNode *gn = Targ_GetNode(targetName); |
1089 | if (doing_depend) | | 1086 | if (doing_depend) |
1090 | ParseMark(gn); | | 1087 | ParseMark(gn); |
1091 | gn->type |= OP_NOTMAIN | OP_SPECIAL; | | 1088 | gn->type |= OP_NOTMAIN | OP_SPECIAL; |
1092 | Lst_Append(targets, gn); | | 1089 | Lst_Append(targets, gn); |
1093 | break; | | 1090 | break; |
1094 | } | | 1091 | } |
1095 | case SP_DEFAULT: { | | 1092 | case SP_DEFAULT: { |
1096 | /* | | 1093 | /* |
1097 | * Need to create a node to hang commands on, but we don't | | 1094 | * Need to create a node to hang commands on, but we don't |
1098 | * want it in the graph, nor do we want it to be the Main | | 1095 | * want it in the graph, nor do we want it to be the Main |
1099 | * Target. We claim the node is a transformation rule to make | | 1096 | * Target. We claim the node is a transformation rule to make |
1100 | * life easier later, when we'll use Make_HandleUse to | | 1097 | * life easier later, when we'll use Make_HandleUse to |
1101 | * actually apply the .DEFAULT commands. | | 1098 | * actually apply the .DEFAULT commands. |
1102 | */ | | 1099 | */ |
1103 | GNode *gn = GNode_New(".DEFAULT"); | | 1100 | GNode *gn = GNode_New(".DEFAULT"); |
1104 | gn->type |= OP_NOTMAIN | OP_TRANSFORM; | | 1101 | gn->type |= OP_NOTMAIN | OP_TRANSFORM; |
1105 | Lst_Append(targets, gn); | | 1102 | Lst_Append(targets, gn); |
1106 | defaultNode = gn; | | 1103 | defaultNode = gn; |
1107 | break; | | 1104 | break; |
1108 | } | | 1105 | } |
1109 | case SP_DELETE_ON_ERROR: | | 1106 | case SP_DELETE_ON_ERROR: |
1110 | deleteOnError = TRUE; | | 1107 | deleteOnError = TRUE; |
1111 | break; | | 1108 | break; |
1112 | case SP_NOTPARALLEL: | | 1109 | case SP_NOTPARALLEL: |
1113 | opts.maxJobs = 1; | | 1110 | opts.maxJobs = 1; |
1114 | break; | | 1111 | break; |
1115 | case SP_SINGLESHELL: | | 1112 | case SP_SINGLESHELL: |
1116 | opts.compatMake = TRUE; | | 1113 | opts.compatMake = TRUE; |
1117 | break; | | 1114 | break; |
1118 | case SP_ORDER: | | 1115 | case SP_ORDER: |
1119 | order_pred = NULL; | | 1116 | order_pred = NULL; |
1120 | break; | | 1117 | break; |
1121 | default: | | 1118 | default: |
1122 | break; | | 1119 | break; |
1123 | } | | 1120 | } |
1124 | } | | 1121 | } |
1125 | | | 1122 | |
1126 | /* | | 1123 | /* |
1127 | * .PATH<suffix> has to be handled specially. | | 1124 | * .PATH<suffix> has to be handled specially. |
1128 | * Call on the suffix module to give us a path to modify. | | 1125 | * Call on the suffix module to give us a path to modify. |
1129 | */ | | 1126 | */ |
1130 | static Boolean | | 1127 | static Boolean |
1131 | ParseDoDependencyTargetPath(const char *suffixName, | | 1128 | ParseDoDependencyTargetPath(const char *suffixName, |
1132 | SearchPathList **inout_paths) | | 1129 | SearchPathList **inout_paths) |
1133 | { | | 1130 | { |
1134 | SearchPath *path; | | 1131 | SearchPath *path; |
1135 | | | 1132 | |
1136 | path = Suff_GetPath(suffixName); | | 1133 | path = Suff_GetPath(suffixName); |
1137 | if (path == NULL) { | | 1134 | if (path == NULL) { |
1138 | Parse_Error(PARSE_FATAL, | | 1135 | Parse_Error(PARSE_FATAL, |
1139 | "Suffix '%s' not defined (yet)", suffixName); | | 1136 | "Suffix '%s' not defined (yet)", suffixName); |
1140 | return FALSE; | | 1137 | return FALSE; |
1141 | } | | 1138 | } |
1142 | | | 1139 | |
1143 | if (*inout_paths == NULL) | | 1140 | if (*inout_paths == NULL) |
1144 | *inout_paths = Lst_New(); | | 1141 | *inout_paths = Lst_New(); |
1145 | Lst_Append(*inout_paths, path); | | 1142 | Lst_Append(*inout_paths, path); |
1146 | | | 1143 | |
1147 | return TRUE; | | 1144 | return TRUE; |
1148 | } | | 1145 | } |
1149 | | | 1146 | |
1150 | /* | | 1147 | /* |
1151 | * See if it's a special target and if so set specType to match it. | | 1148 | * See if it's a special target and if so set specType to match it. |
1152 | */ | | 1149 | */ |
1153 | static Boolean | | 1150 | static Boolean |
1154 | ParseDoDependencyTarget(const char *targetName, | | 1151 | ParseDoDependencyTarget(const char *targetName, |
1155 | ParseSpecial *inout_specType, | | 1152 | ParseSpecial *inout_specType, |
1156 | GNodeType *out_tOp, SearchPathList **inout_paths) | | 1153 | GNodeType *out_tOp, SearchPathList **inout_paths) |
1157 | { | | 1154 | { |
1158 | int keywd; | | 1155 | int keywd; |
1159 | | | 1156 | |
1160 | if (!(targetName[0] == '.' && ch_isupper(targetName[1]))) | | 1157 | if (!(targetName[0] == '.' && ch_isupper(targetName[1]))) |
1161 | return TRUE; | | 1158 | return TRUE; |
1162 | | | 1159 | |
1163 | /* | | 1160 | /* |
1164 | * See if the target is a special target that must have it | | 1161 | * See if the target is a special target that must have it |
1165 | * or its sources handled specially. | | 1162 | * or its sources handled specially. |
1166 | */ | | 1163 | */ |
1167 | keywd = ParseFindKeyword(targetName); | | 1164 | keywd = ParseFindKeyword(targetName); |
1168 | if (keywd != -1) { | | 1165 | if (keywd != -1) { |
1169 | if (*inout_specType == SP_PATH && | | 1166 | if (*inout_specType == SP_PATH && |
1170 | parseKeywords[keywd].spec != SP_PATH) { | | 1167 | parseKeywords[keywd].spec != SP_PATH) { |
1171 | Parse_Error(PARSE_FATAL, "Mismatched special targets"); | | 1168 | Parse_Error(PARSE_FATAL, "Mismatched special targets"); |
1172 | return FALSE; | | 1169 | return FALSE; |
1173 | } | | 1170 | } |
1174 | | | 1171 | |
1175 | *inout_specType = parseKeywords[keywd].spec; | | 1172 | *inout_specType = parseKeywords[keywd].spec; |
1176 | *out_tOp = parseKeywords[keywd].op; | | 1173 | *out_tOp = parseKeywords[keywd].op; |
1177 | | | 1174 | |
1178 | ParseDoDependencyTargetSpecial(inout_specType, targetName, | | 1175 | ParseDoDependencyTargetSpecial(inout_specType, targetName, |
1179 | inout_paths); | | 1176 | inout_paths); |
1180 | | | 1177 | |
1181 | } else if (strncmp(targetName, ".PATH", 5) == 0) { | | 1178 | } else if (strncmp(targetName, ".PATH", 5) == 0) { |
1182 | *inout_specType = SP_PATH; | | 1179 | *inout_specType = SP_PATH; |
1183 | if (!ParseDoDependencyTargetPath(targetName + 5, inout_paths)) | | 1180 | if (!ParseDoDependencyTargetPath(targetName + 5, inout_paths)) |
1184 | return FALSE; | | 1181 | return FALSE; |
1185 | } | | 1182 | } |
1186 | return TRUE; | | 1183 | return TRUE; |
1187 | } | | 1184 | } |
1188 | | | 1185 | |
1189 | static void | | 1186 | static void |
1190 | ParseDoDependencyTargetMundane(char *targetName, StringList *curTargs) | | 1187 | ParseDoDependencyTargetMundane(char *targetName, StringList *curTargs) |
1191 | { | | 1188 | { |
1192 | if (Dir_HasWildcards(targetName)) { | | 1189 | if (Dir_HasWildcards(targetName)) { |
1193 | /* | | 1190 | /* |
1194 | * Targets are to be sought only in the current directory, | | 1191 | * Targets are to be sought only in the current directory, |
1195 | * so create an empty path for the thing. Note we need to | | 1192 | * so create an empty path for the thing. Note we need to |
1196 | * use Dir_Destroy in the destruction of the path as the | | 1193 | * use Dir_Destroy in the destruction of the path as the |
1197 | * Dir module could have added a directory to the path... | | 1194 | * Dir module could have added a directory to the path... |
1198 | */ | | 1195 | */ |
1199 | SearchPath *emptyPath = SearchPath_New(); | | 1196 | SearchPath *emptyPath = SearchPath_New(); |
1200 | | | 1197 | |
1201 | SearchPath_Expand(emptyPath, targetName, curTargs); | | 1198 | SearchPath_Expand(emptyPath, targetName, curTargs); |
1202 | | | 1199 | |
1203 | SearchPath_Free(emptyPath); | | 1200 | SearchPath_Free(emptyPath); |
1204 | } else { | | 1201 | } else { |
1205 | /* | | 1202 | /* |
1206 | * No wildcards, but we want to avoid code duplication, | | 1203 | * No wildcards, but we want to avoid code duplication, |
1207 | * so create a list with the word on it. | | 1204 | * so create a list with the word on it. |
1208 | */ | | 1205 | */ |
1209 | Lst_Append(curTargs, targetName); | | 1206 | Lst_Append(curTargs, targetName); |
1210 | } | | 1207 | } |
1211 | | | 1208 | |
1212 | /* Apply the targets. */ | | 1209 | /* Apply the targets. */ |
1213 | | | 1210 | |
1214 | while (!Lst_IsEmpty(curTargs)) { | | 1211 | while (!Lst_IsEmpty(curTargs)) { |
1215 | char *targName = Lst_Dequeue(curTargs); | | 1212 | char *targName = Lst_Dequeue(curTargs); |
1216 | GNode *gn = Suff_IsTransform(targName) | | 1213 | GNode *gn = Suff_IsTransform(targName) |
1217 | ? Suff_AddTransform(targName) | | 1214 | ? Suff_AddTransform(targName) |
1218 | : Targ_GetNode(targName); | | 1215 | : Targ_GetNode(targName); |
1219 | if (doing_depend) | | 1216 | if (doing_depend) |
1220 | ParseMark(gn); | | 1217 | ParseMark(gn); |
1221 | | | 1218 | |
1222 | Lst_Append(targets, gn); | | 1219 | Lst_Append(targets, gn); |
1223 | } | | 1220 | } |
1224 | } | | 1221 | } |
1225 | | | 1222 | |
1226 | static void | | 1223 | static void |
1227 | ParseDoDependencyTargetExtraWarn(char **pp, const char *lstart) | | 1224 | ParseDoDependencyTargetExtraWarn(char **pp, const char *lstart) |
1228 | { | | 1225 | { |
1229 | Boolean warning = FALSE; | | 1226 | Boolean warning = FALSE; |
1230 | char *cp = *pp; | | 1227 | char *cp = *pp; |
1231 | | | 1228 | |
1232 | while (*cp != '\0') { | | 1229 | while (*cp != '\0') { |
1233 | if (!ParseIsEscaped(lstart, cp) && (*cp == '!' || *cp == ':')) | | 1230 | if (!ParseIsEscaped(lstart, cp) && (*cp == '!' || *cp == ':')) |
1234 | break; | | 1231 | break; |
1235 | if (ParseIsEscaped(lstart, cp) || (*cp != ' ' && *cp != '\t')) | | 1232 | if (ParseIsEscaped(lstart, cp) || (*cp != ' ' && *cp != '\t')) |
1236 | warning = TRUE; | | 1233 | warning = TRUE; |
1237 | cp++; | | 1234 | cp++; |
1238 | } | | 1235 | } |
1239 | if (warning) | | 1236 | if (warning) |
1240 | Parse_Error(PARSE_WARNING, "Extra target ignored"); | | 1237 | Parse_Error(PARSE_WARNING, "Extra target ignored"); |
1241 | | | 1238 | |
1242 | *pp = cp; | | 1239 | *pp = cp; |
1243 | } | | 1240 | } |
1244 | | | 1241 | |
1245 | static void | | 1242 | static void |
1246 | ParseDoDependencyCheckSpec(ParseSpecial specType) | | 1243 | ParseDoDependencyCheckSpec(ParseSpecial specType) |
1247 | { | | 1244 | { |
1248 | switch (specType) { | | 1245 | switch (specType) { |
1249 | default: | | 1246 | default: |
1250 | Parse_Error(PARSE_WARNING, | | 1247 | Parse_Error(PARSE_WARNING, |
1251 | "Special and mundane targets don't mix. " | | 1248 | "Special and mundane targets don't mix. " |
1252 | "Mundane ones ignored"); | | 1249 | "Mundane ones ignored"); |
1253 | break; | | 1250 | break; |
1254 | case SP_DEFAULT: | | 1251 | case SP_DEFAULT: |
1255 | case SP_STALE: | | 1252 | case SP_STALE: |
1256 | case SP_BEGIN: | | 1253 | case SP_BEGIN: |
1257 | case SP_END: | | 1254 | case SP_END: |
1258 | case SP_ERROR: | | 1255 | case SP_ERROR: |
1259 | case SP_INTERRUPT: | | 1256 | case SP_INTERRUPT: |
1260 | /* | | 1257 | /* |
1261 | * These create nodes on which to hang commands, so targets | | 1258 | * These create nodes on which to hang commands, so targets |
1262 | * shouldn't be empty. | | 1259 | * shouldn't be empty. |
1263 | */ | | 1260 | */ |
1264 | case SP_NOT: | | 1261 | case SP_NOT: |
1265 | /* Nothing special here -- targets can be empty if it wants. */ | | 1262 | /* Nothing special here -- targets can be empty if it wants. */ |
1266 | break; | | 1263 | break; |
1267 | } | | 1264 | } |
1268 | } | | 1265 | } |
1269 | | | 1266 | |
1270 | static Boolean | | 1267 | static Boolean |
1271 | ParseDoDependencyParseOp(char **pp, const char *lstart, GNodeType *out_op) | | 1268 | ParseDoDependencyParseOp(char **pp, const char *lstart, GNodeType *out_op) |
1272 | { | | 1269 | { |
1273 | const char *cp = *pp; | | 1270 | const char *cp = *pp; |
1274 | | | 1271 | |
1275 | if (*cp == '!') { | | 1272 | if (*cp == '!') { |
1276 | *out_op = OP_FORCE; | | 1273 | *out_op = OP_FORCE; |
1277 | (*pp)++; | | 1274 | (*pp)++; |
1278 | return TRUE; | | 1275 | return TRUE; |
1279 | } | | 1276 | } |
1280 | | | 1277 | |
1281 | if (*cp == ':') { | | 1278 | if (*cp == ':') { |
1282 | if (cp[1] == ':') { | | 1279 | if (cp[1] == ':') { |
1283 | *out_op = OP_DOUBLEDEP; | | 1280 | *out_op = OP_DOUBLEDEP; |
1284 | (*pp) += 2; | | 1281 | (*pp) += 2; |
1285 | } else { | | 1282 | } else { |
1286 | *out_op = OP_DEPENDS; | | 1283 | *out_op = OP_DEPENDS; |
1287 | (*pp)++; | | 1284 | (*pp)++; |
1288 | } | | 1285 | } |
1289 | return TRUE; | | 1286 | return TRUE; |
1290 | } | | 1287 | } |
1291 | | | 1288 | |
1292 | { | | 1289 | { |
1293 | const char *msg = lstart[0] == '.' | | 1290 | const char *msg = lstart[0] == '.' |
1294 | ? "Unknown directive" : "Missing dependency operator"; | | 1291 | ? "Unknown directive" : "Missing dependency operator"; |
1295 | Parse_Error(PARSE_FATAL, "%s", msg); | | 1292 | Parse_Error(PARSE_FATAL, "%s", msg); |
1296 | return FALSE; | | 1293 | return FALSE; |
1297 | } | | 1294 | } |
1298 | } | | 1295 | } |
1299 | | | 1296 | |
1300 | static void | | 1297 | static void |
1301 | ClearPaths(SearchPathList *paths) | | 1298 | ClearPaths(SearchPathList *paths) |
1302 | { | | 1299 | { |
1303 | if (paths != NULL) { | | 1300 | if (paths != NULL) { |
1304 | SearchPathListNode *ln; | | 1301 | SearchPathListNode *ln; |
1305 | for (ln = paths->first; ln != NULL; ln = ln->next) | | 1302 | for (ln = paths->first; ln != NULL; ln = ln->next) |
1306 | SearchPath_Clear(ln->datum); | | 1303 | SearchPath_Clear(ln->datum); |
1307 | } | | 1304 | } |
1308 | | | 1305 | |
1309 | Dir_SetPATH(); | | 1306 | Dir_SetPATH(); |
1310 | } | | 1307 | } |
1311 | | | 1308 | |
1312 | static void | | 1309 | static void |
1313 | ParseDoDependencySourcesEmpty(ParseSpecial specType, SearchPathList *paths) | | 1310 | ParseDoDependencySourcesEmpty(ParseSpecial specType, SearchPathList *paths) |
1314 | { | | 1311 | { |
1315 | switch (specType) { | | 1312 | switch (specType) { |
1316 | case SP_SUFFIXES: | | 1313 | case SP_SUFFIXES: |
1317 | Suff_ClearSuffixes(); | | 1314 | Suff_ClearSuffixes(); |
1318 | break; | | 1315 | break; |
1319 | case SP_PRECIOUS: | | 1316 | case SP_PRECIOUS: |
1320 | allPrecious = TRUE; | | 1317 | allPrecious = TRUE; |
1321 | break; | | 1318 | break; |
1322 | case SP_IGNORE: | | 1319 | case SP_IGNORE: |
1323 | opts.ignoreErrors = TRUE; | | 1320 | opts.ignoreErrors = TRUE; |
1324 | break; | | 1321 | break; |
1325 | case SP_SILENT: | | 1322 | case SP_SILENT: |
1326 | opts.beSilent = TRUE; | | 1323 | opts.beSilent = TRUE; |
1327 | break; | | 1324 | break; |
1328 | case SP_PATH: | | 1325 | case SP_PATH: |
1329 | ClearPaths(paths); | | 1326 | ClearPaths(paths); |
1330 | break; | | 1327 | break; |
1331 | #ifdef POSIX | | 1328 | #ifdef POSIX |
1332 | case SP_POSIX: | | 1329 | case SP_POSIX: |
1333 | Var_Set("%POSIX", "1003.2", VAR_GLOBAL); | | 1330 | Var_Set("%POSIX", "1003.2", VAR_GLOBAL); |
1334 | break; | | 1331 | break; |
1335 | #endif | | 1332 | #endif |
1336 | default: | | 1333 | default: |
1337 | break; | | 1334 | break; |
1338 | } | | 1335 | } |
1339 | } | | 1336 | } |
1340 | | | 1337 | |
1341 | static void | | 1338 | static void |
1342 | AddToPaths(const char *dir, SearchPathList *paths) | | 1339 | AddToPaths(const char *dir, SearchPathList *paths) |
1343 | { | | 1340 | { |
1344 | if (paths != NULL) { | | 1341 | if (paths != NULL) { |
1345 | SearchPathListNode *ln; | | 1342 | SearchPathListNode *ln; |
1346 | for (ln = paths->first; ln != NULL; ln = ln->next) | | 1343 | for (ln = paths->first; ln != NULL; ln = ln->next) |
1347 | (void)SearchPath_Add(ln->datum, dir); | | 1344 | (void)SearchPath_Add(ln->datum, dir); |
1348 | } | | 1345 | } |
1349 | } | | 1346 | } |
1350 | | | 1347 | |
1351 | /* | | 1348 | /* |
1352 | * If the target was one that doesn't take files as its sources | | 1349 | * If the target was one that doesn't take files as its sources |
1353 | * but takes something like suffixes, we take each | | 1350 | * but takes something like suffixes, we take each |
1354 | * space-separated word on the line as a something and deal | | 1351 | * space-separated word on the line as a something and deal |
1355 | * with it accordingly. | | 1352 | * with it accordingly. |
1356 | * | | 1353 | * |
1357 | * If the target was .SUFFIXES, we take each source as a | | 1354 | * If the target was .SUFFIXES, we take each source as a |
1358 | * suffix and add it to the list of suffixes maintained by the | | 1355 | * suffix and add it to the list of suffixes maintained by the |
1359 | * Suff module. | | 1356 | * Suff module. |
1360 | * | | 1357 | * |
1361 | * If the target was a .PATH, we add the source as a directory | | 1358 | * If the target was a .PATH, we add the source as a directory |
1362 | * to search on the search path. | | 1359 | * to search on the search path. |
1363 | * | | 1360 | * |
1364 | * If it was .INCLUDES, the source is taken to be the suffix of | | 1361 | * If it was .INCLUDES, the source is taken to be the suffix of |
1365 | * files which will be #included and whose search path should | | 1362 | * files which will be #included and whose search path should |
1366 | * be present in the .INCLUDES variable. | | 1363 | * be present in the .INCLUDES variable. |
1367 | * | | 1364 | * |
1368 | * If it was .LIBS, the source is taken to be the suffix of | | 1365 | * If it was .LIBS, the source is taken to be the suffix of |
1369 | * files which are considered libraries and whose search path | | 1366 | * files which are considered libraries and whose search path |
1370 | * should be present in the .LIBS variable. | | 1367 | * should be present in the .LIBS variable. |
1371 | * | | 1368 | * |
1372 | * If it was .NULL, the source is the suffix to use when a file | | 1369 | * If it was .NULL, the source is the suffix to use when a file |
1373 | * has no valid suffix. | | 1370 | * has no valid suffix. |
1374 | * | | 1371 | * |
1375 | * If it was .OBJDIR, the source is a new definition for .OBJDIR, | | 1372 | * If it was .OBJDIR, the source is a new definition for .OBJDIR, |
1376 | * and will cause make to do a new chdir to that path. | | 1373 | * and will cause make to do a new chdir to that path. |
1377 | */ | | 1374 | */ |
1378 | static void | | 1375 | static void |
1379 | ParseDoDependencySourceSpecial(ParseSpecial specType, char *word, | | 1376 | ParseDoDependencySourceSpecial(ParseSpecial specType, char *word, |
1380 | SearchPathList *paths) | | 1377 | SearchPathList *paths) |
1381 | { | | 1378 | { |
1382 | switch (specType) { | | 1379 | switch (specType) { |
1383 | case SP_SUFFIXES: | | 1380 | case SP_SUFFIXES: |
1384 | Suff_AddSuffix(word, &mainNode); | | 1381 | Suff_AddSuffix(word, &mainNode); |
1385 | break; | | 1382 | break; |
1386 | case SP_PATH: | | 1383 | case SP_PATH: |
1387 | AddToPaths(word, paths); | | 1384 | AddToPaths(word, paths); |
1388 | break; | | 1385 | break; |
1389 | case SP_INCLUDES: | | 1386 | case SP_INCLUDES: |
1390 | Suff_AddInclude(word); | | 1387 | Suff_AddInclude(word); |
1391 | break; | | 1388 | break; |
1392 | case SP_LIBS: | | 1389 | case SP_LIBS: |
1393 | Suff_AddLib(word); | | 1390 | Suff_AddLib(word); |
1394 | break; | | 1391 | break; |
1395 | case SP_NULL: | | 1392 | case SP_NULL: |
1396 | Suff_SetNull(word); | | 1393 | Suff_SetNull(word); |
1397 | break; | | 1394 | break; |
1398 | case SP_OBJDIR: | | 1395 | case SP_OBJDIR: |
1399 | Main_SetObjdir(FALSE, "%s", word); | | 1396 | Main_SetObjdir(FALSE, "%s", word); |
1400 | break; | | 1397 | break; |
1401 | default: | | 1398 | default: |
1402 | break; | | 1399 | break; |
1403 | } | | 1400 | } |
1404 | } | | 1401 | } |
1405 | | | 1402 | |
1406 | static Boolean | | 1403 | static Boolean |
1407 | ParseDoDependencyTargets(char **inout_cp, | | 1404 | ParseDoDependencyTargets(char **inout_cp, |
1408 | char **inout_line, | | 1405 | char **inout_line, |
1409 | const char *lstart, | | 1406 | const char *lstart, |
1410 | ParseSpecial *inout_specType, | | 1407 | ParseSpecial *inout_specType, |
1411 | GNodeType *inout_tOp, | | 1408 | GNodeType *inout_tOp, |
1412 | SearchPathList **inout_paths, | | 1409 | SearchPathList **inout_paths, |
1413 | StringList *curTargs) | | 1410 | StringList *curTargs) |
1414 | { | | 1411 | { |
1415 | char *cp; | | 1412 | char *cp; |
1416 | char *tgt = *inout_line; | | 1413 | char *tgt = *inout_line; |
1417 | char savec; | | 1414 | char savec; |
1418 | const char *p; | | 1415 | const char *p; |
1419 | | | 1416 | |
1420 | for (;;) { | | 1417 | for (;;) { |
1421 | /* | | 1418 | /* |
1422 | * Here LINE points to the beginning of the next word, and | | 1419 | * Here LINE points to the beginning of the next word, and |
1423 | * LSTART points to the actual beginning of the line. | | 1420 | * LSTART points to the actual beginning of the line. |
1424 | */ | | 1421 | */ |
1425 | | | 1422 | |
1426 | /* Find the end of the next word. */ | | 1423 | /* Find the end of the next word. */ |
1427 | cp = tgt; | | 1424 | cp = tgt; |
1428 | p = cp; | | 1425 | p = cp; |
1429 | ParseDependencyTargetWord(&p, lstart); | | 1426 | ParseDependencyTargetWord(&p, lstart); |
1430 | cp += p - cp; | | 1427 | cp += p - cp; |
1431 | | | 1428 | |
1432 | /* | | 1429 | /* |
1433 | * If the word is followed by a left parenthesis, it's the | | 1430 | * If the word is followed by a left parenthesis, it's the |
1434 | * name of an object file inside an archive (ar file). | | 1431 | * name of an object file inside an archive (ar file). |
1435 | */ | | 1432 | */ |
1436 | if (!ParseIsEscaped(lstart, cp) && *cp == '(') { | | 1433 | if (!ParseIsEscaped(lstart, cp) && *cp == '(') { |
1437 | /* | | 1434 | /* |
1438 | * Archives must be handled specially to make sure the | | 1435 | * Archives must be handled specially to make sure the |
1439 | * OP_ARCHV flag is set in their 'type' field, for one | | 1436 | * OP_ARCHV flag is set in their 'type' field, for one |
1440 | * thing, and because things like "archive(file1.o | | 1437 | * thing, and because things like "archive(file1.o |
1441 | * file2.o file3.o)" are permissible. | | 1438 | * file2.o file3.o)" are permissible. |
1442 | * | | 1439 | * |
1443 | * Arch_ParseArchive will set 'line' to be the first | | 1440 | * Arch_ParseArchive will set 'line' to be the first |
1444 | * non-blank after the archive-spec. It creates/finds | | 1441 | * non-blank after the archive-spec. It creates/finds |
1445 | * nodes for the members and places them on the given | | 1442 | * nodes for the members and places them on the given |
1446 | * list, returning TRUE if all went well and FALSE if | | 1443 | * list, returning TRUE if all went well and FALSE if |
1447 | * there was an error in the specification. On error, | | 1444 | * there was an error in the specification. On error, |
1448 | * line should remain untouched. | | 1445 | * line should remain untouched. |
1449 | */ | | 1446 | */ |
1450 | if (!Arch_ParseArchive(&tgt, targets, VAR_CMDLINE)) { | | 1447 | if (!Arch_ParseArchive(&tgt, targets, VAR_CMDLINE)) { |
1451 | Parse_Error(PARSE_FATAL, | | 1448 | Parse_Error(PARSE_FATAL, |
1452 | "Error in archive specification: \"%s\"", | | 1449 | "Error in archive specification: \"%s\"", |
1453 | tgt); | | 1450 | tgt); |
1454 | return FALSE; | | 1451 | return FALSE; |
1455 | } | | 1452 | } |
1456 | | | 1453 | |
1457 | cp = tgt; | | 1454 | cp = tgt; |
1458 | continue; | | 1455 | continue; |
1459 | } | | 1456 | } |
1460 | | | 1457 | |
1461 | if (*cp == '\0') { | | 1458 | if (*cp == '\0') { |
1462 | ParseErrorNoDependency(lstart); | | 1459 | ParseErrorNoDependency(lstart); |
1463 | return FALSE; | | 1460 | return FALSE; |
1464 | } | | 1461 | } |
1465 | | | 1462 | |
1466 | /* Insert a null terminator. */ | | 1463 | /* Insert a null terminator. */ |
1467 | savec = *cp; | | 1464 | savec = *cp; |
1468 | *cp = '\0'; | | 1465 | *cp = '\0'; |
1469 | | | 1466 | |
1470 | if (!ParseDoDependencyTarget(tgt, inout_specType, inout_tOp, | | 1467 | if (!ParseDoDependencyTarget(tgt, inout_specType, inout_tOp, |
1471 | inout_paths)) | | 1468 | inout_paths)) |
1472 | return FALSE; | | 1469 | return FALSE; |
1473 | | | 1470 | |
1474 | /* | | 1471 | /* |
1475 | * Have word in line. Get or create its node and stick it at | | 1472 | * Have word in line. Get or create its node and stick it at |
1476 | * the end of the targets list | | 1473 | * the end of the targets list |
1477 | */ | | 1474 | */ |
1478 | if (*inout_specType == SP_NOT && *tgt != '\0') | | 1475 | if (*inout_specType == SP_NOT && *tgt != '\0') |
1479 | ParseDoDependencyTargetMundane(tgt, curTargs); | | 1476 | ParseDoDependencyTargetMundane(tgt, curTargs); |
1480 | else if (*inout_specType == SP_PATH && *tgt != '.' && | | 1477 | else if (*inout_specType == SP_PATH && *tgt != '.' && |
1481 | *tgt != '\0') | | 1478 | *tgt != '\0') |
1482 | Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", | | 1479 | Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", |
1483 | tgt); | | 1480 | tgt); |
1484 | | | 1481 | |
1485 | /* Don't need the inserted null terminator any more. */ | | 1482 | /* Don't need the inserted null terminator any more. */ |
1486 | *cp = savec; | | 1483 | *cp = savec; |
1487 | | | 1484 | |
1488 | /* | | 1485 | /* |
1489 | * If it is a special type and not .PATH, it's the only target | | 1486 | * If it is a special type and not .PATH, it's the only target |
1490 | * we allow on this line. | | 1487 | * we allow on this line. |
1491 | */ | | 1488 | */ |
1492 | if (*inout_specType != SP_NOT && *inout_specType != SP_PATH) | | 1489 | if (*inout_specType != SP_NOT && *inout_specType != SP_PATH) |
1493 | ParseDoDependencyTargetExtraWarn(&cp, lstart); | | 1490 | ParseDoDependencyTargetExtraWarn(&cp, lstart); |
1494 | else | | 1491 | else |
1495 | pp_skip_whitespace(&cp); | | 1492 | pp_skip_whitespace(&cp); |
1496 | | | 1493 | |
1497 | tgt = cp; | | 1494 | tgt = cp; |
1498 | if (*tgt == '\0') | | 1495 | if (*tgt == '\0') |
1499 | break; | | 1496 | break; |
1500 | if ((*tgt == '!' || *tgt == ':') && | | 1497 | if ((*tgt == '!' || *tgt == ':') && |
1501 | !ParseIsEscaped(lstart, tgt)) | | 1498 | !ParseIsEscaped(lstart, tgt)) |
1502 | break; | | 1499 | break; |
1503 | } | | 1500 | } |
1504 | | | 1501 | |
1505 | *inout_cp = cp; | | 1502 | *inout_cp = cp; |
1506 | *inout_line = tgt; | | 1503 | *inout_line = tgt; |
1507 | return TRUE; | | 1504 | return TRUE; |
1508 | } | | 1505 | } |
1509 | | | 1506 | |
1510 | static void | | 1507 | static void |
1511 | ParseDoDependencySourcesSpecial(char *start, char *end, | | 1508 | ParseDoDependencySourcesSpecial(char *start, char *end, |
1512 | ParseSpecial specType, SearchPathList *paths) | | 1509 | ParseSpecial specType, SearchPathList *paths) |
1513 | { | | 1510 | { |
1514 | char savec; | | 1511 | char savec; |
1515 | | | 1512 | |
1516 | while (*start != '\0') { | | 1513 | while (*start != '\0') { |
1517 | while (*end != '\0' && !ch_isspace(*end)) | | 1514 | while (*end != '\0' && !ch_isspace(*end)) |
1518 | end++; | | 1515 | end++; |
1519 | savec = *end; | | 1516 | savec = *end; |
1520 | *end = '\0'; | | 1517 | *end = '\0'; |
1521 | ParseDoDependencySourceSpecial(specType, start, paths); | | 1518 | ParseDoDependencySourceSpecial(specType, start, paths); |
1522 | *end = savec; | | 1519 | *end = savec; |
1523 | if (savec != '\0') | | 1520 | if (savec != '\0') |
1524 | end++; | | 1521 | end++; |
1525 | pp_skip_whitespace(&end); | | 1522 | pp_skip_whitespace(&end); |
1526 | start = end; | | 1523 | start = end; |
1527 | } | | 1524 | } |
1528 | } | | 1525 | } |
1529 | | | 1526 | |
1530 | static Boolean | | 1527 | static Boolean |
1531 | ParseDoDependencySourcesMundane(char *start, char *end, | | 1528 | ParseDoDependencySourcesMundane(char *start, char *end, |
1532 | ParseSpecial specType, GNodeType tOp) | | 1529 | ParseSpecial specType, GNodeType tOp) |
1533 | { | | 1530 | { |
1534 | while (*start != '\0') { | | 1531 | while (*start != '\0') { |
1535 | /* | | 1532 | /* |
1536 | * The targets take real sources, so we must beware of archive | | 1533 | * The targets take real sources, so we must beware of archive |
1537 | * specifications (i.e. things with left parentheses in them) | | 1534 | * specifications (i.e. things with left parentheses in them) |
1538 | * and handle them accordingly. | | 1535 | * and handle them accordingly. |
1539 | */ | | 1536 | */ |
1540 | for (; *end != '\0' && !ch_isspace(*end); end++) { | | 1537 | for (; *end != '\0' && !ch_isspace(*end); end++) { |
1541 | if (*end == '(' && end > start && end[-1] != '$') { | | 1538 | if (*end == '(' && end > start && end[-1] != '$') { |
1542 | /* | | 1539 | /* |
1543 | * Only stop for a left parenthesis if it | | 1540 | * Only stop for a left parenthesis if it |
1544 | * isn't at the start of a word (that'll be | | 1541 | * isn't at the start of a word (that'll be |
1545 | * for variable changes later) and isn't | | 1542 | * for variable changes later) and isn't |
1546 | * preceded by a dollar sign (a dynamic | | 1543 | * preceded by a dollar sign (a dynamic |
1547 | * source). | | 1544 | * source). |
1548 | */ | | 1545 | */ |
1549 | break; | | 1546 | break; |
1550 | } | | 1547 | } |
1551 | } | | 1548 | } |
1552 | | | 1549 | |
1553 | if (*end == '(') { | | 1550 | if (*end == '(') { |
1554 | GNodeList sources = LST_INIT; | | 1551 | GNodeList sources = LST_INIT; |
1555 | if (!Arch_ParseArchive(&start, &sources, VAR_CMDLINE)) { | | 1552 | if (!Arch_ParseArchive(&start, &sources, VAR_CMDLINE)) { |
1556 | Parse_Error(PARSE_FATAL, | | 1553 | Parse_Error(PARSE_FATAL, |
1557 | "Error in source archive spec \"%s\"", | | 1554 | "Error in source archive spec \"%s\"", |
1558 | start); | | 1555 | start); |
1559 | return FALSE; | | 1556 | return FALSE; |
1560 | } | | 1557 | } |
1561 | | | 1558 | |
1562 | while (!Lst_IsEmpty(&sources)) { | | 1559 | while (!Lst_IsEmpty(&sources)) { |
1563 | GNode *gn = Lst_Dequeue(&sources); | | 1560 | GNode *gn = Lst_Dequeue(&sources); |
1564 | ParseDependencySource(tOp, gn->name, specType); | | 1561 | ParseDependencySource(tOp, gn->name, specType); |
1565 | } | | 1562 | } |
1566 | Lst_Done(&sources); | | 1563 | Lst_Done(&sources); |
1567 | end = start; | | 1564 | end = start; |
1568 | } else { | | 1565 | } else { |
1569 | if (*end != '\0') { | | 1566 | if (*end != '\0') { |
1570 | *end = '\0'; | | 1567 | *end = '\0'; |
1571 | end++; | | 1568 | end++; |
1572 | } | | 1569 | } |
1573 | | | 1570 | |
1574 | ParseDependencySource(tOp, start, specType); | | 1571 | ParseDependencySource(tOp, start, specType); |
1575 | } | | 1572 | } |
1576 | pp_skip_whitespace(&end); | | 1573 | pp_skip_whitespace(&end); |
1577 | start = end; | | 1574 | start = end; |
1578 | } | | 1575 | } |
1579 | return TRUE; | | 1576 | return TRUE; |
1580 | } | | 1577 | } |
1581 | | | 1578 | |
1582 | /* | | 1579 | /* |
1583 | * Parse a dependency line consisting of targets, followed by a dependency | | 1580 | * Parse a dependency line consisting of targets, followed by a dependency |
1584 | * operator, optionally followed by sources. | | 1581 | * operator, optionally followed by sources. |
1585 | * | | 1582 | * |
1586 | * The nodes of the sources are linked as children to the nodes of the | | 1583 | * The nodes of the sources are linked as children to the nodes of the |
1587 | * targets. Nodes are created as necessary. | | 1584 | * targets. Nodes are created as necessary. |
1588 | * | | 1585 | * |
1589 | * The operator is applied to each node in the global 'targets' list, | | 1586 | * The operator is applied to each node in the global 'targets' list, |
1590 | * which is where the nodes found for the targets are kept, by means of | | 1587 | * which is where the nodes found for the targets are kept, by means of |
1591 | * the ParseDoOp function. | | 1588 | * the ParseDoOp function. |
1592 | * | | 1589 | * |
1593 | * The sources are parsed in much the same way as the targets, except | | 1590 | * The sources are parsed in much the same way as the targets, except |
1594 | * that they are expanded using the wildcarding scheme of the C-Shell, | | 1591 | * that they are expanded using the wildcarding scheme of the C-Shell, |
1595 | * and a target is created for each expanded word. Each of the resulting | | 1592 | * and a target is created for each expanded word. Each of the resulting |
1596 | * nodes is then linked to each of the targets as one of its children. | | 1593 | * nodes is then linked to each of the targets as one of its children. |
1597 | * | | 1594 | * |
1598 | * Certain targets and sources such as .PHONY or .PRECIOUS are handled | | 1595 | * Certain targets and sources such as .PHONY or .PRECIOUS are handled |
1599 | * specially. These are the ones detailed by the specType variable. | | 1596 | * specially. These are the ones detailed by the specType variable. |
1600 | * | | 1597 | * |
1601 | * The storing of transformation rules such as '.c.o' is also taken care of | | 1598 | * The storing of transformation rules such as '.c.o' is also taken care of |
1602 | * here. A target is recognized as a transformation rule by calling | | 1599 | * here. A target is recognized as a transformation rule by calling |
1603 | * Suff_IsTransform. If it is a transformation rule, its node is gotten | | 1600 | * Suff_IsTransform. If it is a transformation rule, its node is gotten |
1604 | * from the suffix module via Suff_AddTransform rather than the standard | | 1601 | * from the suffix module via Suff_AddTransform rather than the standard |
1605 | * Targ_FindNode in the target module. | | 1602 | * Targ_FindNode in the target module. |
1606 | * | | 1603 | * |
1607 | * Upon return, the value of the line is unspecified. | | 1604 | * Upon return, the value of the line is unspecified. |
1608 | */ | | 1605 | */ |
1609 | static void | | 1606 | static void |
1610 | ParseDoDependency(char *line) | | 1607 | ParseDoDependency(char *line) |
1611 | { | | 1608 | { |
1612 | char *cp; /* our current position */ | | 1609 | char *cp; /* our current position */ |
1613 | GNodeType op; /* the operator on the line */ | | 1610 | GNodeType op; /* the operator on the line */ |
1614 | SearchPathList *paths; /* search paths to alter when parsing | | 1611 | SearchPathList *paths; /* search paths to alter when parsing |
1615 | * a list of .PATH targets */ | | 1612 | * a list of .PATH targets */ |
1616 | GNodeType tOp; /* operator from special target */ | | 1613 | GNodeType tOp; /* operator from special target */ |
1617 | /* target names to be found and added to the targets list */ | | 1614 | /* target names to be found and added to the targets list */ |
1618 | StringList curTargs = LST_INIT; | | 1615 | StringList curTargs = LST_INIT; |
1619 | char *lstart = line; | | 1616 | char *lstart = line; |