| @@ -1,2291 +1,2300 @@ | | | @@ -1,2291 +1,2300 @@ |
1 | /* $NetBSD: parse.c,v 1.239 2020/07/28 16:42:22 rillig Exp $ */ | | 1 | /* $NetBSD: parse.c,v 1.240 2020/07/28 18:15: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 | #ifndef MAKE_NATIVE | | 71 | #ifndef MAKE_NATIVE |
72 | static char rcsid[] = "$NetBSD: parse.c,v 1.239 2020/07/28 16:42:22 rillig Exp $"; | | 72 | static char rcsid[] = "$NetBSD: parse.c,v 1.240 2020/07/28 18:15:11 rillig Exp $"; |
73 | #else | | 73 | #else |
74 | #include <sys/cdefs.h> | | 74 | #include <sys/cdefs.h> |
75 | #ifndef lint | | 75 | #ifndef lint |
76 | #if 0 | | 76 | #if 0 |
77 | static char sccsid[] = "@(#)parse.c 8.3 (Berkeley) 3/19/94"; | | 77 | static char sccsid[] = "@(#)parse.c 8.3 (Berkeley) 3/19/94"; |
78 | #else | | 78 | #else |
79 | __RCSID("$NetBSD: parse.c,v 1.239 2020/07/28 16:42:22 rillig Exp $"); | | 79 | __RCSID("$NetBSD: parse.c,v 1.240 2020/07/28 18:15:11 rillig Exp $"); |
80 | #endif | | 80 | #endif |
81 | #endif /* not lint */ | | 81 | #endif /* not lint */ |
82 | #endif | | 82 | #endif |
83 | | | 83 | |
84 | /*- | | 84 | /*- |
85 | * parse.c -- | | 85 | * parse.c -- |
86 | * Functions to parse a makefile. | | 86 | * Functions to parse a makefile. |
87 | * | | 87 | * |
88 | * One function, Parse_Init, must be called before any functions | | 88 | * One function, Parse_Init, must be called before any functions |
89 | * in this module are used. After that, the function Parse_File is the | | 89 | * in this module are used. After that, the function Parse_File is the |
90 | * main entry point and controls most of the other functions in this | | 90 | * main entry point and controls most of the other functions in this |
91 | * module. | | 91 | * module. |
92 | * | | 92 | * |
93 | * Most important structures are kept in Lsts. Directories for | | 93 | * Most important structures are kept in Lsts. Directories for |
94 | * the .include "..." function are kept in the 'parseIncPath' Lst, while | | 94 | * the .include "..." function are kept in the 'parseIncPath' Lst, while |
95 | * those for the .include <...> are kept in the 'sysIncPath' Lst. The | | 95 | * those for the .include <...> are kept in the 'sysIncPath' Lst. The |
96 | * targets currently being defined are kept in the 'targets' Lst. | | 96 | * targets currently being defined are kept in the 'targets' Lst. |
97 | * | | 97 | * |
98 | * The variables 'fname' and 'lineno' are used to track the name | | 98 | * The variables 'fname' and 'lineno' are used to track the name |
99 | * of the current file and the line number in that file so that error | | 99 | * of the current file and the line number in that file so that error |
100 | * messages can be more meaningful. | | 100 | * messages can be more meaningful. |
101 | * | | 101 | * |
102 | * Interface: | | 102 | * Interface: |
103 | * Parse_Init Initialization function which must be | | 103 | * Parse_Init Initialization function which must be |
104 | * called before anything else in this module | | 104 | * called before anything else in this module |
105 | * is used. | | 105 | * is used. |
106 | * | | 106 | * |
107 | * Parse_End Cleanup the module | | 107 | * Parse_End Cleanup the module |
108 | * | | 108 | * |
109 | * Parse_File Function used to parse a makefile. It must | | 109 | * Parse_File Function used to parse a makefile. It must |
110 | * be given the name of the file, which should | | 110 | * be given the name of the file, which should |
111 | * already have been opened, and a function | | 111 | * already have been opened, and a function |
112 | * to call to read a character from the file. | | 112 | * to call to read a character from the file. |
113 | * | | 113 | * |
114 | * Parse_IsVar Returns TRUE if the given line is a | | 114 | * Parse_IsVar Returns TRUE if the given line is a |
115 | * variable assignment. Used by MainParseArgs | | 115 | * variable assignment. Used by MainParseArgs |
116 | * to determine if an argument is a target | | 116 | * to determine if an argument is a target |
117 | * or a variable assignment. Used internally | | 117 | * or a variable assignment. Used internally |
118 | * for pretty much the same thing... | | 118 | * for pretty much the same thing... |
119 | * | | 119 | * |
120 | * Parse_Error Function called when an error occurs in | | 120 | * Parse_Error Function called when an error occurs in |
121 | * parsing. Used by the variable and | | 121 | * parsing. Used by the variable and |
122 | * conditional modules. | | 122 | * conditional modules. |
123 | * Parse_MainName Returns a Lst of the main target to create. | | 123 | * Parse_MainName Returns a Lst of the main target to create. |
124 | */ | | 124 | */ |
125 | | | 125 | |
126 | #include <sys/types.h> | | 126 | #include <sys/types.h> |
127 | #include <sys/mman.h> | | 127 | #include <sys/mman.h> |
128 | #include <sys/stat.h> | | 128 | #include <sys/stat.h> |
129 | #include <assert.h> | | 129 | #include <assert.h> |
130 | #include <ctype.h> | | 130 | #include <ctype.h> |
131 | #include <errno.h> | | 131 | #include <errno.h> |
132 | #include <stdarg.h> | | 132 | #include <stdarg.h> |
133 | #include <stdio.h> | | 133 | #include <stdio.h> |
134 | #include <stdint.h> | | 134 | #include <stdint.h> |
135 | | | 135 | |
136 | #ifndef MAP_FILE | | 136 | #ifndef MAP_FILE |
137 | #define MAP_FILE 0 | | 137 | #define MAP_FILE 0 |
138 | #endif | | 138 | #endif |
139 | #ifndef MAP_COPY | | 139 | #ifndef MAP_COPY |
140 | #define MAP_COPY MAP_PRIVATE | | 140 | #define MAP_COPY MAP_PRIVATE |
141 | #endif | | 141 | #endif |
142 | | | 142 | |
143 | #include "make.h" | | 143 | #include "make.h" |
144 | #include "hash.h" | | 144 | #include "hash.h" |
145 | #include "dir.h" | | 145 | #include "dir.h" |
146 | #include "job.h" | | 146 | #include "job.h" |
147 | #include "buf.h" | | 147 | #include "buf.h" |
148 | #include "pathnames.h" | | 148 | #include "pathnames.h" |
149 | | | 149 | |
150 | //////////////////////////////////////////////////////////// | | 150 | //////////////////////////////////////////////////////////// |
151 | // types and constants | | 151 | // types and constants |
152 | | | 152 | |
153 | /* | | 153 | /* |
154 | * Structure for a file being read ("included file") | | 154 | * Structure for a file being read ("included file") |
155 | */ | | 155 | */ |
156 | typedef struct IFile { | | 156 | typedef struct IFile { |
157 | char *fname; /* name of file */ | | 157 | char *fname; /* name of file */ |
158 | int lineno; /* current line number in file */ | | 158 | int lineno; /* current line number in file */ |
159 | int first_lineno; /* line number of start of text */ | | 159 | int first_lineno; /* line number of start of text */ |
160 | int cond_depth; /* 'if' nesting when file opened */ | | 160 | int cond_depth; /* 'if' nesting when file opened */ |
161 | Boolean depending; /* state of doing_depend on EOF */ | | 161 | Boolean depending; /* state of doing_depend on EOF */ |
162 | char *P_str; /* point to base of string buffer */ | | 162 | char *P_str; /* point to base of string buffer */ |
163 | char *P_ptr; /* point to next char of string buffer */ | | 163 | char *P_ptr; /* point to next char of string buffer */ |
164 | char *P_end; /* point to the end of string buffer */ | | 164 | char *P_end; /* point to the end of string buffer */ |
165 | char *(*nextbuf)(void *, size_t *); /* Function to get more data */ | | 165 | char *(*nextbuf)(void *, size_t *); /* Function to get more data */ |
166 | void *nextbuf_arg; /* Opaque arg for nextbuf() */ | | 166 | void *nextbuf_arg; /* Opaque arg for nextbuf() */ |
167 | struct loadedfile *lf; /* loadedfile object, if any */ | | 167 | struct loadedfile *lf; /* loadedfile object, if any */ |
168 | } IFile; | | 168 | } IFile; |
169 | | | 169 | |
170 | | | 170 | |
171 | /* | | 171 | /* |
172 | * These values are returned by ParseEOF to tell Parse_File whether to | | 172 | * These values are returned by ParseEOF to tell Parse_File whether to |
173 | * CONTINUE parsing, i.e. it had only reached the end of an include file, | | 173 | * CONTINUE parsing, i.e. it had only reached the end of an include file, |
174 | * or if it's DONE. | | 174 | * or if it's DONE. |
175 | */ | | 175 | */ |
176 | #define CONTINUE 1 | | 176 | #define CONTINUE 1 |
177 | #define DONE 0 | | 177 | #define DONE 0 |
178 | | | 178 | |
179 | /* | | 179 | /* |
180 | * Tokens for target attributes | | 180 | * Tokens for target attributes |
181 | */ | | 181 | */ |
182 | typedef enum { | | 182 | typedef enum { |
183 | Begin, /* .BEGIN */ | | 183 | Begin, /* .BEGIN */ |
184 | Default, /* .DEFAULT */ | | 184 | Default, /* .DEFAULT */ |
185 | DeleteOnError, /* .DELETE_ON_ERROR */ | | 185 | DeleteOnError, /* .DELETE_ON_ERROR */ |
186 | End, /* .END */ | | 186 | End, /* .END */ |
187 | dotError, /* .ERROR */ | | 187 | dotError, /* .ERROR */ |
188 | Ignore, /* .IGNORE */ | | 188 | Ignore, /* .IGNORE */ |
189 | Includes, /* .INCLUDES */ | | 189 | Includes, /* .INCLUDES */ |
190 | Interrupt, /* .INTERRUPT */ | | 190 | Interrupt, /* .INTERRUPT */ |
191 | Libs, /* .LIBS */ | | 191 | Libs, /* .LIBS */ |
192 | Meta, /* .META */ | | 192 | Meta, /* .META */ |
193 | MFlags, /* .MFLAGS or .MAKEFLAGS */ | | 193 | MFlags, /* .MFLAGS or .MAKEFLAGS */ |
194 | Main, /* .MAIN and we don't have anything user-specified to | | 194 | Main, /* .MAIN and we don't have anything user-specified to |
195 | * make */ | | 195 | * make */ |
196 | NoExport, /* .NOEXPORT */ | | 196 | NoExport, /* .NOEXPORT */ |
197 | NoMeta, /* .NOMETA */ | | 197 | NoMeta, /* .NOMETA */ |
198 | NoMetaCmp, /* .NOMETA_CMP */ | | 198 | NoMetaCmp, /* .NOMETA_CMP */ |
199 | NoPath, /* .NOPATH */ | | 199 | NoPath, /* .NOPATH */ |
200 | Not, /* Not special */ | | 200 | Not, /* Not special */ |
201 | NotParallel, /* .NOTPARALLEL */ | | 201 | NotParallel, /* .NOTPARALLEL */ |
202 | Null, /* .NULL */ | | 202 | Null, /* .NULL */ |
203 | ExObjdir, /* .OBJDIR */ | | 203 | ExObjdir, /* .OBJDIR */ |
204 | Order, /* .ORDER */ | | 204 | Order, /* .ORDER */ |
205 | Parallel, /* .PARALLEL */ | | 205 | Parallel, /* .PARALLEL */ |
206 | ExPath, /* .PATH */ | | 206 | ExPath, /* .PATH */ |
207 | Phony, /* .PHONY */ | | 207 | Phony, /* .PHONY */ |
208 | #ifdef POSIX | | 208 | #ifdef POSIX |
209 | Posix, /* .POSIX */ | | 209 | Posix, /* .POSIX */ |
210 | #endif | | 210 | #endif |
211 | Precious, /* .PRECIOUS */ | | 211 | Precious, /* .PRECIOUS */ |
212 | ExShell, /* .SHELL */ | | 212 | ExShell, /* .SHELL */ |
213 | Silent, /* .SILENT */ | | 213 | Silent, /* .SILENT */ |
214 | SingleShell, /* .SINGLESHELL */ | | 214 | SingleShell, /* .SINGLESHELL */ |
215 | Stale, /* .STALE */ | | 215 | Stale, /* .STALE */ |
216 | Suffixes, /* .SUFFIXES */ | | 216 | Suffixes, /* .SUFFIXES */ |
217 | Wait, /* .WAIT */ | | 217 | Wait, /* .WAIT */ |
218 | Attribute /* Generic attribute */ | | 218 | Attribute /* Generic attribute */ |
219 | } ParseSpecial; | | 219 | } ParseSpecial; |
220 | | | 220 | |
221 | /* | | 221 | /* |
222 | * Other tokens | | 222 | * Other tokens |
223 | */ | | 223 | */ |
224 | #define LPAREN '(' | | 224 | #define LPAREN '(' |
225 | #define RPAREN ')' | | 225 | #define RPAREN ')' |
226 | | | 226 | |
227 | | | 227 | |
228 | //////////////////////////////////////////////////////////// | | 228 | //////////////////////////////////////////////////////////// |
229 | // result data | | 229 | // result data |
230 | | | 230 | |
231 | /* | | 231 | /* |
232 | * The main target to create. This is the first target on the first | | 232 | * The main target to create. This is the first target on the first |
233 | * dependency line in the first makefile. | | 233 | * dependency line in the first makefile. |
234 | */ | | 234 | */ |
235 | static GNode *mainNode; | | 235 | static GNode *mainNode; |
236 | | | 236 | |
237 | //////////////////////////////////////////////////////////// | | 237 | //////////////////////////////////////////////////////////// |
238 | // eval state | | 238 | // eval state |
239 | | | 239 | |
240 | /* targets we're working on */ | | 240 | /* targets we're working on */ |
241 | static Lst targets; | | 241 | static Lst targets; |
242 | | | 242 | |
243 | #ifdef CLEANUP | | 243 | #ifdef CLEANUP |
244 | /* command lines for targets */ | | 244 | /* command lines for targets */ |
245 | static Lst targCmds; | | 245 | static Lst targCmds; |
246 | #endif | | 246 | #endif |
247 | | | 247 | |
248 | /* | | 248 | /* |
249 | * specType contains the SPECial TYPE of the current target. It is | | 249 | * specType contains the SPECial TYPE of the current target. It is |
250 | * Not if the target is unspecial. If it *is* special, however, the children | | 250 | * Not if the target is unspecial. If it *is* special, however, the children |
251 | * are linked as children of the parent but not vice versa. This variable is | | 251 | * are linked as children of the parent but not vice versa. This variable is |
252 | * set in ParseDoDependency | | 252 | * set in ParseDoDependency |
253 | */ | | 253 | */ |
254 | static ParseSpecial specType; | | 254 | static ParseSpecial specType; |
255 | | | 255 | |
256 | /* | | 256 | /* |
257 | * Predecessor node for handling .ORDER. Initialized to NULL when .ORDER | | 257 | * Predecessor node for handling .ORDER. Initialized to NULL when .ORDER |
258 | * seen, then set to each successive source on the line. | | 258 | * seen, then set to each successive source on the line. |
259 | */ | | 259 | */ |
260 | static GNode *predecessor; | | 260 | static GNode *predecessor; |
261 | | | 261 | |
262 | //////////////////////////////////////////////////////////// | | 262 | //////////////////////////////////////////////////////////// |
263 | // parser state | | 263 | // parser state |
264 | | | 264 | |
265 | /* true if currently in a dependency line or its commands */ | | 265 | /* true if currently in a dependency line or its commands */ |
266 | static Boolean inLine; | | 266 | static Boolean inLine; |
267 | | | 267 | |
268 | /* number of fatal errors */ | | 268 | /* number of fatal errors */ |
269 | static int fatals = 0; | | 269 | static int fatals = 0; |
270 | | | 270 | |
271 | /* | | 271 | /* |
272 | * Variables for doing includes | | 272 | * Variables for doing includes |
273 | */ | | 273 | */ |
274 | | | 274 | |
275 | /* current file being read */ | | 275 | /* current file being read */ |
276 | static IFile *curFile; | | 276 | static IFile *curFile; |
277 | | | 277 | |
278 | /* stack of IFiles generated by .includes */ | | 278 | /* stack of IFiles generated by .includes */ |
279 | static Lst includes; | | 279 | static Lst includes; |
280 | | | 280 | |
281 | /* include paths (lists of directories) */ | | 281 | /* include paths (lists of directories) */ |
282 | Lst parseIncPath; /* dirs for "..." includes */ | | 282 | Lst parseIncPath; /* dirs for "..." includes */ |
283 | Lst sysIncPath; /* dirs for <...> includes */ | | 283 | Lst sysIncPath; /* dirs for <...> includes */ |
284 | Lst defIncPath; /* default for sysIncPath */ | | 284 | Lst defIncPath; /* default for sysIncPath */ |
285 | | | 285 | |
286 | //////////////////////////////////////////////////////////// | | 286 | //////////////////////////////////////////////////////////// |
287 | // parser tables | | 287 | // parser tables |
288 | | | 288 | |
289 | /* | | 289 | /* |
290 | * The parseKeywords table is searched using binary search when deciding | | 290 | * The parseKeywords table is searched using binary search when deciding |
291 | * if a target or source is special. The 'spec' field is the ParseSpecial | | 291 | * if a target or source is special. The 'spec' field is the ParseSpecial |
292 | * type of the keyword ("Not" if the keyword isn't special as a target) while | | 292 | * type of the keyword ("Not" if the keyword isn't special as a target) while |
293 | * the 'op' field is the operator to apply to the list of targets if the | | 293 | * the 'op' field is the operator to apply to the list of targets if the |
294 | * keyword is used as a source ("0" if the keyword isn't special as a source) | | 294 | * keyword is used as a source ("0" if the keyword isn't special as a source) |
295 | */ | | 295 | */ |
296 | static const struct { | | 296 | static const struct { |
297 | const char *name; /* Name of keyword */ | | 297 | const char *name; /* Name of keyword */ |
298 | ParseSpecial spec; /* Type when used as a target */ | | 298 | ParseSpecial spec; /* Type when used as a target */ |
299 | int op; /* Operator when used as a source */ | | 299 | int op; /* Operator when used as a source */ |
300 | } parseKeywords[] = { | | 300 | } parseKeywords[] = { |
301 | { ".BEGIN", Begin, 0 }, | | 301 | { ".BEGIN", Begin, 0 }, |
302 | { ".DEFAULT", Default, 0 }, | | 302 | { ".DEFAULT", Default, 0 }, |
303 | { ".DELETE_ON_ERROR", DeleteOnError, 0 }, | | 303 | { ".DELETE_ON_ERROR", DeleteOnError, 0 }, |
304 | { ".END", End, 0 }, | | 304 | { ".END", End, 0 }, |
305 | { ".ERROR", dotError, 0 }, | | 305 | { ".ERROR", dotError, 0 }, |
306 | { ".EXEC", Attribute, OP_EXEC }, | | 306 | { ".EXEC", Attribute, OP_EXEC }, |
307 | { ".IGNORE", Ignore, OP_IGNORE }, | | 307 | { ".IGNORE", Ignore, OP_IGNORE }, |
308 | { ".INCLUDES", Includes, 0 }, | | 308 | { ".INCLUDES", Includes, 0 }, |
309 | { ".INTERRUPT", Interrupt, 0 }, | | 309 | { ".INTERRUPT", Interrupt, 0 }, |
310 | { ".INVISIBLE", Attribute, OP_INVISIBLE }, | | 310 | { ".INVISIBLE", Attribute, OP_INVISIBLE }, |
311 | { ".JOIN", Attribute, OP_JOIN }, | | 311 | { ".JOIN", Attribute, OP_JOIN }, |
312 | { ".LIBS", Libs, 0 }, | | 312 | { ".LIBS", Libs, 0 }, |
313 | { ".MADE", Attribute, OP_MADE }, | | 313 | { ".MADE", Attribute, OP_MADE }, |
314 | { ".MAIN", Main, 0 }, | | 314 | { ".MAIN", Main, 0 }, |
315 | { ".MAKE", Attribute, OP_MAKE }, | | 315 | { ".MAKE", Attribute, OP_MAKE }, |
316 | { ".MAKEFLAGS", MFlags, 0 }, | | 316 | { ".MAKEFLAGS", MFlags, 0 }, |
317 | { ".META", Meta, OP_META }, | | 317 | { ".META", Meta, OP_META }, |
318 | { ".MFLAGS", MFlags, 0 }, | | 318 | { ".MFLAGS", MFlags, 0 }, |
319 | { ".NOMETA", NoMeta, OP_NOMETA }, | | 319 | { ".NOMETA", NoMeta, OP_NOMETA }, |
320 | { ".NOMETA_CMP", NoMetaCmp, OP_NOMETA_CMP }, | | 320 | { ".NOMETA_CMP", NoMetaCmp, OP_NOMETA_CMP }, |
321 | { ".NOPATH", NoPath, OP_NOPATH }, | | 321 | { ".NOPATH", NoPath, OP_NOPATH }, |
322 | { ".NOTMAIN", Attribute, OP_NOTMAIN }, | | 322 | { ".NOTMAIN", Attribute, OP_NOTMAIN }, |
323 | { ".NOTPARALLEL", NotParallel, 0 }, | | 323 | { ".NOTPARALLEL", NotParallel, 0 }, |
324 | { ".NO_PARALLEL", NotParallel, 0 }, | | 324 | { ".NO_PARALLEL", NotParallel, 0 }, |
325 | { ".NULL", Null, 0 }, | | 325 | { ".NULL", Null, 0 }, |
326 | { ".OBJDIR", ExObjdir, 0 }, | | 326 | { ".OBJDIR", ExObjdir, 0 }, |
327 | { ".OPTIONAL", Attribute, OP_OPTIONAL }, | | 327 | { ".OPTIONAL", Attribute, OP_OPTIONAL }, |
328 | { ".ORDER", Order, 0 }, | | 328 | { ".ORDER", Order, 0 }, |
329 | { ".PARALLEL", Parallel, 0 }, | | 329 | { ".PARALLEL", Parallel, 0 }, |
330 | { ".PATH", ExPath, 0 }, | | 330 | { ".PATH", ExPath, 0 }, |
331 | { ".PHONY", Phony, OP_PHONY }, | | 331 | { ".PHONY", Phony, OP_PHONY }, |
332 | #ifdef POSIX | | 332 | #ifdef POSIX |
333 | { ".POSIX", Posix, 0 }, | | 333 | { ".POSIX", Posix, 0 }, |
334 | #endif | | 334 | #endif |
335 | { ".PRECIOUS", Precious, OP_PRECIOUS }, | | 335 | { ".PRECIOUS", Precious, OP_PRECIOUS }, |
336 | { ".RECURSIVE", Attribute, OP_MAKE }, | | 336 | { ".RECURSIVE", Attribute, OP_MAKE }, |
337 | { ".SHELL", ExShell, 0 }, | | 337 | { ".SHELL", ExShell, 0 }, |
338 | { ".SILENT", Silent, OP_SILENT }, | | 338 | { ".SILENT", Silent, OP_SILENT }, |
339 | { ".SINGLESHELL", SingleShell, 0 }, | | 339 | { ".SINGLESHELL", SingleShell, 0 }, |
340 | { ".STALE", Stale, 0 }, | | 340 | { ".STALE", Stale, 0 }, |
341 | { ".SUFFIXES", Suffixes, 0 }, | | 341 | { ".SUFFIXES", Suffixes, 0 }, |
342 | { ".USE", Attribute, OP_USE }, | | 342 | { ".USE", Attribute, OP_USE }, |
343 | { ".USEBEFORE", Attribute, OP_USEBEFORE }, | | 343 | { ".USEBEFORE", Attribute, OP_USEBEFORE }, |
344 | { ".WAIT", Wait, 0 }, | | 344 | { ".WAIT", Wait, 0 }, |
345 | }; | | 345 | }; |
346 | | | 346 | |
347 | //////////////////////////////////////////////////////////// | | 347 | //////////////////////////////////////////////////////////// |
348 | // local functions | | 348 | // local functions |
349 | | | 349 | |
350 | static int ParseIsEscaped(const char *, const char *); | | 350 | static int ParseIsEscaped(const char *, const char *); |
351 | static void ParseErrorInternal(const char *, size_t, int, const char *, ...) | | 351 | static void ParseErrorInternal(const char *, size_t, int, const char *, ...) |
352 | MAKE_ATTR_PRINTFLIKE(4,5); | | 352 | MAKE_ATTR_PRINTFLIKE(4,5); |
353 | static void ParseVErrorInternal(FILE *, const char *, size_t, int, const char *, va_list) | | 353 | static void ParseVErrorInternal(FILE *, const char *, size_t, int, const char *, va_list) |
354 | MAKE_ATTR_PRINTFLIKE(5, 0); | | 354 | MAKE_ATTR_PRINTFLIKE(5, 0); |
355 | static int ParseFindKeyword(const char *); | | 355 | static int ParseFindKeyword(const char *); |
356 | static int ParseLinkSrc(void *, void *); | | 356 | static int ParseLinkSrc(void *, void *); |
357 | static int ParseDoOp(void *, void *); | | 357 | static int ParseDoOp(void *, void *); |
358 | static void ParseDoSrc(int, const char *); | | 358 | static void ParseDoSrc(int, const char *); |
359 | static int ParseFindMain(void *, void *); | | 359 | static int ParseFindMain(void *, void *); |
360 | static int ParseAddDir(void *, void *); | | 360 | static int ParseAddDir(void *, void *); |
361 | static int ParseClearPath(void *, void *); | | 361 | static int ParseClearPath(void *, void *); |
362 | static void ParseDoDependency(char *); | | 362 | static void ParseDoDependency(char *); |
363 | static int ParseAddCmd(void *, void *); | | 363 | static int ParseAddCmd(void *, void *); |
364 | static void ParseHasCommands(void *); | | 364 | static void ParseHasCommands(void *); |
365 | static void ParseDoInclude(char *); | | 365 | static void ParseDoInclude(char *); |
366 | static void ParseSetParseFile(const char *); | | 366 | static void ParseSetParseFile(const char *); |
367 | static void ParseSetIncludedFile(void); | | 367 | static void ParseSetIncludedFile(void); |
368 | #ifdef GMAKEEXPORT | | 368 | #ifdef GMAKEEXPORT |
369 | static void ParseGmakeExport(char *); | | 369 | static void ParseGmakeExport(char *); |
370 | #endif | | 370 | #endif |
371 | static int ParseEOF(void); | | 371 | static int ParseEOF(void); |
372 | static char *ParseReadLine(void); | | 372 | static char *ParseReadLine(void); |
373 | static void ParseFinishLine(void); | | 373 | static void ParseFinishLine(void); |
374 | static void ParseMark(GNode *); | | 374 | static void ParseMark(GNode *); |
375 | | | 375 | |
376 | //////////////////////////////////////////////////////////// | | 376 | //////////////////////////////////////////////////////////// |
377 | // file loader | | 377 | // file loader |
378 | | | 378 | |
379 | struct loadedfile { | | 379 | struct loadedfile { |
380 | const char *path; /* name, for error reports */ | | 380 | const char *path; /* name, for error reports */ |
381 | char *buf; /* contents buffer */ | | 381 | char *buf; /* contents buffer */ |
382 | size_t len; /* length of contents */ | | 382 | size_t len; /* length of contents */ |
383 | size_t maplen; /* length of mmap area, or 0 */ | | 383 | size_t maplen; /* length of mmap area, or 0 */ |
384 | Boolean used; /* XXX: have we used the data yet */ | | 384 | Boolean used; /* XXX: have we used the data yet */ |
385 | }; | | 385 | }; |
386 | | | 386 | |
387 | /* | | 387 | /* |
388 | * Constructor/destructor for loadedfile | | 388 | * Constructor/destructor for loadedfile |
389 | */ | | 389 | */ |
390 | static struct loadedfile * | | 390 | static struct loadedfile * |
391 | loadedfile_create(const char *path) | | 391 | loadedfile_create(const char *path) |
392 | { | | 392 | { |
393 | struct loadedfile *lf; | | 393 | struct loadedfile *lf; |
394 | | | 394 | |
395 | lf = bmake_malloc(sizeof(*lf)); | | 395 | lf = bmake_malloc(sizeof(*lf)); |
396 | lf->path = (path == NULL ? "(stdin)" : path); | | 396 | lf->path = (path == NULL ? "(stdin)" : path); |
397 | lf->buf = NULL; | | 397 | lf->buf = NULL; |
398 | lf->len = 0; | | 398 | lf->len = 0; |
399 | lf->maplen = 0; | | 399 | lf->maplen = 0; |
400 | lf->used = FALSE; | | 400 | lf->used = FALSE; |
401 | return lf; | | 401 | return lf; |
402 | } | | 402 | } |
403 | | | 403 | |
404 | static void | | 404 | static void |
405 | loadedfile_destroy(struct loadedfile *lf) | | 405 | loadedfile_destroy(struct loadedfile *lf) |
406 | { | | 406 | { |
407 | if (lf->buf != NULL) { | | 407 | if (lf->buf != NULL) { |
408 | if (lf->maplen > 0) { | | 408 | if (lf->maplen > 0) { |
409 | munmap(lf->buf, lf->maplen); | | 409 | munmap(lf->buf, lf->maplen); |
410 | } else { | | 410 | } else { |
411 | free(lf->buf); | | 411 | free(lf->buf); |
412 | } | | 412 | } |
413 | } | | 413 | } |
414 | free(lf); | | 414 | free(lf); |
415 | } | | 415 | } |
416 | | | 416 | |
417 | /* | | 417 | /* |
418 | * nextbuf() operation for loadedfile, as needed by the weird and twisted | | 418 | * nextbuf() operation for loadedfile, as needed by the weird and twisted |
419 | * logic below. Once that's cleaned up, we can get rid of lf->used... | | 419 | * logic below. Once that's cleaned up, we can get rid of lf->used... |
420 | */ | | 420 | */ |
421 | static char * | | 421 | static char * |
422 | loadedfile_nextbuf(void *x, size_t *len) | | 422 | loadedfile_nextbuf(void *x, size_t *len) |
423 | { | | 423 | { |
424 | struct loadedfile *lf = x; | | 424 | struct loadedfile *lf = x; |
425 | | | 425 | |
426 | if (lf->used) { | | 426 | if (lf->used) { |
427 | return NULL; | | 427 | return NULL; |
428 | } | | 428 | } |
429 | lf->used = TRUE; | | 429 | lf->used = TRUE; |
430 | *len = lf->len; | | 430 | *len = lf->len; |
431 | return lf->buf; | | 431 | return lf->buf; |
432 | } | | 432 | } |
433 | | | 433 | |
434 | /* | | 434 | /* |
435 | * Try to get the size of a file. | | 435 | * Try to get the size of a file. |
436 | */ | | 436 | */ |
437 | static ReturnStatus | | 437 | static ReturnStatus |
438 | load_getsize(int fd, size_t *ret) | | 438 | load_getsize(int fd, size_t *ret) |
439 | { | | 439 | { |
440 | struct stat st; | | 440 | struct stat st; |
441 | | | 441 | |
442 | if (fstat(fd, &st) < 0) { | | 442 | if (fstat(fd, &st) < 0) { |
443 | return FAILURE; | | 443 | return FAILURE; |
444 | } | | 444 | } |
445 | | | 445 | |
446 | if (!S_ISREG(st.st_mode)) { | | 446 | if (!S_ISREG(st.st_mode)) { |
447 | return FAILURE; | | 447 | return FAILURE; |
448 | } | | 448 | } |
449 | | | 449 | |
450 | /* | | 450 | /* |
451 | * st_size is an off_t, which is 64 bits signed; *ret is | | 451 | * st_size is an off_t, which is 64 bits signed; *ret is |
452 | * size_t, which might be 32 bits unsigned or 64 bits | | 452 | * size_t, which might be 32 bits unsigned or 64 bits |
453 | * unsigned. Rather than being elaborate, just punt on | | 453 | * unsigned. Rather than being elaborate, just punt on |
454 | * files that are more than 2^31 bytes. We should never | | 454 | * files that are more than 2^31 bytes. We should never |
455 | * see a makefile that size in practice... | | 455 | * see a makefile that size in practice... |
456 | * | | 456 | * |
457 | * While we're at it reject negative sizes too, just in case. | | 457 | * While we're at it reject negative sizes too, just in case. |
458 | */ | | 458 | */ |
459 | if (st.st_size < 0 || st.st_size > 0x7fffffff) { | | 459 | if (st.st_size < 0 || st.st_size > 0x7fffffff) { |
460 | return FAILURE; | | 460 | return FAILURE; |
461 | } | | 461 | } |
462 | | | 462 | |
463 | *ret = (size_t) st.st_size; | | 463 | *ret = (size_t) st.st_size; |
464 | return SUCCESS; | | 464 | return SUCCESS; |
465 | } | | 465 | } |
466 | | | 466 | |
467 | /* | | 467 | /* |
468 | * Read in a file. | | 468 | * Read in a file. |
469 | * | | 469 | * |
470 | * Until the path search logic can be moved under here instead of | | 470 | * Until the path search logic can be moved under here instead of |
471 | * being in the caller in another source file, we need to have the fd | | 471 | * being in the caller in another source file, we need to have the fd |
472 | * passed in already open. Bleh. | | 472 | * passed in already open. Bleh. |
473 | * | | 473 | * |
474 | * If the path is NULL use stdin and (to insure against fd leaks) | | 474 | * If the path is NULL use stdin and (to insure against fd leaks) |
475 | * assert that the caller passed in -1. | | 475 | * assert that the caller passed in -1. |
476 | */ | | 476 | */ |
477 | static struct loadedfile * | | 477 | static struct loadedfile * |
478 | loadfile(const char *path, int fd) | | 478 | loadfile(const char *path, int fd) |
479 | { | | 479 | { |
480 | struct loadedfile *lf; | | 480 | struct loadedfile *lf; |
481 | static long pagesize = 0; | | 481 | static long pagesize = 0; |
482 | ssize_t result; | | 482 | ssize_t result; |
483 | size_t bufpos; | | 483 | size_t bufpos; |
484 | | | 484 | |
485 | lf = loadedfile_create(path); | | 485 | lf = loadedfile_create(path); |
486 | | | 486 | |
487 | if (path == NULL) { | | 487 | if (path == NULL) { |
488 | assert(fd == -1); | | 488 | assert(fd == -1); |
489 | fd = STDIN_FILENO; | | 489 | fd = STDIN_FILENO; |
490 | } else { | | 490 | } else { |
491 | #if 0 /* notyet */ | | 491 | #if 0 /* notyet */ |
492 | fd = open(path, O_RDONLY); | | 492 | fd = open(path, O_RDONLY); |
493 | if (fd < 0) { | | 493 | if (fd < 0) { |
494 | ... | | 494 | ... |
495 | Error("%s: %s", path, strerror(errno)); | | 495 | Error("%s: %s", path, strerror(errno)); |
496 | exit(1); | | 496 | exit(1); |
497 | } | | 497 | } |
498 | #endif | | 498 | #endif |
499 | } | | 499 | } |
500 | | | 500 | |
501 | if (load_getsize(fd, &lf->len) == SUCCESS) { | | 501 | if (load_getsize(fd, &lf->len) == SUCCESS) { |
502 | /* found a size, try mmap */ | | 502 | /* found a size, try mmap */ |
503 | if (pagesize == 0) | | 503 | if (pagesize == 0) |
504 | pagesize = sysconf(_SC_PAGESIZE); | | 504 | pagesize = sysconf(_SC_PAGESIZE); |
505 | if (pagesize <= 0) { | | 505 | if (pagesize <= 0) { |
506 | pagesize = 0x1000; | | 506 | pagesize = 0x1000; |
507 | } | | 507 | } |
508 | /* round size up to a page */ | | 508 | /* round size up to a page */ |
509 | lf->maplen = pagesize * ((lf->len + pagesize - 1)/pagesize); | | 509 | lf->maplen = pagesize * ((lf->len + pagesize - 1)/pagesize); |
510 | | | 510 | |
511 | /* | | 511 | /* |
512 | * XXX hack for dealing with empty files; remove when | | 512 | * XXX hack for dealing with empty files; remove when |
513 | * we're no longer limited by interfacing to the old | | 513 | * we're no longer limited by interfacing to the old |
514 | * logic elsewhere in this file. | | 514 | * logic elsewhere in this file. |
515 | */ | | 515 | */ |
516 | if (lf->maplen == 0) { | | 516 | if (lf->maplen == 0) { |
517 | lf->maplen = pagesize; | | 517 | lf->maplen = pagesize; |
518 | } | | 518 | } |
519 | | | 519 | |
520 | /* | | 520 | /* |
521 | * FUTURE: remove PROT_WRITE when the parser no longer | | 521 | * FUTURE: remove PROT_WRITE when the parser no longer |
522 | * needs to scribble on the input. | | 522 | * needs to scribble on the input. |
523 | */ | | 523 | */ |
524 | lf->buf = mmap(NULL, lf->maplen, PROT_READ|PROT_WRITE, | | 524 | lf->buf = mmap(NULL, lf->maplen, PROT_READ|PROT_WRITE, |
525 | MAP_FILE|MAP_COPY, fd, 0); | | 525 | MAP_FILE|MAP_COPY, fd, 0); |
526 | if (lf->buf != MAP_FAILED) { | | 526 | if (lf->buf != MAP_FAILED) { |
527 | /* succeeded */ | | 527 | /* succeeded */ |
528 | if (lf->len == lf->maplen && lf->buf[lf->len - 1] != '\n') { | | 528 | if (lf->len == lf->maplen && lf->buf[lf->len - 1] != '\n') { |
529 | char *b = bmake_malloc(lf->len + 1); | | 529 | char *b = bmake_malloc(lf->len + 1); |
530 | b[lf->len] = '\n'; | | 530 | b[lf->len] = '\n'; |
531 | memcpy(b, lf->buf, lf->len++); | | 531 | memcpy(b, lf->buf, lf->len++); |
532 | munmap(lf->buf, lf->maplen); | | 532 | munmap(lf->buf, lf->maplen); |
533 | lf->maplen = 0; | | 533 | lf->maplen = 0; |
534 | lf->buf = b; | | 534 | lf->buf = b; |
535 | } | | 535 | } |
536 | goto done; | | 536 | goto done; |
537 | } | | 537 | } |
538 | } | | 538 | } |
539 | | | 539 | |
540 | /* cannot mmap; load the traditional way */ | | 540 | /* cannot mmap; load the traditional way */ |
541 | | | 541 | |
542 | lf->maplen = 0; | | 542 | lf->maplen = 0; |
543 | lf->len = 1024; | | 543 | lf->len = 1024; |
544 | lf->buf = bmake_malloc(lf->len); | | 544 | lf->buf = bmake_malloc(lf->len); |
545 | | | 545 | |
546 | bufpos = 0; | | 546 | bufpos = 0; |
547 | while (1) { | | 547 | while (1) { |
548 | assert(bufpos <= lf->len); | | 548 | assert(bufpos <= lf->len); |
549 | if (bufpos == lf->len) { | | 549 | if (bufpos == lf->len) { |
550 | if (lf->len > SIZE_MAX/2) { | | 550 | if (lf->len > SIZE_MAX/2) { |
551 | errno = EFBIG; | | 551 | errno = EFBIG; |
552 | Error("%s: file too large", path); | | 552 | Error("%s: file too large", path); |
553 | exit(1); | | 553 | exit(1); |
554 | } | | 554 | } |
555 | lf->len *= 2; | | 555 | lf->len *= 2; |
556 | lf->buf = bmake_realloc(lf->buf, lf->len); | | 556 | lf->buf = bmake_realloc(lf->buf, lf->len); |
557 | } | | 557 | } |
558 | assert(bufpos < lf->len); | | 558 | assert(bufpos < lf->len); |
559 | result = read(fd, lf->buf + bufpos, lf->len - bufpos); | | 559 | result = read(fd, lf->buf + bufpos, lf->len - bufpos); |
560 | if (result < 0) { | | 560 | if (result < 0) { |
561 | Error("%s: read error: %s", path, strerror(errno)); | | 561 | Error("%s: read error: %s", path, strerror(errno)); |
562 | exit(1); | | 562 | exit(1); |
563 | } | | 563 | } |
564 | if (result == 0) { | | 564 | if (result == 0) { |
565 | break; | | 565 | break; |
566 | } | | 566 | } |
567 | bufpos += result; | | 567 | bufpos += result; |
568 | } | | 568 | } |
569 | assert(bufpos <= lf->len); | | 569 | assert(bufpos <= lf->len); |
570 | lf->len = bufpos; | | 570 | lf->len = bufpos; |
571 | | | 571 | |
572 | /* truncate malloc region to actual length (maybe not useful) */ | | 572 | /* truncate malloc region to actual length (maybe not useful) */ |
573 | if (lf->len > 0) { | | 573 | if (lf->len > 0) { |
574 | /* as for mmap case, ensure trailing \n */ | | 574 | /* as for mmap case, ensure trailing \n */ |
575 | if (lf->buf[lf->len - 1] != '\n') | | 575 | if (lf->buf[lf->len - 1] != '\n') |
576 | lf->len++; | | 576 | lf->len++; |
577 | lf->buf = bmake_realloc(lf->buf, lf->len); | | 577 | lf->buf = bmake_realloc(lf->buf, lf->len); |
578 | lf->buf[lf->len - 1] = '\n'; | | 578 | lf->buf[lf->len - 1] = '\n'; |
579 | } | | 579 | } |
580 | | | 580 | |
581 | done: | | 581 | done: |
582 | if (path != NULL) { | | 582 | if (path != NULL) { |
583 | close(fd); | | 583 | close(fd); |
584 | } | | 584 | } |
585 | return lf; | | 585 | return lf; |
586 | } | | 586 | } |
587 | | | 587 | |
588 | //////////////////////////////////////////////////////////// | | 588 | //////////////////////////////////////////////////////////// |
589 | // old code | | 589 | // old code |
590 | | | 590 | |
591 | /*- | | 591 | /*- |
592 | *---------------------------------------------------------------------- | | 592 | *---------------------------------------------------------------------- |
593 | * ParseIsEscaped -- | | 593 | * ParseIsEscaped -- |
594 | * Check if the current character is escaped on the current line | | 594 | * Check if the current character is escaped on the current line |
595 | * | | 595 | * |
596 | * Results: | | 596 | * Results: |
597 | * 0 if the character is not backslash escaped, 1 otherwise | | 597 | * 0 if the character is not backslash escaped, 1 otherwise |
598 | * | | 598 | * |
599 | * Side Effects: | | 599 | * Side Effects: |
600 | * None | | 600 | * None |
601 | *---------------------------------------------------------------------- | | 601 | *---------------------------------------------------------------------- |
602 | */ | | 602 | */ |
603 | static int | | 603 | static int |
604 | ParseIsEscaped(const char *line, const char *c) | | 604 | ParseIsEscaped(const char *line, const char *c) |
605 | { | | 605 | { |
606 | int active = 0; | | 606 | int active = 0; |
607 | for (;;) { | | 607 | for (;;) { |
608 | if (line == c) | | 608 | if (line == c) |
609 | return active; | | 609 | return active; |
610 | if (*--c != '\\') | | 610 | if (*--c != '\\') |
611 | return active; | | 611 | return active; |
612 | active = !active; | | 612 | active = !active; |
613 | } | | 613 | } |
614 | } | | 614 | } |
615 | | | 615 | |
616 | /*- | | 616 | /*- |
617 | *---------------------------------------------------------------------- | | 617 | *---------------------------------------------------------------------- |
618 | * ParseFindKeyword -- | | 618 | * ParseFindKeyword -- |
619 | * Look in the table of keywords for one matching the given string. | | 619 | * Look in the table of keywords for one matching the given string. |
620 | * | | 620 | * |
621 | * Input: | | 621 | * Input: |
622 | * str String to find | | 622 | * str String to find |
623 | * | | 623 | * |
624 | * Results: | | 624 | * Results: |
625 | * The index of the keyword, or -1 if it isn't there. | | 625 | * The index of the keyword, or -1 if it isn't there. |
626 | * | | 626 | * |
627 | * Side Effects: | | 627 | * Side Effects: |
628 | * None | | 628 | * None |
629 | *---------------------------------------------------------------------- | | 629 | *---------------------------------------------------------------------- |
630 | */ | | 630 | */ |
631 | static int | | 631 | static int |
632 | ParseFindKeyword(const char *str) | | 632 | ParseFindKeyword(const char *str) |
633 | { | | 633 | { |
634 | int start, end, cur; | | 634 | int start, end, cur; |
635 | int diff; | | 635 | int diff; |
636 | | | 636 | |
637 | start = 0; | | 637 | start = 0; |
638 | end = (sizeof(parseKeywords)/sizeof(parseKeywords[0])) - 1; | | 638 | end = (sizeof(parseKeywords)/sizeof(parseKeywords[0])) - 1; |
639 | | | 639 | |
640 | do { | | 640 | do { |
641 | cur = start + ((end - start) / 2); | | 641 | cur = start + ((end - start) / 2); |
642 | diff = strcmp(str, parseKeywords[cur].name); | | 642 | diff = strcmp(str, parseKeywords[cur].name); |
643 | | | 643 | |
644 | if (diff == 0) { | | 644 | if (diff == 0) { |
645 | return cur; | | 645 | return cur; |
646 | } else if (diff < 0) { | | 646 | } else if (diff < 0) { |
647 | end = cur - 1; | | 647 | end = cur - 1; |
648 | } else { | | 648 | } else { |
649 | start = cur + 1; | | 649 | start = cur + 1; |
650 | } | | 650 | } |
651 | } while (start <= end); | | 651 | } while (start <= end); |
652 | return -1; | | 652 | return -1; |
653 | } | | 653 | } |
654 | | | 654 | |
655 | /*- | | 655 | /*- |
656 | * ParseVErrorInternal -- | | 656 | * ParseVErrorInternal -- |
657 | * Error message abort function for parsing. Prints out the context | | 657 | * Error message abort function for parsing. Prints out the context |
658 | * of the error (line number and file) as well as the message with | | 658 | * of the error (line number and file) as well as the message with |
659 | * two optional arguments. | | 659 | * two optional arguments. |
660 | * | | 660 | * |
661 | * Results: | | 661 | * Results: |
662 | * None | | 662 | * None |
663 | * | | 663 | * |
664 | * Side Effects: | | 664 | * Side Effects: |
665 | * "fatals" is incremented if the level is PARSE_FATAL. | | 665 | * "fatals" is incremented if the level is PARSE_FATAL. |
666 | */ | | 666 | */ |
667 | /* VARARGS */ | | 667 | /* VARARGS */ |
668 | static void | | 668 | static void |
669 | ParseVErrorInternal(FILE *f, const char *cfname, size_t clineno, int type, | | 669 | ParseVErrorInternal(FILE *f, const char *cfname, size_t clineno, int type, |
670 | const char *fmt, va_list ap) | | 670 | const char *fmt, va_list ap) |
671 | { | | 671 | { |
672 | static Boolean fatal_warning_error_printed = FALSE; | | 672 | static Boolean fatal_warning_error_printed = FALSE; |
673 | char dirbuf[MAXPATHLEN+1]; | | 673 | char dirbuf[MAXPATHLEN+1]; |
674 | | | 674 | |
675 | (void)fprintf(f, "%s: ", progname); | | 675 | (void)fprintf(f, "%s: ", progname); |
676 | | | 676 | |
677 | if (cfname != NULL) { | | 677 | if (cfname != NULL) { |
678 | (void)fprintf(f, "\""); | | 678 | (void)fprintf(f, "\""); |
679 | if (*cfname != '/' && strcmp(cfname, "(stdin)") != 0) { | | 679 | if (*cfname != '/' && strcmp(cfname, "(stdin)") != 0) { |
680 | char *cp, *cp2; | | 680 | char *cp, *cp2; |
681 | const char *dir, *fname; | | 681 | const char *dir, *fname; |
682 | | | 682 | |
683 | /* | | 683 | /* |
684 | * Nothing is more annoying than not knowing | | 684 | * Nothing is more annoying than not knowing |
685 | * which Makefile is the culprit; we try ${.PARSEDIR} | | 685 | * which Makefile is the culprit; we try ${.PARSEDIR} |
686 | * and apply realpath(3) if not absolute. | | 686 | * and apply realpath(3) if not absolute. |
687 | */ | | 687 | */ |
688 | dir = Var_Value(".PARSEDIR", VAR_GLOBAL, &cp); | | 688 | dir = Var_Value(".PARSEDIR", VAR_GLOBAL, &cp); |
689 | if (dir == NULL) | | 689 | if (dir == NULL) |
690 | dir = "."; | | 690 | dir = "."; |
691 | if (*dir != '/') { | | 691 | if (*dir != '/') { |
692 | dir = realpath(dir, dirbuf); | | 692 | dir = realpath(dir, dirbuf); |
693 | } | | 693 | } |
694 | fname = Var_Value(".PARSEFILE", VAR_GLOBAL, &cp2); | | 694 | fname = Var_Value(".PARSEFILE", VAR_GLOBAL, &cp2); |
695 | if (fname == NULL) { | | 695 | if (fname == NULL) { |
696 | if ((fname = strrchr(cfname, '/'))) | | 696 | if ((fname = strrchr(cfname, '/'))) |
697 | fname++; | | 697 | fname++; |
698 | else | | 698 | else |
699 | fname = cfname; | | 699 | fname = cfname; |
700 | } | | 700 | } |
701 | (void)fprintf(f, "%s/%s", dir, fname); | | 701 | (void)fprintf(f, "%s/%s", dir, fname); |
702 | free(cp2); | | 702 | free(cp2); |
703 | free(cp); | | 703 | free(cp); |
704 | } else | | 704 | } else |
705 | (void)fprintf(f, "%s", cfname); | | 705 | (void)fprintf(f, "%s", cfname); |
706 | | | 706 | |
707 | (void)fprintf(f, "\" line %d: ", (int)clineno); | | 707 | (void)fprintf(f, "\" line %d: ", (int)clineno); |
708 | } | | 708 | } |
709 | if (type == PARSE_WARNING) | | 709 | if (type == PARSE_WARNING) |
710 | (void)fprintf(f, "warning: "); | | 710 | (void)fprintf(f, "warning: "); |
711 | (void)vfprintf(f, fmt, ap); | | 711 | (void)vfprintf(f, fmt, ap); |
712 | (void)fprintf(f, "\n"); | | 712 | (void)fprintf(f, "\n"); |
713 | (void)fflush(f); | | 713 | (void)fflush(f); |
714 | if (type == PARSE_INFO) | | 714 | if (type == PARSE_INFO) |
715 | return; | | 715 | return; |
716 | if (type == PARSE_FATAL || parseWarnFatal) | | 716 | if (type == PARSE_FATAL || parseWarnFatal) |
717 | fatals += 1; | | 717 | fatals += 1; |
718 | if (parseWarnFatal && !fatal_warning_error_printed) { | | 718 | if (parseWarnFatal && !fatal_warning_error_printed) { |
719 | Error("parsing warnings being treated as errors"); | | 719 | Error("parsing warnings being treated as errors"); |
720 | fatal_warning_error_printed = TRUE; | | 720 | fatal_warning_error_printed = TRUE; |
721 | } | | 721 | } |
722 | } | | 722 | } |
723 | | | 723 | |
724 | /*- | | 724 | /*- |
725 | * ParseErrorInternal -- | | 725 | * ParseErrorInternal -- |
726 | * Error function | | 726 | * Error function |
727 | * | | 727 | * |
728 | * Results: | | 728 | * Results: |
729 | * None | | 729 | * None |
730 | * | | 730 | * |
731 | * Side Effects: | | 731 | * Side Effects: |
732 | * None | | 732 | * None |
733 | */ | | 733 | */ |
734 | /* VARARGS */ | | 734 | /* VARARGS */ |
735 | static void | | 735 | static void |
736 | ParseErrorInternal(const char *cfname, size_t clineno, int type, | | 736 | ParseErrorInternal(const char *cfname, size_t clineno, int type, |
737 | const char *fmt, ...) | | 737 | const char *fmt, ...) |
738 | { | | 738 | { |
739 | va_list ap; | | 739 | va_list ap; |
740 | | | 740 | |
741 | va_start(ap, fmt); | | 741 | va_start(ap, fmt); |
742 | (void)fflush(stdout); | | 742 | (void)fflush(stdout); |
743 | ParseVErrorInternal(stderr, cfname, clineno, type, fmt, ap); | | 743 | ParseVErrorInternal(stderr, cfname, clineno, type, fmt, ap); |
744 | va_end(ap); | | 744 | va_end(ap); |
745 | | | 745 | |
746 | if (debug_file != stderr && debug_file != stdout) { | | 746 | if (debug_file != stderr && debug_file != stdout) { |
747 | va_start(ap, fmt); | | 747 | va_start(ap, fmt); |
748 | ParseVErrorInternal(debug_file, cfname, clineno, type, fmt, ap); | | 748 | ParseVErrorInternal(debug_file, cfname, clineno, type, fmt, ap); |
749 | va_end(ap); | | 749 | va_end(ap); |
750 | } | | 750 | } |
751 | } | | 751 | } |
752 | | | 752 | |
753 | /*- | | 753 | /*- |
754 | * Parse_Error -- | | 754 | * Parse_Error -- |
755 | * External interface to ParseErrorInternal; uses the default filename | | 755 | * External interface to ParseErrorInternal; uses the default filename |
756 | * Line number. | | 756 | * Line number. |
757 | * | | 757 | * |
758 | * Results: | | 758 | * Results: |
759 | * None | | 759 | * None |
760 | * | | 760 | * |
761 | * Side Effects: | | 761 | * Side Effects: |
762 | * None | | 762 | * None |
763 | */ | | 763 | */ |
764 | /* VARARGS */ | | 764 | /* VARARGS */ |
765 | void | | 765 | void |
766 | Parse_Error(int type, const char *fmt, ...) | | 766 | Parse_Error(int type, const char *fmt, ...) |
767 | { | | 767 | { |
768 | va_list ap; | | 768 | va_list ap; |
769 | const char *fname; | | 769 | const char *fname; |
770 | size_t lineno; | | 770 | size_t lineno; |
771 | | | 771 | |
772 | if (curFile == NULL) { | | 772 | if (curFile == NULL) { |
773 | fname = NULL; | | 773 | fname = NULL; |
774 | lineno = 0; | | 774 | lineno = 0; |
775 | } else { | | 775 | } else { |
776 | fname = curFile->fname; | | 776 | fname = curFile->fname; |
777 | lineno = curFile->lineno; | | 777 | lineno = curFile->lineno; |
778 | } | | 778 | } |
779 | | | 779 | |
780 | va_start(ap, fmt); | | 780 | va_start(ap, fmt); |
781 | (void)fflush(stdout); | | 781 | (void)fflush(stdout); |
782 | ParseVErrorInternal(stderr, fname, lineno, type, fmt, ap); | | 782 | ParseVErrorInternal(stderr, fname, lineno, type, fmt, ap); |
783 | va_end(ap); | | 783 | va_end(ap); |
784 | | | 784 | |
785 | if (debug_file != stderr && debug_file != stdout) { | | 785 | if (debug_file != stderr && debug_file != stdout) { |
786 | va_start(ap, fmt); | | 786 | va_start(ap, fmt); |
787 | ParseVErrorInternal(debug_file, fname, lineno, type, fmt, ap); | | 787 | ParseVErrorInternal(debug_file, fname, lineno, type, fmt, ap); |
788 | va_end(ap); | | 788 | va_end(ap); |
789 | } | | 789 | } |
790 | } | | 790 | } |
791 | | | 791 | |
792 | | | 792 | |
793 | /* | | 793 | /* |
794 | * ParseMessage | | 794 | * ParseMessage |
795 | * Parse a .info .warning or .error directive | | 795 | * Parse a .info .warning or .error directive |
796 | * | | 796 | * |
797 | * The input is the line minus the ".". We substitute | | 797 | * The input is the line minus the ".". We substitute |
798 | * variables, print the message and exit(1) (for .error) or just print | | 798 | * variables, print the message and exit(1) (for .error) or just print |
799 | * a warning if the directive is malformed. | | 799 | * a warning if the directive is malformed. |
800 | */ | | 800 | */ |
801 | static Boolean | | 801 | static Boolean |
802 | ParseMessage(char *line) | | 802 | ParseMessage(char *line) |
803 | { | | 803 | { |
804 | int mtype; | | 804 | int mtype; |
805 | | | 805 | |
806 | switch(*line) { | | 806 | switch(*line) { |
807 | case 'i': | | 807 | case 'i': |
808 | mtype = PARSE_INFO; | | 808 | mtype = PARSE_INFO; |
809 | break; | | 809 | break; |
810 | case 'w': | | 810 | case 'w': |
811 | mtype = PARSE_WARNING; | | 811 | mtype = PARSE_WARNING; |
812 | break; | | 812 | break; |
813 | case 'e': | | 813 | case 'e': |
814 | mtype = PARSE_FATAL; | | 814 | mtype = PARSE_FATAL; |
815 | break; | | 815 | break; |
816 | default: | | 816 | default: |
817 | Parse_Error(PARSE_WARNING, "invalid syntax: \".%s\"", line); | | 817 | Parse_Error(PARSE_WARNING, "invalid syntax: \".%s\"", line); |
818 | return FALSE; | | 818 | return FALSE; |
819 | } | | 819 | } |
820 | | | 820 | |
821 | while (isalpha((unsigned char)*line)) | | 821 | while (isalpha((unsigned char)*line)) |
822 | line++; | | 822 | line++; |
823 | if (!isspace((unsigned char)*line)) | | 823 | if (!isspace((unsigned char)*line)) |
824 | return FALSE; /* not for us */ | | 824 | return FALSE; /* not for us */ |
825 | while (isspace((unsigned char)*line)) | | 825 | while (isspace((unsigned char)*line)) |
826 | line++; | | 826 | line++; |
827 | | | 827 | |
828 | line = Var_Subst(line, VAR_CMD, VARE_WANTRES); | | 828 | line = Var_Subst(line, VAR_CMD, VARE_WANTRES); |
829 | Parse_Error(mtype, "%s", line); | | 829 | Parse_Error(mtype, "%s", line); |
830 | free(line); | | 830 | free(line); |
831 | | | 831 | |
832 | if (mtype == PARSE_FATAL) { | | 832 | if (mtype == PARSE_FATAL) { |
833 | /* Terminate immediately. */ | | 833 | /* Terminate immediately. */ |
834 | exit(1); | | 834 | exit(1); |
835 | } | | 835 | } |
836 | return TRUE; | | 836 | return TRUE; |
837 | } | | 837 | } |
838 | | | 838 | |
839 | /*- | | 839 | /*- |
840 | *--------------------------------------------------------------------- | | 840 | *--------------------------------------------------------------------- |
841 | * ParseLinkSrc -- | | 841 | * ParseLinkSrc -- |
842 | * Link the parent node to its new child. Used in a Lst_ForEach by | | 842 | * Link the parent node to its new child. Used in a Lst_ForEach by |
843 | * ParseDoDependency. If the specType isn't 'Not', the parent | | 843 | * ParseDoDependency. If the specType isn't 'Not', the parent |
844 | * isn't linked as a parent of the child. | | 844 | * isn't linked as a parent of the child. |
845 | * | | 845 | * |
846 | * Input: | | 846 | * Input: |
847 | * pgnp The parent node | | 847 | * pgnp The parent node |
848 | * cgpn The child node | | 848 | * cgpn The child node |
849 | * | | 849 | * |
850 | * Results: | | 850 | * Results: |
851 | * Always = 0 | | 851 | * Always = 0 |
852 | * | | 852 | * |
853 | * Side Effects: | | 853 | * Side Effects: |
854 | * New elements are added to the parents list of cgn and the | | 854 | * New elements are added to the parents list of cgn and the |
855 | * children list of cgn. the unmade field of pgn is updated | | 855 | * children list of cgn. the unmade field of pgn is updated |
856 | * to reflect the additional child. | | 856 | * to reflect the additional child. |
857 | *--------------------------------------------------------------------- | | 857 | *--------------------------------------------------------------------- |
858 | */ | | 858 | */ |
859 | static int | | 859 | static int |
860 | ParseLinkSrc(void *pgnp, void *cgnp) | | 860 | ParseLinkSrc(void *pgnp, void *cgnp) |
861 | { | | 861 | { |
862 | GNode *pgn = (GNode *)pgnp; | | 862 | GNode *pgn = (GNode *)pgnp; |
863 | GNode *cgn = (GNode *)cgnp; | | 863 | GNode *cgn = (GNode *)cgnp; |
864 | | | 864 | |
865 | if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (pgn->cohorts)) | | 865 | if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (pgn->cohorts)) |
866 | pgn = (GNode *)Lst_Datum(Lst_Last(pgn->cohorts)); | | 866 | pgn = (GNode *)Lst_Datum(Lst_Last(pgn->cohorts)); |
867 | (void)Lst_AtEnd(pgn->children, cgn); | | 867 | (void)Lst_AtEnd(pgn->children, cgn); |
868 | if (specType == Not) | | 868 | if (specType == Not) |
869 | (void)Lst_AtEnd(cgn->parents, pgn); | | 869 | (void)Lst_AtEnd(cgn->parents, pgn); |
870 | pgn->unmade += 1; | | 870 | pgn->unmade += 1; |
871 | if (DEBUG(PARSE)) { | | 871 | if (DEBUG(PARSE)) { |
872 | fprintf(debug_file, "# %s: added child %s - %s\n", __func__, | | 872 | fprintf(debug_file, "# %s: added child %s - %s\n", __func__, |
873 | pgn->name, cgn->name); | | 873 | pgn->name, cgn->name); |
874 | Targ_PrintNode(pgn, 0); | | 874 | Targ_PrintNode(pgn, 0); |
875 | Targ_PrintNode(cgn, 0); | | 875 | Targ_PrintNode(cgn, 0); |
876 | } | | 876 | } |
877 | return 0; | | 877 | return 0; |
878 | } | | 878 | } |
879 | | | 879 | |
880 | /*- | | 880 | /*- |
881 | *--------------------------------------------------------------------- | | 881 | *--------------------------------------------------------------------- |
882 | * ParseDoOp -- | | 882 | * ParseDoOp -- |
883 | * Apply the parsed operator to the given target node. Used in a | | 883 | * Apply the parsed operator to the given target node. Used in a |
884 | * Lst_ForEach call by ParseDoDependency once all targets have | | 884 | * Lst_ForEach call by ParseDoDependency once all targets have |
885 | * been found and their operator parsed. If the previous and new | | 885 | * been found and their operator parsed. If the previous and new |
886 | * operators are incompatible, a major error is taken. | | 886 | * operators are incompatible, a major error is taken. |
887 | * | | 887 | * |
888 | * Input: | | 888 | * Input: |
889 | * gnp The node to which the operator is to be applied | | 889 | * gnp The node to which the operator is to be applied |
890 | * opp The operator to apply | | 890 | * opp The operator to apply |
891 | * | | 891 | * |
892 | * Results: | | 892 | * Results: |
893 | * Always 0 | | 893 | * Always 0 |
894 | * | | 894 | * |
895 | * Side Effects: | | 895 | * Side Effects: |
896 | * The type field of the node is altered to reflect any new bits in | | 896 | * The type field of the node is altered to reflect any new bits in |
897 | * the op. | | 897 | * the op. |
898 | *--------------------------------------------------------------------- | | 898 | *--------------------------------------------------------------------- |
899 | */ | | 899 | */ |
900 | static int | | 900 | static int |
901 | ParseDoOp(void *gnp, void *opp) | | 901 | ParseDoOp(void *gnp, void *opp) |
902 | { | | 902 | { |
903 | GNode *gn = (GNode *)gnp; | | 903 | GNode *gn = (GNode *)gnp; |
904 | int op = *(int *)opp; | | 904 | int op = *(int *)opp; |
905 | /* | | 905 | /* |
906 | * If the dependency mask of the operator and the node don't match and | | 906 | * If the dependency mask of the operator and the node don't match and |
907 | * the node has actually had an operator applied to it before, and | | 907 | * the node has actually had an operator applied to it before, and |
908 | * the operator actually has some dependency information in it, complain. | | 908 | * the operator actually has some dependency information in it, complain. |
909 | */ | | 909 | */ |
910 | if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) && | | 910 | if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) && |
911 | !OP_NOP(gn->type) && !OP_NOP(op)) | | 911 | !OP_NOP(gn->type) && !OP_NOP(op)) |
912 | { | | 912 | { |
913 | Parse_Error(PARSE_FATAL, "Inconsistent operator for %s", gn->name); | | 913 | Parse_Error(PARSE_FATAL, "Inconsistent operator for %s", gn->name); |
914 | return 1; | | 914 | return 1; |
915 | } | | 915 | } |
916 | | | 916 | |
917 | if ((op == OP_DOUBLEDEP) && ((gn->type & OP_OPMASK) == OP_DOUBLEDEP)) { | | 917 | if ((op == OP_DOUBLEDEP) && ((gn->type & OP_OPMASK) == OP_DOUBLEDEP)) { |
918 | /* | | 918 | /* |
919 | * If the node was the object of a :: operator, we need to create a | | 919 | * If the node was the object of a :: operator, we need to create a |
920 | * new instance of it for the children and commands on this dependency | | 920 | * new instance of it for the children and commands on this dependency |
921 | * line. The new instance is placed on the 'cohorts' list of the | | 921 | * line. The new instance is placed on the 'cohorts' list of the |
922 | * initial one (note the initial one is not on its own cohorts list) | | 922 | * initial one (note the initial one is not on its own cohorts list) |
923 | * and the new instance is linked to all parents of the initial | | 923 | * and the new instance is linked to all parents of the initial |
924 | * instance. | | 924 | * instance. |
925 | */ | | 925 | */ |
926 | GNode *cohort; | | 926 | GNode *cohort; |
927 | | | 927 | |
928 | /* | | 928 | /* |
929 | * Propagate copied bits to the initial node. They'll be propagated | | 929 | * Propagate copied bits to the initial node. They'll be propagated |
930 | * back to the rest of the cohorts later. | | 930 | * back to the rest of the cohorts later. |
931 | */ | | 931 | */ |
932 | gn->type |= op & ~OP_OPMASK; | | 932 | gn->type |= op & ~OP_OPMASK; |
933 | | | 933 | |
934 | cohort = Targ_FindNode(gn->name, TARG_NOHASH); | | 934 | cohort = Targ_FindNode(gn->name, TARG_NOHASH); |
935 | if (doing_depend) | | 935 | if (doing_depend) |
936 | ParseMark(cohort); | | 936 | ParseMark(cohort); |
937 | /* | | 937 | /* |
938 | * Make the cohort invisible as well to avoid duplicating it into | | 938 | * Make the cohort invisible as well to avoid duplicating it into |
939 | * other variables. True, parents of this target won't tend to do | | 939 | * other variables. True, parents of this target won't tend to do |
940 | * anything with their local variables, but better safe than | | 940 | * anything with their local variables, but better safe than |
941 | * sorry. (I think this is pointless now, since the relevant list | | 941 | * sorry. (I think this is pointless now, since the relevant list |
942 | * traversals will no longer see this node anyway. -mycroft) | | 942 | * traversals will no longer see this node anyway. -mycroft) |
943 | */ | | 943 | */ |
944 | cohort->type = op | OP_INVISIBLE; | | 944 | cohort->type = op | OP_INVISIBLE; |
945 | (void)Lst_AtEnd(gn->cohorts, cohort); | | 945 | (void)Lst_AtEnd(gn->cohorts, cohort); |
946 | cohort->centurion = gn; | | 946 | cohort->centurion = gn; |
947 | gn->unmade_cohorts += 1; | | 947 | gn->unmade_cohorts += 1; |
948 | snprintf(cohort->cohort_num, sizeof cohort->cohort_num, "#%d", | | 948 | snprintf(cohort->cohort_num, sizeof cohort->cohort_num, "#%d", |
949 | gn->unmade_cohorts); | | 949 | gn->unmade_cohorts); |
950 | } else { | | 950 | } else { |
951 | /* | | 951 | /* |
952 | * We don't want to nuke any previous flags (whatever they were) so we | | 952 | * We don't want to nuke any previous flags (whatever they were) so we |
953 | * just OR the new operator into the old | | 953 | * just OR the new operator into the old |
954 | */ | | 954 | */ |
955 | gn->type |= op; | | 955 | gn->type |= op; |
956 | } | | 956 | } |
957 | | | 957 | |
958 | return 0; | | 958 | return 0; |
959 | } | | 959 | } |
960 | | | 960 | |
961 | /*- | | 961 | /*- |
962 | *--------------------------------------------------------------------- | | 962 | *--------------------------------------------------------------------- |
963 | * ParseDoSrc -- | | 963 | * ParseDoSrc -- |
964 | * Given the name of a source, figure out if it is an attribute | | 964 | * Given the name of a source, figure out if it is an attribute |
965 | * and apply it to the targets if it is. Else decide if there is | | 965 | * and apply it to the targets if it is. Else decide if there is |
966 | * some attribute which should be applied *to* the source because | | 966 | * some attribute which should be applied *to* the source because |
967 | * of some special target and apply it if so. Otherwise, make the | | 967 | * of some special target and apply it if so. Otherwise, make the |
968 | * source be a child of the targets in the list 'targets' | | 968 | * source be a child of the targets in the list 'targets' |
969 | * | | 969 | * |
970 | * Input: | | 970 | * Input: |
971 | * tOp operator (if any) from special targets | | 971 | * tOp operator (if any) from special targets |
972 | * src name of the source to handle | | 972 | * src name of the source to handle |
973 | * | | 973 | * |
974 | * Results: | | 974 | * Results: |
975 | * None | | 975 | * None |
976 | * | | 976 | * |
977 | * Side Effects: | | 977 | * Side Effects: |
978 | * Operator bits may be added to the list of targets or to the source. | | 978 | * Operator bits may be added to the list of targets or to the source. |
979 | * The targets may have a new source added to their lists of children. | | 979 | * The targets may have a new source added to their lists of children. |
980 | *--------------------------------------------------------------------- | | 980 | *--------------------------------------------------------------------- |
981 | */ | | 981 | */ |
982 | static void | | 982 | static void |
983 | ParseDoSrc(int tOp, const char *src) | | 983 | ParseDoSrc(int tOp, const char *src) |
984 | { | | 984 | { |
985 | GNode *gn = NULL; | | 985 | GNode *gn = NULL; |
986 | static int wait_number = 0; | | 986 | static int wait_number = 0; |
987 | char wait_src[16]; | | 987 | char wait_src[16]; |
988 | | | 988 | |
989 | if (*src == '.' && isupper ((unsigned char)src[1])) { | | 989 | if (*src == '.' && isupper ((unsigned char)src[1])) { |
990 | int keywd = ParseFindKeyword(src); | | 990 | int keywd = ParseFindKeyword(src); |
991 | if (keywd != -1) { | | 991 | if (keywd != -1) { |
992 | int op = parseKeywords[keywd].op; | | 992 | int op = parseKeywords[keywd].op; |
993 | if (op != 0) { | | 993 | if (op != 0) { |
994 | Lst_ForEach(targets, ParseDoOp, &op); | | 994 | Lst_ForEach(targets, ParseDoOp, &op); |
995 | return; | | 995 | return; |
996 | } | | 996 | } |
997 | if (parseKeywords[keywd].spec == Wait) { | | 997 | if (parseKeywords[keywd].spec == Wait) { |
998 | /* | | 998 | /* |
999 | * We add a .WAIT node in the dependency list. | | 999 | * We add a .WAIT node in the dependency list. |
1000 | * After any dynamic dependencies (and filename globbing) | | 1000 | * After any dynamic dependencies (and filename globbing) |
1001 | * have happened, it is given a dependency on the each | | 1001 | * have happened, it is given a dependency on the each |
1002 | * previous child back to and previous .WAIT node. | | 1002 | * previous child back to and previous .WAIT node. |
1003 | * The next child won't be scheduled until the .WAIT node | | 1003 | * The next child won't be scheduled until the .WAIT node |
1004 | * is built. | | 1004 | * is built. |
1005 | * We give each .WAIT node a unique name (mainly for diag). | | 1005 | * We give each .WAIT node a unique name (mainly for diag). |
1006 | */ | | 1006 | */ |
1007 | snprintf(wait_src, sizeof wait_src, ".WAIT_%u", ++wait_number); | | 1007 | snprintf(wait_src, sizeof wait_src, ".WAIT_%u", ++wait_number); |
1008 | gn = Targ_FindNode(wait_src, TARG_NOHASH); | | 1008 | gn = Targ_FindNode(wait_src, TARG_NOHASH); |
1009 | if (doing_depend) | | 1009 | if (doing_depend) |
1010 | ParseMark(gn); | | 1010 | ParseMark(gn); |
1011 | gn->type = OP_WAIT | OP_PHONY | OP_DEPENDS | OP_NOTMAIN; | | 1011 | gn->type = OP_WAIT | OP_PHONY | OP_DEPENDS | OP_NOTMAIN; |
1012 | Lst_ForEach(targets, ParseLinkSrc, gn); | | 1012 | Lst_ForEach(targets, ParseLinkSrc, gn); |
1013 | return; | | 1013 | return; |
1014 | } | | 1014 | } |
1015 | } | | 1015 | } |
1016 | } | | 1016 | } |
1017 | | | 1017 | |
1018 | switch (specType) { | | 1018 | switch (specType) { |
1019 | case Main: | | 1019 | case Main: |
1020 | /* | | 1020 | /* |
1021 | * If we have noted the existence of a .MAIN, it means we need | | 1021 | * If we have noted the existence of a .MAIN, it means we need |
1022 | * to add the sources of said target to the list of things | | 1022 | * to add the sources of said target to the list of things |
1023 | * to create. The string 'src' is likely to be free, so we | | 1023 | * to create. The string 'src' is likely to be free, so we |
1024 | * must make a new copy of it. Note that this will only be | | 1024 | * must make a new copy of it. Note that this will only be |
1025 | * invoked if the user didn't specify a target on the command | | 1025 | * invoked if the user didn't specify a target on the command |
1026 | * line. This is to allow #ifmake's to succeed, or something... | | 1026 | * line. This is to allow #ifmake's to succeed, or something... |
1027 | */ | | 1027 | */ |
1028 | (void)Lst_AtEnd(create, bmake_strdup(src)); | | 1028 | (void)Lst_AtEnd(create, bmake_strdup(src)); |
1029 | /* | | 1029 | /* |
1030 | * Add the name to the .TARGETS variable as well, so the user can | | 1030 | * Add the name to the .TARGETS variable as well, so the user can |
1031 | * employ that, if desired. | | 1031 | * employ that, if desired. |
1032 | */ | | 1032 | */ |
1033 | Var_Append(".TARGETS", src, VAR_GLOBAL); | | 1033 | Var_Append(".TARGETS", src, VAR_GLOBAL); |
1034 | return; | | 1034 | return; |
1035 | | | 1035 | |
1036 | case Order: | | 1036 | case Order: |
1037 | /* | | 1037 | /* |
1038 | * Create proper predecessor/successor links between the previous | | 1038 | * Create proper predecessor/successor links between the previous |
1039 | * source and the current one. | | 1039 | * source and the current one. |
1040 | */ | | 1040 | */ |
1041 | gn = Targ_FindNode(src, TARG_CREATE); | | 1041 | gn = Targ_FindNode(src, TARG_CREATE); |
1042 | if (doing_depend) | | 1042 | if (doing_depend) |
1043 | ParseMark(gn); | | 1043 | ParseMark(gn); |
1044 | if (predecessor != NULL) { | | 1044 | if (predecessor != NULL) { |
1045 | (void)Lst_AtEnd(predecessor->order_succ, gn); | | 1045 | (void)Lst_AtEnd(predecessor->order_succ, gn); |
1046 | (void)Lst_AtEnd(gn->order_pred, predecessor); | | 1046 | (void)Lst_AtEnd(gn->order_pred, predecessor); |
1047 | if (DEBUG(PARSE)) { | | 1047 | if (DEBUG(PARSE)) { |
1048 | fprintf(debug_file, "# %s: added Order dependency %s - %s\n", | | 1048 | fprintf(debug_file, "# %s: added Order dependency %s - %s\n", |
1049 | __func__, predecessor->name, gn->name); | | 1049 | __func__, predecessor->name, gn->name); |
1050 | Targ_PrintNode(predecessor, 0); | | 1050 | Targ_PrintNode(predecessor, 0); |
1051 | Targ_PrintNode(gn, 0); | | 1051 | Targ_PrintNode(gn, 0); |
1052 | } | | 1052 | } |
1053 | } | | 1053 | } |
1054 | /* | | 1054 | /* |
1055 | * The current source now becomes the predecessor for the next one. | | 1055 | * The current source now becomes the predecessor for the next one. |
1056 | */ | | 1056 | */ |
1057 | predecessor = gn; | | 1057 | predecessor = gn; |
1058 | break; | | 1058 | break; |
1059 | | | 1059 | |
1060 | default: | | 1060 | default: |
1061 | /* | | 1061 | /* |
1062 | * If the source is not an attribute, we need to find/create | | 1062 | * If the source is not an attribute, we need to find/create |
1063 | * a node for it. After that we can apply any operator to it | | 1063 | * a node for it. After that we can apply any operator to it |
1064 | * from a special target or link it to its parents, as | | 1064 | * from a special target or link it to its parents, as |
1065 | * appropriate. | | 1065 | * appropriate. |
1066 | * | | 1066 | * |
1067 | * In the case of a source that was the object of a :: operator, | | 1067 | * In the case of a source that was the object of a :: operator, |
1068 | * the attribute is applied to all of its instances (as kept in | | 1068 | * the attribute is applied to all of its instances (as kept in |
1069 | * the 'cohorts' list of the node) or all the cohorts are linked | | 1069 | * the 'cohorts' list of the node) or all the cohorts are linked |
1070 | * to all the targets. | | 1070 | * to all the targets. |
1071 | */ | | 1071 | */ |
1072 | | | 1072 | |
1073 | /* Find/create the 'src' node and attach to all targets */ | | 1073 | /* Find/create the 'src' node and attach to all targets */ |
1074 | gn = Targ_FindNode(src, TARG_CREATE); | | 1074 | gn = Targ_FindNode(src, TARG_CREATE); |
1075 | if (doing_depend) | | 1075 | if (doing_depend) |
1076 | ParseMark(gn); | | 1076 | ParseMark(gn); |
1077 | if (tOp) { | | 1077 | if (tOp) { |
1078 | gn->type |= tOp; | | 1078 | gn->type |= tOp; |
1079 | } else { | | 1079 | } else { |
1080 | Lst_ForEach(targets, ParseLinkSrc, gn); | | 1080 | Lst_ForEach(targets, ParseLinkSrc, gn); |
1081 | } | | 1081 | } |
1082 | break; | | 1082 | break; |
1083 | } | | 1083 | } |
1084 | } | | 1084 | } |
1085 | | | 1085 | |
1086 | /*- | | 1086 | /*- |
1087 | *----------------------------------------------------------------------- | | 1087 | *----------------------------------------------------------------------- |
1088 | * ParseFindMain -- | | 1088 | * ParseFindMain -- |
1089 | * Find a real target in the list and set it to be the main one. | | 1089 | * Find a real target in the list and set it to be the main one. |
1090 | * Called by ParseDoDependency when a main target hasn't been found | | 1090 | * Called by ParseDoDependency when a main target hasn't been found |
1091 | * yet. | | 1091 | * yet. |
1092 | * | | 1092 | * |
1093 | * Input: | | 1093 | * Input: |
1094 | * gnp Node to examine | | 1094 | * gnp Node to examine |
1095 | * | | 1095 | * |
1096 | * Results: | | 1096 | * Results: |
1097 | * 0 if main not found yet, 1 if it is. | | 1097 | * 0 if main not found yet, 1 if it is. |
1098 | * | | 1098 | * |
1099 | * Side Effects: | | 1099 | * Side Effects: |
1100 | * mainNode is changed and Targ_SetMain is called. | | 1100 | * mainNode is changed and Targ_SetMain is called. |
1101 | * | | 1101 | * |
1102 | *----------------------------------------------------------------------- | | 1102 | *----------------------------------------------------------------------- |
1103 | */ | | 1103 | */ |
1104 | static int | | 1104 | static int |
1105 | ParseFindMain(void *gnp, void *dummy MAKE_ATTR_UNUSED) | | 1105 | ParseFindMain(void *gnp, void *dummy MAKE_ATTR_UNUSED) |
1106 | { | | 1106 | { |
1107 | GNode *gn = (GNode *)gnp; | | 1107 | GNode *gn = (GNode *)gnp; |
1108 | if ((gn->type & OP_NOTARGET) == 0) { | | 1108 | if ((gn->type & OP_NOTARGET) == 0) { |
1109 | mainNode = gn; | | 1109 | mainNode = gn; |
1110 | Targ_SetMain(gn); | | 1110 | Targ_SetMain(gn); |
1111 | return 1; | | 1111 | return 1; |
1112 | } else { | | 1112 | } else { |
1113 | return 0; | | 1113 | return 0; |
1114 | } | | 1114 | } |
1115 | } | | 1115 | } |
1116 | | | 1116 | |
1117 | /*- | | 1117 | /*- |
1118 | *----------------------------------------------------------------------- | | 1118 | *----------------------------------------------------------------------- |
1119 | * ParseAddDir -- | | 1119 | * ParseAddDir -- |
1120 | * Front-end for Dir_AddDir to make sure Lst_ForEach keeps going | | 1120 | * Front-end for Dir_AddDir to make sure Lst_ForEach keeps going |
1121 | * | | 1121 | * |
1122 | * Results: | | 1122 | * Results: |
1123 | * === 0 | | 1123 | * === 0 |
1124 | * | | 1124 | * |
1125 | * Side Effects: | | 1125 | * Side Effects: |
1126 | * See Dir_AddDir. | | 1126 | * See Dir_AddDir. |
1127 | * | | 1127 | * |
1128 | *----------------------------------------------------------------------- | | 1128 | *----------------------------------------------------------------------- |
1129 | */ | | 1129 | */ |
1130 | static int | | 1130 | static int |
1131 | ParseAddDir(void *path, void *name) | | 1131 | ParseAddDir(void *path, void *name) |
1132 | { | | 1132 | { |
1133 | (void)Dir_AddDir((Lst) path, (char *)name); | | 1133 | (void)Dir_AddDir((Lst) path, (char *)name); |
1134 | return 0; | | 1134 | return 0; |
1135 | } | | 1135 | } |
1136 | | | 1136 | |
1137 | /*- | | 1137 | /*- |
1138 | *----------------------------------------------------------------------- | | 1138 | *----------------------------------------------------------------------- |
1139 | * ParseClearPath -- | | 1139 | * ParseClearPath -- |
1140 | * Front-end for Dir_ClearPath to make sure Lst_ForEach keeps going | | 1140 | * Front-end for Dir_ClearPath to make sure Lst_ForEach keeps going |
1141 | * | | 1141 | * |
1142 | * Results: | | 1142 | * Results: |
1143 | * === 0 | | 1143 | * === 0 |
1144 | * | | 1144 | * |
1145 | * Side Effects: | | 1145 | * Side Effects: |
1146 | * See Dir_ClearPath | | 1146 | * See Dir_ClearPath |
1147 | * | | 1147 | * |
1148 | *----------------------------------------------------------------------- | | 1148 | *----------------------------------------------------------------------- |
1149 | */ | | 1149 | */ |
1150 | static int | | 1150 | static int |
1151 | ParseClearPath(void *path, void *dummy MAKE_ATTR_UNUSED) | | 1151 | ParseClearPath(void *path, void *dummy MAKE_ATTR_UNUSED) |
1152 | { | | 1152 | { |
1153 | Dir_ClearPath((Lst) path); | | 1153 | Dir_ClearPath((Lst) path); |
1154 | return 0; | | 1154 | return 0; |
1155 | } | | 1155 | } |
1156 | | | 1156 | |
1157 | /*- | | 1157 | /*- |
1158 | *--------------------------------------------------------------------- | | 1158 | *--------------------------------------------------------------------- |
1159 | * ParseDoDependency -- | | 1159 | * ParseDoDependency -- |
1160 | * Parse the dependency line in line. | | 1160 | * Parse the dependency line in line. |
1161 | * | | 1161 | * |
1162 | * Input: | | 1162 | * Input: |
1163 | * line the line to parse | | 1163 | * line the line to parse |
1164 | * | | 1164 | * |
1165 | * Results: | | 1165 | * Results: |
1166 | * None | | 1166 | * None |
1167 | * | | 1167 | * |
1168 | * Side Effects: | | 1168 | * Side Effects: |
1169 | * The nodes of the sources are linked as children to the nodes of the | | 1169 | * The nodes of the sources are linked as children to the nodes of the |
1170 | * targets. Some nodes may be created. | | 1170 | * targets. Some nodes may be created. |
1171 | * | | 1171 | * |
1172 | * We parse a dependency line by first extracting words from the line and | | 1172 | * We parse a dependency line by first extracting words from the line and |
1173 | * finding nodes in the list of all targets with that name. This is done | | 1173 | * finding nodes in the list of all targets with that name. This is done |
1174 | * until a character is encountered which is an operator character. Currently | | 1174 | * until a character is encountered which is an operator character. Currently |
1175 | * these are only ! and :. At this point the operator is parsed and the | | 1175 | * these are only ! and :. At this point the operator is parsed and the |
1176 | * pointer into the line advanced until the first source is encountered. | | 1176 | * pointer into the line advanced until the first source is encountered. |
1177 | * The parsed operator is applied to each node in the 'targets' list, | | 1177 | * The parsed operator is applied to each node in the 'targets' list, |
1178 | * which is where the nodes found for the targets are kept, by means of | | 1178 | * which is where the nodes found for the targets are kept, by means of |
1179 | * the ParseDoOp function. | | 1179 | * the ParseDoOp function. |
1180 | * The sources are read in much the same way as the targets were except | | 1180 | * The sources are read in much the same way as the targets were except |
1181 | * that now they are expanded using the wildcarding scheme of the C-Shell | | 1181 | * that now they are expanded using the wildcarding scheme of the C-Shell |
1182 | * and all instances of the resulting words in the list of all targets | | 1182 | * and all instances of the resulting words in the list of all targets |
1183 | * are found. Each of the resulting nodes is then linked to each of the | | 1183 | * are found. Each of the resulting nodes is then linked to each of the |
1184 | * targets as one of its children. | | 1184 | * targets as one of its children. |
1185 | * Certain targets are handled specially. These are the ones detailed | | 1185 | * Certain targets are handled specially. These are the ones detailed |
1186 | * by the specType variable. | | 1186 | * by the specType variable. |
1187 | * The storing of transformation rules is also taken care of here. | | 1187 | * The storing of transformation rules is also taken care of here. |
1188 | * A target is recognized as a transformation rule by calling | | 1188 | * A target is recognized as a transformation rule by calling |
1189 | * Suff_IsTransform. If it is a transformation rule, its node is gotten | | 1189 | * Suff_IsTransform. If it is a transformation rule, its node is gotten |
1190 | * from the suffix module via Suff_AddTransform rather than the standard | | 1190 | * from the suffix module via Suff_AddTransform rather than the standard |
1191 | * Targ_FindNode in the target module. | | 1191 | * Targ_FindNode in the target module. |
1192 | *--------------------------------------------------------------------- | | 1192 | *--------------------------------------------------------------------- |
1193 | */ | | 1193 | */ |
1194 | static void | | 1194 | static void |
1195 | ParseDoDependency(char *line) | | 1195 | ParseDoDependency(char *line) |
1196 | { | | 1196 | { |
1197 | char *cp; /* our current position */ | | 1197 | char *cp; /* our current position */ |
1198 | GNode *gn = NULL; /* a general purpose temporary node */ | | 1198 | GNode *gn = NULL; /* a general purpose temporary node */ |
1199 | int op; /* the operator on the line */ | | 1199 | int op; /* the operator on the line */ |
1200 | char savec; /* a place to save a character */ | | 1200 | char savec; /* a place to save a character */ |
1201 | Lst paths; /* List of search paths to alter when parsing | | 1201 | Lst paths; /* List of search paths to alter when parsing |
1202 | * a list of .PATH targets */ | | 1202 | * a list of .PATH targets */ |
1203 | int tOp; /* operator from special target */ | | 1203 | int tOp; /* operator from special target */ |
1204 | Lst sources; /* list of archive source names after | | 1204 | Lst sources; /* list of archive source names after |
1205 | * expansion */ | | 1205 | * expansion */ |
1206 | Lst curTargs; /* list of target names to be found and added | | 1206 | Lst curTargs; /* list of target names to be found and added |
1207 | * to the targets list */ | | 1207 | * to the targets list */ |
1208 | char *lstart = line; | | 1208 | char *lstart = line; |
1209 | | | 1209 | |
1210 | if (DEBUG(PARSE)) | | 1210 | if (DEBUG(PARSE)) |
1211 | fprintf(debug_file, "ParseDoDependency(%s)\n", line); | | 1211 | fprintf(debug_file, "ParseDoDependency(%s)\n", line); |
1212 | tOp = 0; | | 1212 | tOp = 0; |
1213 | | | 1213 | |
1214 | specType = Not; | | 1214 | specType = Not; |
1215 | paths = NULL; | | 1215 | paths = NULL; |
1216 | | | 1216 | |
1217 | curTargs = Lst_Init(FALSE); | | 1217 | curTargs = Lst_Init(FALSE); |
1218 | | | 1218 | |
1219 | /* | | 1219 | /* |
1220 | * First, grind through the targets. | | 1220 | * First, grind through the targets. |
1221 | */ | | 1221 | */ |
1222 | | | 1222 | |
1223 | do { | | 1223 | do { |
1224 | /* | | 1224 | /* |
1225 | * Here LINE points to the beginning of the next word, and | | 1225 | * Here LINE points to the beginning of the next word, and |
1226 | * LSTART points to the actual beginning of the line. | | 1226 | * LSTART points to the actual beginning of the line. |
1227 | */ | | 1227 | */ |
1228 | | | 1228 | |
1229 | /* Find the end of the next word. */ | | 1229 | /* Find the end of the next word. */ |
1230 | for (cp = line; *cp && (ParseIsEscaped(lstart, cp) || | | 1230 | for (cp = line; *cp && (ParseIsEscaped(lstart, cp) || |
1231 | !(isspace((unsigned char)*cp) || | | 1231 | !(isspace((unsigned char)*cp) || |
1232 | *cp == '!' || *cp == ':' || *cp == LPAREN)); | | 1232 | *cp == '!' || *cp == ':' || *cp == LPAREN)); |
1233 | cp++) { | | 1233 | cp++) { |
1234 | if (*cp == '$') { | | 1234 | if (*cp == '$') { |
1235 | /* | | 1235 | /* |
1236 | * Must be a dynamic source (would have been expanded | | 1236 | * Must be a dynamic source (would have been expanded |
1237 | * otherwise), so call the Var module to parse the puppy | | 1237 | * otherwise), so call the Var module to parse the puppy |
1238 | * so we can safely advance beyond it...There should be | | 1238 | * so we can safely advance beyond it...There should be |
1239 | * no errors in this, as they would have been discovered | | 1239 | * no errors in this, as they would have been discovered |
1240 | * in the initial Var_Subst and we wouldn't be here. | | 1240 | * in the initial Var_Subst and we wouldn't be here. |
1241 | */ | | 1241 | */ |
1242 | int length; | | 1242 | int length; |
1243 | void *freeIt; | | 1243 | void *freeIt; |
1244 | | | 1244 | |
1245 | (void)Var_Parse(cp, VAR_CMD, VARE_UNDEFERR|VARE_WANTRES, | | 1245 | (void)Var_Parse(cp, VAR_CMD, VARE_UNDEFERR|VARE_WANTRES, |
1246 | &length, &freeIt); | | 1246 | &length, &freeIt); |
1247 | free(freeIt); | | 1247 | free(freeIt); |
1248 | cp += length-1; | | 1248 | cp += length-1; |
1249 | } | | 1249 | } |
1250 | } | | 1250 | } |
1251 | | | 1251 | |
1252 | /* | | 1252 | /* |
1253 | * If the word is followed by a left parenthesis, it's the | | 1253 | * If the word is followed by a left parenthesis, it's the |
1254 | * name of an object file inside an archive (ar file). | | 1254 | * name of an object file inside an archive (ar file). |
1255 | */ | | 1255 | */ |
1256 | if (!ParseIsEscaped(lstart, cp) && *cp == LPAREN) { | | 1256 | if (!ParseIsEscaped(lstart, cp) && *cp == LPAREN) { |
1257 | /* | | 1257 | /* |
1258 | * Archives must be handled specially to make sure the OP_ARCHV | | 1258 | * Archives must be handled specially to make sure the OP_ARCHV |
1259 | * flag is set in their 'type' field, for one thing, and because | | 1259 | * flag is set in their 'type' field, for one thing, and because |
1260 | * things like "archive(file1.o file2.o file3.o)" are permissible. | | 1260 | * things like "archive(file1.o file2.o file3.o)" are permissible. |
1261 | * Arch_ParseArchive will set 'line' to be the first non-blank | | 1261 | * Arch_ParseArchive will set 'line' to be the first non-blank |
1262 | * after the archive-spec. It creates/finds nodes for the members | | 1262 | * after the archive-spec. It creates/finds nodes for the members |
1263 | * and places them on the given list, returning SUCCESS if all | | 1263 | * and places them on the given list, returning SUCCESS if all |
1264 | * went well and FAILURE if there was an error in the | | 1264 | * went well and FAILURE if there was an error in the |
1265 | * specification. On error, line should remain untouched. | | 1265 | * specification. On error, line should remain untouched. |
1266 | */ | | 1266 | */ |
1267 | if (Arch_ParseArchive(&line, targets, VAR_CMD) != SUCCESS) { | | 1267 | if (Arch_ParseArchive(&line, targets, VAR_CMD) != SUCCESS) { |
1268 | Parse_Error(PARSE_FATAL, | | 1268 | Parse_Error(PARSE_FATAL, |
1269 | "Error in archive specification: \"%s\"", line); | | 1269 | "Error in archive specification: \"%s\"", line); |
1270 | goto out; | | 1270 | goto out; |
1271 | } else { | | 1271 | } else { |
1272 | /* Done with this word; on to the next. */ | | 1272 | /* Done with this word; on to the next. */ |
1273 | cp = line; | | 1273 | cp = line; |
1274 | continue; | | 1274 | continue; |
1275 | } | | 1275 | } |
1276 | } | | 1276 | } |
1277 | | | 1277 | |
1278 | if (!*cp) { | | 1278 | if (!*cp) { |
1279 | /* | | 1279 | /* |
1280 | * We got to the end of the line while we were still | | 1280 | * We got to the end of the line while we were still |
1281 | * looking at targets. | | 1281 | * looking at targets. |
1282 | * | | 1282 | * |
1283 | * Ending a dependency line without an operator is a Bozo | | 1283 | * Ending a dependency line without an operator is a Bozo |
1284 | * no-no. As a heuristic, this is also often triggered by | | 1284 | * no-no. As a heuristic, this is also often triggered by |
1285 | * undetected conflicts from cvs/rcs merges. | | 1285 | * undetected conflicts from cvs/rcs merges. |
1286 | */ | | 1286 | */ |
1287 | if ((strncmp(line, "<<<<<<", 6) == 0) || | | 1287 | if ((strncmp(line, "<<<<<<", 6) == 0) || |
1288 | (strncmp(line, "======", 6) == 0) || | | 1288 | (strncmp(line, "======", 6) == 0) || |
1289 | (strncmp(line, ">>>>>>", 6) == 0)) | | 1289 | (strncmp(line, ">>>>>>", 6) == 0)) |
1290 | Parse_Error(PARSE_FATAL, | | 1290 | Parse_Error(PARSE_FATAL, |
1291 | "Makefile appears to contain unresolved cvs/rcs/??? merge conflicts"); | | 1291 | "Makefile appears to contain unresolved cvs/rcs/??? merge conflicts"); |
1292 | else | | 1292 | else if (lstart[0] == '.') { |
| | | 1293 | const char *dirstart = lstart + 1; |
| | | 1294 | while (isspace((unsigned char)*dirstart)) |
| | | 1295 | dirstart++; |
| | | 1296 | const char *dirend = dirstart; |
| | | 1297 | while (isalnum((unsigned char)*dirend) || *dirend == '-') |
| | | 1298 | dirend++; |
| | | 1299 | Parse_Error(PARSE_FATAL, "Unknown directive \"%.*s\"", |
| | | 1300 | (int)(dirend - dirstart), dirstart); |
| | | 1301 | } else |
1293 | Parse_Error(PARSE_FATAL, lstart[0] == '.' ? "Unknown directive" | | 1302 | Parse_Error(PARSE_FATAL, lstart[0] == '.' ? "Unknown directive" |
1294 | : "Need an operator"); | | 1303 | : "Need an operator"); |
1295 | goto out; | | 1304 | goto out; |
1296 | } | | 1305 | } |
1297 | | | 1306 | |
1298 | /* Insert a null terminator. */ | | 1307 | /* Insert a null terminator. */ |
1299 | savec = *cp; | | 1308 | savec = *cp; |
1300 | *cp = '\0'; | | 1309 | *cp = '\0'; |
1301 | | | 1310 | |
1302 | /* | | 1311 | /* |
1303 | * Got the word. See if it's a special target and if so set | | 1312 | * Got the word. See if it's a special target and if so set |
1304 | * specType to match it. | | 1313 | * specType to match it. |
1305 | */ | | 1314 | */ |
1306 | if (*line == '.' && isupper ((unsigned char)line[1])) { | | 1315 | if (*line == '.' && isupper ((unsigned char)line[1])) { |
1307 | /* | | 1316 | /* |
1308 | * See if the target is a special target that must have it | | 1317 | * See if the target is a special target that must have it |
1309 | * or its sources handled specially. | | 1318 | * or its sources handled specially. |
1310 | */ | | 1319 | */ |
1311 | int keywd = ParseFindKeyword(line); | | 1320 | int keywd = ParseFindKeyword(line); |
1312 | if (keywd != -1) { | | 1321 | if (keywd != -1) { |
1313 | if (specType == ExPath && parseKeywords[keywd].spec != ExPath) { | | 1322 | if (specType == ExPath && parseKeywords[keywd].spec != ExPath) { |
1314 | Parse_Error(PARSE_FATAL, "Mismatched special targets"); | | 1323 | Parse_Error(PARSE_FATAL, "Mismatched special targets"); |
1315 | goto out; | | 1324 | goto out; |
1316 | } | | 1325 | } |
1317 | | | 1326 | |
1318 | specType = parseKeywords[keywd].spec; | | 1327 | specType = parseKeywords[keywd].spec; |
1319 | tOp = parseKeywords[keywd].op; | | 1328 | tOp = parseKeywords[keywd].op; |
1320 | | | 1329 | |
1321 | /* | | 1330 | /* |
1322 | * Certain special targets have special semantics: | | 1331 | * Certain special targets have special semantics: |
1323 | * .PATH Have to set the dirSearchPath | | 1332 | * .PATH Have to set the dirSearchPath |
1324 | * variable too | | 1333 | * variable too |
1325 | * .MAIN Its sources are only used if | | 1334 | * .MAIN Its sources are only used if |
1326 | * nothing has been specified to | | 1335 | * nothing has been specified to |
1327 | * create. | | 1336 | * create. |
1328 | * .DEFAULT Need to create a node to hang | | 1337 | * .DEFAULT Need to create a node to hang |
1329 | * commands on, but we don't want | | 1338 | * commands on, but we don't want |
1330 | * it in the graph, nor do we want | | 1339 | * it in the graph, nor do we want |
1331 | * it to be the Main Target, so we | | 1340 | * it to be the Main Target, so we |
1332 | * create it, set OP_NOTMAIN and | | 1341 | * create it, set OP_NOTMAIN and |
1333 | * add it to the list, setting | | 1342 | * add it to the list, setting |
1334 | * DEFAULT to the new node for | | 1343 | * DEFAULT to the new node for |
1335 | * later use. We claim the node is | | 1344 | * later use. We claim the node is |
1336 | * A transformation rule to make | | 1345 | * A transformation rule to make |
1337 | * life easier later, when we'll | | 1346 | * life easier later, when we'll |
1338 | * use Make_HandleUse to actually | | 1347 | * use Make_HandleUse to actually |
1339 | * apply the .DEFAULT commands. | | 1348 | * apply the .DEFAULT commands. |
1340 | * .PHONY The list of targets | | 1349 | * .PHONY The list of targets |
1341 | * .NOPATH Don't search for file in the path | | 1350 | * .NOPATH Don't search for file in the path |
1342 | * .STALE | | 1351 | * .STALE |
1343 | * .BEGIN | | 1352 | * .BEGIN |
1344 | * .END | | 1353 | * .END |
1345 | * .ERROR | | 1354 | * .ERROR |
1346 | * .DELETE_ON_ERROR | | 1355 | * .DELETE_ON_ERROR |
1347 | * .INTERRUPT Are not to be considered the | | 1356 | * .INTERRUPT Are not to be considered the |
1348 | * main target. | | 1357 | * main target. |
1349 | * .NOTPARALLEL Make only one target at a time. | | 1358 | * .NOTPARALLEL Make only one target at a time. |
1350 | * .SINGLESHELL Create a shell for each command. | | 1359 | * .SINGLESHELL Create a shell for each command. |
1351 | * .ORDER Must set initial predecessor to NULL | | 1360 | * .ORDER Must set initial predecessor to NULL |
1352 | */ | | 1361 | */ |
1353 | switch (specType) { | | 1362 | switch (specType) { |
1354 | case ExPath: | | 1363 | case ExPath: |
1355 | if (paths == NULL) { | | 1364 | if (paths == NULL) { |
1356 | paths = Lst_Init(FALSE); | | 1365 | paths = Lst_Init(FALSE); |
1357 | } | | 1366 | } |
1358 | (void)Lst_AtEnd(paths, dirSearchPath); | | 1367 | (void)Lst_AtEnd(paths, dirSearchPath); |
1359 | break; | | 1368 | break; |
1360 | case Main: | | 1369 | case Main: |
1361 | if (!Lst_IsEmpty(create)) { | | 1370 | if (!Lst_IsEmpty(create)) { |
1362 | specType = Not; | | 1371 | specType = Not; |
1363 | } | | 1372 | } |
1364 | break; | | 1373 | break; |
1365 | case Begin: | | 1374 | case Begin: |
1366 | case End: | | 1375 | case End: |
1367 | case Stale: | | 1376 | case Stale: |
1368 | case dotError: | | 1377 | case dotError: |
1369 | case Interrupt: | | 1378 | case Interrupt: |
1370 | gn = Targ_FindNode(line, TARG_CREATE); | | 1379 | gn = Targ_FindNode(line, TARG_CREATE); |
1371 | if (doing_depend) | | 1380 | if (doing_depend) |
1372 | ParseMark(gn); | | 1381 | ParseMark(gn); |
1373 | gn->type |= OP_NOTMAIN|OP_SPECIAL; | | 1382 | gn->type |= OP_NOTMAIN|OP_SPECIAL; |
1374 | (void)Lst_AtEnd(targets, gn); | | 1383 | (void)Lst_AtEnd(targets, gn); |
1375 | break; | | 1384 | break; |
1376 | case Default: | | 1385 | case Default: |
1377 | gn = Targ_NewGN(".DEFAULT"); | | 1386 | gn = Targ_NewGN(".DEFAULT"); |
1378 | gn->type |= (OP_NOTMAIN|OP_TRANSFORM); | | 1387 | gn->type |= (OP_NOTMAIN|OP_TRANSFORM); |
1379 | (void)Lst_AtEnd(targets, gn); | | 1388 | (void)Lst_AtEnd(targets, gn); |
1380 | DEFAULT = gn; | | 1389 | DEFAULT = gn; |
1381 | break; | | 1390 | break; |
1382 | case DeleteOnError: | | 1391 | case DeleteOnError: |
1383 | deleteOnError = TRUE; | | 1392 | deleteOnError = TRUE; |
1384 | break; | | 1393 | break; |
1385 | case NotParallel: | | 1394 | case NotParallel: |
1386 | maxJobs = 1; | | 1395 | maxJobs = 1; |
1387 | break; | | 1396 | break; |
1388 | case SingleShell: | | 1397 | case SingleShell: |
1389 | compatMake = TRUE; | | 1398 | compatMake = TRUE; |
1390 | break; | | 1399 | break; |
1391 | case Order: | | 1400 | case Order: |
1392 | predecessor = NULL; | | 1401 | predecessor = NULL; |
1393 | break; | | 1402 | break; |
1394 | default: | | 1403 | default: |
1395 | break; | | 1404 | break; |
1396 | } | | 1405 | } |
1397 | } else if (strncmp(line, ".PATH", 5) == 0) { | | 1406 | } else if (strncmp(line, ".PATH", 5) == 0) { |
1398 | /* | | 1407 | /* |
1399 | * .PATH<suffix> has to be handled specially. | | 1408 | * .PATH<suffix> has to be handled specially. |
1400 | * Call on the suffix module to give us a path to | | 1409 | * Call on the suffix module to give us a path to |
1401 | * modify. | | 1410 | * modify. |
1402 | */ | | 1411 | */ |
1403 | Lst path; | | 1412 | Lst path; |
1404 | | | 1413 | |
1405 | specType = ExPath; | | 1414 | specType = ExPath; |
1406 | path = Suff_GetPath(&line[5]); | | 1415 | path = Suff_GetPath(&line[5]); |
1407 | if (path == NULL) { | | 1416 | if (path == NULL) { |
1408 | Parse_Error(PARSE_FATAL, | | 1417 | Parse_Error(PARSE_FATAL, |
1409 | "Suffix '%s' not defined (yet)", | | 1418 | "Suffix '%s' not defined (yet)", |
1410 | &line[5]); | | 1419 | &line[5]); |
1411 | goto out; | | 1420 | goto out; |
1412 | } else { | | 1421 | } else { |
1413 | if (paths == NULL) { | | 1422 | if (paths == NULL) { |
1414 | paths = Lst_Init(FALSE); | | 1423 | paths = Lst_Init(FALSE); |
1415 | } | | 1424 | } |
1416 | (void)Lst_AtEnd(paths, path); | | 1425 | (void)Lst_AtEnd(paths, path); |
1417 | } | | 1426 | } |
1418 | } | | 1427 | } |
1419 | } | | 1428 | } |
1420 | | | 1429 | |
1421 | /* | | 1430 | /* |
1422 | * Have word in line. Get or create its node and stick it at | | 1431 | * Have word in line. Get or create its node and stick it at |
1423 | * the end of the targets list | | 1432 | * the end of the targets list |
1424 | */ | | 1433 | */ |
1425 | if ((specType == Not) && (*line != '\0')) { | | 1434 | if ((specType == Not) && (*line != '\0')) { |
1426 | if (Dir_HasWildcards(line)) { | | 1435 | if (Dir_HasWildcards(line)) { |
1427 | /* | | 1436 | /* |
1428 | * Targets are to be sought only in the current directory, | | 1437 | * Targets are to be sought only in the current directory, |
1429 | * so create an empty path for the thing. Note we need to | | 1438 | * so create an empty path for the thing. Note we need to |
1430 | * use Dir_Destroy in the destruction of the path as the | | 1439 | * use Dir_Destroy in the destruction of the path as the |
1431 | * Dir module could have added a directory to the path... | | 1440 | * Dir module could have added a directory to the path... |
1432 | */ | | 1441 | */ |
1433 | Lst emptyPath = Lst_Init(FALSE); | | 1442 | Lst emptyPath = Lst_Init(FALSE); |
1434 | | | 1443 | |
1435 | Dir_Expand(line, emptyPath, curTargs); | | 1444 | Dir_Expand(line, emptyPath, curTargs); |
1436 | | | 1445 | |
1437 | Lst_Destroy(emptyPath, Dir_Destroy); | | 1446 | Lst_Destroy(emptyPath, Dir_Destroy); |
1438 | } else { | | 1447 | } else { |
1439 | /* | | 1448 | /* |
1440 | * No wildcards, but we want to avoid code duplication, | | 1449 | * No wildcards, but we want to avoid code duplication, |
1441 | * so create a list with the word on it. | | 1450 | * so create a list with the word on it. |
1442 | */ | | 1451 | */ |
1443 | (void)Lst_AtEnd(curTargs, line); | | 1452 | (void)Lst_AtEnd(curTargs, line); |
1444 | } | | 1453 | } |
1445 | | | 1454 | |
1446 | /* Apply the targets. */ | | 1455 | /* Apply the targets. */ |
1447 | | | 1456 | |
1448 | while(!Lst_IsEmpty(curTargs)) { | | 1457 | while(!Lst_IsEmpty(curTargs)) { |
1449 | char *targName = (char *)Lst_DeQueue(curTargs); | | 1458 | char *targName = (char *)Lst_DeQueue(curTargs); |
1450 | | | 1459 | |
1451 | if (!Suff_IsTransform (targName)) { | | 1460 | if (!Suff_IsTransform (targName)) { |
1452 | gn = Targ_FindNode(targName, TARG_CREATE); | | 1461 | gn = Targ_FindNode(targName, TARG_CREATE); |
1453 | } else { | | 1462 | } else { |
1454 | gn = Suff_AddTransform(targName); | | 1463 | gn = Suff_AddTransform(targName); |
1455 | } | | 1464 | } |
1456 | if (doing_depend) | | 1465 | if (doing_depend) |
1457 | ParseMark(gn); | | 1466 | ParseMark(gn); |
1458 | | | 1467 | |
1459 | (void)Lst_AtEnd(targets, gn); | | 1468 | (void)Lst_AtEnd(targets, gn); |
1460 | } | | 1469 | } |
1461 | } else if (specType == ExPath && *line != '.' && *line != '\0') { | | 1470 | } else if (specType == ExPath && *line != '.' && *line != '\0') { |
1462 | Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line); | | 1471 | Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line); |
1463 | } | | 1472 | } |
1464 | | | 1473 | |
1465 | /* Don't need the inserted null terminator any more. */ | | 1474 | /* Don't need the inserted null terminator any more. */ |
1466 | *cp = savec; | | 1475 | *cp = savec; |
1467 | | | 1476 | |
1468 | /* | | 1477 | /* |
1469 | * If it is a special type and not .PATH, it's the only target we | | 1478 | * If it is a special type and not .PATH, it's the only target we |
1470 | * allow on this line... | | 1479 | * allow on this line... |
1471 | */ | | 1480 | */ |
1472 | if (specType != Not && specType != ExPath) { | | 1481 | if (specType != Not && specType != ExPath) { |
1473 | Boolean warning = FALSE; | | 1482 | Boolean warning = FALSE; |
1474 | | | 1483 | |
1475 | while (*cp && (ParseIsEscaped(lstart, cp) || | | 1484 | while (*cp && (ParseIsEscaped(lstart, cp) || |
1476 | ((*cp != '!') && (*cp != ':')))) { | | 1485 | ((*cp != '!') && (*cp != ':')))) { |
1477 | if (ParseIsEscaped(lstart, cp) || | | 1486 | if (ParseIsEscaped(lstart, cp) || |
1478 | (*cp != ' ' && *cp != '\t')) { | | 1487 | (*cp != ' ' && *cp != '\t')) { |
1479 | warning = TRUE; | | 1488 | warning = TRUE; |
1480 | } | | 1489 | } |
1481 | cp++; | | 1490 | cp++; |
1482 | } | | 1491 | } |
1483 | if (warning) { | | 1492 | if (warning) { |
1484 | Parse_Error(PARSE_WARNING, "Extra target ignored"); | | 1493 | Parse_Error(PARSE_WARNING, "Extra target ignored"); |
1485 | } | | 1494 | } |
1486 | } else { | | 1495 | } else { |
1487 | while (*cp && isspace ((unsigned char)*cp)) { | | 1496 | while (*cp && isspace ((unsigned char)*cp)) { |
1488 | cp++; | | 1497 | cp++; |
1489 | } | | 1498 | } |
1490 | } | | 1499 | } |
1491 | line = cp; | | 1500 | line = cp; |
1492 | } while (*line && (ParseIsEscaped(lstart, line) || | | 1501 | } while (*line && (ParseIsEscaped(lstart, line) || |
1493 | ((*line != '!') && (*line != ':')))); | | 1502 | ((*line != '!') && (*line != ':')))); |
1494 | | | 1503 | |
1495 | /* | | 1504 | /* |
1496 | * Don't need the list of target names anymore... | | 1505 | * Don't need the list of target names anymore... |
1497 | */ | | 1506 | */ |
1498 | Lst_Destroy(curTargs, NULL); | | 1507 | Lst_Destroy(curTargs, NULL); |
1499 | curTargs = NULL; | | 1508 | curTargs = NULL; |
1500 | | | 1509 | |
1501 | if (!Lst_IsEmpty(targets)) { | | 1510 | if (!Lst_IsEmpty(targets)) { |
1502 | switch(specType) { | | 1511 | switch(specType) { |
1503 | default: | | 1512 | default: |
1504 | Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. Mundane ones ignored"); | | 1513 | Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. Mundane ones ignored"); |
1505 | break; | | 1514 | break; |
1506 | case Default: | | 1515 | case Default: |
1507 | case Stale: | | 1516 | case Stale: |
1508 | case Begin: | | 1517 | case Begin: |
1509 | case End: | | 1518 | case End: |
1510 | case dotError: | | 1519 | case dotError: |
1511 | case Interrupt: | | 1520 | case Interrupt: |
1512 | /* | | 1521 | /* |
1513 | * These four create nodes on which to hang commands, so | | 1522 | * These four create nodes on which to hang commands, so |
1514 | * targets shouldn't be empty... | | 1523 | * targets shouldn't be empty... |
1515 | */ | | 1524 | */ |
1516 | case Not: | | 1525 | case Not: |
1517 | /* | | 1526 | /* |
1518 | * Nothing special here -- targets can be empty if it wants. | | 1527 | * Nothing special here -- targets can be empty if it wants. |
1519 | */ | | 1528 | */ |
1520 | break; | | 1529 | break; |
1521 | } | | 1530 | } |
1522 | } | | 1531 | } |
1523 | | | 1532 | |
1524 | /* | | 1533 | /* |
1525 | * Have now parsed all the target names. Must parse the operator next. The | | 1534 | * Have now parsed all the target names. Must parse the operator next. The |
1526 | * result is left in op . | | 1535 | * result is left in op . |
1527 | */ | | 1536 | */ |
1528 | if (*cp == '!') { | | 1537 | if (*cp == '!') { |
1529 | op = OP_FORCE; | | 1538 | op = OP_FORCE; |
1530 | } else if (*cp == ':') { | | 1539 | } else if (*cp == ':') { |
1531 | if (cp[1] == ':') { | | 1540 | if (cp[1] == ':') { |
1532 | op = OP_DOUBLEDEP; | | 1541 | op = OP_DOUBLEDEP; |
1533 | cp++; | | 1542 | cp++; |
1534 | } else { | | 1543 | } else { |
1535 | op = OP_DEPENDS; | | 1544 | op = OP_DEPENDS; |
1536 | } | | 1545 | } |
1537 | } else { | | 1546 | } else { |
1538 | Parse_Error(PARSE_FATAL, lstart[0] == '.' ? "Unknown directive" | | 1547 | Parse_Error(PARSE_FATAL, lstart[0] == '.' ? "Unknown directive" |
1539 | : "Missing dependency operator"); | | 1548 | : "Missing dependency operator"); |
1540 | goto out; | | 1549 | goto out; |
1541 | } | | 1550 | } |
1542 | | | 1551 | |
1543 | /* Advance beyond the operator */ | | 1552 | /* Advance beyond the operator */ |
1544 | cp++; | | 1553 | cp++; |
1545 | | | 1554 | |
1546 | /* | | 1555 | /* |
1547 | * Apply the operator to the target. This is how we remember which | | 1556 | * Apply the operator to the target. This is how we remember which |
1548 | * operator a target was defined with. It fails if the operator | | 1557 | * operator a target was defined with. It fails if the operator |
1549 | * used isn't consistent across all references. | | 1558 | * used isn't consistent across all references. |
1550 | */ | | 1559 | */ |
1551 | Lst_ForEach(targets, ParseDoOp, &op); | | 1560 | Lst_ForEach(targets, ParseDoOp, &op); |
1552 | | | 1561 | |
1553 | /* | | 1562 | /* |
1554 | * Onward to the sources. | | 1563 | * Onward to the sources. |
1555 | * | | 1564 | * |
1556 | * LINE will now point to the first source word, if any, or the | | 1565 | * LINE will now point to the first source word, if any, or the |
1557 | * end of the string if not. | | 1566 | * end of the string if not. |
1558 | */ | | 1567 | */ |
1559 | while (*cp && isspace ((unsigned char)*cp)) { | | 1568 | while (*cp && isspace ((unsigned char)*cp)) { |
1560 | cp++; | | 1569 | cp++; |
1561 | } | | 1570 | } |
1562 | line = cp; | | 1571 | line = cp; |
1563 | | | 1572 | |
1564 | /* | | 1573 | /* |
1565 | * Several special targets take different actions if present with no | | 1574 | * Several special targets take different actions if present with no |
1566 | * sources: | | 1575 | * sources: |
1567 | * a .SUFFIXES line with no sources clears out all old suffixes | | 1576 | * a .SUFFIXES line with no sources clears out all old suffixes |
1568 | * a .PRECIOUS line makes all targets precious | | 1577 | * a .PRECIOUS line makes all targets precious |
1569 | * a .IGNORE line ignores errors for all targets | | 1578 | * a .IGNORE line ignores errors for all targets |
1570 | * a .SILENT line creates silence when making all targets | | 1579 | * a .SILENT line creates silence when making all targets |
1571 | * a .PATH removes all directories from the search path(s). | | 1580 | * a .PATH removes all directories from the search path(s). |
1572 | */ | | 1581 | */ |
1573 | if (!*line) { | | 1582 | if (!*line) { |
1574 | switch (specType) { | | 1583 | switch (specType) { |
1575 | case Suffixes: | | 1584 | case Suffixes: |
1576 | Suff_ClearSuffixes(); | | 1585 | Suff_ClearSuffixes(); |
1577 | break; | | 1586 | break; |
1578 | case Precious: | | 1587 | case Precious: |
1579 | allPrecious = TRUE; | | 1588 | allPrecious = TRUE; |
1580 | break; | | 1589 | break; |
1581 | case Ignore: | | 1590 | case Ignore: |
1582 | ignoreErrors = TRUE; | | 1591 | ignoreErrors = TRUE; |
1583 | break; | | 1592 | break; |
1584 | case Silent: | | 1593 | case Silent: |
1585 | beSilent = TRUE; | | 1594 | beSilent = TRUE; |
1586 | break; | | 1595 | break; |
1587 | case ExPath: | | 1596 | case ExPath: |
1588 | Lst_ForEach(paths, ParseClearPath, NULL); | | 1597 | Lst_ForEach(paths, ParseClearPath, NULL); |
1589 | Dir_SetPATH(); | | 1598 | Dir_SetPATH(); |
1590 | break; | | 1599 | break; |
1591 | #ifdef POSIX | | 1600 | #ifdef POSIX |
1592 | case Posix: | | 1601 | case Posix: |
1593 | Var_Set("%POSIX", "1003.2", VAR_GLOBAL); | | 1602 | Var_Set("%POSIX", "1003.2", VAR_GLOBAL); |
1594 | break; | | 1603 | break; |
1595 | #endif | | 1604 | #endif |
1596 | default: | | 1605 | default: |
1597 | break; | | 1606 | break; |
1598 | } | | 1607 | } |
1599 | } else if (specType == MFlags) { | | 1608 | } else if (specType == MFlags) { |
1600 | /* | | 1609 | /* |
1601 | * Call on functions in main.c to deal with these arguments and | | 1610 | * Call on functions in main.c to deal with these arguments and |
1602 | * set the initial character to a null-character so the loop to | | 1611 | * set the initial character to a null-character so the loop to |
1603 | * get sources won't get anything | | 1612 | * get sources won't get anything |
1604 | */ | | 1613 | */ |
1605 | Main_ParseArgLine(line); | | 1614 | Main_ParseArgLine(line); |
1606 | *line = '\0'; | | 1615 | *line = '\0'; |
1607 | } else if (specType == ExShell) { | | 1616 | } else if (specType == ExShell) { |
1608 | if (Job_ParseShell(line) != SUCCESS) { | | 1617 | if (Job_ParseShell(line) != SUCCESS) { |
1609 | Parse_Error(PARSE_FATAL, "improper shell specification"); | | 1618 | Parse_Error(PARSE_FATAL, "improper shell specification"); |
1610 | goto out; | | 1619 | goto out; |
1611 | } | | 1620 | } |
1612 | *line = '\0'; | | 1621 | *line = '\0'; |
1613 | } else if ((specType == NotParallel) || (specType == SingleShell) || | | 1622 | } else if ((specType == NotParallel) || (specType == SingleShell) || |
1614 | (specType == DeleteOnError)) { | | 1623 | (specType == DeleteOnError)) { |
1615 | *line = '\0'; | | 1624 | *line = '\0'; |
1616 | } | | 1625 | } |
1617 | | | 1626 | |
1618 | /* | | 1627 | /* |
1619 | * NOW GO FOR THE SOURCES | | 1628 | * NOW GO FOR THE SOURCES |
1620 | */ | | 1629 | */ |
1621 | if ((specType == Suffixes) || (specType == ExPath) || | | 1630 | if ((specType == Suffixes) || (specType == ExPath) || |
1622 | (specType == Includes) || (specType == Libs) || | | 1631 | (specType == Includes) || (specType == Libs) || |
1623 | (specType == Null) || (specType == ExObjdir)) | | 1632 | (specType == Null) || (specType == ExObjdir)) |
1624 | { | | 1633 | { |
1625 | while (*line) { | | 1634 | while (*line) { |
1626 | /* | | 1635 | /* |
1627 | * If the target was one that doesn't take files as its sources | | 1636 | * If the target was one that doesn't take files as its sources |
1628 | * but takes something like suffixes, we take each | | 1637 | * but takes something like suffixes, we take each |
1629 | * space-separated word on the line as a something and deal | | 1638 | * space-separated word on the line as a something and deal |
1630 | * with it accordingly. | | 1639 | * with it accordingly. |
1631 | * | | 1640 | * |
1632 | * If the target was .SUFFIXES, we take each source as a | | 1641 | * If the target was .SUFFIXES, we take each source as a |
1633 | * suffix and add it to the list of suffixes maintained by the | | 1642 | * suffix and add it to the list of suffixes maintained by the |
1634 | * Suff module. | | 1643 | * Suff module. |
1635 | * | | 1644 | * |
1636 | * If the target was a .PATH, we add the source as a directory | | 1645 | * If the target was a .PATH, we add the source as a directory |
1637 | * to search on the search path. | | 1646 | * to search on the search path. |
1638 | * | | 1647 | * |
1639 | * If it was .INCLUDES, the source is taken to be the suffix of | | 1648 | * If it was .INCLUDES, the source is taken to be the suffix of |
1640 | * files which will be #included and whose search path should | | 1649 | * files which will be #included and whose search path should |
1641 | * be present in the .INCLUDES variable. | | 1650 | * be present in the .INCLUDES variable. |
1642 | * | | 1651 | * |
1643 | * If it was .LIBS, the source is taken to be the suffix of | | 1652 | * If it was .LIBS, the source is taken to be the suffix of |
1644 | * files which are considered libraries and whose search path | | 1653 | * files which are considered libraries and whose search path |
1645 | * should be present in the .LIBS variable. | | 1654 | * should be present in the .LIBS variable. |
1646 | * | | 1655 | * |
1647 | * If it was .NULL, the source is the suffix to use when a file | | 1656 | * If it was .NULL, the source is the suffix to use when a file |
1648 | * has no valid suffix. | | 1657 | * has no valid suffix. |
1649 | * | | 1658 | * |
1650 | * If it was .OBJDIR, the source is a new definition for .OBJDIR, | | 1659 | * If it was .OBJDIR, the source is a new definition for .OBJDIR, |
1651 | * and will cause make to do a new chdir to that path. | | 1660 | * and will cause make to do a new chdir to that path. |
1652 | */ | | 1661 | */ |
1653 | while (*cp && !isspace ((unsigned char)*cp)) { | | 1662 | while (*cp && !isspace ((unsigned char)*cp)) { |
1654 | cp++; | | 1663 | cp++; |
1655 | } | | 1664 | } |
1656 | savec = *cp; | | 1665 | savec = *cp; |
1657 | *cp = '\0'; | | 1666 | *cp = '\0'; |
1658 | switch (specType) { | | 1667 | switch (specType) { |
1659 | case Suffixes: | | 1668 | case Suffixes: |
1660 | Suff_AddSuffix(line, &mainNode); | | 1669 | Suff_AddSuffix(line, &mainNode); |
1661 | break; | | 1670 | break; |
1662 | case ExPath: | | 1671 | case ExPath: |
1663 | Lst_ForEach(paths, ParseAddDir, line); | | 1672 | Lst_ForEach(paths, ParseAddDir, line); |
1664 | break; | | 1673 | break; |
1665 | case Includes: | | 1674 | case Includes: |
1666 | Suff_AddInclude(line); | | 1675 | Suff_AddInclude(line); |
1667 | break; | | 1676 | break; |
1668 | case Libs: | | 1677 | case Libs: |
1669 | Suff_AddLib(line); | | 1678 | Suff_AddLib(line); |
1670 | break; | | 1679 | break; |
1671 | case Null: | | 1680 | case Null: |
1672 | Suff_SetNull(line); | | 1681 | Suff_SetNull(line); |
1673 | break; | | 1682 | break; |
1674 | case ExObjdir: | | 1683 | case ExObjdir: |
1675 | Main_SetObjdir("%s", line); | | 1684 | Main_SetObjdir("%s", line); |
1676 | break; | | 1685 | break; |
1677 | default: | | 1686 | default: |
1678 | break; | | 1687 | break; |
1679 | } | | 1688 | } |
1680 | *cp = savec; | | 1689 | *cp = savec; |
1681 | if (savec != '\0') { | | 1690 | if (savec != '\0') { |
1682 | cp++; | | 1691 | cp++; |
1683 | } | | 1692 | } |
1684 | while (*cp && isspace ((unsigned char)*cp)) { | | 1693 | while (*cp && isspace ((unsigned char)*cp)) { |
1685 | cp++; | | 1694 | cp++; |
1686 | } | | 1695 | } |
1687 | line = cp; | | 1696 | line = cp; |
1688 | } | | 1697 | } |
1689 | if (paths) { | | 1698 | if (paths) { |
1690 | Lst_Destroy(paths, NULL); | | 1699 | Lst_Destroy(paths, NULL); |
1691 | paths = NULL; | | 1700 | paths = NULL; |
1692 | } | | 1701 | } |
1693 | if (specType == ExPath) | | 1702 | if (specType == ExPath) |
1694 | Dir_SetPATH(); | | 1703 | Dir_SetPATH(); |
1695 | } else { | | 1704 | } else { |
1696 | assert(paths == NULL); | | 1705 | assert(paths == NULL); |
1697 | while (*line) { | | 1706 | while (*line) { |
1698 | /* | | 1707 | /* |
1699 | * The targets take real sources, so we must beware of archive | | 1708 | * The targets take real sources, so we must beware of archive |
1700 | * specifications (i.e. things with left parentheses in them) | | 1709 | * specifications (i.e. things with left parentheses in them) |
1701 | * and handle them accordingly. | | 1710 | * and handle them accordingly. |
1702 | */ | | 1711 | */ |
1703 | for (; *cp && !isspace ((unsigned char)*cp); cp++) { | | 1712 | for (; *cp && !isspace ((unsigned char)*cp); cp++) { |
1704 | if ((*cp == LPAREN) && (cp > line) && (cp[-1] != '$')) { | | 1713 | if ((*cp == LPAREN) && (cp > line) && (cp[-1] != '$')) { |
1705 | /* | | 1714 | /* |
1706 | * Only stop for a left parenthesis if it isn't at the | | 1715 | * Only stop for a left parenthesis if it isn't at the |
1707 | * start of a word (that'll be for variable changes | | 1716 | * start of a word (that'll be for variable changes |
1708 | * later) and isn't preceded by a dollar sign (a dynamic | | 1717 | * later) and isn't preceded by a dollar sign (a dynamic |
1709 | * source). | | 1718 | * source). |
1710 | */ | | 1719 | */ |
1711 | break; | | 1720 | break; |
1712 | } | | 1721 | } |
1713 | } | | 1722 | } |
1714 | | | 1723 | |
1715 | if (*cp == LPAREN) { | | 1724 | if (*cp == LPAREN) { |
1716 | sources = Lst_Init(FALSE); | | 1725 | sources = Lst_Init(FALSE); |
1717 | if (Arch_ParseArchive(&line, sources, VAR_CMD) != SUCCESS) { | | 1726 | if (Arch_ParseArchive(&line, sources, VAR_CMD) != SUCCESS) { |
1718 | Parse_Error(PARSE_FATAL, | | 1727 | Parse_Error(PARSE_FATAL, |
1719 | "Error in source archive spec \"%s\"", line); | | 1728 | "Error in source archive spec \"%s\"", line); |
1720 | goto out; | | 1729 | goto out; |
1721 | } | | 1730 | } |
1722 | | | 1731 | |
1723 | while (!Lst_IsEmpty (sources)) { | | 1732 | while (!Lst_IsEmpty (sources)) { |
1724 | gn = (GNode *)Lst_DeQueue(sources); | | 1733 | gn = (GNode *)Lst_DeQueue(sources); |
1725 | ParseDoSrc(tOp, gn->name); | | 1734 | ParseDoSrc(tOp, gn->name); |
1726 | } | | 1735 | } |
1727 | Lst_Destroy(sources, NULL); | | 1736 | Lst_Destroy(sources, NULL); |
1728 | cp = line; | | 1737 | cp = line; |
1729 | } else { | | 1738 | } else { |
1730 | if (*cp) { | | 1739 | if (*cp) { |
1731 | *cp = '\0'; | | 1740 | *cp = '\0'; |
1732 | cp += 1; | | 1741 | cp += 1; |
1733 | } | | 1742 | } |
1734 | | | 1743 | |
1735 | ParseDoSrc(tOp, line); | | 1744 | ParseDoSrc(tOp, line); |
1736 | } | | 1745 | } |
1737 | while (*cp && isspace ((unsigned char)*cp)) { | | 1746 | while (*cp && isspace ((unsigned char)*cp)) { |
1738 | cp++; | | 1747 | cp++; |
1739 | } | | 1748 | } |
1740 | line = cp; | | 1749 | line = cp; |
1741 | } | | 1750 | } |
1742 | } | | 1751 | } |
1743 | | | 1752 | |
1744 | if (mainNode == NULL) { | | 1753 | if (mainNode == NULL) { |
1745 | /* | | 1754 | /* |
1746 | * If we have yet to decide on a main target to make, in the | | 1755 | * If we have yet to decide on a main target to make, in the |
1747 | * absence of any user input, we want the first target on | | 1756 | * absence of any user input, we want the first target on |
1748 | * the first dependency line that is actually a real target | | 1757 | * the first dependency line that is actually a real target |
1749 | * (i.e. isn't a .USE or .EXEC rule) to be made. | | 1758 | * (i.e. isn't a .USE or .EXEC rule) to be made. |
1750 | */ | | 1759 | */ |
1751 | Lst_ForEach(targets, ParseFindMain, NULL); | | 1760 | Lst_ForEach(targets, ParseFindMain, NULL); |
1752 | } | | 1761 | } |
1753 | | | 1762 | |
1754 | out: | | 1763 | out: |
1755 | if (paths) | | 1764 | if (paths) |
1756 | Lst_Destroy(paths, NULL); | | 1765 | Lst_Destroy(paths, NULL); |
1757 | if (curTargs) | | 1766 | if (curTargs) |
1758 | Lst_Destroy(curTargs, NULL); | | 1767 | Lst_Destroy(curTargs, NULL); |
1759 | } | | 1768 | } |
1760 | | | 1769 | |
1761 | /*- | | 1770 | /*- |
1762 | *--------------------------------------------------------------------- | | 1771 | *--------------------------------------------------------------------- |
1763 | * Parse_IsVar -- | | 1772 | * Parse_IsVar -- |
1764 | * Return TRUE if the passed line is a variable assignment. A variable | | 1773 | * Return TRUE if the passed line is a variable assignment. A variable |
1765 | * assignment consists of a single word followed by optional whitespace | | 1774 | * assignment consists of a single word followed by optional whitespace |
1766 | * followed by either a += or an = operator. | | 1775 | * followed by either a += or an = operator. |
1767 | * This function is used both by the Parse_File function and main when | | 1776 | * This function is used both by the Parse_File function and main when |
1768 | * parsing the command-line arguments. | | 1777 | * parsing the command-line arguments. |
1769 | * | | 1778 | * |
1770 | * Input: | | 1779 | * Input: |
1771 | * line the line to check | | 1780 | * line the line to check |
1772 | * | | 1781 | * |
1773 | * Results: | | 1782 | * Results: |
1774 | * TRUE if it is. FALSE if it ain't | | 1783 | * TRUE if it is. FALSE if it ain't |
1775 | * | | 1784 | * |
1776 | * Side Effects: | | 1785 | * Side Effects: |
1777 | * none | | 1786 | * none |
1778 | *--------------------------------------------------------------------- | | 1787 | *--------------------------------------------------------------------- |
1779 | */ | | 1788 | */ |
1780 | Boolean | | 1789 | Boolean |
1781 | Parse_IsVar(char *line) | | 1790 | Parse_IsVar(char *line) |
1782 | { | | 1791 | { |
1783 | Boolean wasSpace = FALSE; /* set TRUE if found a space */ | | 1792 | Boolean wasSpace = FALSE; /* set TRUE if found a space */ |
1784 | char ch; | | 1793 | char ch; |
1785 | int level = 0; | | 1794 | int level = 0; |
1786 | #define ISEQOPERATOR(c) \ | | 1795 | #define ISEQOPERATOR(c) \ |
1787 | (((c) == '+') || ((c) == ':') || ((c) == '?') || ((c) == '!')) | | 1796 | (((c) == '+') || ((c) == ':') || ((c) == '?') || ((c) == '!')) |
1788 | | | 1797 | |
1789 | /* | | 1798 | /* |
1790 | * Skip to variable name | | 1799 | * Skip to variable name |
1791 | */ | | 1800 | */ |
1792 | for (;(*line == ' ') || (*line == '\t'); line++) | | 1801 | for (;(*line == ' ') || (*line == '\t'); line++) |
1793 | continue; | | 1802 | continue; |
1794 | | | 1803 | |
1795 | /* Scan for one of the assignment operators outside a variable expansion */ | | 1804 | /* Scan for one of the assignment operators outside a variable expansion */ |
1796 | while ((ch = *line++) != 0) { | | 1805 | while ((ch = *line++) != 0) { |
1797 | if (ch == '(' || ch == '{') { | | 1806 | if (ch == '(' || ch == '{') { |
1798 | level++; | | 1807 | level++; |
1799 | continue; | | 1808 | continue; |
1800 | } | | 1809 | } |
1801 | if (ch == ')' || ch == '}') { | | 1810 | if (ch == ')' || ch == '}') { |
1802 | level--; | | 1811 | level--; |
1803 | continue; | | 1812 | continue; |
1804 | } | | 1813 | } |
1805 | if (level != 0) | | 1814 | if (level != 0) |
1806 | continue; | | 1815 | continue; |
1807 | while (ch == ' ' || ch == '\t') { | | 1816 | while (ch == ' ' || ch == '\t') { |
1808 | ch = *line++; | | 1817 | ch = *line++; |
1809 | wasSpace = TRUE; | | 1818 | wasSpace = TRUE; |
1810 | } | | 1819 | } |
1811 | #ifdef SUNSHCMD | | 1820 | #ifdef SUNSHCMD |
1812 | if (ch == ':' && strncmp(line, "sh", 2) == 0) { | | 1821 | if (ch == ':' && strncmp(line, "sh", 2) == 0) { |
1813 | line += 2; | | 1822 | line += 2; |
1814 | continue; | | 1823 | continue; |
1815 | } | | 1824 | } |
1816 | #endif | | 1825 | #endif |
1817 | if (ch == '=') | | 1826 | if (ch == '=') |
1818 | return TRUE; | | 1827 | return TRUE; |
1819 | if (*line == '=' && ISEQOPERATOR(ch)) | | 1828 | if (*line == '=' && ISEQOPERATOR(ch)) |
1820 | return TRUE; | | 1829 | return TRUE; |
1821 | if (wasSpace) | | 1830 | if (wasSpace) |
1822 | return FALSE; | | 1831 | return FALSE; |
1823 | } | | 1832 | } |
1824 | | | 1833 | |
1825 | return FALSE; | | 1834 | return FALSE; |
1826 | } | | 1835 | } |
1827 | | | 1836 | |
1828 | /*- | | 1837 | /*- |
1829 | *--------------------------------------------------------------------- | | 1838 | *--------------------------------------------------------------------- |
1830 | * Parse_DoVar -- | | 1839 | * Parse_DoVar -- |
1831 | * Take the variable assignment in the passed line and do it in the | | 1840 | * Take the variable assignment in the passed line and do it in the |
1832 | * global context. | | 1841 | * global context. |
1833 | * | | 1842 | * |
1834 | * Note: There is a lexical ambiguity with assignment modifier characters | | 1843 | * Note: There is a lexical ambiguity with assignment modifier characters |
1835 | * in variable names. This routine interprets the character before the = | | 1844 | * in variable names. This routine interprets the character before the = |
1836 | * as a modifier. Therefore, an assignment like | | 1845 | * as a modifier. Therefore, an assignment like |
1837 | * C++=/usr/bin/CC | | 1846 | * C++=/usr/bin/CC |
1838 | * is interpreted as "C+ +=" instead of "C++ =". | | 1847 | * is interpreted as "C+ +=" instead of "C++ =". |
1839 | * | | 1848 | * |
1840 | * Input: | | 1849 | * Input: |
1841 | * line a line guaranteed to be a variable assignment. | | 1850 | * line a line guaranteed to be a variable assignment. |
1842 | * This reduces error checks | | 1851 | * This reduces error checks |
1843 | * ctxt Context in which to do the assignment | | 1852 | * ctxt Context in which to do the assignment |
1844 | * | | 1853 | * |
1845 | * Results: | | 1854 | * Results: |
1846 | * none | | 1855 | * none |
1847 | * | | 1856 | * |
1848 | * Side Effects: | | 1857 | * Side Effects: |
1849 | * the variable structure of the given variable name is altered in the | | 1858 | * the variable structure of the given variable name is altered in the |
1850 | * global context. | | 1859 | * global context. |
1851 | *--------------------------------------------------------------------- | | 1860 | *--------------------------------------------------------------------- |
1852 | */ | | 1861 | */ |
1853 | void | | 1862 | void |
1854 | Parse_DoVar(char *line, GNode *ctxt) | | 1863 | Parse_DoVar(char *line, GNode *ctxt) |
1855 | { | | 1864 | { |
1856 | char *cp; /* pointer into line */ | | 1865 | char *cp; /* pointer into line */ |
1857 | enum { | | 1866 | enum { |
1858 | VAR_SUBST, VAR_APPEND, VAR_SHELL, VAR_NORMAL | | 1867 | VAR_SUBST, VAR_APPEND, VAR_SHELL, VAR_NORMAL |
1859 | } type; /* Type of assignment */ | | 1868 | } type; /* Type of assignment */ |
1860 | char *opc; /* ptr to operator character to | | 1869 | char *opc; /* ptr to operator character to |
1861 | * null-terminate the variable name */ | | 1870 | * null-terminate the variable name */ |
1862 | Boolean freeCp = FALSE; /* TRUE if cp needs to be freed, | | 1871 | Boolean freeCp = FALSE; /* TRUE if cp needs to be freed, |
1863 | * i.e. if any variable expansion was | | 1872 | * i.e. if any variable expansion was |
1864 | * performed */ | | 1873 | * performed */ |
1865 | int depth; | | 1874 | int depth; |
1866 | | | 1875 | |
1867 | /* | | 1876 | /* |
1868 | * Skip to variable name | | 1877 | * Skip to variable name |
1869 | */ | | 1878 | */ |
1870 | while ((*line == ' ') || (*line == '\t')) { | | 1879 | while ((*line == ' ') || (*line == '\t')) { |
1871 | line++; | | 1880 | line++; |
1872 | } | | 1881 | } |
1873 | | | 1882 | |
1874 | /* | | 1883 | /* |
1875 | * Skip to operator character, nulling out whitespace as we go | | 1884 | * Skip to operator character, nulling out whitespace as we go |
1876 | * XXX Rather than counting () and {} we should look for $ and | | 1885 | * XXX Rather than counting () and {} we should look for $ and |
1877 | * then expand the variable. | | 1886 | * then expand the variable. |
1878 | */ | | 1887 | */ |
1879 | for (depth = 0, cp = line + 1; depth > 0 || *cp != '='; cp++) { | | 1888 | for (depth = 0, cp = line + 1; depth > 0 || *cp != '='; cp++) { |
1880 | if (*cp == '(' || *cp == '{') { | | 1889 | if (*cp == '(' || *cp == '{') { |
1881 | depth++; | | 1890 | depth++; |
1882 | continue; | | 1891 | continue; |
1883 | } | | 1892 | } |
1884 | if (*cp == ')' || *cp == '}') { | | 1893 | if (*cp == ')' || *cp == '}') { |
1885 | depth--; | | 1894 | depth--; |
1886 | continue; | | 1895 | continue; |
1887 | } | | 1896 | } |
1888 | if (depth == 0 && isspace ((unsigned char)*cp)) { | | 1897 | if (depth == 0 && isspace ((unsigned char)*cp)) { |
1889 | *cp = '\0'; | | 1898 | *cp = '\0'; |
1890 | } | | 1899 | } |
1891 | } | | 1900 | } |
1892 | opc = cp-1; /* operator is the previous character */ | | 1901 | opc = cp-1; /* operator is the previous character */ |
1893 | *cp++ = '\0'; /* nuke the = */ | | 1902 | *cp++ = '\0'; /* nuke the = */ |
1894 | | | 1903 | |
1895 | /* | | 1904 | /* |
1896 | * Check operator type | | 1905 | * Check operator type |
1897 | */ | | 1906 | */ |
1898 | switch (*opc) { | | 1907 | switch (*opc) { |
1899 | case '+': | | 1908 | case '+': |
1900 | type = VAR_APPEND; | | 1909 | type = VAR_APPEND; |
1901 | *opc = '\0'; | | 1910 | *opc = '\0'; |
1902 | break; | | 1911 | break; |
1903 | | | 1912 | |
1904 | case '?': | | 1913 | case '?': |
1905 | /* | | 1914 | /* |
1906 | * If the variable already has a value, we don't do anything. | | 1915 | * If the variable already has a value, we don't do anything. |
1907 | */ | | 1916 | */ |
1908 | *opc = '\0'; | | 1917 | *opc = '\0'; |
1909 | if (Var_Exists(line, ctxt)) { | | 1918 | if (Var_Exists(line, ctxt)) { |
1910 | return; | | 1919 | return; |
1911 | } else { | | 1920 | } else { |
1912 | type = VAR_NORMAL; | | 1921 | type = VAR_NORMAL; |
1913 | } | | 1922 | } |
1914 | break; | | 1923 | break; |
1915 | | | 1924 | |
1916 | case ':': | | 1925 | case ':': |
1917 | type = VAR_SUBST; | | 1926 | type = VAR_SUBST; |
1918 | *opc = '\0'; | | 1927 | *opc = '\0'; |
1919 | break; | | 1928 | break; |
1920 | | | 1929 | |
1921 | case '!': | | 1930 | case '!': |
1922 | type = VAR_SHELL; | | 1931 | type = VAR_SHELL; |
1923 | *opc = '\0'; | | 1932 | *opc = '\0'; |
1924 | break; | | 1933 | break; |
1925 | | | 1934 | |
1926 | default: | | 1935 | default: |
1927 | #ifdef SUNSHCMD | | 1936 | #ifdef SUNSHCMD |
1928 | while (opc > line && *opc != ':') | | 1937 | while (opc > line && *opc != ':') |
1929 | opc--; | | 1938 | opc--; |
1930 | | | 1939 | |
1931 | if (strncmp(opc, ":sh", 3) == 0) { | | 1940 | if (strncmp(opc, ":sh", 3) == 0) { |
1932 | type = VAR_SHELL; | | 1941 | type = VAR_SHELL; |
1933 | *opc = '\0'; | | 1942 | *opc = '\0'; |
1934 | break; | | 1943 | break; |
1935 | } | | 1944 | } |
1936 | #endif | | 1945 | #endif |
1937 | type = VAR_NORMAL; | | 1946 | type = VAR_NORMAL; |
1938 | break; | | 1947 | break; |
1939 | } | | 1948 | } |
1940 | | | 1949 | |
1941 | while (isspace((unsigned char)*cp)) | | 1950 | while (isspace((unsigned char)*cp)) |
1942 | cp++; | | 1951 | cp++; |
1943 | | | 1952 | |
1944 | if (type == VAR_APPEND) { | | 1953 | if (type == VAR_APPEND) { |
1945 | Var_Append(line, cp, ctxt); | | 1954 | Var_Append(line, cp, ctxt); |
1946 | } else if (type == VAR_SUBST) { | | 1955 | } else if (type == VAR_SUBST) { |
1947 | /* | | 1956 | /* |
1948 | * Allow variables in the old value to be undefined, but leave their | | 1957 | * Allow variables in the old value to be undefined, but leave their |
1949 | * invocation alone -- this is done by forcing oldVars to be false. | | 1958 | * invocation alone -- this is done by forcing oldVars to be false. |
1950 | * XXX: This can cause recursive variables, but that's not hard to do, | | 1959 | * XXX: This can cause recursive variables, but that's not hard to do, |
1951 | * and this allows someone to do something like | | 1960 | * and this allows someone to do something like |
1952 | * | | 1961 | * |
1953 | * CFLAGS = $(.INCLUDES) | | 1962 | * CFLAGS = $(.INCLUDES) |
1954 | * CFLAGS := -I.. $(CFLAGS) | | 1963 | * CFLAGS := -I.. $(CFLAGS) |
1955 | * | | 1964 | * |
1956 | * And not get an error. | | 1965 | * And not get an error. |
1957 | */ | | 1966 | */ |
1958 | Boolean oldOldVars = oldVars; | | 1967 | Boolean oldOldVars = oldVars; |
1959 | | | 1968 | |
1960 | oldVars = FALSE; | | 1969 | oldVars = FALSE; |
1961 | | | 1970 | |
1962 | /* | | 1971 | /* |
1963 | * make sure that we set the variable the first time to nothing | | 1972 | * make sure that we set the variable the first time to nothing |
1964 | * so that it gets substituted! | | 1973 | * so that it gets substituted! |
1965 | */ | | 1974 | */ |
1966 | if (!Var_Exists(line, ctxt)) | | 1975 | if (!Var_Exists(line, ctxt)) |
1967 | Var_Set(line, "", ctxt); | | 1976 | Var_Set(line, "", ctxt); |
1968 | | | 1977 | |
1969 | cp = Var_Subst(cp, ctxt, VARE_WANTRES|VARE_ASSIGN); | | 1978 | cp = Var_Subst(cp, ctxt, VARE_WANTRES|VARE_ASSIGN); |
1970 | oldVars = oldOldVars; | | 1979 | oldVars = oldOldVars; |
1971 | freeCp = TRUE; | | 1980 | freeCp = TRUE; |
1972 | | | 1981 | |
1973 | Var_Set(line, cp, ctxt); | | 1982 | Var_Set(line, cp, ctxt); |
1974 | } else if (type == VAR_SHELL) { | | 1983 | } else if (type == VAR_SHELL) { |
1975 | char *res; | | 1984 | char *res; |
1976 | const char *error; | | 1985 | const char *error; |
1977 | | | 1986 | |
1978 | if (strchr(cp, '$') != NULL) { | | 1987 | if (strchr(cp, '$') != NULL) { |
1979 | /* | | 1988 | /* |
1980 | * There's a dollar sign in the command, so perform variable | | 1989 | * There's a dollar sign in the command, so perform variable |
1981 | * expansion on the whole thing. The resulting string will need | | 1990 | * expansion on the whole thing. The resulting string will need |
1982 | * freeing when we're done. | | 1991 | * freeing when we're done. |
1983 | */ | | 1992 | */ |
1984 | cp = Var_Subst(cp, VAR_CMD, VARE_UNDEFERR|VARE_WANTRES); | | 1993 | cp = Var_Subst(cp, VAR_CMD, VARE_UNDEFERR|VARE_WANTRES); |
1985 | freeCp = TRUE; | | 1994 | freeCp = TRUE; |
1986 | } | | 1995 | } |
1987 | | | 1996 | |
1988 | res = Cmd_Exec(cp, &error); | | 1997 | res = Cmd_Exec(cp, &error); |
1989 | Var_Set(line, res, ctxt); | | 1998 | Var_Set(line, res, ctxt); |
1990 | free(res); | | 1999 | free(res); |
1991 | | | 2000 | |
1992 | if (error) | | 2001 | if (error) |
1993 | Parse_Error(PARSE_WARNING, error, cp); | | 2002 | Parse_Error(PARSE_WARNING, error, cp); |
1994 | } else { | | 2003 | } else { |
1995 | /* | | 2004 | /* |
1996 | * Normal assignment -- just do it. | | 2005 | * Normal assignment -- just do it. |
1997 | */ | | 2006 | */ |
1998 | Var_Set(line, cp, ctxt); | | 2007 | Var_Set(line, cp, ctxt); |
1999 | } | | 2008 | } |
2000 | if (strcmp(line, MAKEOVERRIDES) == 0) | | 2009 | if (strcmp(line, MAKEOVERRIDES) == 0) |
2001 | Main_ExportMAKEFLAGS(FALSE); /* re-export MAKEFLAGS */ | | 2010 | Main_ExportMAKEFLAGS(FALSE); /* re-export MAKEFLAGS */ |
2002 | else if (strcmp(line, ".CURDIR") == 0) { | | 2011 | else if (strcmp(line, ".CURDIR") == 0) { |
2003 | /* | | 2012 | /* |
2004 | * Somone is being (too?) clever... | | 2013 | * Somone is being (too?) clever... |
2005 | * Let's pretend they know what they are doing and | | 2014 | * Let's pretend they know what they are doing and |
2006 | * re-initialize the 'cur' Path. | | 2015 | * re-initialize the 'cur' Path. |
2007 | */ | | 2016 | */ |
2008 | Dir_InitCur(cp); | | 2017 | Dir_InitCur(cp); |
2009 | Dir_SetPATH(); | | 2018 | Dir_SetPATH(); |
2010 | } else if (strcmp(line, MAKE_JOB_PREFIX) == 0) { | | 2019 | } else if (strcmp(line, MAKE_JOB_PREFIX) == 0) { |
2011 | Job_SetPrefix(); | | 2020 | Job_SetPrefix(); |
2012 | } else if (strcmp(line, MAKE_EXPORTED) == 0) { | | 2021 | } else if (strcmp(line, MAKE_EXPORTED) == 0) { |
2013 | Var_Export(cp, 0); | | 2022 | Var_Export(cp, 0); |
2014 | } | | 2023 | } |
2015 | if (freeCp) | | 2024 | if (freeCp) |
2016 | free(cp); | | 2025 | free(cp); |
2017 | } | | 2026 | } |
2018 | | | 2027 | |
2019 | | | 2028 | |
2020 | /* | | 2029 | /* |
2021 | * ParseMaybeSubMake -- | | 2030 | * ParseMaybeSubMake -- |
2022 | * Scan the command string to see if it a possible submake node | | 2031 | * Scan the command string to see if it a possible submake node |
2023 | * Input: | | 2032 | * Input: |
2024 | * cmd the command to scan | | 2033 | * cmd the command to scan |
2025 | * Results: | | 2034 | * Results: |
2026 | * TRUE if the command is possibly a submake, FALSE if not. | | 2035 | * TRUE if the command is possibly a submake, FALSE if not. |
2027 | */ | | 2036 | */ |
2028 | static Boolean | | 2037 | static Boolean |
2029 | ParseMaybeSubMake(const char *cmd) | | 2038 | ParseMaybeSubMake(const char *cmd) |
2030 | { | | 2039 | { |
2031 | size_t i; | | 2040 | size_t i; |
2032 | static struct { | | 2041 | static struct { |
2033 | const char *name; | | 2042 | const char *name; |
2034 | size_t len; | | 2043 | size_t len; |
2035 | } vals[] = { | | 2044 | } vals[] = { |
2036 | #define MKV(A) { A, sizeof(A) - 1 } | | 2045 | #define MKV(A) { A, sizeof(A) - 1 } |
2037 | MKV("${MAKE}"), | | 2046 | MKV("${MAKE}"), |
2038 | MKV("${.MAKE}"), | | 2047 | MKV("${.MAKE}"), |
2039 | MKV("$(MAKE)"), | | 2048 | MKV("$(MAKE)"), |
2040 | MKV("$(.MAKE)"), | | 2049 | MKV("$(.MAKE)"), |
2041 | MKV("make"), | | 2050 | MKV("make"), |
2042 | }; | | 2051 | }; |
2043 | for (i = 0; i < sizeof(vals)/sizeof(vals[0]); i++) { | | 2052 | for (i = 0; i < sizeof(vals)/sizeof(vals[0]); i++) { |
2044 | char *ptr; | | 2053 | char *ptr; |
2045 | if ((ptr = strstr(cmd, vals[i].name)) == NULL) | | 2054 | if ((ptr = strstr(cmd, vals[i].name)) == NULL) |
2046 | continue; | | 2055 | continue; |
2047 | if ((ptr == cmd || !isalnum((unsigned char)ptr[-1])) | | 2056 | if ((ptr == cmd || !isalnum((unsigned char)ptr[-1])) |
2048 | && !isalnum((unsigned char)ptr[vals[i].len])) | | 2057 | && !isalnum((unsigned char)ptr[vals[i].len])) |
2049 | return TRUE; | | 2058 | return TRUE; |
2050 | } | | 2059 | } |
2051 | return FALSE; | | 2060 | return FALSE; |
2052 | } | | 2061 | } |
2053 | | | 2062 | |
2054 | /*- | | 2063 | /*- |
2055 | * ParseAddCmd -- | | 2064 | * ParseAddCmd -- |
2056 | * Lst_ForEach function to add a command line to all targets | | 2065 | * Lst_ForEach function to add a command line to all targets |
2057 | * | | 2066 | * |
2058 | * Input: | | 2067 | * Input: |
2059 | * gnp the node to which the command is to be added | | 2068 | * gnp the node to which the command is to be added |
2060 | * cmd the command to add | | 2069 | * cmd the command to add |
2061 | * | | 2070 | * |
2062 | * Results: | | 2071 | * Results: |
2063 | * Always 0 | | 2072 | * Always 0 |
2064 | * | | 2073 | * |
2065 | * Side Effects: | | 2074 | * Side Effects: |
2066 | * A new element is added to the commands list of the node, | | 2075 | * A new element is added to the commands list of the node, |
2067 | * and the node can be marked as a submake node if the command is | | 2076 | * and the node can be marked as a submake node if the command is |
2068 | * determined to be that. | | 2077 | * determined to be that. |
2069 | */ | | 2078 | */ |
2070 | static int | | 2079 | static int |
2071 | ParseAddCmd(void *gnp, void *cmd) | | 2080 | ParseAddCmd(void *gnp, void *cmd) |
2072 | { | | 2081 | { |
2073 | GNode *gn = (GNode *)gnp; | | 2082 | GNode *gn = (GNode *)gnp; |
2074 | | | 2083 | |
2075 | /* Add to last (ie current) cohort for :: targets */ | | 2084 | /* Add to last (ie current) cohort for :: targets */ |
2076 | if ((gn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (gn->cohorts)) | | 2085 | if ((gn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (gn->cohorts)) |
2077 | gn = (GNode *)Lst_Datum(Lst_Last(gn->cohorts)); | | 2086 | gn = (GNode *)Lst_Datum(Lst_Last(gn->cohorts)); |
2078 | | | 2087 | |
2079 | /* if target already supplied, ignore commands */ | | 2088 | /* if target already supplied, ignore commands */ |
2080 | if (!(gn->type & OP_HAS_COMMANDS)) { | | 2089 | if (!(gn->type & OP_HAS_COMMANDS)) { |
2081 | (void)Lst_AtEnd(gn->commands, cmd); | | 2090 | (void)Lst_AtEnd(gn->commands, cmd); |
2082 | if (ParseMaybeSubMake(cmd)) | | 2091 | if (ParseMaybeSubMake(cmd)) |
2083 | gn->type |= OP_SUBMAKE; | | 2092 | gn->type |= OP_SUBMAKE; |
2084 | ParseMark(gn); | | 2093 | ParseMark(gn); |
2085 | } else { | | 2094 | } else { |
2086 | #ifdef notyet | | 2095 | #ifdef notyet |
2087 | /* XXX: We cannot do this until we fix the tree */ | | 2096 | /* XXX: We cannot do this until we fix the tree */ |
2088 | (void)Lst_AtEnd(gn->commands, cmd); | | 2097 | (void)Lst_AtEnd(gn->commands, cmd); |
2089 | Parse_Error(PARSE_WARNING, | | 2098 | Parse_Error(PARSE_WARNING, |
2090 | "overriding commands for target \"%s\"; " | | 2099 | "overriding commands for target \"%s\"; " |
2091 | "previous commands defined at %s: %d ignored", | | 2100 | "previous commands defined at %s: %d ignored", |
2092 | gn->name, gn->fname, gn->lineno); | | 2101 | gn->name, gn->fname, gn->lineno); |
2093 | #else | | 2102 | #else |
2094 | Parse_Error(PARSE_WARNING, | | 2103 | Parse_Error(PARSE_WARNING, |
2095 | "duplicate script for target \"%s\" ignored", | | 2104 | "duplicate script for target \"%s\" ignored", |
2096 | gn->name); | | 2105 | gn->name); |
2097 | ParseErrorInternal(gn->fname, gn->lineno, PARSE_WARNING, | | 2106 | ParseErrorInternal(gn->fname, gn->lineno, PARSE_WARNING, |
2098 | "using previous script for \"%s\" defined here", | | 2107 | "using previous script for \"%s\" defined here", |
2099 | gn->name); | | 2108 | gn->name); |
2100 | #endif | | 2109 | #endif |
2101 | } | | 2110 | } |
2102 | return 0; | | 2111 | return 0; |
2103 | } | | 2112 | } |
2104 | | | 2113 | |
2105 | /*- | | 2114 | /*- |
2106 | *----------------------------------------------------------------------- | | 2115 | *----------------------------------------------------------------------- |
2107 | * ParseHasCommands -- | | 2116 | * ParseHasCommands -- |
2108 | * Callback procedure for Parse_File when destroying the list of | | 2117 | * Callback procedure for Parse_File when destroying the list of |
2109 | * targets on the last dependency line. Marks a target as already | | 2118 | * targets on the last dependency line. Marks a target as already |
2110 | * having commands if it does, to keep from having shell commands | | 2119 | * having commands if it does, to keep from having shell commands |
2111 | * on multiple dependency lines. | | 2120 | * on multiple dependency lines. |
2112 | * | | 2121 | * |
2113 | * Input: | | 2122 | * Input: |
2114 | * gnp Node to examine | | 2123 | * gnp Node to examine |
2115 | * | | 2124 | * |
2116 | * Results: | | 2125 | * Results: |
2117 | * None | | 2126 | * None |
2118 | * | | 2127 | * |
2119 | * Side Effects: | | 2128 | * Side Effects: |
2120 | * OP_HAS_COMMANDS may be set for the target. | | 2129 | * OP_HAS_COMMANDS may be set for the target. |
2121 | * | | 2130 | * |
2122 | *----------------------------------------------------------------------- | | 2131 | *----------------------------------------------------------------------- |
2123 | */ | | 2132 | */ |
2124 | static void | | 2133 | static void |
2125 | ParseHasCommands(void *gnp) | | 2134 | ParseHasCommands(void *gnp) |
2126 | { | | 2135 | { |
2127 | GNode *gn = (GNode *)gnp; | | 2136 | GNode *gn = (GNode *)gnp; |
2128 | if (!Lst_IsEmpty(gn->commands)) { | | 2137 | if (!Lst_IsEmpty(gn->commands)) { |
2129 | gn->type |= OP_HAS_COMMANDS; | | 2138 | gn->type |= OP_HAS_COMMANDS; |
2130 | } | | 2139 | } |
2131 | } | | 2140 | } |
2132 | | | 2141 | |
2133 | /*- | | 2142 | /*- |
2134 | *----------------------------------------------------------------------- | | 2143 | *----------------------------------------------------------------------- |
2135 | * Parse_AddIncludeDir -- | | 2144 | * Parse_AddIncludeDir -- |
2136 | * Add a directory to the path searched for included makefiles | | 2145 | * Add a directory to the path searched for included makefiles |
2137 | * bracketed by double-quotes. Used by functions in main.c | | 2146 | * bracketed by double-quotes. Used by functions in main.c |
2138 | * | | 2147 | * |
2139 | * Input: | | 2148 | * Input: |
2140 | * dir The name of the directory to add | | 2149 | * dir The name of the directory to add |
2141 | * | | 2150 | * |
2142 | * Results: | | 2151 | * Results: |
2143 | * None. | | 2152 | * None. |
2144 | * | | 2153 | * |
2145 | * Side Effects: | | 2154 | * Side Effects: |
2146 | * The directory is appended to the list. | | 2155 | * The directory is appended to the list. |
2147 | * | | 2156 | * |
2148 | *----------------------------------------------------------------------- | | 2157 | *----------------------------------------------------------------------- |
2149 | */ | | 2158 | */ |
2150 | void | | 2159 | void |
2151 | Parse_AddIncludeDir(char *dir) | | 2160 | Parse_AddIncludeDir(char *dir) |
2152 | { | | 2161 | { |
2153 | (void)Dir_AddDir(parseIncPath, dir); | | 2162 | (void)Dir_AddDir(parseIncPath, dir); |
2154 | } | | 2163 | } |
2155 | | | 2164 | |
2156 | /*- | | 2165 | /*- |
2157 | *--------------------------------------------------------------------- | | 2166 | *--------------------------------------------------------------------- |
2158 | * ParseDoInclude -- | | 2167 | * ParseDoInclude -- |
2159 | * Push to another file. | | 2168 | * Push to another file. |
2160 | * | | 2169 | * |
2161 | * The input is the line minus the `.'. A file spec is a string | | 2170 | * The input is the line minus the `.'. A file spec is a string |
2162 | * enclosed in <> or "". The former is looked for only in sysIncPath. | | 2171 | * enclosed in <> or "". The former is looked for only in sysIncPath. |
2163 | * The latter in . and the directories specified by -I command line | | 2172 | * The latter in . and the directories specified by -I command line |
2164 | * options | | 2173 | * options |
2165 | * | | 2174 | * |
2166 | * Results: | | 2175 | * Results: |
2167 | * None | | 2176 | * None |
2168 | * | | 2177 | * |
2169 | * Side Effects: | | 2178 | * Side Effects: |
2170 | * A structure is added to the includes Lst and readProc, lineno, | | 2179 | * A structure is added to the includes Lst and readProc, lineno, |
2171 | * fname and curFILE are altered for the new file | | 2180 | * fname and curFILE are altered for the new file |
2172 | *--------------------------------------------------------------------- | | 2181 | *--------------------------------------------------------------------- |
2173 | */ | | 2182 | */ |
2174 | | | 2183 | |
2175 | static void | | 2184 | static void |
2176 | Parse_include_file(char *file, Boolean isSystem, Boolean depinc, int silent) | | 2185 | Parse_include_file(char *file, Boolean isSystem, Boolean depinc, int silent) |
2177 | { | | 2186 | { |
2178 | struct loadedfile *lf; | | 2187 | struct loadedfile *lf; |
2179 | char *fullname; /* full pathname of file */ | | 2188 | char *fullname; /* full pathname of file */ |
2180 | char *newName; | | 2189 | char *newName; |
2181 | char *prefEnd, *incdir; | | 2190 | char *prefEnd, *incdir; |
2182 | int fd; | | 2191 | int fd; |
2183 | int i; | | 2192 | int i; |
2184 | | | 2193 | |
2185 | /* | | 2194 | /* |
2186 | * Now we know the file's name and its search path, we attempt to | | 2195 | * Now we know the file's name and its search path, we attempt to |
2187 | * find the durn thing. A return of NULL indicates the file don't | | 2196 | * find the durn thing. A return of NULL indicates the file don't |
2188 | * exist. | | 2197 | * exist. |
2189 | */ | | 2198 | */ |
2190 | fullname = file[0] == '/' ? bmake_strdup(file) : NULL; | | 2199 | fullname = file[0] == '/' ? bmake_strdup(file) : NULL; |
2191 | | | 2200 | |
2192 | if (fullname == NULL && !isSystem) { | | 2201 | if (fullname == NULL && !isSystem) { |
2193 | /* | | 2202 | /* |
2194 | * Include files contained in double-quotes are first searched for | | 2203 | * Include files contained in double-quotes are first searched for |
2195 | * relative to the including file's location. We don't want to | | 2204 | * relative to the including file's location. We don't want to |
2196 | * cd there, of course, so we just tack on the old file's | | 2205 | * cd there, of course, so we just tack on the old file's |
2197 | * leading path components and call Dir_FindFile to see if | | 2206 | * leading path components and call Dir_FindFile to see if |
2198 | * we can locate the beast. | | 2207 | * we can locate the beast. |
2199 | */ | | 2208 | */ |
2200 | | | 2209 | |
2201 | incdir = bmake_strdup(curFile->fname); | | 2210 | incdir = bmake_strdup(curFile->fname); |
2202 | prefEnd = strrchr(incdir, '/'); | | 2211 | prefEnd = strrchr(incdir, '/'); |
2203 | if (prefEnd != NULL) { | | 2212 | if (prefEnd != NULL) { |
2204 | *prefEnd = '\0'; | | 2213 | *prefEnd = '\0'; |
2205 | /* Now do lexical processing of leading "../" on the filename */ | | 2214 | /* Now do lexical processing of leading "../" on the filename */ |
2206 | for (i = 0; strncmp(file + i, "../", 3) == 0; i += 3) { | | 2215 | for (i = 0; strncmp(file + i, "../", 3) == 0; i += 3) { |
2207 | prefEnd = strrchr(incdir + 1, '/'); | | 2216 | prefEnd = strrchr(incdir + 1, '/'); |
2208 | if (prefEnd == NULL || strcmp(prefEnd, "/..") == 0) | | 2217 | if (prefEnd == NULL || strcmp(prefEnd, "/..") == 0) |
2209 | break; | | 2218 | break; |
2210 | *prefEnd = '\0'; | | 2219 | *prefEnd = '\0'; |
2211 | } | | 2220 | } |
2212 | newName = str_concat(incdir, file + i, STR_ADDSLASH); | | 2221 | newName = str_concat(incdir, file + i, STR_ADDSLASH); |
2213 | fullname = Dir_FindFile(newName, parseIncPath); | | 2222 | fullname = Dir_FindFile(newName, parseIncPath); |
2214 | if (fullname == NULL) | | 2223 | if (fullname == NULL) |
2215 | fullname = Dir_FindFile(newName, dirSearchPath); | | 2224 | fullname = Dir_FindFile(newName, dirSearchPath); |
2216 | free(newName); | | 2225 | free(newName); |
2217 | } | | 2226 | } |
2218 | free(incdir); | | 2227 | free(incdir); |
2219 | | | 2228 | |
2220 | if (fullname == NULL) { | | 2229 | if (fullname == NULL) { |
2221 | /* | | 2230 | /* |
2222 | * Makefile wasn't found in same directory as included makefile. | | 2231 | * Makefile wasn't found in same directory as included makefile. |
2223 | * Search for it first on the -I search path, | | 2232 | * Search for it first on the -I search path, |
2224 | * then on the .PATH search path, if not found in a -I directory. | | 2233 | * then on the .PATH search path, if not found in a -I directory. |
2225 | * If we have a suffix specific path we should use that. | | 2234 | * If we have a suffix specific path we should use that. |
2226 | */ | | 2235 | */ |
2227 | char *suff; | | 2236 | char *suff; |
2228 | Lst suffPath = NULL; | | 2237 | Lst suffPath = NULL; |
2229 | | | 2238 | |
2230 | if ((suff = strrchr(file, '.'))) { | | 2239 | if ((suff = strrchr(file, '.'))) { |
2231 | suffPath = Suff_GetPath(suff); | | 2240 | suffPath = Suff_GetPath(suff); |
2232 | if (suffPath != NULL) { | | 2241 | if (suffPath != NULL) { |
2233 | fullname = Dir_FindFile(file, suffPath); | | 2242 | fullname = Dir_FindFile(file, suffPath); |
2234 | } | | 2243 | } |
2235 | } | | 2244 | } |
2236 | if (fullname == NULL) { | | 2245 | if (fullname == NULL) { |
2237 | fullname = Dir_FindFile(file, parseIncPath); | | 2246 | fullname = Dir_FindFile(file, parseIncPath); |
2238 | if (fullname == NULL) { | | 2247 | if (fullname == NULL) { |
2239 | fullname = Dir_FindFile(file, dirSearchPath); | | 2248 | fullname = Dir_FindFile(file, dirSearchPath); |
2240 | } | | 2249 | } |
2241 | } | | 2250 | } |
2242 | } | | 2251 | } |
2243 | } | | 2252 | } |
2244 | | | 2253 | |
2245 | /* Looking for a system file or file still not found */ | | 2254 | /* Looking for a system file or file still not found */ |
2246 | if (fullname == NULL) { | | 2255 | if (fullname == NULL) { |
2247 | /* | | 2256 | /* |
2248 | * Look for it on the system path | | 2257 | * Look for it on the system path |
2249 | */ | | 2258 | */ |
2250 | fullname = Dir_FindFile(file, | | 2259 | fullname = Dir_FindFile(file, |
2251 | Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath); | | 2260 | Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath); |
2252 | } | | 2261 | } |
2253 | | | 2262 | |
2254 | if (fullname == NULL) { | | 2263 | if (fullname == NULL) { |
2255 | if (!silent) | | 2264 | if (!silent) |
2256 | Parse_Error(PARSE_FATAL, "Could not find %s", file); | | 2265 | Parse_Error(PARSE_FATAL, "Could not find %s", file); |
2257 | return; | | 2266 | return; |
2258 | } | | 2267 | } |
2259 | | | 2268 | |
2260 | /* Actually open the file... */ | | 2269 | /* Actually open the file... */ |
2261 | fd = open(fullname, O_RDONLY); | | 2270 | fd = open(fullname, O_RDONLY); |
2262 | if (fd == -1) { | | 2271 | if (fd == -1) { |
2263 | if (!silent) | | 2272 | if (!silent) |
2264 | Parse_Error(PARSE_FATAL, "Cannot open %s", fullname); | | 2273 | Parse_Error(PARSE_FATAL, "Cannot open %s", fullname); |
2265 | free(fullname); | | 2274 | free(fullname); |
2266 | return; | | 2275 | return; |
2267 | } | | 2276 | } |
2268 | | | 2277 | |
2269 | /* load it */ | | 2278 | /* load it */ |
2270 | lf = loadfile(fullname, fd); | | 2279 | lf = loadfile(fullname, fd); |
2271 | | | 2280 | |
2272 | ParseSetIncludedFile(); | | 2281 | ParseSetIncludedFile(); |
2273 | /* Start reading from this file next */ | | 2282 | /* Start reading from this file next */ |
2274 | Parse_SetInput(fullname, 0, -1, loadedfile_nextbuf, lf); | | 2283 | Parse_SetInput(fullname, 0, -1, loadedfile_nextbuf, lf); |
2275 | curFile->lf = lf; | | 2284 | curFile->lf = lf; |
2276 | if (depinc) | | 2285 | if (depinc) |
2277 | doing_depend = depinc; /* only turn it on */ | | 2286 | doing_depend = depinc; /* only turn it on */ |
2278 | } | | 2287 | } |
2279 | | | 2288 | |
2280 | static void | | 2289 | static void |
2281 | ParseDoInclude(char *line) | | 2290 | ParseDoInclude(char *line) |
2282 | { | | 2291 | { |
2283 | char endc; /* the character which ends the file spec */ | | 2292 | char endc; /* the character which ends the file spec */ |
2284 | char *cp; /* current position in file spec */ | | 2293 | char *cp; /* current position in file spec */ |
2285 | int silent = (*line != 'i') ? 1 : 0; | | 2294 | int silent = (*line != 'i') ? 1 : 0; |
2286 | char *file = &line[7 + silent]; | | 2295 | char *file = &line[7 + silent]; |
2287 | | | 2296 | |
2288 | /* Skip to delimiter character so we know where to look */ | | 2297 | /* Skip to delimiter character so we know where to look */ |
2289 | while (*file == ' ' || *file == '\t') | | 2298 | while (*file == ' ' || *file == '\t') |
2290 | file++; | | 2299 | file++; |
2291 | | | 2300 | |