| @@ -1,1161 +1,1160 @@ | | | @@ -1,1161 +1,1160 @@ |
1 | /* $NetBSD: parse.c,v 1.404 2020/10/28 01:43:01 rillig Exp $ */ | | 1 | /* $NetBSD: parse.c,v 1.405 2020/10/28 01:47:11 rillig Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1988, 1989, 1990, 1993 | | 4 | * Copyright (c) 1988, 1989, 1990, 1993 |
5 | * The Regents of the University of California. All rights reserved. | | 5 | * The Regents of the University of California. All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to Berkeley by | | 7 | * This code is derived from software contributed to Berkeley by |
8 | * Adam de Boor. | | 8 | * Adam de Boor. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * 3. Neither the name of the University nor the names of its contributors | | 18 | * 3. Neither the name of the University nor the names of its contributors |
19 | * may be used to endorse or promote products derived from this software | | 19 | * may be used to endorse or promote products derived from this software |
20 | * without specific prior written permission. | | 20 | * without specific prior written permission. |
21 | * | | 21 | * |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
32 | * SUCH DAMAGE. | | 32 | * SUCH DAMAGE. |
33 | */ | | 33 | */ |
34 | | | 34 | |
35 | /* | | 35 | /* |
36 | * Copyright (c) 1989 by Berkeley Softworks | | 36 | * Copyright (c) 1989 by Berkeley Softworks |
37 | * All rights reserved. | | 37 | * All rights reserved. |
38 | * | | 38 | * |
39 | * This code is derived from software contributed to Berkeley by | | 39 | * This code is derived from software contributed to Berkeley by |
40 | * Adam de Boor. | | 40 | * Adam de Boor. |
41 | * | | 41 | * |
42 | * Redistribution and use in source and binary forms, with or without | | 42 | * Redistribution and use in source and binary forms, with or without |
43 | * modification, are permitted provided that the following conditions | | 43 | * modification, are permitted provided that the following conditions |
44 | * are met: | | 44 | * are met: |
45 | * 1. Redistributions of source code must retain the above copyright | | 45 | * 1. Redistributions of source code must retain the above copyright |
46 | * notice, this list of conditions and the following disclaimer. | | 46 | * notice, this list of conditions and the following disclaimer. |
47 | * 2. Redistributions in binary form must reproduce the above copyright | | 47 | * 2. Redistributions in binary form must reproduce the above copyright |
48 | * notice, this list of conditions and the following disclaimer in the | | 48 | * notice, this list of conditions and the following disclaimer in the |
49 | * documentation and/or other materials provided with the distribution. | | 49 | * documentation and/or other materials provided with the distribution. |
50 | * 3. All advertising materials mentioning features or use of this software | | 50 | * 3. All advertising materials mentioning features or use of this software |
51 | * must display the following acknowledgement: | | 51 | * must display the following acknowledgement: |
52 | * This product includes software developed by the University of | | 52 | * This product includes software developed by the University of |
53 | * California, Berkeley and its contributors. | | 53 | * California, Berkeley and its contributors. |
54 | * 4. Neither the name of the University nor the names of its contributors | | 54 | * 4. Neither the name of the University nor the names of its contributors |
55 | * may be used to endorse or promote products derived from this software | | 55 | * may be used to endorse or promote products derived from this software |
56 | * without specific prior written permission. | | 56 | * without specific prior written permission. |
57 | * | | 57 | * |
58 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 58 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
59 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 59 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
60 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 60 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
61 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 61 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
62 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 62 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
63 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 63 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
64 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 64 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
65 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 65 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
66 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 66 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
67 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 67 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
68 | * SUCH DAMAGE. | | 68 | * SUCH DAMAGE. |
69 | */ | | 69 | */ |
70 | | | 70 | |
71 | /* | | 71 | /* |
72 | * Parsing of makefiles. | | 72 | * Parsing of makefiles. |
73 | * | | 73 | * |
74 | * Parse_File is the main entry point and controls most of the other | | 74 | * Parse_File is the main entry point and controls most of the other |
75 | * functions in this module. | | 75 | * functions in this module. |
76 | * | | 76 | * |
77 | * The directories for the .include "..." directive are kept in | | 77 | * The directories for the .include "..." directive are kept in |
78 | * 'parseIncPath', while those for .include <...> are kept in 'sysIncPath'. | | 78 | * 'parseIncPath', while those for .include <...> are kept in 'sysIncPath'. |
79 | * The targets currently being defined are kept in 'targets'. | | 79 | * The targets currently being defined are kept in 'targets'. |
80 | * | | 80 | * |
81 | * Interface: | | 81 | * Interface: |
82 | * Parse_Init Initialize the module | | 82 | * Parse_Init Initialize the module |
83 | * | | 83 | * |
84 | * Parse_End Clean up the module | | 84 | * Parse_End Clean up the module |
85 | * | | 85 | * |
86 | * Parse_File Parse a top-level makefile. Included files are | | 86 | * Parse_File Parse a top-level makefile. Included files are |
87 | * handled by Parse_include_file though. | | 87 | * handled by Parse_include_file though. |
88 | * | | 88 | * |
89 | * Parse_IsVar Return TRUE if the given line is a variable | | 89 | * Parse_IsVar Return TRUE if the given line is a variable |
90 | * assignment. Used by MainParseArgs to determine if | | 90 | * assignment. Used by MainParseArgs to determine if |
91 | * an argument is a target or a variable assignment. | | 91 | * an argument is a target or a variable assignment. |
92 | * Used internally for pretty much the same thing. | | 92 | * Used internally for pretty much the same thing. |
93 | * | | 93 | * |
94 | * Parse_Error Report a parse error, a warning or an informational | | 94 | * Parse_Error Report a parse error, a warning or an informational |
95 | * message. | | 95 | * message. |
96 | * | | 96 | * |
97 | * Parse_MainName Returns a list of the main target to create. | | 97 | * Parse_MainName Returns a list of the main target to create. |
98 | */ | | 98 | */ |
99 | | | 99 | |
100 | #include <sys/types.h> | | 100 | #include <sys/types.h> |
101 | #include <sys/mman.h> | | 101 | #include <sys/mman.h> |
102 | #include <sys/stat.h> | | 102 | #include <sys/stat.h> |
103 | #include <errno.h> | | 103 | #include <errno.h> |
104 | #include <stdarg.h> | | 104 | #include <stdarg.h> |
105 | #include <stdint.h> | | 105 | #include <stdint.h> |
106 | | | 106 | |
107 | #ifndef MAP_FILE | | 107 | #ifndef MAP_FILE |
108 | #define MAP_FILE 0 | | 108 | #define MAP_FILE 0 |
109 | #endif | | 109 | #endif |
110 | #ifndef MAP_COPY | | 110 | #ifndef MAP_COPY |
111 | #define MAP_COPY MAP_PRIVATE | | 111 | #define MAP_COPY MAP_PRIVATE |
112 | #endif | | 112 | #endif |
113 | | | 113 | |
114 | #include "make.h" | | 114 | #include "make.h" |
115 | #include "dir.h" | | 115 | #include "dir.h" |
116 | #include "job.h" | | 116 | #include "job.h" |
117 | #include "pathnames.h" | | 117 | #include "pathnames.h" |
118 | | | 118 | |
119 | /* "@(#)parse.c 8.3 (Berkeley) 3/19/94" */ | | 119 | /* "@(#)parse.c 8.3 (Berkeley) 3/19/94" */ |
120 | MAKE_RCSID("$NetBSD: parse.c,v 1.404 2020/10/28 01:43:01 rillig Exp $"); | | 120 | MAKE_RCSID("$NetBSD: parse.c,v 1.405 2020/10/28 01:47:11 rillig Exp $"); |
121 | | | 121 | |
122 | /* types and constants */ | | 122 | /* types and constants */ |
123 | | | 123 | |
124 | /* | | 124 | /* |
125 | * Structure for a file being read ("included file") | | 125 | * Structure for a file being read ("included file") |
126 | */ | | 126 | */ |
127 | typedef struct IFile { | | 127 | typedef struct IFile { |
128 | char *fname; /* name of file */ | | 128 | char *fname; /* name of file */ |
129 | Boolean fromForLoop; /* simulated .include by the .for loop */ | | 129 | Boolean fromForLoop; /* simulated .include by the .for loop */ |
130 | int lineno; /* current line number in file */ | | 130 | int lineno; /* current line number in file */ |
131 | int first_lineno; /* line number of start of text */ | | 131 | int first_lineno; /* line number of start of text */ |
132 | unsigned int cond_depth; /* 'if' nesting when file opened */ | | 132 | unsigned int cond_depth; /* 'if' nesting when file opened */ |
133 | Boolean depending; /* state of doing_depend on EOF */ | | 133 | Boolean depending; /* state of doing_depend on EOF */ |
134 | | | 134 | |
135 | /* The buffer from which the file's content is read. */ | | 135 | /* The buffer from which the file's content is read. */ |
136 | char *buf_freeIt; | | 136 | char *buf_freeIt; |
137 | char *buf_ptr; /* next char to be read */ | | 137 | char *buf_ptr; /* next char to be read */ |
138 | char *buf_end; | | 138 | char *buf_end; |
139 | | | 139 | |
140 | char *(*nextbuf)(void *, size_t *); /* Function to get more data */ | | 140 | char *(*nextbuf)(void *, size_t *); /* Function to get more data */ |
141 | void *nextbuf_arg; /* Opaque arg for nextbuf() */ | | 141 | void *nextbuf_arg; /* Opaque arg for nextbuf() */ |
142 | struct loadedfile *lf; /* loadedfile object, if any */ | | 142 | struct loadedfile *lf; /* loadedfile object, if any */ |
143 | } IFile; | | 143 | } IFile; |
144 | | | 144 | |
145 | /* | | 145 | /* |
146 | * Tokens for target attributes | | 146 | * Tokens for target attributes |
147 | */ | | 147 | */ |
148 | typedef enum ParseSpecial { | | 148 | typedef enum ParseSpecial { |
149 | SP_BEGIN, /* .BEGIN */ | | 149 | SP_BEGIN, /* .BEGIN */ |
150 | SP_DEFAULT, /* .DEFAULT */ | | 150 | SP_DEFAULT, /* .DEFAULT */ |
151 | SP_DELETE_ON_ERROR, /* .DELETE_ON_ERROR */ | | 151 | SP_DELETE_ON_ERROR, /* .DELETE_ON_ERROR */ |
152 | SP_END, /* .END */ | | 152 | SP_END, /* .END */ |
153 | SP_ERROR, /* .ERROR */ | | 153 | SP_ERROR, /* .ERROR */ |
154 | SP_IGNORE, /* .IGNORE */ | | 154 | SP_IGNORE, /* .IGNORE */ |
155 | SP_INCLUDES, /* .INCLUDES; not mentioned in the manual page */ | | 155 | SP_INCLUDES, /* .INCLUDES; not mentioned in the manual page */ |
156 | SP_INTERRUPT, /* .INTERRUPT */ | | 156 | SP_INTERRUPT, /* .INTERRUPT */ |
157 | SP_LIBS, /* .LIBS; not mentioned in the manual page */ | | 157 | SP_LIBS, /* .LIBS; not mentioned in the manual page */ |
158 | SP_META, /* .META */ | | 158 | SP_META, /* .META */ |
159 | SP_MFLAGS, /* .MFLAGS or .MAKEFLAGS */ | | 159 | SP_MFLAGS, /* .MFLAGS or .MAKEFLAGS */ |
160 | SP_MAIN, /* .MAIN and we don't have anything user-specified to | | 160 | SP_MAIN, /* .MAIN and we don't have anything user-specified to |
161 | * make */ | | 161 | * make */ |
162 | SP_NOEXPORT, /* .NOEXPORT; not mentioned in the manual page */ | | | |
163 | SP_NOMETA, /* .NOMETA */ | | 162 | SP_NOMETA, /* .NOMETA */ |
164 | SP_NOMETA_CMP, /* .NOMETA_CMP */ | | 163 | SP_NOMETA_CMP, /* .NOMETA_CMP */ |
165 | SP_NOPATH, /* .NOPATH */ | | 164 | SP_NOPATH, /* .NOPATH */ |
166 | SP_NOT, /* Not special */ | | 165 | SP_NOT, /* Not special */ |
167 | SP_NOTPARALLEL, /* .NOTPARALLEL or .NO_PARALLEL */ | | 166 | SP_NOTPARALLEL, /* .NOTPARALLEL or .NO_PARALLEL */ |
168 | SP_NULL, /* .NULL; not mentioned in the manual page */ | | 167 | SP_NULL, /* .NULL; not mentioned in the manual page */ |
169 | SP_OBJDIR, /* .OBJDIR */ | | 168 | SP_OBJDIR, /* .OBJDIR */ |
170 | SP_ORDER, /* .ORDER */ | | 169 | SP_ORDER, /* .ORDER */ |
171 | SP_PARALLEL, /* .PARALLEL; not mentioned in the manual page */ | | 170 | SP_PARALLEL, /* .PARALLEL; not mentioned in the manual page */ |
172 | SP_PATH, /* .PATH or .PATH.suffix */ | | 171 | SP_PATH, /* .PATH or .PATH.suffix */ |
173 | SP_PHONY, /* .PHONY */ | | 172 | SP_PHONY, /* .PHONY */ |
174 | #ifdef POSIX | | 173 | #ifdef POSIX |
175 | SP_POSIX, /* .POSIX; not mentioned in the manual page */ | | 174 | SP_POSIX, /* .POSIX; not mentioned in the manual page */ |
176 | #endif | | 175 | #endif |
177 | SP_PRECIOUS, /* .PRECIOUS */ | | 176 | SP_PRECIOUS, /* .PRECIOUS */ |
178 | SP_SHELL, /* .SHELL */ | | 177 | SP_SHELL, /* .SHELL */ |
179 | SP_SILENT, /* .SILENT */ | | 178 | SP_SILENT, /* .SILENT */ |
180 | SP_SINGLESHELL, /* .SINGLESHELL; not mentioned in the manual page */ | | 179 | SP_SINGLESHELL, /* .SINGLESHELL; not mentioned in the manual page */ |
181 | SP_STALE, /* .STALE */ | | 180 | SP_STALE, /* .STALE */ |
182 | SP_SUFFIXES, /* .SUFFIXES */ | | 181 | SP_SUFFIXES, /* .SUFFIXES */ |
183 | SP_WAIT, /* .WAIT */ | | 182 | SP_WAIT, /* .WAIT */ |
184 | SP_ATTRIBUTE /* Generic attribute */ | | 183 | SP_ATTRIBUTE /* Generic attribute */ |
185 | } ParseSpecial; | | 184 | } ParseSpecial; |
186 | | | 185 | |
187 | typedef List SearchPathList; | | 186 | typedef List SearchPathList; |
188 | typedef ListNode SearchPathListNode; | | 187 | typedef ListNode SearchPathListNode; |
189 | | | 188 | |
190 | /* result data */ | | 189 | /* result data */ |
191 | | | 190 | |
192 | /* | | 191 | /* |
193 | * The main target to create. This is the first target on the first | | 192 | * The main target to create. This is the first target on the first |
194 | * dependency line in the first makefile. | | 193 | * dependency line in the first makefile. |
195 | */ | | 194 | */ |
196 | static GNode *mainNode; | | 195 | static GNode *mainNode; |
197 | | | 196 | |
198 | /* eval state */ | | 197 | /* eval state */ |
199 | | | 198 | |
200 | /* During parsing, the targets from the currently active dependency line, | | 199 | /* During parsing, the targets from the currently active dependency line, |
201 | * or NULL if the current line does not belong to a dependency line, for | | 200 | * or NULL if the current line does not belong to a dependency line, for |
202 | * example because it is a variable assignment. | | 201 | * example because it is a variable assignment. |
203 | * | | 202 | * |
204 | * See unit-tests/deptgt.mk, keyword "parse.c:targets". */ | | 203 | * See unit-tests/deptgt.mk, keyword "parse.c:targets". */ |
205 | static GNodeList *targets; | | 204 | static GNodeList *targets; |
206 | | | 205 | |
207 | #ifdef CLEANUP | | 206 | #ifdef CLEANUP |
208 | /* All shell commands for all targets, in no particular order and possibly | | 207 | /* All shell commands for all targets, in no particular order and possibly |
209 | * with duplicates. Kept in a separate list since the commands from .USE or | | 208 | * with duplicates. Kept in a separate list since the commands from .USE or |
210 | * .USEBEFORE nodes are shared with other GNodes, thereby giving up the | | 209 | * .USEBEFORE nodes are shared with other GNodes, thereby giving up the |
211 | * easily understandable ownership over the allocated strings. */ | | 210 | * easily understandable ownership over the allocated strings. */ |
212 | static StringList *targCmds; | | 211 | static StringList *targCmds; |
213 | #endif | | 212 | #endif |
214 | | | 213 | |
215 | /* | | 214 | /* |
216 | * Predecessor node for handling .ORDER. Initialized to NULL when .ORDER | | 215 | * Predecessor node for handling .ORDER. Initialized to NULL when .ORDER |
217 | * seen, then set to each successive source on the line. | | 216 | * seen, then set to each successive source on the line. |
218 | */ | | 217 | */ |
219 | static GNode *predecessor; | | 218 | static GNode *predecessor; |
220 | | | 219 | |
221 | /* parser state */ | | 220 | /* parser state */ |
222 | | | 221 | |
223 | /* number of fatal errors */ | | 222 | /* number of fatal errors */ |
224 | static int fatals = 0; | | 223 | static int fatals = 0; |
225 | | | 224 | |
226 | /* | | 225 | /* |
227 | * Variables for doing includes | | 226 | * Variables for doing includes |
228 | */ | | 227 | */ |
229 | | | 228 | |
230 | /* current file being read */ | | 229 | /* current file being read */ |
231 | static IFile *curFile; | | 230 | static IFile *curFile; |
232 | | | 231 | |
233 | /* The include chain of makefiles that leads to curFile. At the bottom of | | 232 | /* The include chain of makefiles that leads to curFile. At the bottom of |
234 | * the stack is the top-level makefile from the command line, and on top of | | 233 | * the stack is the top-level makefile from the command line, and on top of |
235 | * this file, there are the included files or .for loops, up to but excluding | | 234 | * this file, there are the included files or .for loops, up to but excluding |
236 | * curFile. | | 235 | * curFile. |
237 | * | | 236 | * |
238 | * This data could be used to print stack traces on parse errors. As of | | 237 | * This data could be used to print stack traces on parse errors. As of |
239 | * 2020-09-14, this is not done though. It seems quite simple to print the | | 238 | * 2020-09-14, this is not done though. It seems quite simple to print the |
240 | * tuples (fname:lineno:fromForLoop), from top to bottom. This simple idea is | | 239 | * tuples (fname:lineno:fromForLoop), from top to bottom. This simple idea is |
241 | * made complicated by the fact that the .for loops also use this stack for | | 240 | * made complicated by the fact that the .for loops also use this stack for |
242 | * storing information. | | 241 | * storing information. |
243 | * | | 242 | * |
244 | * The lineno fields of the IFiles with fromForLoop == TRUE look confusing, | | 243 | * The lineno fields of the IFiles with fromForLoop == TRUE look confusing, |
245 | * which is demonstrated by the test 'include-main.mk'. They seem sorted | | 244 | * which is demonstrated by the test 'include-main.mk'. They seem sorted |
246 | * backwards since they tell the number of completely parsed lines, which for | | 245 | * backwards since they tell the number of completely parsed lines, which for |
247 | * a .for loop is right after the terminating .endfor. To compensate for this | | 246 | * a .for loop is right after the terminating .endfor. To compensate for this |
248 | * confusion, there is another field first_lineno pointing at the start of the | | 247 | * confusion, there is another field first_lineno pointing at the start of the |
249 | * .for loop, 1-based for human consumption. | | 248 | * .for loop, 1-based for human consumption. |
250 | * | | 249 | * |
251 | * To make the stack trace intuitive, the entry below the first .for loop must | | 250 | * To make the stack trace intuitive, the entry below the first .for loop must |
252 | * be ignored completely since neither its lineno nor its first_lineno is | | 251 | * be ignored completely since neither its lineno nor its first_lineno is |
253 | * useful. Instead, the topmost .for loop needs to be printed twice, once | | 252 | * useful. Instead, the topmost .for loop needs to be printed twice, once |
254 | * with its first_lineno and once with its lineno. | | 253 | * with its first_lineno and once with its lineno. |
255 | * | | 254 | * |
256 | * As of 2020-09-15, using the above rules, the stack trace for the .info line | | 255 | * As of 2020-09-15, using the above rules, the stack trace for the .info line |
257 | * in include-subsub.mk would be: | | 256 | * in include-subsub.mk would be: |
258 | * | | 257 | * |
259 | * curFile: include-subsub.mk:4 | | 258 | * curFile: include-subsub.mk:4 |
260 | * (lineno, from an .include) | | 259 | * (lineno, from an .include) |
261 | * includes[4]: include-sub.mk:32 | | 260 | * includes[4]: include-sub.mk:32 |
262 | * (lineno, from a .for loop below an .include) | | 261 | * (lineno, from a .for loop below an .include) |
263 | * includes[4]: include-sub.mk:31 | | 262 | * includes[4]: include-sub.mk:31 |
264 | * (first_lineno, from a .for loop, lineno == 32) | | 263 | * (first_lineno, from a .for loop, lineno == 32) |
265 | * includes[3]: include-sub.mk:30 | | 264 | * includes[3]: include-sub.mk:30 |
266 | * (first_lineno, from a .for loop, lineno == 33) | | 265 | * (first_lineno, from a .for loop, lineno == 33) |
267 | * includes[2]: include-sub.mk:29 | | 266 | * includes[2]: include-sub.mk:29 |
268 | * (first_lineno, from a .for loop, lineno == 34) | | 267 | * (first_lineno, from a .for loop, lineno == 34) |
269 | * includes[1]: include-sub.mk:35 | | 268 | * includes[1]: include-sub.mk:35 |
270 | * (not printed since it is below a .for loop) | | 269 | * (not printed since it is below a .for loop) |
271 | * includes[0]: include-main.mk:27 | | 270 | * includes[0]: include-main.mk:27 |
272 | */ | | 271 | */ |
273 | static Vector /* of IFile pointer */ includes; | | 272 | static Vector /* of IFile pointer */ includes; |
274 | | | 273 | |
275 | static IFile * | | 274 | static IFile * |
276 | GetInclude(size_t i) | | 275 | GetInclude(size_t i) |
277 | { | | 276 | { |
278 | return *((IFile **)Vector_Get(&includes, i)); | | 277 | return *((IFile **)Vector_Get(&includes, i)); |
279 | } | | 278 | } |
280 | | | 279 | |
281 | /* include paths (lists of directories) */ | | 280 | /* include paths (lists of directories) */ |
282 | SearchPath *parseIncPath; /* dirs for "..." includes */ | | 281 | SearchPath *parseIncPath; /* dirs for "..." includes */ |
283 | SearchPath *sysIncPath; /* dirs for <...> includes */ | | 282 | SearchPath *sysIncPath; /* dirs for <...> includes */ |
284 | SearchPath *defIncPath; /* default for sysIncPath */ | | 283 | SearchPath *defIncPath; /* default for sysIncPath */ |
285 | | | 284 | |
286 | /* parser tables */ | | 285 | /* parser tables */ |
287 | | | 286 | |
288 | /* | | 287 | /* |
289 | * The parseKeywords table is searched using binary search when deciding | | 288 | * The parseKeywords table is searched using binary search when deciding |
290 | * if a target or source is special. The 'spec' field is the ParseSpecial | | 289 | * if a target or source is special. The 'spec' field is the ParseSpecial |
291 | * type of the keyword (SP_NOT if the keyword isn't special as a target) while | | 290 | * type of the keyword (SP_NOT if the keyword isn't special as a target) while |
292 | * the 'op' field is the operator to apply to the list of targets if the | | 291 | * the 'op' field is the operator to apply to the list of targets if the |
293 | * keyword is used as a source ("0" if the keyword isn't special as a source) | | 292 | * keyword is used as a source ("0" if the keyword isn't special as a source) |
294 | */ | | 293 | */ |
295 | static const struct { | | 294 | static const struct { |
296 | const char *name; /* Name of keyword */ | | 295 | const char *name; /* Name of keyword */ |
297 | ParseSpecial spec; /* Type when used as a target */ | | 296 | ParseSpecial spec; /* Type when used as a target */ |
298 | GNodeType op; /* Operator when used as a source */ | | 297 | GNodeType op; /* Operator when used as a source */ |
299 | } parseKeywords[] = { | | 298 | } parseKeywords[] = { |
300 | { ".BEGIN", SP_BEGIN, 0 }, | | 299 | { ".BEGIN", SP_BEGIN, 0 }, |
301 | { ".DEFAULT", SP_DEFAULT, 0 }, | | 300 | { ".DEFAULT", SP_DEFAULT, 0 }, |
302 | { ".DELETE_ON_ERROR", SP_DELETE_ON_ERROR, 0 }, | | 301 | { ".DELETE_ON_ERROR", SP_DELETE_ON_ERROR, 0 }, |
303 | { ".END", SP_END, 0 }, | | 302 | { ".END", SP_END, 0 }, |
304 | { ".ERROR", SP_ERROR, 0 }, | | 303 | { ".ERROR", SP_ERROR, 0 }, |
305 | { ".EXEC", SP_ATTRIBUTE, OP_EXEC }, | | 304 | { ".EXEC", SP_ATTRIBUTE, OP_EXEC }, |
306 | { ".IGNORE", SP_IGNORE, OP_IGNORE }, | | 305 | { ".IGNORE", SP_IGNORE, OP_IGNORE }, |
307 | { ".INCLUDES", SP_INCLUDES, 0 }, | | 306 | { ".INCLUDES", SP_INCLUDES, 0 }, |
308 | { ".INTERRUPT", SP_INTERRUPT, 0 }, | | 307 | { ".INTERRUPT", SP_INTERRUPT, 0 }, |
309 | { ".INVISIBLE", SP_ATTRIBUTE, OP_INVISIBLE }, | | 308 | { ".INVISIBLE", SP_ATTRIBUTE, OP_INVISIBLE }, |
310 | { ".JOIN", SP_ATTRIBUTE, OP_JOIN }, | | 309 | { ".JOIN", SP_ATTRIBUTE, OP_JOIN }, |
311 | { ".LIBS", SP_LIBS, 0 }, | | 310 | { ".LIBS", SP_LIBS, 0 }, |
312 | { ".MADE", SP_ATTRIBUTE, OP_MADE }, | | 311 | { ".MADE", SP_ATTRIBUTE, OP_MADE }, |
313 | { ".MAIN", SP_MAIN, 0 }, | | 312 | { ".MAIN", SP_MAIN, 0 }, |
314 | { ".MAKE", SP_ATTRIBUTE, OP_MAKE }, | | 313 | { ".MAKE", SP_ATTRIBUTE, OP_MAKE }, |
315 | { ".MAKEFLAGS", SP_MFLAGS, 0 }, | | 314 | { ".MAKEFLAGS", SP_MFLAGS, 0 }, |
316 | { ".META", SP_META, OP_META }, | | 315 | { ".META", SP_META, OP_META }, |
317 | { ".MFLAGS", SP_MFLAGS, 0 }, | | 316 | { ".MFLAGS", SP_MFLAGS, 0 }, |
318 | { ".NOMETA", SP_NOMETA, OP_NOMETA }, | | 317 | { ".NOMETA", SP_NOMETA, OP_NOMETA }, |
319 | { ".NOMETA_CMP", SP_NOMETA_CMP, OP_NOMETA_CMP }, | | 318 | { ".NOMETA_CMP", SP_NOMETA_CMP, OP_NOMETA_CMP }, |
320 | { ".NOPATH", SP_NOPATH, OP_NOPATH }, | | 319 | { ".NOPATH", SP_NOPATH, OP_NOPATH }, |
321 | { ".NOTMAIN", SP_ATTRIBUTE, OP_NOTMAIN }, | | 320 | { ".NOTMAIN", SP_ATTRIBUTE, OP_NOTMAIN }, |
322 | { ".NOTPARALLEL", SP_NOTPARALLEL, 0 }, | | 321 | { ".NOTPARALLEL", SP_NOTPARALLEL, 0 }, |
323 | { ".NO_PARALLEL", SP_NOTPARALLEL, 0 }, | | 322 | { ".NO_PARALLEL", SP_NOTPARALLEL, 0 }, |
324 | { ".NULL", SP_NULL, 0 }, | | 323 | { ".NULL", SP_NULL, 0 }, |
325 | { ".OBJDIR", SP_OBJDIR, 0 }, | | 324 | { ".OBJDIR", SP_OBJDIR, 0 }, |
326 | { ".OPTIONAL", SP_ATTRIBUTE, OP_OPTIONAL }, | | 325 | { ".OPTIONAL", SP_ATTRIBUTE, OP_OPTIONAL }, |
327 | { ".ORDER", SP_ORDER, 0 }, | | 326 | { ".ORDER", SP_ORDER, 0 }, |
328 | { ".PARALLEL", SP_PARALLEL, 0 }, | | 327 | { ".PARALLEL", SP_PARALLEL, 0 }, |
329 | { ".PATH", SP_PATH, 0 }, | | 328 | { ".PATH", SP_PATH, 0 }, |
330 | { ".PHONY", SP_PHONY, OP_PHONY }, | | 329 | { ".PHONY", SP_PHONY, OP_PHONY }, |
331 | #ifdef POSIX | | 330 | #ifdef POSIX |
332 | { ".POSIX", SP_POSIX, 0 }, | | 331 | { ".POSIX", SP_POSIX, 0 }, |
333 | #endif | | 332 | #endif |
334 | { ".PRECIOUS", SP_PRECIOUS, OP_PRECIOUS }, | | 333 | { ".PRECIOUS", SP_PRECIOUS, OP_PRECIOUS }, |
335 | { ".RECURSIVE", SP_ATTRIBUTE, OP_MAKE }, | | 334 | { ".RECURSIVE", SP_ATTRIBUTE, OP_MAKE }, |
336 | { ".SHELL", SP_SHELL, 0 }, | | 335 | { ".SHELL", SP_SHELL, 0 }, |
337 | { ".SILENT", SP_SILENT, OP_SILENT }, | | 336 | { ".SILENT", SP_SILENT, OP_SILENT }, |
338 | { ".SINGLESHELL", SP_SINGLESHELL, 0 }, | | 337 | { ".SINGLESHELL", SP_SINGLESHELL, 0 }, |
339 | { ".STALE", SP_STALE, 0 }, | | 338 | { ".STALE", SP_STALE, 0 }, |
340 | { ".SUFFIXES", SP_SUFFIXES, 0 }, | | 339 | { ".SUFFIXES", SP_SUFFIXES, 0 }, |
341 | { ".USE", SP_ATTRIBUTE, OP_USE }, | | 340 | { ".USE", SP_ATTRIBUTE, OP_USE }, |
342 | { ".USEBEFORE", SP_ATTRIBUTE, OP_USEBEFORE }, | | 341 | { ".USEBEFORE", SP_ATTRIBUTE, OP_USEBEFORE }, |
343 | { ".WAIT", SP_WAIT, 0 }, | | 342 | { ".WAIT", SP_WAIT, 0 }, |
344 | }; | | 343 | }; |
345 | | | 344 | |
346 | /* file loader */ | | 345 | /* file loader */ |
347 | | | 346 | |
348 | struct loadedfile { | | 347 | struct loadedfile { |
349 | const char *path; /* name, for error reports */ | | 348 | const char *path; /* name, for error reports */ |
350 | char *buf; /* contents buffer */ | | 349 | char *buf; /* contents buffer */ |
351 | size_t len; /* length of contents */ | | 350 | size_t len; /* length of contents */ |
352 | size_t maplen; /* length of mmap area, or 0 */ | | 351 | size_t maplen; /* length of mmap area, or 0 */ |
353 | Boolean used; /* XXX: have we used the data yet */ | | 352 | Boolean used; /* XXX: have we used the data yet */ |
354 | }; | | 353 | }; |
355 | | | 354 | |
356 | static struct loadedfile * | | 355 | static struct loadedfile * |
357 | loadedfile_create(const char *path) | | 356 | loadedfile_create(const char *path) |
358 | { | | 357 | { |
359 | struct loadedfile *lf; | | 358 | struct loadedfile *lf; |
360 | | | 359 | |
361 | lf = bmake_malloc(sizeof(*lf)); | | 360 | lf = bmake_malloc(sizeof(*lf)); |
362 | lf->path = path == NULL ? "(stdin)" : path; | | 361 | lf->path = path == NULL ? "(stdin)" : path; |
363 | lf->buf = NULL; | | 362 | lf->buf = NULL; |
364 | lf->len = 0; | | 363 | lf->len = 0; |
365 | lf->maplen = 0; | | 364 | lf->maplen = 0; |
366 | lf->used = FALSE; | | 365 | lf->used = FALSE; |
367 | return lf; | | 366 | return lf; |
368 | } | | 367 | } |
369 | | | 368 | |
370 | static void | | 369 | static void |
371 | loadedfile_destroy(struct loadedfile *lf) | | 370 | loadedfile_destroy(struct loadedfile *lf) |
372 | { | | 371 | { |
373 | if (lf->buf != NULL) { | | 372 | if (lf->buf != NULL) { |
374 | if (lf->maplen > 0) { | | 373 | if (lf->maplen > 0) { |
375 | munmap(lf->buf, lf->maplen); | | 374 | munmap(lf->buf, lf->maplen); |
376 | } else { | | 375 | } else { |
377 | free(lf->buf); | | 376 | free(lf->buf); |
378 | } | | 377 | } |
379 | } | | 378 | } |
380 | free(lf); | | 379 | free(lf); |
381 | } | | 380 | } |
382 | | | 381 | |
383 | /* | | 382 | /* |
384 | * nextbuf() operation for loadedfile, as needed by the weird and twisted | | 383 | * nextbuf() operation for loadedfile, as needed by the weird and twisted |
385 | * logic below. Once that's cleaned up, we can get rid of lf->used... | | 384 | * logic below. Once that's cleaned up, we can get rid of lf->used... |
386 | */ | | 385 | */ |
387 | static char * | | 386 | static char * |
388 | loadedfile_nextbuf(void *x, size_t *len) | | 387 | loadedfile_nextbuf(void *x, size_t *len) |
389 | { | | 388 | { |
390 | struct loadedfile *lf = x; | | 389 | struct loadedfile *lf = x; |
391 | | | 390 | |
392 | if (lf->used) { | | 391 | if (lf->used) { |
393 | return NULL; | | 392 | return NULL; |
394 | } | | 393 | } |
395 | lf->used = TRUE; | | 394 | lf->used = TRUE; |
396 | *len = lf->len; | | 395 | *len = lf->len; |
397 | return lf->buf; | | 396 | return lf->buf; |
398 | } | | 397 | } |
399 | | | 398 | |
400 | /* | | 399 | /* |
401 | * Try to get the size of a file. | | 400 | * Try to get the size of a file. |
402 | */ | | 401 | */ |
403 | static Boolean | | 402 | static Boolean |
404 | load_getsize(int fd, size_t *ret) | | 403 | load_getsize(int fd, size_t *ret) |
405 | { | | 404 | { |
406 | struct stat st; | | 405 | struct stat st; |
407 | | | 406 | |
408 | if (fstat(fd, &st) < 0) { | | 407 | if (fstat(fd, &st) < 0) { |
409 | return FALSE; | | 408 | return FALSE; |
410 | } | | 409 | } |
411 | | | 410 | |
412 | if (!S_ISREG(st.st_mode)) { | | 411 | if (!S_ISREG(st.st_mode)) { |
413 | return FALSE; | | 412 | return FALSE; |
414 | } | | 413 | } |
415 | | | 414 | |
416 | /* | | 415 | /* |
417 | * st_size is an off_t, which is 64 bits signed; *ret is | | 416 | * st_size is an off_t, which is 64 bits signed; *ret is |
418 | * size_t, which might be 32 bits unsigned or 64 bits | | 417 | * size_t, which might be 32 bits unsigned or 64 bits |
419 | * unsigned. Rather than being elaborate, just punt on | | 418 | * unsigned. Rather than being elaborate, just punt on |
420 | * files that are more than 2^31 bytes. We should never | | 419 | * files that are more than 2^31 bytes. We should never |
421 | * see a makefile that size in practice... | | 420 | * see a makefile that size in practice... |
422 | * | | 421 | * |
423 | * While we're at it reject negative sizes too, just in case. | | 422 | * While we're at it reject negative sizes too, just in case. |
424 | */ | | 423 | */ |
425 | if (st.st_size < 0 || st.st_size > 0x7fffffff) { | | 424 | if (st.st_size < 0 || st.st_size > 0x7fffffff) { |
426 | return FALSE; | | 425 | return FALSE; |
427 | } | | 426 | } |
428 | | | 427 | |
429 | *ret = (size_t)st.st_size; | | 428 | *ret = (size_t)st.st_size; |
430 | return TRUE; | | 429 | return TRUE; |
431 | } | | 430 | } |
432 | | | 431 | |
433 | /* | | 432 | /* |
434 | * Read in a file. | | 433 | * Read in a file. |
435 | * | | 434 | * |
436 | * Until the path search logic can be moved under here instead of | | 435 | * Until the path search logic can be moved under here instead of |
437 | * being in the caller in another source file, we need to have the fd | | 436 | * being in the caller in another source file, we need to have the fd |
438 | * passed in already open. Bleh. | | 437 | * passed in already open. Bleh. |
439 | * | | 438 | * |
440 | * If the path is NULL use stdin and (to insure against fd leaks) | | 439 | * If the path is NULL use stdin and (to insure against fd leaks) |
441 | * assert that the caller passed in -1. | | 440 | * assert that the caller passed in -1. |
442 | */ | | 441 | */ |
443 | static struct loadedfile * | | 442 | static struct loadedfile * |
444 | loadfile(const char *path, int fd) | | 443 | loadfile(const char *path, int fd) |
445 | { | | 444 | { |
446 | struct loadedfile *lf; | | 445 | struct loadedfile *lf; |
447 | static unsigned long pagesize = 0; | | 446 | static unsigned long pagesize = 0; |
448 | ssize_t result; | | 447 | ssize_t result; |
449 | size_t bufpos; | | 448 | size_t bufpos; |
450 | | | 449 | |
451 | lf = loadedfile_create(path); | | 450 | lf = loadedfile_create(path); |
452 | | | 451 | |
453 | if (path == NULL) { | | 452 | if (path == NULL) { |
454 | assert(fd == -1); | | 453 | assert(fd == -1); |
455 | fd = STDIN_FILENO; | | 454 | fd = STDIN_FILENO; |
456 | } else { | | 455 | } else { |
457 | #if 0 /* notyet */ | | 456 | #if 0 /* notyet */ |
458 | fd = open(path, O_RDONLY); | | 457 | fd = open(path, O_RDONLY); |
459 | if (fd < 0) { | | 458 | if (fd < 0) { |
460 | ... | | 459 | ... |
461 | Error("%s: %s", path, strerror(errno)); | | 460 | Error("%s: %s", path, strerror(errno)); |
462 | exit(1); | | 461 | exit(1); |
463 | } | | 462 | } |
464 | #endif | | 463 | #endif |
465 | } | | 464 | } |
466 | | | 465 | |
467 | if (load_getsize(fd, &lf->len)) { | | 466 | if (load_getsize(fd, &lf->len)) { |
468 | /* found a size, try mmap */ | | 467 | /* found a size, try mmap */ |
469 | if (pagesize == 0) | | 468 | if (pagesize == 0) |
470 | pagesize = (unsigned long)sysconf(_SC_PAGESIZE); | | 469 | pagesize = (unsigned long)sysconf(_SC_PAGESIZE); |
471 | if (pagesize == 0 || pagesize == (unsigned long)-1) { | | 470 | if (pagesize == 0 || pagesize == (unsigned long)-1) { |
472 | pagesize = 0x1000; | | 471 | pagesize = 0x1000; |
473 | } | | 472 | } |
474 | /* round size up to a page */ | | 473 | /* round size up to a page */ |
475 | lf->maplen = pagesize * ((lf->len + pagesize - 1)/pagesize); | | 474 | lf->maplen = pagesize * ((lf->len + pagesize - 1)/pagesize); |
476 | | | 475 | |
477 | /* | | 476 | /* |
478 | * XXX hack for dealing with empty files; remove when | | 477 | * XXX hack for dealing with empty files; remove when |
479 | * we're no longer limited by interfacing to the old | | 478 | * we're no longer limited by interfacing to the old |
480 | * logic elsewhere in this file. | | 479 | * logic elsewhere in this file. |
481 | */ | | 480 | */ |
482 | if (lf->maplen == 0) { | | 481 | if (lf->maplen == 0) { |
483 | lf->maplen = pagesize; | | 482 | lf->maplen = pagesize; |
484 | } | | 483 | } |
485 | | | 484 | |
486 | /* | | 485 | /* |
487 | * FUTURE: remove PROT_WRITE when the parser no longer | | 486 | * FUTURE: remove PROT_WRITE when the parser no longer |
488 | * needs to scribble on the input. | | 487 | * needs to scribble on the input. |
489 | */ | | 488 | */ |
490 | lf->buf = mmap(NULL, lf->maplen, PROT_READ|PROT_WRITE, | | 489 | lf->buf = mmap(NULL, lf->maplen, PROT_READ|PROT_WRITE, |
491 | MAP_FILE|MAP_COPY, fd, 0); | | 490 | MAP_FILE|MAP_COPY, fd, 0); |
492 | if (lf->buf != MAP_FAILED) { | | 491 | if (lf->buf != MAP_FAILED) { |
493 | /* succeeded */ | | 492 | /* succeeded */ |
494 | if (lf->len == lf->maplen && lf->buf[lf->len - 1] != '\n') { | | 493 | if (lf->len == lf->maplen && lf->buf[lf->len - 1] != '\n') { |
495 | char *b = bmake_malloc(lf->len + 1); | | 494 | char *b = bmake_malloc(lf->len + 1); |
496 | b[lf->len] = '\n'; | | 495 | b[lf->len] = '\n'; |
497 | memcpy(b, lf->buf, lf->len++); | | 496 | memcpy(b, lf->buf, lf->len++); |
498 | munmap(lf->buf, lf->maplen); | | 497 | munmap(lf->buf, lf->maplen); |
499 | lf->maplen = 0; | | 498 | lf->maplen = 0; |
500 | lf->buf = b; | | 499 | lf->buf = b; |
501 | } | | 500 | } |
502 | goto done; | | 501 | goto done; |
503 | } | | 502 | } |
504 | } | | 503 | } |
505 | | | 504 | |
506 | /* cannot mmap; load the traditional way */ | | 505 | /* cannot mmap; load the traditional way */ |
507 | | | 506 | |
508 | lf->maplen = 0; | | 507 | lf->maplen = 0; |
509 | lf->len = 1024; | | 508 | lf->len = 1024; |
510 | lf->buf = bmake_malloc(lf->len); | | 509 | lf->buf = bmake_malloc(lf->len); |
511 | | | 510 | |
512 | bufpos = 0; | | 511 | bufpos = 0; |
513 | while (1) { | | 512 | while (1) { |
514 | assert(bufpos <= lf->len); | | 513 | assert(bufpos <= lf->len); |
515 | if (bufpos == lf->len) { | | 514 | if (bufpos == lf->len) { |
516 | if (lf->len > SIZE_MAX/2) { | | 515 | if (lf->len > SIZE_MAX/2) { |
517 | errno = EFBIG; | | 516 | errno = EFBIG; |
518 | Error("%s: file too large", path); | | 517 | Error("%s: file too large", path); |
519 | exit(1); | | 518 | exit(1); |
520 | } | | 519 | } |
521 | lf->len *= 2; | | 520 | lf->len *= 2; |
522 | lf->buf = bmake_realloc(lf->buf, lf->len); | | 521 | lf->buf = bmake_realloc(lf->buf, lf->len); |
523 | } | | 522 | } |
524 | assert(bufpos < lf->len); | | 523 | assert(bufpos < lf->len); |
525 | result = read(fd, lf->buf + bufpos, lf->len - bufpos); | | 524 | result = read(fd, lf->buf + bufpos, lf->len - bufpos); |
526 | if (result < 0) { | | 525 | if (result < 0) { |
527 | Error("%s: read error: %s", path, strerror(errno)); | | 526 | Error("%s: read error: %s", path, strerror(errno)); |
528 | exit(1); | | 527 | exit(1); |
529 | } | | 528 | } |
530 | if (result == 0) { | | 529 | if (result == 0) { |
531 | break; | | 530 | break; |
532 | } | | 531 | } |
533 | bufpos += (size_t)result; | | 532 | bufpos += (size_t)result; |
534 | } | | 533 | } |
535 | assert(bufpos <= lf->len); | | 534 | assert(bufpos <= lf->len); |
536 | lf->len = bufpos; | | 535 | lf->len = bufpos; |
537 | | | 536 | |
538 | /* truncate malloc region to actual length (maybe not useful) */ | | 537 | /* truncate malloc region to actual length (maybe not useful) */ |
539 | if (lf->len > 0) { | | 538 | if (lf->len > 0) { |
540 | /* as for mmap case, ensure trailing \n */ | | 539 | /* as for mmap case, ensure trailing \n */ |
541 | if (lf->buf[lf->len - 1] != '\n') | | 540 | if (lf->buf[lf->len - 1] != '\n') |
542 | lf->len++; | | 541 | lf->len++; |
543 | lf->buf = bmake_realloc(lf->buf, lf->len); | | 542 | lf->buf = bmake_realloc(lf->buf, lf->len); |
544 | lf->buf[lf->len - 1] = '\n'; | | 543 | lf->buf[lf->len - 1] = '\n'; |
545 | } | | 544 | } |
546 | | | 545 | |
547 | done: | | 546 | done: |
548 | if (path != NULL) { | | 547 | if (path != NULL) { |
549 | close(fd); | | 548 | close(fd); |
550 | } | | 549 | } |
551 | return lf; | | 550 | return lf; |
552 | } | | 551 | } |
553 | | | 552 | |
554 | /* old code */ | | 553 | /* old code */ |
555 | | | 554 | |
556 | /* Check if the current character is escaped on the current line. */ | | 555 | /* Check if the current character is escaped on the current line. */ |
557 | static Boolean | | 556 | static Boolean |
558 | ParseIsEscaped(const char *line, const char *c) | | 557 | ParseIsEscaped(const char *line, const char *c) |
559 | { | | 558 | { |
560 | Boolean active = FALSE; | | 559 | Boolean active = FALSE; |
561 | for (;;) { | | 560 | for (;;) { |
562 | if (line == c) | | 561 | if (line == c) |
563 | return active; | | 562 | return active; |
564 | if (*--c != '\\') | | 563 | if (*--c != '\\') |
565 | return active; | | 564 | return active; |
566 | active = !active; | | 565 | active = !active; |
567 | } | | 566 | } |
568 | } | | 567 | } |
569 | | | 568 | |
570 | /* Add the filename and lineno to the GNode so that we remember where it | | 569 | /* Add the filename and lineno to the GNode so that we remember where it |
571 | * was first defined. */ | | 570 | * was first defined. */ |
572 | static void | | 571 | static void |
573 | ParseMark(GNode *gn) | | 572 | ParseMark(GNode *gn) |
574 | { | | 573 | { |
575 | gn->fname = curFile->fname; | | 574 | gn->fname = curFile->fname; |
576 | gn->lineno = curFile->lineno; | | 575 | gn->lineno = curFile->lineno; |
577 | } | | 576 | } |
578 | | | 577 | |
579 | /* Look in the table of keywords for one matching the given string. | | 578 | /* Look in the table of keywords for one matching the given string. |
580 | * Return the index of the keyword, or -1 if it isn't there. */ | | 579 | * Return the index of the keyword, or -1 if it isn't there. */ |
581 | static int | | 580 | static int |
582 | ParseFindKeyword(const char *str) | | 581 | ParseFindKeyword(const char *str) |
583 | { | | 582 | { |
584 | int start, end, cur; | | 583 | int start, end, cur; |
585 | int diff; | | 584 | int diff; |
586 | | | 585 | |
587 | start = 0; | | 586 | start = 0; |
588 | end = sizeof parseKeywords / sizeof parseKeywords[0] - 1; | | 587 | end = sizeof parseKeywords / sizeof parseKeywords[0] - 1; |
589 | | | 588 | |
590 | do { | | 589 | do { |
591 | cur = start + (end - start) / 2; | | 590 | cur = start + (end - start) / 2; |
592 | diff = strcmp(str, parseKeywords[cur].name); | | 591 | diff = strcmp(str, parseKeywords[cur].name); |
593 | | | 592 | |
594 | if (diff == 0) { | | 593 | if (diff == 0) { |
595 | return cur; | | 594 | return cur; |
596 | } else if (diff < 0) { | | 595 | } else if (diff < 0) { |
597 | end = cur - 1; | | 596 | end = cur - 1; |
598 | } else { | | 597 | } else { |
599 | start = cur + 1; | | 598 | start = cur + 1; |
600 | } | | 599 | } |
601 | } while (start <= end); | | 600 | } while (start <= end); |
602 | return -1; | | 601 | return -1; |
603 | } | | 602 | } |
604 | | | 603 | |
605 | static void | | 604 | static void |
606 | PrintLocation(FILE *f, const char *filename, size_t lineno) | | 605 | PrintLocation(FILE *f, const char *filename, size_t lineno) |
607 | { | | 606 | { |
608 | char dirbuf[MAXPATHLEN+1]; | | 607 | char dirbuf[MAXPATHLEN+1]; |
609 | const char *dir, *base; | | 608 | const char *dir, *base; |
610 | char *dir_freeIt, *base_freeIt; | | 609 | char *dir_freeIt, *base_freeIt; |
611 | | | 610 | |
612 | if (*filename == '/' || strcmp(filename, "(stdin)") == 0) { | | 611 | if (*filename == '/' || strcmp(filename, "(stdin)") == 0) { |
613 | (void)fprintf(f, "\"%s\" line %zu: ", filename, lineno); | | 612 | (void)fprintf(f, "\"%s\" line %zu: ", filename, lineno); |
614 | return; | | 613 | return; |
615 | } | | 614 | } |
616 | | | 615 | |
617 | /* Find out which makefile is the culprit. | | 616 | /* Find out which makefile is the culprit. |
618 | * We try ${.PARSEDIR} and apply realpath(3) if not absolute. */ | | 617 | * We try ${.PARSEDIR} and apply realpath(3) if not absolute. */ |
619 | | | 618 | |
620 | dir = Var_Value(".PARSEDIR", VAR_GLOBAL, &dir_freeIt); | | 619 | dir = Var_Value(".PARSEDIR", VAR_GLOBAL, &dir_freeIt); |
621 | if (dir == NULL) | | 620 | if (dir == NULL) |
622 | dir = "."; | | 621 | dir = "."; |
623 | if (*dir != '/') | | 622 | if (*dir != '/') |
624 | dir = realpath(dir, dirbuf); | | 623 | dir = realpath(dir, dirbuf); |
625 | | | 624 | |
626 | base = Var_Value(".PARSEFILE", VAR_GLOBAL, &base_freeIt); | | 625 | base = Var_Value(".PARSEFILE", VAR_GLOBAL, &base_freeIt); |
627 | if (base == NULL) { | | 626 | if (base == NULL) { |
628 | const char *slash = strrchr(filename, '/'); | | 627 | const char *slash = strrchr(filename, '/'); |
629 | base = slash != NULL ? slash + 1 : filename; | | 628 | base = slash != NULL ? slash + 1 : filename; |
630 | } | | 629 | } |
631 | | | 630 | |
632 | (void)fprintf(f, "\"%s/%s\" line %zu: ", dir, base, lineno); | | 631 | (void)fprintf(f, "\"%s/%s\" line %zu: ", dir, base, lineno); |
633 | bmake_free(base_freeIt); | | 632 | bmake_free(base_freeIt); |
634 | bmake_free(dir_freeIt); | | 633 | bmake_free(dir_freeIt); |
635 | } | | 634 | } |
636 | | | 635 | |
637 | /* Print a parse error message, including location information. | | 636 | /* Print a parse error message, including location information. |
638 | * | | 637 | * |
639 | * Increment "fatals" if the level is PARSE_FATAL, and continue parsing | | 638 | * Increment "fatals" if the level is PARSE_FATAL, and continue parsing |
640 | * until the end of the current top-level makefile, then exit (see | | 639 | * until the end of the current top-level makefile, then exit (see |
641 | * Parse_File). */ | | 640 | * Parse_File). */ |
642 | static void | | 641 | static void |
643 | ParseVErrorInternal(FILE *f, const char *cfname, size_t clineno, | | 642 | ParseVErrorInternal(FILE *f, const char *cfname, size_t clineno, |
644 | ParseErrorLevel type, const char *fmt, va_list ap) | | 643 | ParseErrorLevel type, const char *fmt, va_list ap) |
645 | { | | 644 | { |
646 | static Boolean fatal_warning_error_printed = FALSE; | | 645 | static Boolean fatal_warning_error_printed = FALSE; |
647 | | | 646 | |
648 | (void)fprintf(f, "%s: ", progname); | | 647 | (void)fprintf(f, "%s: ", progname); |
649 | | | 648 | |
650 | if (cfname != NULL) | | 649 | if (cfname != NULL) |
651 | PrintLocation(f, cfname, clineno); | | 650 | PrintLocation(f, cfname, clineno); |
652 | if (type == PARSE_WARNING) | | 651 | if (type == PARSE_WARNING) |
653 | (void)fprintf(f, "warning: "); | | 652 | (void)fprintf(f, "warning: "); |
654 | (void)vfprintf(f, fmt, ap); | | 653 | (void)vfprintf(f, fmt, ap); |
655 | (void)fprintf(f, "\n"); | | 654 | (void)fprintf(f, "\n"); |
656 | (void)fflush(f); | | 655 | (void)fflush(f); |
657 | | | 656 | |
658 | if (type == PARSE_INFO) | | 657 | if (type == PARSE_INFO) |
659 | return; | | 658 | return; |
660 | if (type == PARSE_FATAL || opts.parseWarnFatal) | | 659 | if (type == PARSE_FATAL || opts.parseWarnFatal) |
661 | fatals++; | | 660 | fatals++; |
662 | if (opts.parseWarnFatal && !fatal_warning_error_printed) { | | 661 | if (opts.parseWarnFatal && !fatal_warning_error_printed) { |
663 | Error("parsing warnings being treated as errors"); | | 662 | Error("parsing warnings being treated as errors"); |
664 | fatal_warning_error_printed = TRUE; | | 663 | fatal_warning_error_printed = TRUE; |
665 | } | | 664 | } |
666 | } | | 665 | } |
667 | | | 666 | |
668 | static void | | 667 | static void |
669 | ParseErrorInternal(const char *cfname, size_t clineno, ParseErrorLevel type, | | 668 | ParseErrorInternal(const char *cfname, size_t clineno, ParseErrorLevel type, |
670 | const char *fmt, ...) | | 669 | const char *fmt, ...) |
671 | { | | 670 | { |
672 | va_list ap; | | 671 | va_list ap; |
673 | | | 672 | |
674 | va_start(ap, fmt); | | 673 | va_start(ap, fmt); |
675 | (void)fflush(stdout); | | 674 | (void)fflush(stdout); |
676 | ParseVErrorInternal(stderr, cfname, clineno, type, fmt, ap); | | 675 | ParseVErrorInternal(stderr, cfname, clineno, type, fmt, ap); |
677 | va_end(ap); | | 676 | va_end(ap); |
678 | | | 677 | |
679 | if (opts.debug_file != stderr && opts.debug_file != stdout) { | | 678 | if (opts.debug_file != stderr && opts.debug_file != stdout) { |
680 | va_start(ap, fmt); | | 679 | va_start(ap, fmt); |
681 | ParseVErrorInternal(opts.debug_file, cfname, clineno, type, | | 680 | ParseVErrorInternal(opts.debug_file, cfname, clineno, type, |
682 | fmt, ap); | | 681 | fmt, ap); |
683 | va_end(ap); | | 682 | va_end(ap); |
684 | } | | 683 | } |
685 | } | | 684 | } |
686 | | | 685 | |
687 | /* External interface to ParseErrorInternal; uses the default filename and | | 686 | /* External interface to ParseErrorInternal; uses the default filename and |
688 | * line number. | | 687 | * line number. |
689 | * | | 688 | * |
690 | * Fmt is given without a trailing newline. */ | | 689 | * Fmt is given without a trailing newline. */ |
691 | void | | 690 | void |
692 | Parse_Error(ParseErrorLevel type, const char *fmt, ...) | | 691 | Parse_Error(ParseErrorLevel type, const char *fmt, ...) |
693 | { | | 692 | { |
694 | va_list ap; | | 693 | va_list ap; |
695 | const char *fname; | | 694 | const char *fname; |
696 | size_t lineno; | | 695 | size_t lineno; |
697 | | | 696 | |
698 | if (curFile == NULL) { | | 697 | if (curFile == NULL) { |
699 | fname = NULL; | | 698 | fname = NULL; |
700 | lineno = 0; | | 699 | lineno = 0; |
701 | } else { | | 700 | } else { |
702 | fname = curFile->fname; | | 701 | fname = curFile->fname; |
703 | lineno = (size_t)curFile->lineno; | | 702 | lineno = (size_t)curFile->lineno; |
704 | } | | 703 | } |
705 | | | 704 | |
706 | va_start(ap, fmt); | | 705 | va_start(ap, fmt); |
707 | (void)fflush(stdout); | | 706 | (void)fflush(stdout); |
708 | ParseVErrorInternal(stderr, fname, lineno, type, fmt, ap); | | 707 | ParseVErrorInternal(stderr, fname, lineno, type, fmt, ap); |
709 | va_end(ap); | | 708 | va_end(ap); |
710 | | | 709 | |
711 | if (opts.debug_file != stderr && opts.debug_file != stdout) { | | 710 | if (opts.debug_file != stderr && opts.debug_file != stdout) { |
712 | va_start(ap, fmt); | | 711 | va_start(ap, fmt); |
713 | ParseVErrorInternal(opts.debug_file, fname, lineno, type, | | 712 | ParseVErrorInternal(opts.debug_file, fname, lineno, type, |
714 | fmt, ap); | | 713 | fmt, ap); |
715 | va_end(ap); | | 714 | va_end(ap); |
716 | } | | 715 | } |
717 | } | | 716 | } |
718 | | | 717 | |
719 | | | 718 | |
720 | /* Parse a .info .warning or .error directive. | | 719 | /* Parse a .info .warning or .error directive. |
721 | * | | 720 | * |
722 | * The input is the line minus the ".". We substitute variables, print the | | 721 | * The input is the line minus the ".". We substitute variables, print the |
723 | * message and exit(1) (for .error) or just print a warning if the directive | | 722 | * message and exit(1) (for .error) or just print a warning if the directive |
724 | * is malformed. | | 723 | * is malformed. |
725 | */ | | 724 | */ |
726 | static Boolean | | 725 | static Boolean |
727 | ParseMessage(const char *directive) | | 726 | ParseMessage(const char *directive) |
728 | { | | 727 | { |
729 | const char *p = directive; | | 728 | const char *p = directive; |
730 | int mtype = *p == 'i' ? PARSE_INFO : | | 729 | int mtype = *p == 'i' ? PARSE_INFO : |
731 | *p == 'w' ? PARSE_WARNING : PARSE_FATAL; | | 730 | *p == 'w' ? PARSE_WARNING : PARSE_FATAL; |
732 | char *arg; | | 731 | char *arg; |
733 | | | 732 | |
734 | while (ch_isalpha(*p)) | | 733 | while (ch_isalpha(*p)) |
735 | p++; | | 734 | p++; |
736 | if (!ch_isspace(*p)) | | 735 | if (!ch_isspace(*p)) |
737 | return FALSE; /* missing argument */ | | 736 | return FALSE; /* missing argument */ |
738 | | | 737 | |
739 | cpp_skip_whitespace(&p); | | 738 | cpp_skip_whitespace(&p); |
740 | (void)Var_Subst(p, VAR_CMD, VARE_WANTRES, &arg); | | 739 | (void)Var_Subst(p, VAR_CMD, VARE_WANTRES, &arg); |
741 | /* TODO: handle errors */ | | 740 | /* TODO: handle errors */ |
742 | | | 741 | |
743 | Parse_Error(mtype, "%s", arg); | | 742 | Parse_Error(mtype, "%s", arg); |
744 | free(arg); | | 743 | free(arg); |
745 | | | 744 | |
746 | if (mtype == PARSE_FATAL) { | | 745 | if (mtype == PARSE_FATAL) { |
747 | PrintOnError(NULL, NULL); | | 746 | PrintOnError(NULL, NULL); |
748 | exit(1); | | 747 | exit(1); |
749 | } | | 748 | } |
750 | return TRUE; | | 749 | return TRUE; |
751 | } | | 750 | } |
752 | | | 751 | |
753 | /* Add the child to the parent's children. | | 752 | /* Add the child to the parent's children. |
754 | * | | 753 | * |
755 | * Additionally, add the parent to the child's parents, but only if the | | 754 | * Additionally, add the parent to the child's parents, but only if the |
756 | * target is not special. An example for such a special target is .END, | | 755 | * target is not special. An example for such a special target is .END, |
757 | * which does not need to be informed once the child target has been made. */ | | 756 | * which does not need to be informed once the child target has been made. */ |
758 | static void | | 757 | static void |
759 | LinkSource(GNode *pgn, GNode *cgn, Boolean isSpecial) | | 758 | LinkSource(GNode *pgn, GNode *cgn, Boolean isSpecial) |
760 | { | | 759 | { |
761 | if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty(pgn->cohorts)) | | 760 | if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty(pgn->cohorts)) |
762 | pgn = pgn->cohorts->last->datum; | | 761 | pgn = pgn->cohorts->last->datum; |
763 | | | 762 | |
764 | Lst_Append(pgn->children, cgn); | | 763 | Lst_Append(pgn->children, cgn); |
765 | pgn->unmade++; | | 764 | pgn->unmade++; |
766 | | | 765 | |
767 | /* Special targets like .END don't need any children. */ | | 766 | /* Special targets like .END don't need any children. */ |
768 | if (!isSpecial) | | 767 | if (!isSpecial) |
769 | Lst_Append(cgn->parents, pgn); | | 768 | Lst_Append(cgn->parents, pgn); |
770 | | | 769 | |
771 | if (DEBUG(PARSE)) { | | 770 | if (DEBUG(PARSE)) { |
772 | debug_printf("# %s: added child %s - %s\n", | | 771 | debug_printf("# %s: added child %s - %s\n", |
773 | __func__, pgn->name, cgn->name); | | 772 | __func__, pgn->name, cgn->name); |
774 | Targ_PrintNode(pgn, 0); | | 773 | Targ_PrintNode(pgn, 0); |
775 | Targ_PrintNode(cgn, 0); | | 774 | Targ_PrintNode(cgn, 0); |
776 | } | | 775 | } |
777 | } | | 776 | } |
778 | | | 777 | |
779 | /* Add the node to each target from the current dependency group. */ | | 778 | /* Add the node to each target from the current dependency group. */ |
780 | static void | | 779 | static void |
781 | LinkToTargets(GNode *gn, Boolean isSpecial) | | 780 | LinkToTargets(GNode *gn, Boolean isSpecial) |
782 | { | | 781 | { |
783 | GNodeListNode *ln; | | 782 | GNodeListNode *ln; |
784 | for (ln = targets->first; ln != NULL; ln = ln->next) | | 783 | for (ln = targets->first; ln != NULL; ln = ln->next) |
785 | LinkSource(ln->datum, gn, isSpecial); | | 784 | LinkSource(ln->datum, gn, isSpecial); |
786 | } | | 785 | } |
787 | | | 786 | |
788 | static Boolean | | 787 | static Boolean |
789 | TryApplyDependencyOperator(GNode *gn, GNodeType op) | | 788 | TryApplyDependencyOperator(GNode *gn, GNodeType op) |
790 | { | | 789 | { |
791 | /* | | 790 | /* |
792 | * If the node occurred on the left-hand side of a dependency and the | | 791 | * If the node occurred on the left-hand side of a dependency and the |
793 | * operator also defines a dependency, they must match. | | 792 | * operator also defines a dependency, they must match. |
794 | */ | | 793 | */ |
795 | if ((op & OP_OPMASK) && (gn->type & OP_OPMASK) && | | 794 | if ((op & OP_OPMASK) && (gn->type & OP_OPMASK) && |
796 | ((op & OP_OPMASK) != (gn->type & OP_OPMASK))) | | 795 | ((op & OP_OPMASK) != (gn->type & OP_OPMASK))) |
797 | { | | 796 | { |
798 | Parse_Error(PARSE_FATAL, "Inconsistent operator for %s", gn->name); | | 797 | Parse_Error(PARSE_FATAL, "Inconsistent operator for %s", gn->name); |
799 | return FALSE; | | 798 | return FALSE; |
800 | } | | 799 | } |
801 | | | 800 | |
802 | if (op == OP_DOUBLEDEP && (gn->type & OP_OPMASK) == OP_DOUBLEDEP) { | | 801 | if (op == OP_DOUBLEDEP && (gn->type & OP_OPMASK) == OP_DOUBLEDEP) { |
803 | /* | | 802 | /* |
804 | * If the node was the object of a :: operator, we need to create a | | 803 | * If the node was the object of a :: operator, we need to create a |
805 | * new instance of it for the children and commands on this dependency | | 804 | * new instance of it for the children and commands on this dependency |
806 | * line. The new instance is placed on the 'cohorts' list of the | | 805 | * line. The new instance is placed on the 'cohorts' list of the |
807 | * initial one (note the initial one is not on its own cohorts list) | | 806 | * initial one (note the initial one is not on its own cohorts list) |
808 | * and the new instance is linked to all parents of the initial | | 807 | * and the new instance is linked to all parents of the initial |
809 | * instance. | | 808 | * instance. |
810 | */ | | 809 | */ |
811 | GNode *cohort; | | 810 | GNode *cohort; |
812 | | | 811 | |
813 | /* | | 812 | /* |
814 | * Propagate copied bits to the initial node. They'll be propagated | | 813 | * Propagate copied bits to the initial node. They'll be propagated |
815 | * back to the rest of the cohorts later. | | 814 | * back to the rest of the cohorts later. |
816 | */ | | 815 | */ |
817 | gn->type |= op & ~OP_OPMASK; | | 816 | gn->type |= op & ~OP_OPMASK; |
818 | | | 817 | |
819 | cohort = Targ_NewInternalNode(gn->name); | | 818 | cohort = Targ_NewInternalNode(gn->name); |
820 | if (doing_depend) | | 819 | if (doing_depend) |
821 | ParseMark(cohort); | | 820 | ParseMark(cohort); |
822 | /* | | 821 | /* |
823 | * Make the cohort invisible as well to avoid duplicating it into | | 822 | * Make the cohort invisible as well to avoid duplicating it into |
824 | * other variables. True, parents of this target won't tend to do | | 823 | * other variables. True, parents of this target won't tend to do |
825 | * anything with their local variables, but better safe than | | 824 | * anything with their local variables, but better safe than |
826 | * sorry. (I think this is pointless now, since the relevant list | | 825 | * sorry. (I think this is pointless now, since the relevant list |
827 | * traversals will no longer see this node anyway. -mycroft) | | 826 | * traversals will no longer see this node anyway. -mycroft) |
828 | */ | | 827 | */ |
829 | cohort->type = op | OP_INVISIBLE; | | 828 | cohort->type = op | OP_INVISIBLE; |
830 | Lst_Append(gn->cohorts, cohort); | | 829 | Lst_Append(gn->cohorts, cohort); |
831 | cohort->centurion = gn; | | 830 | cohort->centurion = gn; |
832 | gn->unmade_cohorts++; | | 831 | gn->unmade_cohorts++; |
833 | snprintf(cohort->cohort_num, sizeof cohort->cohort_num, "#%d", | | 832 | snprintf(cohort->cohort_num, sizeof cohort->cohort_num, "#%d", |
834 | (unsigned int)gn->unmade_cohorts % 1000000); | | 833 | (unsigned int)gn->unmade_cohorts % 1000000); |
835 | } else { | | 834 | } else { |
836 | /* | | 835 | /* |
837 | * We don't want to nuke any previous flags (whatever they were) so we | | 836 | * We don't want to nuke any previous flags (whatever they were) so we |
838 | * just OR the new operator into the old | | 837 | * just OR the new operator into the old |
839 | */ | | 838 | */ |
840 | gn->type |= op; | | 839 | gn->type |= op; |
841 | } | | 840 | } |
842 | | | 841 | |
843 | return TRUE; | | 842 | return TRUE; |
844 | } | | 843 | } |
845 | | | 844 | |
846 | static void | | 845 | static void |
847 | ApplyDependencyOperator(GNodeType op) | | 846 | ApplyDependencyOperator(GNodeType op) |
848 | { | | 847 | { |
849 | GNodeListNode *ln; | | 848 | GNodeListNode *ln; |
850 | for (ln = targets->first; ln != NULL; ln = ln->next) | | 849 | for (ln = targets->first; ln != NULL; ln = ln->next) |
851 | if (!TryApplyDependencyOperator(ln->datum, op)) | | 850 | if (!TryApplyDependencyOperator(ln->datum, op)) |
852 | break; | | 851 | break; |
853 | } | | 852 | } |
854 | | | 853 | |
855 | static Boolean | | 854 | static Boolean |
856 | ParseDoSrcKeyword(const char *src, ParseSpecial specType) | | 855 | ParseDoSrcKeyword(const char *src, ParseSpecial specType) |
857 | { | | 856 | { |
858 | static int wait_number = 0; | | 857 | static int wait_number = 0; |
859 | char wait_src[16]; | | 858 | char wait_src[16]; |
860 | GNode *gn; | | 859 | GNode *gn; |
861 | | | 860 | |
862 | if (*src == '.' && ch_isupper(src[1])) { | | 861 | if (*src == '.' && ch_isupper(src[1])) { |
863 | int keywd = ParseFindKeyword(src); | | 862 | int keywd = ParseFindKeyword(src); |
864 | if (keywd != -1) { | | 863 | if (keywd != -1) { |
865 | int op = parseKeywords[keywd].op; | | 864 | int op = parseKeywords[keywd].op; |
866 | if (op != 0) { | | 865 | if (op != 0) { |
867 | ApplyDependencyOperator(op); | | 866 | ApplyDependencyOperator(op); |
868 | return TRUE; | | 867 | return TRUE; |
869 | } | | 868 | } |
870 | if (parseKeywords[keywd].spec == SP_WAIT) { | | 869 | if (parseKeywords[keywd].spec == SP_WAIT) { |
871 | /* | | 870 | /* |
872 | * We add a .WAIT node in the dependency list. | | 871 | * We add a .WAIT node in the dependency list. |
873 | * After any dynamic dependencies (and filename globbing) | | 872 | * After any dynamic dependencies (and filename globbing) |
874 | * have happened, it is given a dependency on the each | | 873 | * have happened, it is given a dependency on the each |
875 | * previous child back to and previous .WAIT node. | | 874 | * previous child back to and previous .WAIT node. |
876 | * The next child won't be scheduled until the .WAIT node | | 875 | * The next child won't be scheduled until the .WAIT node |
877 | * is built. | | 876 | * is built. |
878 | * We give each .WAIT node a unique name (mainly for diag). | | 877 | * We give each .WAIT node a unique name (mainly for diag). |
879 | */ | | 878 | */ |
880 | snprintf(wait_src, sizeof wait_src, ".WAIT_%u", ++wait_number); | | 879 | snprintf(wait_src, sizeof wait_src, ".WAIT_%u", ++wait_number); |
881 | gn = Targ_NewInternalNode(wait_src); | | 880 | gn = Targ_NewInternalNode(wait_src); |
882 | if (doing_depend) | | 881 | if (doing_depend) |
883 | ParseMark(gn); | | 882 | ParseMark(gn); |
884 | gn->type = OP_WAIT | OP_PHONY | OP_DEPENDS | OP_NOTMAIN; | | 883 | gn->type = OP_WAIT | OP_PHONY | OP_DEPENDS | OP_NOTMAIN; |
885 | LinkToTargets(gn, specType != SP_NOT); | | 884 | LinkToTargets(gn, specType != SP_NOT); |
886 | return TRUE; | | 885 | return TRUE; |
887 | } | | 886 | } |
888 | } | | 887 | } |
889 | } | | 888 | } |
890 | return FALSE; | | 889 | return FALSE; |
891 | } | | 890 | } |
892 | | | 891 | |
893 | static void | | 892 | static void |
894 | ParseDoSrcMain(const char *src) | | 893 | ParseDoSrcMain(const char *src) |
895 | { | | 894 | { |
896 | /* | | 895 | /* |
897 | * If we have noted the existence of a .MAIN, it means we need | | 896 | * If we have noted the existence of a .MAIN, it means we need |
898 | * to add the sources of said target to the list of things | | 897 | * to add the sources of said target to the list of things |
899 | * to create. The string 'src' is likely to be free, so we | | 898 | * to create. The string 'src' is likely to be free, so we |
900 | * must make a new copy of it. Note that this will only be | | 899 | * must make a new copy of it. Note that this will only be |
901 | * invoked if the user didn't specify a target on the command | | 900 | * invoked if the user didn't specify a target on the command |
902 | * line. This is to allow #ifmake's to succeed, or something... | | 901 | * line. This is to allow #ifmake's to succeed, or something... |
903 | */ | | 902 | */ |
904 | Lst_Append(opts.create, bmake_strdup(src)); | | 903 | Lst_Append(opts.create, bmake_strdup(src)); |
905 | /* | | 904 | /* |
906 | * Add the name to the .TARGETS variable as well, so the user can | | 905 | * Add the name to the .TARGETS variable as well, so the user can |
907 | * employ that, if desired. | | 906 | * employ that, if desired. |
908 | */ | | 907 | */ |
909 | Var_Append(".TARGETS", src, VAR_GLOBAL); | | 908 | Var_Append(".TARGETS", src, VAR_GLOBAL); |
910 | } | | 909 | } |
911 | | | 910 | |
912 | static void | | 911 | static void |
913 | ParseDoSrcOrder(const char *src) | | 912 | ParseDoSrcOrder(const char *src) |
914 | { | | 913 | { |
915 | GNode *gn; | | 914 | GNode *gn; |
916 | /* | | 915 | /* |
917 | * Create proper predecessor/successor links between the previous | | 916 | * Create proper predecessor/successor links between the previous |
918 | * source and the current one. | | 917 | * source and the current one. |
919 | */ | | 918 | */ |
920 | gn = Targ_GetNode(src); | | 919 | gn = Targ_GetNode(src); |
921 | if (doing_depend) | | 920 | if (doing_depend) |
922 | ParseMark(gn); | | 921 | ParseMark(gn); |
923 | if (predecessor != NULL) { | | 922 | if (predecessor != NULL) { |
924 | Lst_Append(predecessor->order_succ, gn); | | 923 | Lst_Append(predecessor->order_succ, gn); |
925 | Lst_Append(gn->order_pred, predecessor); | | 924 | Lst_Append(gn->order_pred, predecessor); |
926 | if (DEBUG(PARSE)) { | | 925 | if (DEBUG(PARSE)) { |
927 | debug_printf("# %s: added Order dependency %s - %s\n", | | 926 | debug_printf("# %s: added Order dependency %s - %s\n", |
928 | __func__, predecessor->name, gn->name); | | 927 | __func__, predecessor->name, gn->name); |
929 | Targ_PrintNode(predecessor, 0); | | 928 | Targ_PrintNode(predecessor, 0); |
930 | Targ_PrintNode(gn, 0); | | 929 | Targ_PrintNode(gn, 0); |
931 | } | | 930 | } |
932 | } | | 931 | } |
933 | /* | | 932 | /* |
934 | * The current source now becomes the predecessor for the next one. | | 933 | * The current source now becomes the predecessor for the next one. |
935 | */ | | 934 | */ |
936 | predecessor = gn; | | 935 | predecessor = gn; |
937 | } | | 936 | } |
938 | | | 937 | |
939 | static void | | 938 | static void |
940 | ParseDoSrcOther(const char *src, GNodeType tOp, ParseSpecial specType) | | 939 | ParseDoSrcOther(const char *src, GNodeType tOp, ParseSpecial specType) |
941 | { | | 940 | { |
942 | GNode *gn; | | 941 | GNode *gn; |
943 | | | 942 | |
944 | /* | | 943 | /* |
945 | * If the source is not an attribute, we need to find/create | | 944 | * If the source is not an attribute, we need to find/create |
946 | * a node for it. After that we can apply any operator to it | | 945 | * a node for it. After that we can apply any operator to it |
947 | * from a special target or link it to its parents, as | | 946 | * from a special target or link it to its parents, as |
948 | * appropriate. | | 947 | * appropriate. |
949 | * | | 948 | * |
950 | * In the case of a source that was the object of a :: operator, | | 949 | * In the case of a source that was the object of a :: operator, |
951 | * the attribute is applied to all of its instances (as kept in | | 950 | * the attribute is applied to all of its instances (as kept in |
952 | * the 'cohorts' list of the node) or all the cohorts are linked | | 951 | * the 'cohorts' list of the node) or all the cohorts are linked |
953 | * to all the targets. | | 952 | * to all the targets. |
954 | */ | | 953 | */ |
955 | | | 954 | |
956 | /* Find/create the 'src' node and attach to all targets */ | | 955 | /* Find/create the 'src' node and attach to all targets */ |
957 | gn = Targ_GetNode(src); | | 956 | gn = Targ_GetNode(src); |
958 | if (doing_depend) | | 957 | if (doing_depend) |
959 | ParseMark(gn); | | 958 | ParseMark(gn); |
960 | if (tOp) { | | 959 | if (tOp) { |
961 | gn->type |= tOp; | | 960 | gn->type |= tOp; |
962 | } else { | | 961 | } else { |
963 | LinkToTargets(gn, specType != SP_NOT); | | 962 | LinkToTargets(gn, specType != SP_NOT); |
964 | } | | 963 | } |
965 | } | | 964 | } |
966 | | | 965 | |
967 | /* Given the name of a source in a dependency line, figure out if it is an | | 966 | /* Given the name of a source in a dependency line, figure out if it is an |
968 | * attribute (such as .SILENT) and apply it to the targets if it is. Else | | 967 | * attribute (such as .SILENT) and apply it to the targets if it is. Else |
969 | * decide if there is some attribute which should be applied *to* the source | | 968 | * decide if there is some attribute which should be applied *to* the source |
970 | * because of some special target (such as .PHONY) and apply it if so. | | 969 | * because of some special target (such as .PHONY) and apply it if so. |
971 | * Otherwise, make the source a child of the targets in the list 'targets'. | | 970 | * Otherwise, make the source a child of the targets in the list 'targets'. |
972 | * | | 971 | * |
973 | * Input: | | 972 | * Input: |
974 | * tOp operator (if any) from special targets | | 973 | * tOp operator (if any) from special targets |
975 | * src name of the source to handle | | 974 | * src name of the source to handle |
976 | */ | | 975 | */ |
977 | static void | | 976 | static void |
978 | ParseDoSrc(GNodeType tOp, const char *src, ParseSpecial specType) | | 977 | ParseDoSrc(GNodeType tOp, const char *src, ParseSpecial specType) |
979 | { | | 978 | { |
980 | if (ParseDoSrcKeyword(src, specType)) | | 979 | if (ParseDoSrcKeyword(src, specType)) |
981 | return; | | 980 | return; |
982 | | | 981 | |
983 | if (specType == SP_MAIN) | | 982 | if (specType == SP_MAIN) |
984 | ParseDoSrcMain(src); | | 983 | ParseDoSrcMain(src); |
985 | else if (specType == SP_ORDER) | | 984 | else if (specType == SP_ORDER) |
986 | ParseDoSrcOrder(src); | | 985 | ParseDoSrcOrder(src); |
987 | else | | 986 | else |
988 | ParseDoSrcOther(src, tOp, specType); | | 987 | ParseDoSrcOther(src, tOp, specType); |
989 | } | | 988 | } |
990 | | | 989 | |
991 | /* If we have yet to decide on a main target to make, in the absence of any | | 990 | /* If we have yet to decide on a main target to make, in the absence of any |
992 | * user input, we want the first target on the first dependency line that is | | 991 | * user input, we want the first target on the first dependency line that is |
993 | * actually a real target (i.e. isn't a .USE or .EXEC rule) to be made. */ | | 992 | * actually a real target (i.e. isn't a .USE or .EXEC rule) to be made. */ |
994 | static void | | 993 | static void |
995 | FindMainTarget(void) | | 994 | FindMainTarget(void) |
996 | { | | 995 | { |
997 | GNodeListNode *ln; | | 996 | GNodeListNode *ln; |
998 | | | 997 | |
999 | if (mainNode != NULL) | | 998 | if (mainNode != NULL) |
1000 | return; | | 999 | return; |
1001 | | | 1000 | |
1002 | for (ln = targets->first; ln != NULL; ln = ln->next) { | | 1001 | for (ln = targets->first; ln != NULL; ln = ln->next) { |
1003 | GNode *gn = ln->datum; | | 1002 | GNode *gn = ln->datum; |
1004 | if (!(gn->type & OP_NOTARGET)) { | | 1003 | if (!(gn->type & OP_NOTARGET)) { |
1005 | mainNode = gn; | | 1004 | mainNode = gn; |
1006 | Targ_SetMain(gn); | | 1005 | Targ_SetMain(gn); |
1007 | return; | | 1006 | return; |
1008 | } | | 1007 | } |
1009 | } | | 1008 | } |
1010 | } | | 1009 | } |
1011 | | | 1010 | |
1012 | /* | | 1011 | /* |
1013 | * We got to the end of the line while we were still looking at targets. | | 1012 | * We got to the end of the line while we were still looking at targets. |
1014 | * | | 1013 | * |
1015 | * Ending a dependency line without an operator is a Bozo no-no. As a | | 1014 | * Ending a dependency line without an operator is a Bozo no-no. As a |
1016 | * heuristic, this is also often triggered by undetected conflicts from | | 1015 | * heuristic, this is also often triggered by undetected conflicts from |
1017 | * cvs/rcs merges. | | 1016 | * cvs/rcs merges. |
1018 | */ | | 1017 | */ |
1019 | static void | | 1018 | static void |
1020 | ParseErrorNoDependency(const char *lstart) | | 1019 | ParseErrorNoDependency(const char *lstart) |
1021 | { | | 1020 | { |
1022 | if ((strncmp(lstart, "<<<<<<", 6) == 0) || | | 1021 | if ((strncmp(lstart, "<<<<<<", 6) == 0) || |
1023 | (strncmp(lstart, "======", 6) == 0) || | | 1022 | (strncmp(lstart, "======", 6) == 0) || |
1024 | (strncmp(lstart, ">>>>>>", 6) == 0)) | | 1023 | (strncmp(lstart, ">>>>>>", 6) == 0)) |
1025 | Parse_Error(PARSE_FATAL, | | 1024 | Parse_Error(PARSE_FATAL, |
1026 | "Makefile appears to contain unresolved cvs/rcs/??? merge conflicts"); | | 1025 | "Makefile appears to contain unresolved cvs/rcs/??? merge conflicts"); |
1027 | else if (lstart[0] == '.') { | | 1026 | else if (lstart[0] == '.') { |
1028 | const char *dirstart = lstart + 1; | | 1027 | const char *dirstart = lstart + 1; |
1029 | const char *dirend; | | 1028 | const char *dirend; |
1030 | cpp_skip_whitespace(&dirstart); | | 1029 | cpp_skip_whitespace(&dirstart); |
1031 | dirend = dirstart; | | 1030 | dirend = dirstart; |
1032 | while (ch_isalnum(*dirend) || *dirend == '-') | | 1031 | while (ch_isalnum(*dirend) || *dirend == '-') |
1033 | dirend++; | | 1032 | dirend++; |
1034 | Parse_Error(PARSE_FATAL, "Unknown directive \"%.*s\"", | | 1033 | Parse_Error(PARSE_FATAL, "Unknown directive \"%.*s\"", |
1035 | (int)(dirend - dirstart), dirstart); | | 1034 | (int)(dirend - dirstart), dirstart); |
1036 | } else | | 1035 | } else |
1037 | Parse_Error(PARSE_FATAL, "Need an operator"); | | 1036 | Parse_Error(PARSE_FATAL, "Need an operator"); |
1038 | } | | 1037 | } |
1039 | | | 1038 | |
1040 | static void | | 1039 | static void |
1041 | ParseDependencyTargetWord(/*const*/ char **pp, const char *lstart) | | 1040 | ParseDependencyTargetWord(/*const*/ char **pp, const char *lstart) |
1042 | { | | 1041 | { |
1043 | /*const*/ char *cp = *pp; | | 1042 | /*const*/ char *cp = *pp; |
1044 | | | 1043 | |
1045 | while (*cp != '\0') { | | 1044 | while (*cp != '\0') { |
1046 | if ((ch_isspace(*cp) || *cp == '!' || *cp == ':' || *cp == '(') && | | 1045 | if ((ch_isspace(*cp) || *cp == '!' || *cp == ':' || *cp == '(') && |
1047 | !ParseIsEscaped(lstart, cp)) | | 1046 | !ParseIsEscaped(lstart, cp)) |
1048 | break; | | 1047 | break; |
1049 | | | 1048 | |
1050 | if (*cp == '$') { | | 1049 | if (*cp == '$') { |
1051 | /* | | 1050 | /* |
1052 | * Must be a dynamic source (would have been expanded | | 1051 | * Must be a dynamic source (would have been expanded |
1053 | * otherwise), so call the Var module to parse the puppy | | 1052 | * otherwise), so call the Var module to parse the puppy |
1054 | * so we can safely advance beyond it...There should be | | 1053 | * so we can safely advance beyond it...There should be |
1055 | * no errors in this, as they would have been discovered | | 1054 | * no errors in this, as they would have been discovered |
1056 | * in the initial Var_Subst and we wouldn't be here. | | 1055 | * in the initial Var_Subst and we wouldn't be here. |
1057 | */ | | 1056 | */ |
1058 | const char *nested_p = cp; | | 1057 | const char *nested_p = cp; |
1059 | const char *nested_val; | | 1058 | const char *nested_val; |
1060 | void *freeIt; | | 1059 | void *freeIt; |
1061 | | | 1060 | |
1062 | (void)Var_Parse(&nested_p, VAR_CMD, VARE_UNDEFERR|VARE_WANTRES, | | 1061 | (void)Var_Parse(&nested_p, VAR_CMD, VARE_UNDEFERR|VARE_WANTRES, |
1063 | &nested_val, &freeIt); | | 1062 | &nested_val, &freeIt); |
1064 | /* TODO: handle errors */ | | 1063 | /* TODO: handle errors */ |
1065 | free(freeIt); | | 1064 | free(freeIt); |
1066 | cp += nested_p - cp; | | 1065 | cp += nested_p - cp; |
1067 | } else | | 1066 | } else |
1068 | cp++; | | 1067 | cp++; |
1069 | } | | 1068 | } |
1070 | | | 1069 | |
1071 | *pp = cp; | | 1070 | *pp = cp; |
1072 | } | | 1071 | } |
1073 | | | 1072 | |
1074 | /* | | 1073 | /* |
1075 | * Certain special targets have special semantics: | | 1074 | * Certain special targets have special semantics: |
1076 | * .PATH Have to set the dirSearchPath | | 1075 | * .PATH Have to set the dirSearchPath |
1077 | * variable too | | 1076 | * variable too |
1078 | * .MAIN Its sources are only used if | | 1077 | * .MAIN Its sources are only used if |
1079 | * nothing has been specified to | | 1078 | * nothing has been specified to |
1080 | * create. | | 1079 | * create. |
1081 | * .DEFAULT Need to create a node to hang | | 1080 | * .DEFAULT Need to create a node to hang |
1082 | * commands on, but we don't want | | 1081 | * commands on, but we don't want |
1083 | * it in the graph, nor do we want | | 1082 | * it in the graph, nor do we want |
1084 | * it to be the Main Target, so we | | 1083 | * it to be the Main Target, so we |
1085 | * create it, set OP_NOTMAIN and | | 1084 | * create it, set OP_NOTMAIN and |
1086 | * add it to the list, setting | | 1085 | * add it to the list, setting |
1087 | * DEFAULT to the new node for | | 1086 | * DEFAULT to the new node for |
1088 | * later use. We claim the node is | | 1087 | * later use. We claim the node is |
1089 | * A transformation rule to make | | 1088 | * A transformation rule to make |
1090 | * life easier later, when we'll | | 1089 | * life easier later, when we'll |
1091 | * use Make_HandleUse to actually | | 1090 | * use Make_HandleUse to actually |
1092 | * apply the .DEFAULT commands. | | 1091 | * apply the .DEFAULT commands. |
1093 | * .PHONY The list of targets | | 1092 | * .PHONY The list of targets |
1094 | * .NOPATH Don't search for file in the path | | 1093 | * .NOPATH Don't search for file in the path |
1095 | * .STALE | | 1094 | * .STALE |
1096 | * .BEGIN | | 1095 | * .BEGIN |
1097 | * .END | | 1096 | * .END |
1098 | * .ERROR | | 1097 | * .ERROR |
1099 | * .DELETE_ON_ERROR | | 1098 | * .DELETE_ON_ERROR |
1100 | * .INTERRUPT Are not to be considered the | | 1099 | * .INTERRUPT Are not to be considered the |
1101 | * main target. | | 1100 | * main target. |
1102 | * .NOTPARALLEL Make only one target at a time. | | 1101 | * .NOTPARALLEL Make only one target at a time. |
1103 | * .SINGLESHELL Create a shell for each command. | | 1102 | * .SINGLESHELL Create a shell for each command. |
1104 | * .ORDER Must set initial predecessor to NULL | | 1103 | * .ORDER Must set initial predecessor to NULL |
1105 | */ | | 1104 | */ |
1106 | static void | | 1105 | static void |
1107 | ParseDoDependencyTargetSpecial(ParseSpecial *inout_specType, | | 1106 | ParseDoDependencyTargetSpecial(ParseSpecial *inout_specType, |
1108 | const char *line, | | 1107 | const char *line, |
1109 | SearchPathList **inout_paths) | | 1108 | SearchPathList **inout_paths) |
1110 | { | | 1109 | { |
1111 | switch (*inout_specType) { | | 1110 | switch (*inout_specType) { |
1112 | case SP_PATH: | | 1111 | case SP_PATH: |
1113 | if (*inout_paths == NULL) { | | 1112 | if (*inout_paths == NULL) { |
1114 | *inout_paths = Lst_New(); | | 1113 | *inout_paths = Lst_New(); |
1115 | } | | 1114 | } |
1116 | Lst_Append(*inout_paths, dirSearchPath); | | 1115 | Lst_Append(*inout_paths, dirSearchPath); |
1117 | break; | | 1116 | break; |
1118 | case SP_MAIN: | | 1117 | case SP_MAIN: |
1119 | if (!Lst_IsEmpty(opts.create)) { | | 1118 | if (!Lst_IsEmpty(opts.create)) { |
1120 | *inout_specType = SP_NOT; | | 1119 | *inout_specType = SP_NOT; |
1121 | } | | 1120 | } |
1122 | break; | | 1121 | break; |
1123 | case SP_BEGIN: | | 1122 | case SP_BEGIN: |
1124 | case SP_END: | | 1123 | case SP_END: |
1125 | case SP_STALE: | | 1124 | case SP_STALE: |
1126 | case SP_ERROR: | | 1125 | case SP_ERROR: |
1127 | case SP_INTERRUPT: { | | 1126 | case SP_INTERRUPT: { |
1128 | GNode *gn = Targ_GetNode(line); | | 1127 | GNode *gn = Targ_GetNode(line); |
1129 | if (doing_depend) | | 1128 | if (doing_depend) |
1130 | ParseMark(gn); | | 1129 | ParseMark(gn); |
1131 | gn->type |= OP_NOTMAIN|OP_SPECIAL; | | 1130 | gn->type |= OP_NOTMAIN|OP_SPECIAL; |
1132 | Lst_Append(targets, gn); | | 1131 | Lst_Append(targets, gn); |
1133 | break; | | 1132 | break; |
1134 | } | | 1133 | } |
1135 | case SP_DEFAULT: { | | 1134 | case SP_DEFAULT: { |
1136 | GNode *gn = Targ_NewGN(".DEFAULT"); | | 1135 | GNode *gn = Targ_NewGN(".DEFAULT"); |
1137 | gn->type |= OP_NOTMAIN|OP_TRANSFORM; | | 1136 | gn->type |= OP_NOTMAIN|OP_TRANSFORM; |
1138 | Lst_Append(targets, gn); | | 1137 | Lst_Append(targets, gn); |
1139 | DEFAULT = gn; | | 1138 | DEFAULT = gn; |
1140 | break; | | 1139 | break; |
1141 | } | | 1140 | } |
1142 | case SP_DELETE_ON_ERROR: | | 1141 | case SP_DELETE_ON_ERROR: |
1143 | deleteOnError = TRUE; | | 1142 | deleteOnError = TRUE; |
1144 | break; | | 1143 | break; |
1145 | case SP_NOTPARALLEL: | | 1144 | case SP_NOTPARALLEL: |
1146 | opts.maxJobs = 1; | | 1145 | opts.maxJobs = 1; |
1147 | break; | | 1146 | break; |
1148 | case SP_SINGLESHELL: | | 1147 | case SP_SINGLESHELL: |
1149 | opts.compatMake = TRUE; | | 1148 | opts.compatMake = TRUE; |
1150 | break; | | 1149 | break; |
1151 | case SP_ORDER: | | 1150 | case SP_ORDER: |
1152 | predecessor = NULL; | | 1151 | predecessor = NULL; |
1153 | break; | | 1152 | break; |
1154 | default: | | 1153 | default: |
1155 | break; | | 1154 | break; |
1156 | } | | 1155 | } |
1157 | } | | 1156 | } |
1158 | | | 1157 | |
1159 | /* | | 1158 | /* |
1160 | * .PATH<suffix> has to be handled specially. | | 1159 | * .PATH<suffix> has to be handled specially. |
1161 | * Call on the suffix module to give us a path to modify. | | 1160 | * Call on the suffix module to give us a path to modify. |