1 1.753 rillig /* $NetBSD: parse.c,v 1.753 2025/06/28 22:39:27 rillig Exp $ */ 2 1.15 christos 3 1.1 cgd /* 4 1.27 christos * Copyright (c) 1988, 1989, 1990, 1993 5 1.27 christos * The Regents of the University of California. All rights reserved. 6 1.94 agc * 7 1.94 agc * This code is derived from software contributed to Berkeley by 8 1.94 agc * Adam de Boor. 9 1.94 agc * 10 1.94 agc * Redistribution and use in source and binary forms, with or without 11 1.94 agc * modification, are permitted provided that the following conditions 12 1.94 agc * are met: 13 1.94 agc * 1. Redistributions of source code must retain the above copyright 14 1.94 agc * notice, this list of conditions and the following disclaimer. 15 1.94 agc * 2. Redistributions in binary form must reproduce the above copyright 16 1.94 agc * notice, this list of conditions and the following disclaimer in the 17 1.94 agc * documentation and/or other materials provided with the distribution. 18 1.94 agc * 3. Neither the name of the University nor the names of its contributors 19 1.94 agc * may be used to endorse or promote products derived from this software 20 1.94 agc * without specific prior written permission. 21 1.94 agc * 22 1.94 agc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 1.94 agc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.94 agc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.94 agc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 1.94 agc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.94 agc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.94 agc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.94 agc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.94 agc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.94 agc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.94 agc * SUCH DAMAGE. 33 1.94 agc */ 34 1.94 agc 35 1.94 agc /* 36 1.1 cgd * Copyright (c) 1989 by Berkeley Softworks 37 1.1 cgd * All rights reserved. 38 1.1 cgd * 39 1.1 cgd * This code is derived from software contributed to Berkeley by 40 1.1 cgd * Adam de Boor. 41 1.1 cgd * 42 1.1 cgd * Redistribution and use in source and binary forms, with or without 43 1.1 cgd * modification, are permitted provided that the following conditions 44 1.1 cgd * are met: 45 1.1 cgd * 1. Redistributions of source code must retain the above copyright 46 1.1 cgd * notice, this list of conditions and the following disclaimer. 47 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 48 1.1 cgd * notice, this list of conditions and the following disclaimer in the 49 1.1 cgd * documentation and/or other materials provided with the distribution. 50 1.1 cgd * 3. All advertising materials mentioning features or use of this software 51 1.1 cgd * must display the following acknowledgement: 52 1.1 cgd * This product includes software developed by the University of 53 1.1 cgd * California, Berkeley and its contributors. 54 1.1 cgd * 4. Neither the name of the University nor the names of its contributors 55 1.1 cgd * may be used to endorse or promote products derived from this software 56 1.1 cgd * without specific prior written permission. 57 1.1 cgd * 58 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 1.1 cgd * SUCH DAMAGE. 69 1.1 cgd */ 70 1.1 cgd 71 1.402 rillig /* 72 1.402 rillig * Parsing of makefiles. 73 1.402 rillig * 74 1.402 rillig * Parse_File is the main entry point and controls most of the other 75 1.402 rillig * functions in this module. 76 1.1 cgd * 77 1.1 cgd * Interface: 78 1.402 rillig * Parse_Init Initialize the module 79 1.338 rillig * 80 1.383 rillig * Parse_End Clean up the module 81 1.338 rillig * 82 1.402 rillig * Parse_File Parse a top-level makefile. Included files are 83 1.537 rillig * handled by IncludeFile instead. 84 1.402 rillig * 85 1.609 rillig * Parse_VarAssign 86 1.609 rillig * Try to parse the given line as a variable assignment. 87 1.609 rillig * Used by MainParseArgs to determine if an argument is 88 1.609 rillig * a target or a variable assignment. Used internally 89 1.609 rillig * for pretty much the same thing. 90 1.402 rillig * 91 1.402 rillig * Parse_Error Report a parse error, a warning or an informational 92 1.402 rillig * message. 93 1.338 rillig * 94 1.697 rillig * Parse_MainName Populate the list of targets to create. 95 1.1 cgd */ 96 1.1 cgd 97 1.170 dholland #include <sys/types.h> 98 1.171 dholland #include <sys/stat.h> 99 1.84 wiz #include <errno.h> 100 1.5 cgd #include <stdarg.h> 101 1.84 wiz 102 1.1 cgd #include "make.h" 103 1.5 cgd #include "dir.h" 104 1.5 cgd #include "job.h" 105 1.1 cgd #include "pathnames.h" 106 1.1 cgd 107 1.303 rillig /* "@(#)parse.c 8.3 (Berkeley) 3/19/94" */ 108 1.753 rillig MAKE_RCSID("$NetBSD: parse.c,v 1.753 2025/06/28 22:39:27 rillig Exp $"); 109 1.700 rillig 110 1.700 rillig /* Detects a multiple-inclusion guard in a makefile. */ 111 1.700 rillig typedef enum { 112 1.700 rillig GS_START, /* at the beginning of the file */ 113 1.700 rillig GS_COND, /* after the guard condition */ 114 1.700 rillig GS_DONE, /* after the closing .endif */ 115 1.700 rillig GS_NO /* the file is not guarded */ 116 1.700 rillig } GuardState; 117 1.166 dholland 118 1.716 rillig /* A file being parsed. */ 119 1.627 rillig typedef struct IncludedFile { 120 1.576 rillig FStr name; /* absolute or relative to the cwd */ 121 1.661 rillig unsigned lineno; /* 1-based */ 122 1.661 rillig unsigned readLines; /* the number of physical lines that have 123 1.639 rillig * been read from the file */ 124 1.661 rillig unsigned forHeadLineno; /* 1-based */ 125 1.661 rillig unsigned forBodyReadLines; /* the number of physical lines that have 126 1.627 rillig * been read from the file above the body of 127 1.639 rillig * the .for loop */ 128 1.744 rillig unsigned condMinDepth; /* depth of nested 'if' directives, at the 129 1.687 rillig * beginning of the file */ 130 1.618 rillig bool depending; /* state of doing_depend on EOF */ 131 1.469 rillig 132 1.618 rillig Buffer buf; /* the file's content or the body of the .for 133 1.667 rillig * loop; either empty or ends with '\n' */ 134 1.704 rillig char *buf_ptr; /* next char to be read from buf */ 135 1.571 rillig char *buf_end; /* buf_end[-1] == '\n' */ 136 1.469 rillig 137 1.702 rillig GuardState guardState; 138 1.702 rillig Guard *guard; 139 1.700 rillig 140 1.616 rillig struct ForLoop *forLoop; 141 1.627 rillig } IncludedFile; 142 1.1 cgd 143 1.628 rillig /* Special attributes for target nodes. */ 144 1.386 rillig typedef enum ParseSpecial { 145 1.469 rillig SP_ATTRIBUTE, /* Generic attribute */ 146 1.469 rillig SP_BEGIN, /* .BEGIN */ 147 1.469 rillig SP_DEFAULT, /* .DEFAULT */ 148 1.469 rillig SP_DELETE_ON_ERROR, /* .DELETE_ON_ERROR */ 149 1.469 rillig SP_END, /* .END */ 150 1.469 rillig SP_ERROR, /* .ERROR */ 151 1.469 rillig SP_IGNORE, /* .IGNORE */ 152 1.469 rillig SP_INCLUDES, /* .INCLUDES; not mentioned in the manual page */ 153 1.469 rillig SP_INTERRUPT, /* .INTERRUPT */ 154 1.469 rillig SP_LIBS, /* .LIBS; not mentioned in the manual page */ 155 1.589 rillig SP_MAIN, /* .MAIN and no user-specified targets to make */ 156 1.469 rillig SP_META, /* .META */ 157 1.469 rillig SP_MFLAGS, /* .MFLAGS or .MAKEFLAGS */ 158 1.469 rillig SP_NOMETA, /* .NOMETA */ 159 1.469 rillig SP_NOMETA_CMP, /* .NOMETA_CMP */ 160 1.469 rillig SP_NOPATH, /* .NOPATH */ 161 1.691 sjg SP_NOREADONLY, /* .NOREADONLY */ 162 1.469 rillig SP_NOT, /* Not special */ 163 1.469 rillig SP_NOTPARALLEL, /* .NOTPARALLEL or .NO_PARALLEL */ 164 1.469 rillig SP_NULL, /* .NULL; not mentioned in the manual page */ 165 1.469 rillig SP_OBJDIR, /* .OBJDIR */ 166 1.469 rillig SP_ORDER, /* .ORDER */ 167 1.469 rillig SP_PARALLEL, /* .PARALLEL; not mentioned in the manual page */ 168 1.469 rillig SP_PATH, /* .PATH or .PATH.suffix */ 169 1.469 rillig SP_PHONY, /* .PHONY */ 170 1.469 rillig SP_POSIX, /* .POSIX; not mentioned in the manual page */ 171 1.469 rillig SP_PRECIOUS, /* .PRECIOUS */ 172 1.691 sjg SP_READONLY, /* .READONLY */ 173 1.469 rillig SP_SHELL, /* .SHELL */ 174 1.469 rillig SP_SILENT, /* .SILENT */ 175 1.469 rillig SP_SINGLESHELL, /* .SINGLESHELL; not mentioned in the manual page */ 176 1.469 rillig SP_STALE, /* .STALE */ 177 1.469 rillig SP_SUFFIXES, /* .SUFFIXES */ 178 1.692 sjg SP_SYSPATH, /* .SYSPATH */ 179 1.469 rillig SP_WAIT /* .WAIT */ 180 1.1 cgd } ParseSpecial; 181 1.1 cgd 182 1.368 rillig typedef List SearchPathList; 183 1.392 rillig typedef ListNode SearchPathListNode; 184 1.368 rillig 185 1.656 sjg 186 1.656 sjg typedef enum VarAssignOp { 187 1.656 sjg VAR_NORMAL, /* = */ 188 1.656 sjg VAR_APPEND, /* += */ 189 1.656 sjg VAR_DEFAULT, /* ?= */ 190 1.656 sjg VAR_SUBST, /* := */ 191 1.656 sjg VAR_SHELL /* != or :sh= */ 192 1.656 sjg } VarAssignOp; 193 1.656 sjg 194 1.656 sjg typedef struct VarAssign { 195 1.656 sjg char *varname; /* unexpanded */ 196 1.656 sjg VarAssignOp op; 197 1.656 sjg const char *value; /* unexpanded */ 198 1.656 sjg } VarAssign; 199 1.656 sjg 200 1.656 sjg static bool Parse_IsVar(const char *, VarAssign *); 201 1.658 rillig static void Parse_Var(VarAssign *, GNode *); 202 1.656 sjg 203 1.166 dholland /* 204 1.631 rillig * The target to be made if no targets are specified in the command line. 205 1.631 rillig * This is the first target defined in any of the makefiles. 206 1.166 dholland */ 207 1.631 rillig GNode *mainNode; 208 1.166 dholland 209 1.524 rillig /* 210 1.524 rillig * During parsing, the targets from the left-hand side of the currently 211 1.415 rillig * active dependency line, or NULL if the current line does not belong to a 212 1.415 rillig * dependency line, for example because it is a variable assignment. 213 1.318 rillig * 214 1.524 rillig * See unit-tests/deptgt.mk, keyword "parse.c:targets". 215 1.524 rillig */ 216 1.322 rillig static GNodeList *targets; 217 1.166 dholland 218 1.166 dholland #ifdef CLEANUP 219 1.524 rillig /* 220 1.524 rillig * All shell commands for all targets, in no particular order and possibly 221 1.726 rillig * with duplicate values. Kept in a separate list since the commands from 222 1.726 rillig * .USE or .USEBEFORE nodes are shared with other GNodes, thereby giving up 223 1.726 rillig * the easily understandable ownership over the allocated strings. 224 1.524 rillig */ 225 1.461 rillig static StringList targCmds = LST_INIT; 226 1.166 dholland #endif 227 1.166 dholland 228 1.166 dholland /* 229 1.152 dsl * Predecessor node for handling .ORDER. Initialized to NULL when .ORDER 230 1.628 rillig * is seen, then set to each successive source on the line. 231 1.1 cgd */ 232 1.407 rillig static GNode *order_pred; 233 1.1 cgd 234 1.734 rillig int parseErrors; 235 1.166 dholland 236 1.166 dholland /* 237 1.532 rillig * The include chain of makefiles. At index 0 is the top-level makefile from 238 1.532 rillig * the command line, followed by the included files or .for loops, up to and 239 1.532 rillig * including the current file. 240 1.532 rillig * 241 1.532 rillig * See PrintStackTrace for how to interpret the data. 242 1.319 rillig */ 243 1.627 rillig static Vector /* of IncludedFile */ includes; 244 1.400 rillig 245 1.549 rillig SearchPath *parseIncPath; /* directories for "..." includes */ 246 1.549 rillig SearchPath *sysIncPath; /* directories for <...> includes */ 247 1.414 rillig SearchPath *defSysIncPath; /* default for sysIncPath */ 248 1.166 dholland 249 1.1 cgd /* 250 1.1 cgd * The parseKeywords table is searched using binary search when deciding 251 1.697 rillig * if a target or source is special. 252 1.1 cgd */ 253 1.168 dholland static const struct { 254 1.590 rillig const char name[17]; 255 1.590 rillig ParseSpecial special; /* when used as a target */ 256 1.590 rillig GNodeType targetAttr; /* when used as a source */ 257 1.1 cgd } parseKeywords[] = { 258 1.466 rillig { ".BEGIN", SP_BEGIN, OP_NONE }, 259 1.466 rillig { ".DEFAULT", SP_DEFAULT, OP_NONE }, 260 1.466 rillig { ".DELETE_ON_ERROR", SP_DELETE_ON_ERROR, OP_NONE }, 261 1.466 rillig { ".END", SP_END, OP_NONE }, 262 1.466 rillig { ".ERROR", SP_ERROR, OP_NONE }, 263 1.404 rillig { ".EXEC", SP_ATTRIBUTE, OP_EXEC }, 264 1.404 rillig { ".IGNORE", SP_IGNORE, OP_IGNORE }, 265 1.466 rillig { ".INCLUDES", SP_INCLUDES, OP_NONE }, 266 1.466 rillig { ".INTERRUPT", SP_INTERRUPT, OP_NONE }, 267 1.404 rillig { ".INVISIBLE", SP_ATTRIBUTE, OP_INVISIBLE }, 268 1.404 rillig { ".JOIN", SP_ATTRIBUTE, OP_JOIN }, 269 1.466 rillig { ".LIBS", SP_LIBS, OP_NONE }, 270 1.404 rillig { ".MADE", SP_ATTRIBUTE, OP_MADE }, 271 1.466 rillig { ".MAIN", SP_MAIN, OP_NONE }, 272 1.404 rillig { ".MAKE", SP_ATTRIBUTE, OP_MAKE }, 273 1.466 rillig { ".MAKEFLAGS", SP_MFLAGS, OP_NONE }, 274 1.404 rillig { ".META", SP_META, OP_META }, 275 1.466 rillig { ".MFLAGS", SP_MFLAGS, OP_NONE }, 276 1.404 rillig { ".NOMETA", SP_NOMETA, OP_NOMETA }, 277 1.404 rillig { ".NOMETA_CMP", SP_NOMETA_CMP, OP_NOMETA_CMP }, 278 1.404 rillig { ".NOPATH", SP_NOPATH, OP_NOPATH }, 279 1.691 sjg { ".NOREADONLY", SP_NOREADONLY, OP_NONE }, 280 1.404 rillig { ".NOTMAIN", SP_ATTRIBUTE, OP_NOTMAIN }, 281 1.466 rillig { ".NOTPARALLEL", SP_NOTPARALLEL, OP_NONE }, 282 1.466 rillig { ".NO_PARALLEL", SP_NOTPARALLEL, OP_NONE }, 283 1.466 rillig { ".NULL", SP_NULL, OP_NONE }, 284 1.466 rillig { ".OBJDIR", SP_OBJDIR, OP_NONE }, 285 1.404 rillig { ".OPTIONAL", SP_ATTRIBUTE, OP_OPTIONAL }, 286 1.466 rillig { ".ORDER", SP_ORDER, OP_NONE }, 287 1.466 rillig { ".PARALLEL", SP_PARALLEL, OP_NONE }, 288 1.466 rillig { ".PATH", SP_PATH, OP_NONE }, 289 1.404 rillig { ".PHONY", SP_PHONY, OP_PHONY }, 290 1.466 rillig { ".POSIX", SP_POSIX, OP_NONE }, 291 1.404 rillig { ".PRECIOUS", SP_PRECIOUS, OP_PRECIOUS }, 292 1.691 sjg { ".READONLY", SP_READONLY, OP_NONE }, 293 1.404 rillig { ".RECURSIVE", SP_ATTRIBUTE, OP_MAKE }, 294 1.466 rillig { ".SHELL", SP_SHELL, OP_NONE }, 295 1.404 rillig { ".SILENT", SP_SILENT, OP_SILENT }, 296 1.466 rillig { ".SINGLESHELL", SP_SINGLESHELL, OP_NONE }, 297 1.466 rillig { ".STALE", SP_STALE, OP_NONE }, 298 1.466 rillig { ".SUFFIXES", SP_SUFFIXES, OP_NONE }, 299 1.692 sjg { ".SYSPATH", SP_SYSPATH, OP_NONE }, 300 1.404 rillig { ".USE", SP_ATTRIBUTE, OP_USE }, 301 1.404 rillig { ".USEBEFORE", SP_ATTRIBUTE, OP_USEBEFORE }, 302 1.466 rillig { ".WAIT", SP_WAIT, OP_NONE }, 303 1.1 cgd }; 304 1.1 cgd 305 1.669 rillig enum PosixState posix_state = PS_NOT_YET; 306 1.170 dholland 307 1.702 rillig static HashTable /* full file name -> Guard */ guards; 308 1.700 rillig 309 1.713 rillig 310 1.713 rillig static List * 311 1.713 rillig Lst_New(void) 312 1.713 rillig { 313 1.713 rillig List *list = bmake_malloc(sizeof *list); 314 1.713 rillig Lst_Init(list); 315 1.713 rillig return list; 316 1.713 rillig } 317 1.713 rillig 318 1.713 rillig static void 319 1.713 rillig Lst_Free(List *list) 320 1.713 rillig { 321 1.713 rillig 322 1.713 rillig Lst_Done(list); 323 1.713 rillig free(list); 324 1.713 rillig } 325 1.713 rillig 326 1.627 rillig static IncludedFile * 327 1.618 rillig GetInclude(size_t i) 328 1.618 rillig { 329 1.686 rillig assert(i < includes.len); 330 1.618 rillig return Vector_Get(&includes, i); 331 1.618 rillig } 332 1.618 rillig 333 1.715 rillig /* The makefile or the body of a .for loop that is currently being read. */ 334 1.627 rillig static IncludedFile * 335 1.618 rillig CurFile(void) 336 1.618 rillig { 337 1.618 rillig return GetInclude(includes.len - 1); 338 1.618 rillig } 339 1.618 rillig 340 1.744 rillig unsigned 341 1.687 rillig CurFile_CondMinDepth(void) 342 1.687 rillig { 343 1.687 rillig return CurFile()->condMinDepth; 344 1.687 rillig } 345 1.687 rillig 346 1.616 rillig static Buffer 347 1.675 rillig LoadFile(const char *path, int fd) 348 1.414 rillig { 349 1.522 rillig ssize_t n; 350 1.522 rillig Buffer buf; 351 1.612 rillig size_t bufSize; 352 1.612 rillig struct stat st; 353 1.414 rillig 354 1.612 rillig bufSize = fstat(fd, &st) == 0 && S_ISREG(st.st_mode) && 355 1.634 rillig st.st_size > 0 && st.st_size < 1024 * 1024 * 1024 356 1.612 rillig ? (size_t)st.st_size : 1024; 357 1.612 rillig Buf_InitSize(&buf, bufSize); 358 1.170 dholland 359 1.428 rillig for (;;) { 360 1.522 rillig if (buf.len == buf.cap) { 361 1.634 rillig if (buf.cap >= 512 * 1024 * 1024) { 362 1.221 riastrad Error("%s: file too large", path); 363 1.518 rillig exit(2); /* Not 1 so -q can distinguish error */ 364 1.221 riastrad } 365 1.523 rillig Buf_Expand(&buf); 366 1.170 dholland } 367 1.522 rillig assert(buf.len < buf.cap); 368 1.522 rillig n = read(fd, buf.data + buf.len, buf.cap - buf.len); 369 1.522 rillig if (n < 0) { 370 1.747 rillig Error("%s: %s", path, strerror(errno)); 371 1.518 rillig exit(2); /* Not 1 so -q can distinguish error */ 372 1.170 dholland } 373 1.522 rillig if (n == 0) 374 1.170 dholland break; 375 1.430 rillig 376 1.522 rillig buf.len += (size_t)n; 377 1.170 dholland } 378 1.522 rillig assert(buf.len <= buf.cap); 379 1.170 dholland 380 1.714 sjg if (buf.len > 0 && !Buf_EndsWith(&buf, '\n')) 381 1.522 rillig Buf_AddByte(&buf, '\n'); 382 1.170 dholland 383 1.630 rillig return buf; /* may not be null-terminated */ 384 1.170 dholland } 385 1.170 dholland 386 1.751 rillig const char * 387 1.751 rillig GetParentStackTrace(void) 388 1.751 rillig { 389 1.751 rillig static bool initialized; 390 1.751 rillig static const char *parentStackTrace; 391 1.751 rillig 392 1.751 rillig if (!initialized) { 393 1.751 rillig const char *env = getenv("MAKE_STACK_TRACE"); 394 1.751 rillig parentStackTrace = env == NULL ? NULL 395 1.751 rillig : env[0] == '\t' ? bmake_strdup(env) 396 1.751 rillig : strcmp(env, "yes") == 0 ? bmake_strdup("") 397 1.751 rillig : NULL; 398 1.751 rillig initialized = true; 399 1.751 rillig } 400 1.751 rillig return parentStackTrace; 401 1.751 rillig } 402 1.751 rillig 403 1.659 rillig /* 404 1.659 rillig * Print the current chain of .include and .for directives. In Parse_Fatal 405 1.659 rillig * or other functions that already print the location, includingInnermost 406 1.659 rillig * would be redundant, but in other cases like Error or Fatal it needs to be 407 1.659 rillig * included. 408 1.659 rillig */ 409 1.745 rillig char * 410 1.745 rillig GetStackTrace(bool includingInnermost) 411 1.532 rillig { 412 1.751 rillig const char *parentStackTrace; 413 1.745 rillig Buffer buffer, *buf = &buffer; 414 1.627 rillig const IncludedFile *entries; 415 1.532 rillig size_t i, n; 416 1.750 rillig bool hasDetails; 417 1.532 rillig 418 1.745 rillig Buf_Init(buf); 419 1.745 rillig hasDetails = EvalStack_Details(buf); 420 1.532 rillig n = includes.len; 421 1.532 rillig if (n == 0) 422 1.750 rillig goto add_parent_stack_trace; 423 1.643 rillig 424 1.686 rillig entries = GetInclude(0); 425 1.739 rillig if (!includingInnermost && !(hasDetails && n > 1) 426 1.739 rillig && entries[n - 1].forLoop == NULL) 427 1.643 rillig n--; /* already in the diagnostic */ 428 1.532 rillig 429 1.532 rillig for (i = n; i-- > 0;) { 430 1.627 rillig const IncludedFile *entry = entries + i; 431 1.576 rillig const char *fname = entry->name.str; 432 1.532 rillig char dirbuf[MAXPATHLEN + 1]; 433 1.532 rillig 434 1.698 rillig if (fname[0] != '/' && strcmp(fname, "(stdin)") != 0) { 435 1.698 rillig const char *realPath = realpath(fname, dirbuf); 436 1.698 rillig if (realPath != NULL) 437 1.698 rillig fname = realPath; 438 1.698 rillig } 439 1.532 rillig 440 1.643 rillig if (entry->forLoop != NULL) { 441 1.644 rillig char *details = ForLoop_Details(entry->forLoop); 442 1.745 rillig Buf_AddStr(buf, "\tin .for loop from "); 443 1.745 rillig Buf_AddStr(buf, fname); 444 1.745 rillig Buf_AddStr(buf, ":"); 445 1.745 rillig Buf_AddInt(buf, (int)entry->forHeadLineno); 446 1.745 rillig Buf_AddStr(buf, " with "); 447 1.745 rillig Buf_AddStr(buf, details); 448 1.745 rillig Buf_AddStr(buf, "\n"); 449 1.644 rillig free(details); 450 1.646 rillig } else if (i + 1 < n && entries[i + 1].forLoop != NULL) { 451 1.646 rillig /* entry->lineno is not a useful line number */ 452 1.745 rillig } else { 453 1.745 rillig Buf_AddStr(buf, "\tin "); 454 1.745 rillig Buf_AddStr(buf, fname); 455 1.745 rillig Buf_AddStr(buf, ":"); 456 1.745 rillig Buf_AddInt(buf, (int)entry->lineno); 457 1.745 rillig Buf_AddStr(buf, "\n"); 458 1.745 rillig } 459 1.745 rillig } 460 1.745 rillig 461 1.750 rillig add_parent_stack_trace: 462 1.751 rillig parentStackTrace = GetParentStackTrace(); 463 1.750 rillig if ((makelevel > 0 && (n > 0 || !includingInnermost)) 464 1.750 rillig || parentStackTrace != NULL) { 465 1.749 rillig Buf_AddStr(buf, "\tin "); 466 1.749 rillig Buf_AddStr(buf, progname); 467 1.749 rillig Buf_AddStr(buf, " in directory \""); 468 1.745 rillig Buf_AddStr(buf, curdir); 469 1.748 rillig Buf_AddStr(buf, "\"\n"); 470 1.532 rillig } 471 1.745 rillig 472 1.750 rillig if (parentStackTrace != NULL) 473 1.750 rillig Buf_AddStr(buf, parentStackTrace); 474 1.750 rillig 475 1.745 rillig return Buf_DoneData(buf); 476 1.745 rillig } 477 1.745 rillig 478 1.745 rillig void 479 1.745 rillig PrintStackTrace(bool includingInnermost) 480 1.745 rillig { 481 1.745 rillig char *stackTrace = GetStackTrace(includingInnermost); 482 1.745 rillig fprintf(stderr, "%s", stackTrace); 483 1.746 sjg fflush(stderr); 484 1.745 rillig free(stackTrace); 485 1.532 rillig } 486 1.77 christos 487 1.279 rillig /* Check if the current character is escaped on the current line. */ 488 1.553 rillig static bool 489 1.602 rillig IsEscaped(const char *line, const char *p) 490 1.77 christos { 491 1.628 rillig bool escaped = false; 492 1.594 rillig while (p > line && *--p == '\\') 493 1.628 rillig escaped = !escaped; 494 1.628 rillig return escaped; 495 1.77 christos } 496 1.77 christos 497 1.524 rillig /* 498 1.712 rillig * Remember the location (filename and lineno) where the last command was 499 1.712 rillig * added or where the node was mentioned in a .depend file. 500 1.524 rillig */ 501 1.278 rillig static void 502 1.562 rillig RememberLocation(GNode *gn) 503 1.278 rillig { 504 1.627 rillig IncludedFile *curFile = CurFile(); 505 1.576 rillig gn->fname = Str_Intern(curFile->name.str); 506 1.639 rillig gn->lineno = curFile->lineno; 507 1.278 rillig } 508 1.278 rillig 509 1.524 rillig /* 510 1.524 rillig * Look in the table of keywords for one matching the given string. 511 1.524 rillig * Return the index of the keyword, or -1 if it isn't there. 512 1.524 rillig */ 513 1.1 cgd static int 514 1.602 rillig FindKeyword(const char *str) 515 1.1 cgd { 516 1.469 rillig int start = 0; 517 1.469 rillig int end = sizeof parseKeywords / sizeof parseKeywords[0] - 1; 518 1.1 cgd 519 1.611 rillig while (start <= end) { 520 1.469 rillig int curr = start + (end - start) / 2; 521 1.469 rillig int diff = strcmp(str, parseKeywords[curr].name); 522 1.469 rillig 523 1.469 rillig if (diff == 0) 524 1.469 rillig return curr; 525 1.469 rillig if (diff < 0) 526 1.469 rillig end = curr - 1; 527 1.469 rillig else 528 1.469 rillig start = curr + 1; 529 1.611 rillig } 530 1.430 rillig 531 1.469 rillig return -1; 532 1.1 cgd } 533 1.1 cgd 534 1.660 rillig void 535 1.680 rillig PrintLocation(FILE *f, bool useVars, const GNode *gn) 536 1.291 rillig { 537 1.469 rillig char dirbuf[MAXPATHLEN + 1]; 538 1.505 rillig FStr dir, base; 539 1.680 rillig const char *fname; 540 1.680 rillig unsigned lineno; 541 1.680 rillig 542 1.680 rillig if (gn != NULL) { 543 1.680 rillig fname = gn->fname; 544 1.680 rillig lineno = gn->lineno; 545 1.680 rillig } else if (includes.len > 0) { 546 1.680 rillig IncludedFile *curFile = CurFile(); 547 1.680 rillig fname = curFile->name.str; 548 1.680 rillig lineno = curFile->lineno; 549 1.680 rillig } else 550 1.680 rillig return; 551 1.291 rillig 552 1.653 rillig if (!useVars || fname[0] == '/' || strcmp(fname, "(stdin)") == 0) { 553 1.740 rillig (void)fprintf(f, "%s:%u: ", fname, lineno); 554 1.299 rillig return; 555 1.299 rillig } 556 1.291 rillig 557 1.548 rillig dir = Var_Value(SCOPE_GLOBAL, ".PARSEDIR"); 558 1.505 rillig if (dir.str == NULL) 559 1.505 rillig dir.str = "."; 560 1.505 rillig if (dir.str[0] != '/') 561 1.505 rillig dir.str = realpath(dir.str, dirbuf); 562 1.505 rillig 563 1.548 rillig base = Var_Value(SCOPE_GLOBAL, ".PARSEFILE"); 564 1.505 rillig if (base.str == NULL) 565 1.505 rillig base.str = str_basename(fname); 566 1.505 rillig 567 1.740 rillig (void)fprintf(f, "%s/%s:%u: ", dir.str, base.str, lineno); 568 1.505 rillig 569 1.505 rillig FStr_Done(&base); 570 1.505 rillig FStr_Done(&dir); 571 1.291 rillig } 572 1.291 rillig 573 1.680 rillig static void MAKE_ATTR_PRINTFLIKE(5, 0) 574 1.680 rillig ParseVErrorInternal(FILE *f, bool useVars, const GNode *gn, 575 1.664 rillig ParseErrorLevel level, const char *fmt, va_list ap) 576 1.38 christos { 577 1.553 rillig static bool fatal_warning_error_printed = false; 578 1.56 christos 579 1.148 sjg (void)fprintf(f, "%s: ", progname); 580 1.63 christos 581 1.680 rillig PrintLocation(f, useVars, gn); 582 1.664 rillig if (level == PARSE_WARNING) 583 1.127 dsl (void)fprintf(f, "warning: "); 584 1.127 dsl (void)vfprintf(f, fmt, ap); 585 1.127 dsl (void)fprintf(f, "\n"); 586 1.127 dsl (void)fflush(f); 587 1.300 rillig 588 1.664 rillig if (level == PARSE_FATAL) 589 1.621 rillig parseErrors++; 590 1.664 rillig if (level == PARSE_WARNING && opts.parseWarnFatal) { 591 1.621 rillig if (!fatal_warning_error_printed) { 592 1.621 rillig Error("parsing warnings being treated as errors"); 593 1.621 rillig fatal_warning_error_printed = true; 594 1.621 rillig } 595 1.621 rillig parseErrors++; 596 1.56 christos } 597 1.532 rillig 598 1.752 rillig if (level == PARSE_FATAL || DEBUG(PARSE) 599 1.752 rillig || (gn == NULL && includes.len == 0 /* see PrintLocation */)) 600 1.659 rillig PrintStackTrace(false); 601 1.38 christos } 602 1.38 christos 603 1.680 rillig static void MAKE_ATTR_PRINTFLIKE(3, 4) 604 1.680 rillig ParseErrorInternal(const GNode *gn, 605 1.664 rillig ParseErrorLevel level, const char *fmt, ...) 606 1.203 joerg { 607 1.203 joerg va_list ap; 608 1.203 joerg 609 1.441 rillig (void)fflush(stdout); 610 1.203 joerg va_start(ap, fmt); 611 1.680 rillig ParseVErrorInternal(stderr, false, gn, level, fmt, ap); 612 1.203 joerg va_end(ap); 613 1.203 joerg 614 1.622 rillig if (opts.debug_file != stdout && opts.debug_file != stderr) { 615 1.203 joerg va_start(ap, fmt); 616 1.680 rillig ParseVErrorInternal(opts.debug_file, false, gn, 617 1.664 rillig level, fmt, ap); 618 1.203 joerg va_end(ap); 619 1.203 joerg } 620 1.203 joerg } 621 1.203 joerg 622 1.524 rillig /* 623 1.708 rillig * Print a message, including location information. 624 1.441 rillig * 625 1.441 rillig * If the level is PARSE_FATAL, continue parsing until the end of the 626 1.441 rillig * current top-level makefile, then exit (see Parse_File). 627 1.38 christos * 628 1.524 rillig * Fmt is given without a trailing newline. 629 1.524 rillig */ 630 1.1 cgd void 631 1.664 rillig Parse_Error(ParseErrorLevel level, const char *fmt, ...) 632 1.1 cgd { 633 1.1 cgd va_list ap; 634 1.156 dsl 635 1.633 rillig (void)fflush(stdout); 636 1.156 dsl va_start(ap, fmt); 637 1.680 rillig ParseVErrorInternal(stderr, true, NULL, level, fmt, ap); 638 1.1 cgd va_end(ap); 639 1.127 dsl 640 1.622 rillig if (opts.debug_file != stdout && opts.debug_file != stderr) { 641 1.127 dsl va_start(ap, fmt); 642 1.680 rillig ParseVErrorInternal(opts.debug_file, true, NULL, 643 1.664 rillig level, fmt, ap); 644 1.127 dsl va_end(ap); 645 1.127 dsl } 646 1.1 cgd } 647 1.1 cgd 648 1.161 sjg 649 1.524 rillig /* 650 1.602 rillig * Handle an .info, .warning or .error directive. For an .error directive, 651 1.602 rillig * exit immediately. 652 1.524 rillig */ 653 1.503 rillig static void 654 1.602 rillig HandleMessage(ParseErrorLevel level, const char *levelName, const char *umsg) 655 1.161 sjg { 656 1.475 rillig char *xmsg; 657 1.469 rillig 658 1.503 rillig if (umsg[0] == '\0') { 659 1.503 rillig Parse_Error(PARSE_FATAL, "Missing argument for \".%s\"", 660 1.503 rillig levelName); 661 1.503 rillig return; 662 1.503 rillig } 663 1.469 rillig 664 1.730 rillig xmsg = Var_Subst(umsg, SCOPE_CMDLINE, VARE_EVAL); 665 1.469 rillig /* TODO: handle errors */ 666 1.469 rillig 667 1.475 rillig Parse_Error(level, "%s", xmsg); 668 1.475 rillig free(xmsg); 669 1.469 rillig 670 1.475 rillig if (level == PARSE_FATAL) { 671 1.655 rillig PrintOnError(NULL, "\n"); 672 1.469 rillig exit(1); 673 1.469 rillig } 674 1.161 sjg } 675 1.161 sjg 676 1.524 rillig /* 677 1.630 rillig * Add the child to the parent's children, and for non-special targets, vice 678 1.708 rillig * versa. 679 1.524 rillig */ 680 1.382 rillig static void 681 1.553 rillig LinkSource(GNode *pgn, GNode *cgn, bool isSpecial) 682 1.382 rillig { 683 1.469 rillig if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty(&pgn->cohorts)) 684 1.469 rillig pgn = pgn->cohorts.last->datum; 685 1.316 rillig 686 1.469 rillig Lst_Append(&pgn->children, cgn); 687 1.469 rillig pgn->unmade++; 688 1.316 rillig 689 1.708 rillig /* 690 1.708 rillig * Special targets like .END do not need to be informed once the child 691 1.708 rillig * target has been made. 692 1.708 rillig */ 693 1.469 rillig if (!isSpecial) 694 1.469 rillig Lst_Append(&cgn->parents, pgn); 695 1.469 rillig 696 1.469 rillig if (DEBUG(PARSE)) { 697 1.727 rillig debug_printf("Target \"%s\" depends on \"%s\"\n", 698 1.586 rillig pgn->name, cgn->name); 699 1.469 rillig Targ_PrintNode(pgn, 0); 700 1.469 rillig Targ_PrintNode(cgn, 0); 701 1.469 rillig } 702 1.1 cgd } 703 1.1 cgd 704 1.382 rillig /* Add the node to each target from the current dependency group. */ 705 1.382 rillig static void 706 1.553 rillig LinkToTargets(GNode *gn, bool isSpecial) 707 1.382 rillig { 708 1.469 rillig GNodeListNode *ln; 709 1.469 rillig 710 1.469 rillig for (ln = targets->first; ln != NULL; ln = ln->next) 711 1.469 rillig LinkSource(ln->datum, gn, isSpecial); 712 1.382 rillig } 713 1.382 rillig 714 1.553 rillig static bool 715 1.337 rillig TryApplyDependencyOperator(GNode *gn, GNodeType op) 716 1.1 cgd { 717 1.1 cgd /* 718 1.469 rillig * If the node occurred on the left-hand side of a dependency and the 719 1.469 rillig * operator also defines a dependency, they must match. 720 1.1 cgd */ 721 1.469 rillig if ((op & OP_OPMASK) && (gn->type & OP_OPMASK) && 722 1.469 rillig ((op & OP_OPMASK) != (gn->type & OP_OPMASK))) { 723 1.469 rillig Parse_Error(PARSE_FATAL, "Inconsistent operator for %s", 724 1.469 rillig gn->name); 725 1.553 rillig return false; 726 1.469 rillig } 727 1.469 rillig 728 1.469 rillig if (op == OP_DOUBLEDEP && (gn->type & OP_OPMASK) == OP_DOUBLEDEP) { 729 1.469 rillig /* 730 1.697 rillig * If the node was on the left-hand side of a '::' operator, 731 1.708 rillig * create a new node for the children and commands on this 732 1.708 rillig * dependency line, since each of these dependency groups has 733 1.708 rillig * its own attributes and commands, separate from the others. 734 1.469 rillig * 735 1.469 rillig * The new instance is placed on the 'cohorts' list of the 736 1.469 rillig * initial one (note the initial one is not on its own 737 1.469 rillig * cohorts list) and the new instance is linked to all 738 1.469 rillig * parents of the initial instance. 739 1.469 rillig */ 740 1.469 rillig GNode *cohort; 741 1.27 christos 742 1.469 rillig /* 743 1.469 rillig * Propagate copied bits to the initial node. They'll be 744 1.469 rillig * propagated back to the rest of the cohorts later. 745 1.469 rillig */ 746 1.688 rillig gn->type |= op & (unsigned)~OP_OPMASK; 747 1.33 mycroft 748 1.469 rillig cohort = Targ_NewInternalNode(gn->name); 749 1.469 rillig if (doing_depend) 750 1.562 rillig RememberLocation(cohort); 751 1.469 rillig /* 752 1.708 rillig * Make the cohort invisible to avoid duplicating it 753 1.469 rillig * into other variables. True, parents of this target won't 754 1.469 rillig * tend to do anything with their local variables, but better 755 1.469 rillig * safe than sorry. 756 1.469 rillig * 757 1.469 rillig * (I think this is pointless now, since the relevant list 758 1.469 rillig * traversals will no longer see this node anyway. -mycroft) 759 1.469 rillig */ 760 1.469 rillig cohort->type = op | OP_INVISIBLE; 761 1.469 rillig Lst_Append(&gn->cohorts, cohort); 762 1.469 rillig cohort->centurion = gn; 763 1.469 rillig gn->unmade_cohorts++; 764 1.469 rillig snprintf(cohort->cohort_num, sizeof cohort->cohort_num, "#%d", 765 1.744 rillig (unsigned)gn->unmade_cohorts % 1000000); 766 1.469 rillig } else { 767 1.708 rillig gn->type |= op; /* preserve any previous flags */ 768 1.469 rillig } 769 1.33 mycroft 770 1.553 rillig return true; 771 1.337 rillig } 772 1.337 rillig 773 1.337 rillig static void 774 1.337 rillig ApplyDependencyOperator(GNodeType op) 775 1.337 rillig { 776 1.469 rillig GNodeListNode *ln; 777 1.469 rillig 778 1.469 rillig for (ln = targets->first; ln != NULL; ln = ln->next) 779 1.469 rillig if (!TryApplyDependencyOperator(ln->datum, op)) 780 1.469 rillig break; 781 1.1 cgd } 782 1.1 cgd 783 1.467 rillig /* 784 1.708 rillig * Add a .WAIT node in the dependency list. After any dynamic dependencies 785 1.467 rillig * (and filename globbing) have happened, it is given a dependency on each 786 1.467 rillig * previous child, back until the previous .WAIT node. The next child won't 787 1.467 rillig * be scheduled until the .WAIT node is built. 788 1.467 rillig * 789 1.708 rillig * Give each .WAIT node a unique name (mainly for diagnostics). 790 1.467 rillig */ 791 1.467 rillig static void 792 1.593 rillig ApplyDependencySourceWait(bool isSpecial) 793 1.467 rillig { 794 1.645 rillig static unsigned wait_number = 0; 795 1.671 rillig char name[6 + 10 + 1]; 796 1.467 rillig GNode *gn; 797 1.467 rillig 798 1.671 rillig snprintf(name, sizeof name, ".WAIT_%u", ++wait_number); 799 1.671 rillig gn = Targ_NewInternalNode(name); 800 1.467 rillig if (doing_depend) 801 1.562 rillig RememberLocation(gn); 802 1.467 rillig gn->type = OP_WAIT | OP_PHONY | OP_DEPENDS | OP_NOTMAIN; 803 1.467 rillig LinkToTargets(gn, isSpecial); 804 1.467 rillig } 805 1.467 rillig 806 1.553 rillig static bool 807 1.593 rillig ApplyDependencySourceKeyword(const char *src, ParseSpecial special) 808 1.1 cgd { 809 1.468 rillig int keywd; 810 1.590 rillig GNodeType targetAttr; 811 1.1 cgd 812 1.468 rillig if (*src != '.' || !ch_isupper(src[1])) 813 1.553 rillig return false; 814 1.468 rillig 815 1.602 rillig keywd = FindKeyword(src); 816 1.468 rillig if (keywd == -1) 817 1.553 rillig return false; 818 1.468 rillig 819 1.590 rillig targetAttr = parseKeywords[keywd].targetAttr; 820 1.590 rillig if (targetAttr != OP_NONE) { 821 1.590 rillig ApplyDependencyOperator(targetAttr); 822 1.553 rillig return true; 823 1.468 rillig } 824 1.590 rillig if (parseKeywords[keywd].special == SP_WAIT) { 825 1.593 rillig ApplyDependencySourceWait(special != SP_NOT); 826 1.553 rillig return true; 827 1.1 cgd } 828 1.553 rillig return false; 829 1.368 rillig } 830 1.18 christos 831 1.630 rillig /* 832 1.630 rillig * In a line like ".MAIN: source1 source2", add all sources to the list of 833 1.630 rillig * things to create, but only if the user didn't specify a target on the 834 1.630 rillig * command line and .MAIN occurs for the first time. 835 1.630 rillig * 836 1.630 rillig * See HandleDependencyTargetSpecial, branch SP_MAIN. 837 1.630 rillig * See unit-tests/cond-func-make-main.mk. 838 1.630 rillig */ 839 1.368 rillig static void 840 1.593 rillig ApplyDependencySourceMain(const char *src) 841 1.368 rillig { 842 1.469 rillig Lst_Append(&opts.create, bmake_strdup(src)); 843 1.469 rillig /* 844 1.469 rillig * Add the name to the .TARGETS variable as well, so the user can 845 1.469 rillig * employ that, if desired. 846 1.469 rillig */ 847 1.542 rillig Global_Append(".TARGETS", src); 848 1.368 rillig } 849 1.18 christos 850 1.665 rillig /* 851 1.665 rillig * For the sources of a .ORDER target, create predecessor/successor links 852 1.665 rillig * between the previous source and the current one. 853 1.665 rillig */ 854 1.368 rillig static void 855 1.593 rillig ApplyDependencySourceOrder(const char *src) 856 1.368 rillig { 857 1.469 rillig GNode *gn; 858 1.665 rillig 859 1.469 rillig gn = Targ_GetNode(src); 860 1.469 rillig if (doing_depend) 861 1.562 rillig RememberLocation(gn); 862 1.469 rillig if (order_pred != NULL) { 863 1.469 rillig Lst_Append(&order_pred->order_succ, gn); 864 1.469 rillig Lst_Append(&gn->order_pred, order_pred); 865 1.469 rillig if (DEBUG(PARSE)) { 866 1.586 rillig debug_printf( 867 1.592 rillig "# .ORDER forces '%s' to be made before '%s'\n", 868 1.586 rillig order_pred->name, gn->name); 869 1.469 rillig Targ_PrintNode(order_pred, 0); 870 1.469 rillig Targ_PrintNode(gn, 0); 871 1.469 rillig } 872 1.469 rillig } 873 1.708 rillig /* The current source now becomes the predecessor for the next one. */ 874 1.469 rillig order_pred = gn; 875 1.368 rillig } 876 1.368 rillig 877 1.630 rillig /* The source is not an attribute, so find/create a node for it. */ 878 1.368 rillig static void 879 1.593 rillig ApplyDependencySourceOther(const char *src, GNodeType targetAttr, 880 1.587 rillig ParseSpecial special) 881 1.368 rillig { 882 1.469 rillig GNode *gn; 883 1.469 rillig 884 1.469 rillig gn = Targ_GetNode(src); 885 1.469 rillig if (doing_depend) 886 1.562 rillig RememberLocation(gn); 887 1.590 rillig if (targetAttr != OP_NONE) 888 1.590 rillig gn->type |= targetAttr; 889 1.469 rillig else 890 1.587 rillig LinkToTargets(gn, special != SP_NOT); 891 1.1 cgd } 892 1.1 cgd 893 1.469 rillig /* 894 1.469 rillig * Given the name of a source in a dependency line, figure out if it is an 895 1.590 rillig * attribute (such as .SILENT) and if so, apply it to all targets. Otherwise 896 1.368 rillig * decide if there is some attribute which should be applied *to* the source 897 1.368 rillig * because of some special target (such as .PHONY) and apply it if so. 898 1.590 rillig * Otherwise, make the source a child of the targets. 899 1.368 rillig */ 900 1.368 rillig static void 901 1.593 rillig ApplyDependencySource(GNodeType targetAttr, const char *src, 902 1.590 rillig ParseSpecial special) 903 1.368 rillig { 904 1.593 rillig if (ApplyDependencySourceKeyword(src, special)) 905 1.469 rillig return; 906 1.368 rillig 907 1.587 rillig if (special == SP_MAIN) 908 1.593 rillig ApplyDependencySourceMain(src); 909 1.587 rillig else if (special == SP_ORDER) 910 1.593 rillig ApplyDependencySourceOrder(src); 911 1.469 rillig else 912 1.593 rillig ApplyDependencySourceOther(src, targetAttr, special); 913 1.368 rillig } 914 1.368 rillig 915 1.469 rillig /* 916 1.469 rillig * If we have yet to decide on a main target to make, in the absence of any 917 1.335 rillig * user input, we want the first target on the first dependency line that is 918 1.469 rillig * actually a real target (i.e. isn't a .USE or .EXEC rule) to be made. 919 1.469 rillig */ 920 1.335 rillig static void 921 1.630 rillig MaybeUpdateMainTarget(void) 922 1.1 cgd { 923 1.469 rillig GNodeListNode *ln; 924 1.335 rillig 925 1.469 rillig if (mainNode != NULL) 926 1.469 rillig return; 927 1.335 rillig 928 1.469 rillig for (ln = targets->first; ln != NULL; ln = ln->next) { 929 1.469 rillig GNode *gn = ln->datum; 930 1.589 rillig if (GNode_IsMainCandidate(gn)) { 931 1.709 rillig DEBUG1(MAKE, "Setting main node to \"%s\"\n", 932 1.709 rillig gn->name); 933 1.469 rillig mainNode = gn; 934 1.469 rillig return; 935 1.469 rillig } 936 1.335 rillig } 937 1.1 cgd } 938 1.1 cgd 939 1.311 rillig static void 940 1.706 rillig InvalidLineType(const char *line, const char *unexpanded_line) 941 1.311 rillig { 942 1.706 rillig if (unexpanded_line[0] == '.') { 943 1.706 rillig const char *dirstart = unexpanded_line + 1; 944 1.469 rillig const char *dirend; 945 1.469 rillig cpp_skip_whitespace(&dirstart); 946 1.469 rillig dirend = dirstart; 947 1.469 rillig while (ch_isalnum(*dirend) || *dirend == '-') 948 1.469 rillig dirend++; 949 1.469 rillig Parse_Error(PARSE_FATAL, "Unknown directive \"%.*s\"", 950 1.311 rillig (int)(dirend - dirstart), dirstart); 951 1.706 rillig } else if (strcmp(line, unexpanded_line) == 0) 952 1.753 rillig Parse_Error(PARSE_FATAL, "Invalid line \"%s\"", line); 953 1.706 rillig else 954 1.709 rillig Parse_Error(PARSE_FATAL, 955 1.753 rillig "Invalid line \"%s\", expanded to \"%s\"", 956 1.706 rillig unexpanded_line, line); 957 1.311 rillig } 958 1.311 rillig 959 1.314 rillig static void 960 1.599 rillig ParseDependencyTargetWord(char **pp, const char *lstart) 961 1.314 rillig { 962 1.709 rillig const char *p = *pp; 963 1.469 rillig 964 1.709 rillig while (*p != '\0') { 965 1.709 rillig if ((ch_isspace(*p) || *p == '!' || *p == ':' || *p == '(') 966 1.709 rillig && !IsEscaped(lstart, p)) 967 1.469 rillig break; 968 1.314 rillig 969 1.709 rillig if (*p == '$') { 970 1.730 rillig FStr val = Var_Parse(&p, SCOPE_CMDLINE, VARE_PARSE); 971 1.708 rillig /* TODO: handle errors */ 972 1.624 rillig FStr_Done(&val); 973 1.469 rillig } else 974 1.709 rillig p++; 975 1.469 rillig } 976 1.314 rillig 977 1.709 rillig *pp += p - *pp; 978 1.314 rillig } 979 1.314 rillig 980 1.559 rillig /* 981 1.559 rillig * Handle special targets like .PATH, .DEFAULT, .BEGIN, .ORDER. 982 1.559 rillig * 983 1.559 rillig * See the tests deptgt-*.mk. 984 1.559 rillig */ 985 1.368 rillig static void 986 1.602 rillig HandleDependencyTargetSpecial(const char *targetName, 987 1.602 rillig ParseSpecial *inout_special, 988 1.602 rillig SearchPathList **inout_paths) 989 1.368 rillig { 990 1.587 rillig switch (*inout_special) { 991 1.469 rillig case SP_PATH: 992 1.469 rillig if (*inout_paths == NULL) 993 1.469 rillig *inout_paths = Lst_New(); 994 1.469 rillig Lst_Append(*inout_paths, &dirSearchPath); 995 1.469 rillig break; 996 1.692 sjg case SP_SYSPATH: 997 1.692 sjg if (*inout_paths == NULL) 998 1.692 sjg *inout_paths = Lst_New(); 999 1.692 sjg Lst_Append(*inout_paths, sysIncPath); 1000 1.692 sjg break; 1001 1.469 rillig case SP_MAIN: 1002 1.469 rillig /* 1003 1.469 rillig * Allow targets from the command line to override the 1004 1.469 rillig * .MAIN node. 1005 1.469 rillig */ 1006 1.469 rillig if (!Lst_IsEmpty(&opts.create)) 1007 1.587 rillig *inout_special = SP_NOT; 1008 1.469 rillig break; 1009 1.469 rillig case SP_BEGIN: 1010 1.469 rillig case SP_END: 1011 1.469 rillig case SP_STALE: 1012 1.469 rillig case SP_ERROR: 1013 1.469 rillig case SP_INTERRUPT: { 1014 1.530 rillig GNode *gn = Targ_GetNode(targetName); 1015 1.469 rillig if (doing_depend) 1016 1.562 rillig RememberLocation(gn); 1017 1.469 rillig gn->type |= OP_NOTMAIN | OP_SPECIAL; 1018 1.469 rillig Lst_Append(targets, gn); 1019 1.469 rillig break; 1020 1.469 rillig } 1021 1.469 rillig case SP_DEFAULT: { 1022 1.469 rillig /* 1023 1.469 rillig * Need to create a node to hang commands on, but we don't 1024 1.469 rillig * want it in the graph, nor do we want it to be the Main 1025 1.469 rillig * Target. We claim the node is a transformation rule to make 1026 1.469 rillig * life easier later, when we'll use Make_HandleUse to 1027 1.469 rillig * actually apply the .DEFAULT commands. 1028 1.469 rillig */ 1029 1.469 rillig GNode *gn = GNode_New(".DEFAULT"); 1030 1.469 rillig gn->type |= OP_NOTMAIN | OP_TRANSFORM; 1031 1.469 rillig Lst_Append(targets, gn); 1032 1.469 rillig defaultNode = gn; 1033 1.469 rillig break; 1034 1.469 rillig } 1035 1.469 rillig case SP_DELETE_ON_ERROR: 1036 1.553 rillig deleteOnError = true; 1037 1.469 rillig break; 1038 1.469 rillig case SP_NOTPARALLEL: 1039 1.469 rillig opts.maxJobs = 1; 1040 1.469 rillig break; 1041 1.469 rillig case SP_SINGLESHELL: 1042 1.553 rillig opts.compatMake = true; 1043 1.469 rillig break; 1044 1.469 rillig case SP_ORDER: 1045 1.469 rillig order_pred = NULL; 1046 1.469 rillig break; 1047 1.469 rillig default: 1048 1.469 rillig break; 1049 1.469 rillig } 1050 1.368 rillig } 1051 1.368 rillig 1052 1.553 rillig static bool 1053 1.602 rillig HandleDependencyTargetPath(const char *suffixName, 1054 1.602 rillig SearchPathList **inout_paths) 1055 1.368 rillig { 1056 1.469 rillig SearchPath *path; 1057 1.368 rillig 1058 1.530 rillig path = Suff_GetPath(suffixName); 1059 1.469 rillig if (path == NULL) { 1060 1.469 rillig Parse_Error(PARSE_FATAL, 1061 1.753 rillig "Suffix \"%s\" not defined (yet)", suffixName); 1062 1.553 rillig return false; 1063 1.469 rillig } 1064 1.430 rillig 1065 1.469 rillig if (*inout_paths == NULL) 1066 1.469 rillig *inout_paths = Lst_New(); 1067 1.469 rillig Lst_Append(*inout_paths, path); 1068 1.430 rillig 1069 1.553 rillig return true; 1070 1.368 rillig } 1071 1.368 rillig 1072 1.628 rillig /* See if it's a special target and if so set inout_special to match it. */ 1073 1.553 rillig static bool 1074 1.602 rillig HandleDependencyTarget(const char *targetName, 1075 1.602 rillig ParseSpecial *inout_special, 1076 1.602 rillig GNodeType *inout_targetAttr, 1077 1.602 rillig SearchPathList **inout_paths) 1078 1.364 rillig { 1079 1.469 rillig int keywd; 1080 1.469 rillig 1081 1.530 rillig if (!(targetName[0] == '.' && ch_isupper(targetName[1]))) 1082 1.553 rillig return true; 1083 1.469 rillig 1084 1.469 rillig /* 1085 1.469 rillig * See if the target is a special target that must have it 1086 1.469 rillig * or its sources handled specially. 1087 1.469 rillig */ 1088 1.602 rillig keywd = FindKeyword(targetName); 1089 1.469 rillig if (keywd != -1) { 1090 1.587 rillig if (*inout_special == SP_PATH && 1091 1.590 rillig parseKeywords[keywd].special != SP_PATH) { 1092 1.469 rillig Parse_Error(PARSE_FATAL, "Mismatched special targets"); 1093 1.553 rillig return false; 1094 1.469 rillig } 1095 1.469 rillig 1096 1.590 rillig *inout_special = parseKeywords[keywd].special; 1097 1.590 rillig *inout_targetAttr = parseKeywords[keywd].targetAttr; 1098 1.469 rillig 1099 1.602 rillig HandleDependencyTargetSpecial(targetName, inout_special, 1100 1.469 rillig inout_paths); 1101 1.364 rillig 1102 1.530 rillig } else if (strncmp(targetName, ".PATH", 5) == 0) { 1103 1.587 rillig *inout_special = SP_PATH; 1104 1.602 rillig if (!HandleDependencyTargetPath(targetName + 5, inout_paths)) 1105 1.553 rillig return false; 1106 1.469 rillig } 1107 1.553 rillig return true; 1108 1.368 rillig } 1109 1.368 rillig 1110 1.368 rillig static void 1111 1.677 rillig HandleSingleDependencyTargetMundane(const char *name) 1112 1.677 rillig { 1113 1.677 rillig GNode *gn = Suff_IsTransform(name) 1114 1.677 rillig ? Suff_AddTransform(name) 1115 1.677 rillig : Targ_GetNode(name); 1116 1.677 rillig if (doing_depend) 1117 1.677 rillig RememberLocation(gn); 1118 1.677 rillig 1119 1.677 rillig Lst_Append(targets, gn); 1120 1.677 rillig } 1121 1.677 rillig 1122 1.677 rillig static void 1123 1.678 rillig HandleDependencyTargetMundane(const char *targetName) 1124 1.368 rillig { 1125 1.678 rillig if (Dir_HasWildcards(targetName)) { 1126 1.678 rillig StringList targetNames = LST_INIT; 1127 1.595 rillig 1128 1.469 rillig SearchPath *emptyPath = SearchPath_New(); 1129 1.595 rillig SearchPath_Expand(emptyPath, targetName, &targetNames); 1130 1.469 rillig SearchPath_Free(emptyPath); 1131 1.678 rillig 1132 1.678 rillig while (!Lst_IsEmpty(&targetNames)) { 1133 1.678 rillig char *targName = Lst_Dequeue(&targetNames); 1134 1.678 rillig HandleSingleDependencyTargetMundane(targName); 1135 1.679 rillig free(targName); 1136 1.678 rillig } 1137 1.595 rillig } else 1138 1.678 rillig HandleSingleDependencyTargetMundane(targetName); 1139 1.368 rillig } 1140 1.368 rillig 1141 1.368 rillig static void 1142 1.603 rillig SkipExtraTargets(char **pp, const char *lstart) 1143 1.368 rillig { 1144 1.553 rillig bool warning = false; 1145 1.628 rillig const char *p = *pp; 1146 1.368 rillig 1147 1.628 rillig while (*p != '\0') { 1148 1.628 rillig if (!IsEscaped(lstart, p) && (*p == '!' || *p == ':')) 1149 1.469 rillig break; 1150 1.628 rillig if (IsEscaped(lstart, p) || (*p != ' ' && *p != '\t')) 1151 1.553 rillig warning = true; 1152 1.628 rillig p++; 1153 1.469 rillig } 1154 1.690 rillig if (warning) { 1155 1.690 rillig const char *start = *pp; 1156 1.690 rillig cpp_skip_whitespace(&start); 1157 1.753 rillig Parse_Error(PARSE_WARNING, "Extra target \"%.*s\" ignored", 1158 1.690 rillig (int)(p - start), start); 1159 1.690 rillig } 1160 1.430 rillig 1161 1.628 rillig *pp += p - *pp; 1162 1.368 rillig } 1163 1.368 rillig 1164 1.368 rillig static void 1165 1.628 rillig CheckSpecialMundaneMixture(ParseSpecial special) 1166 1.368 rillig { 1167 1.587 rillig switch (special) { 1168 1.469 rillig case SP_DEFAULT: 1169 1.469 rillig case SP_STALE: 1170 1.469 rillig case SP_BEGIN: 1171 1.469 rillig case SP_END: 1172 1.469 rillig case SP_ERROR: 1173 1.469 rillig case SP_INTERRUPT: 1174 1.469 rillig /* 1175 1.469 rillig * These create nodes on which to hang commands, so targets 1176 1.469 rillig * shouldn't be empty. 1177 1.469 rillig */ 1178 1.469 rillig case SP_NOT: 1179 1.665 rillig /* Nothing special here -- targets may be empty. */ 1180 1.469 rillig break; 1181 1.582 rillig default: 1182 1.582 rillig Parse_Error(PARSE_WARNING, 1183 1.582 rillig "Special and mundane targets don't mix. " 1184 1.582 rillig "Mundane ones ignored"); 1185 1.582 rillig break; 1186 1.469 rillig } 1187 1.368 rillig } 1188 1.368 rillig 1189 1.560 rillig /* 1190 1.560 rillig * In a dependency line like 'targets: sources' or 'targets! sources', parse 1191 1.560 rillig * the operator ':', '::' or '!' from between the targets and the sources. 1192 1.560 rillig */ 1193 1.578 rillig static GNodeType 1194 1.578 rillig ParseDependencyOp(char **pp) 1195 1.368 rillig { 1196 1.578 rillig if (**pp == '!') 1197 1.578 rillig return (*pp)++, OP_FORCE; 1198 1.681 rillig if (**pp == ':' && (*pp)[1] == ':') 1199 1.630 rillig return *pp += 2, OP_DOUBLEDEP; 1200 1.681 rillig else if (**pp == ':') 1201 1.681 rillig return (*pp)++, OP_DEPENDS; 1202 1.578 rillig else 1203 1.681 rillig return OP_NONE; 1204 1.368 rillig } 1205 1.364 rillig 1206 1.368 rillig static void 1207 1.692 sjg ClearPaths(ParseSpecial special, SearchPathList *paths) 1208 1.392 rillig { 1209 1.469 rillig if (paths != NULL) { 1210 1.469 rillig SearchPathListNode *ln; 1211 1.469 rillig for (ln = paths->first; ln != NULL; ln = ln->next) 1212 1.469 rillig SearchPath_Clear(ln->datum); 1213 1.469 rillig } 1214 1.692 sjg if (special == SP_SYSPATH) 1215 1.692 sjg Dir_SetSYSPATH(); 1216 1.692 sjg else 1217 1.692 sjg Dir_SetPATH(); 1218 1.392 rillig } 1219 1.392 rillig 1220 1.673 rillig static char * 1221 1.673 rillig FindInDirOfIncludingFile(const char *file) 1222 1.673 rillig { 1223 1.673 rillig char *fullname, *incdir, *slash, *newName; 1224 1.673 rillig int i; 1225 1.673 rillig 1226 1.673 rillig fullname = NULL; 1227 1.673 rillig incdir = bmake_strdup(CurFile()->name.str); 1228 1.673 rillig slash = strrchr(incdir, '/'); 1229 1.673 rillig if (slash != NULL) { 1230 1.673 rillig *slash = '\0'; 1231 1.673 rillig /* 1232 1.673 rillig * Now do lexical processing of leading "../" on the 1233 1.673 rillig * filename. 1234 1.673 rillig */ 1235 1.673 rillig for (i = 0; strncmp(file + i, "../", 3) == 0; i += 3) { 1236 1.673 rillig slash = strrchr(incdir + 1, '/'); 1237 1.673 rillig if (slash == NULL || strcmp(slash, "/..") == 0) 1238 1.673 rillig break; 1239 1.673 rillig *slash = '\0'; 1240 1.673 rillig } 1241 1.673 rillig newName = str_concat3(incdir, "/", file + i); 1242 1.673 rillig fullname = Dir_FindFile(newName, parseIncPath); 1243 1.673 rillig if (fullname == NULL) 1244 1.673 rillig fullname = Dir_FindFile(newName, &dirSearchPath); 1245 1.673 rillig free(newName); 1246 1.673 rillig } 1247 1.673 rillig free(incdir); 1248 1.673 rillig return fullname; 1249 1.673 rillig } 1250 1.673 rillig 1251 1.674 rillig static char * 1252 1.674 rillig FindInQuotPath(const char *file) 1253 1.674 rillig { 1254 1.674 rillig const char *suff; 1255 1.674 rillig SearchPath *suffPath; 1256 1.674 rillig char *fullname; 1257 1.674 rillig 1258 1.674 rillig fullname = FindInDirOfIncludingFile(file); 1259 1.674 rillig if (fullname == NULL && 1260 1.674 rillig (suff = strrchr(file, '.')) != NULL && 1261 1.674 rillig (suffPath = Suff_GetPath(suff)) != NULL) 1262 1.674 rillig fullname = Dir_FindFile(file, suffPath); 1263 1.674 rillig if (fullname == NULL) 1264 1.674 rillig fullname = Dir_FindFile(file, parseIncPath); 1265 1.674 rillig if (fullname == NULL) 1266 1.674 rillig fullname = Dir_FindFile(file, &dirSearchPath); 1267 1.674 rillig return fullname; 1268 1.674 rillig } 1269 1.674 rillig 1270 1.701 rillig static bool 1271 1.701 rillig SkipGuarded(const char *fullname) 1272 1.701 rillig { 1273 1.702 rillig Guard *guard = HashTable_FindValue(&guards, fullname); 1274 1.702 rillig if (guard != NULL && guard->kind == GK_VARIABLE 1275 1.702 rillig && GNode_ValueDirect(SCOPE_GLOBAL, guard->name) != NULL) 1276 1.702 rillig goto skip; 1277 1.702 rillig if (guard != NULL && guard->kind == GK_TARGET 1278 1.702 rillig && Targ_FindNode(guard->name) != NULL) 1279 1.702 rillig goto skip; 1280 1.701 rillig return false; 1281 1.702 rillig 1282 1.702 rillig skip: 1283 1.702 rillig DEBUG2(PARSE, "Skipping '%s' because '%s' is defined\n", 1284 1.702 rillig fullname, guard->name); 1285 1.702 rillig return true; 1286 1.701 rillig } 1287 1.701 rillig 1288 1.668 sjg /* 1289 1.668 sjg * Handle one of the .[-ds]include directives by remembering the current file 1290 1.668 sjg * and pushing the included file on the stack. After the included file has 1291 1.668 sjg * finished, parsing continues with the including file; see Parse_PushInput 1292 1.668 sjg * and ParseEOF. 1293 1.668 sjg * 1294 1.668 sjg * System includes are looked up in sysIncPath, any other includes are looked 1295 1.668 sjg * up in the parsedir and then in the directories specified by the -I command 1296 1.668 sjg * line options. 1297 1.668 sjg */ 1298 1.668 sjg static void 1299 1.668 sjg IncludeFile(const char *file, bool isSystem, bool depinc, bool silent) 1300 1.668 sjg { 1301 1.668 sjg Buffer buf; 1302 1.668 sjg char *fullname; /* full pathname of file */ 1303 1.668 sjg int fd; 1304 1.668 sjg 1305 1.668 sjg fullname = file[0] == '/' ? bmake_strdup(file) : NULL; 1306 1.668 sjg 1307 1.674 rillig if (fullname == NULL && !isSystem) 1308 1.674 rillig fullname = FindInQuotPath(file); 1309 1.668 sjg 1310 1.668 sjg if (fullname == NULL) { 1311 1.668 sjg SearchPath *path = Lst_IsEmpty(&sysIncPath->dirs) 1312 1.668 sjg ? defSysIncPath : sysIncPath; 1313 1.723 sjg fullname = Dir_FindInclude(file, path); 1314 1.668 sjg } 1315 1.668 sjg 1316 1.668 sjg if (fullname == NULL) { 1317 1.668 sjg if (!silent) 1318 1.668 sjg Parse_Error(PARSE_FATAL, "Could not find %s", file); 1319 1.668 sjg return; 1320 1.668 sjg } 1321 1.668 sjg 1322 1.701 rillig if (SkipGuarded(fullname)) 1323 1.724 rillig goto done; 1324 1.700 rillig 1325 1.674 rillig if ((fd = open(fullname, O_RDONLY)) == -1) { 1326 1.668 sjg if (!silent) 1327 1.668 sjg Parse_Error(PARSE_FATAL, "Cannot open %s", fullname); 1328 1.724 rillig goto done; 1329 1.668 sjg } 1330 1.668 sjg 1331 1.675 rillig buf = LoadFile(fullname, fd); 1332 1.668 sjg (void)close(fd); 1333 1.668 sjg 1334 1.668 sjg Parse_PushInput(fullname, 1, 0, buf, NULL); 1335 1.668 sjg if (depinc) 1336 1.668 sjg doing_depend = depinc; /* only turn it on */ 1337 1.724 rillig done: 1338 1.668 sjg free(fullname); 1339 1.668 sjg } 1340 1.668 sjg 1341 1.630 rillig /* Handle a "dependency" line like '.SPECIAL:' without any sources. */ 1342 1.392 rillig static void 1343 1.630 rillig HandleDependencySourcesEmpty(ParseSpecial special, SearchPathList *paths) 1344 1.368 rillig { 1345 1.587 rillig switch (special) { 1346 1.469 rillig case SP_SUFFIXES: 1347 1.469 rillig Suff_ClearSuffixes(); 1348 1.469 rillig break; 1349 1.469 rillig case SP_PRECIOUS: 1350 1.553 rillig allPrecious = true; 1351 1.469 rillig break; 1352 1.469 rillig case SP_IGNORE: 1353 1.553 rillig opts.ignoreErrors = true; 1354 1.469 rillig break; 1355 1.469 rillig case SP_SILENT: 1356 1.584 rillig opts.silent = true; 1357 1.469 rillig break; 1358 1.469 rillig case SP_PATH: 1359 1.692 sjg case SP_SYSPATH: 1360 1.692 sjg ClearPaths(special, paths); 1361 1.469 rillig break; 1362 1.469 rillig case SP_POSIX: 1363 1.669 rillig if (posix_state == PS_NOW_OR_NEVER) { 1364 1.670 sjg /* 1365 1.670 sjg * With '-r', 'posix.mk' (if it exists) 1366 1.670 sjg * can effectively substitute for 'sys.mk', 1367 1.670 sjg * otherwise it is an extension. 1368 1.670 sjg */ 1369 1.669 rillig Global_Set("%POSIX", "1003.2"); 1370 1.741 sjg posix_state = PS_SET; 1371 1.669 rillig IncludeFile("posix.mk", true, false, true); 1372 1.668 sjg } 1373 1.469 rillig break; 1374 1.469 rillig default: 1375 1.469 rillig break; 1376 1.469 rillig } 1377 1.368 rillig } 1378 1.364 rillig 1379 1.393 rillig static void 1380 1.393 rillig AddToPaths(const char *dir, SearchPathList *paths) 1381 1.393 rillig { 1382 1.469 rillig if (paths != NULL) { 1383 1.469 rillig SearchPathListNode *ln; 1384 1.469 rillig for (ln = paths->first; ln != NULL; ln = ln->next) 1385 1.529 rillig (void)SearchPath_Add(ln->datum, dir); 1386 1.469 rillig } 1387 1.393 rillig } 1388 1.393 rillig 1389 1.368 rillig /* 1390 1.610 rillig * If the target was one that doesn't take files as its sources but takes 1391 1.610 rillig * something like suffixes, we take each space-separated word on the line as 1392 1.610 rillig * a something and deal with it accordingly. 1393 1.368 rillig */ 1394 1.368 rillig static void 1395 1.622 rillig ParseDependencySourceSpecial(ParseSpecial special, const char *word, 1396 1.556 rillig SearchPathList *paths) 1397 1.368 rillig { 1398 1.587 rillig switch (special) { 1399 1.469 rillig case SP_SUFFIXES: 1400 1.632 rillig Suff_AddSuffix(word); 1401 1.469 rillig break; 1402 1.469 rillig case SP_PATH: 1403 1.709 rillig case SP_SYSPATH: 1404 1.469 rillig AddToPaths(word, paths); 1405 1.469 rillig break; 1406 1.469 rillig case SP_INCLUDES: 1407 1.469 rillig Suff_AddInclude(word); 1408 1.469 rillig break; 1409 1.469 rillig case SP_LIBS: 1410 1.469 rillig Suff_AddLib(word); 1411 1.469 rillig break; 1412 1.691 sjg case SP_NOREADONLY: 1413 1.691 sjg Var_ReadOnly(word, false); 1414 1.691 sjg break; 1415 1.469 rillig case SP_NULL: 1416 1.469 rillig Suff_SetNull(word); 1417 1.469 rillig break; 1418 1.469 rillig case SP_OBJDIR: 1419 1.553 rillig Main_SetObjdir(false, "%s", word); 1420 1.469 rillig break; 1421 1.691 sjg case SP_READONLY: 1422 1.691 sjg Var_ReadOnly(word, true); 1423 1.691 sjg break; 1424 1.469 rillig default: 1425 1.469 rillig break; 1426 1.469 rillig } 1427 1.368 rillig } 1428 1.364 rillig 1429 1.553 rillig static bool 1430 1.601 rillig ApplyDependencyTarget(char *name, char *nameEnd, ParseSpecial *inout_special, 1431 1.601 rillig GNodeType *inout_targetAttr, 1432 1.601 rillig SearchPathList **inout_paths) 1433 1.601 rillig { 1434 1.709 rillig char savedNameEnd = *nameEnd; 1435 1.601 rillig *nameEnd = '\0'; 1436 1.601 rillig 1437 1.602 rillig if (!HandleDependencyTarget(name, inout_special, 1438 1.601 rillig inout_targetAttr, inout_paths)) 1439 1.601 rillig return false; 1440 1.601 rillig 1441 1.601 rillig if (*inout_special == SP_NOT && *name != '\0') 1442 1.602 rillig HandleDependencyTargetMundane(name); 1443 1.601 rillig else if (*inout_special == SP_PATH && *name != '.' && *name != '\0') 1444 1.753 rillig Parse_Error(PARSE_WARNING, "Extra target \"%s\" ignored", 1445 1.753 rillig name); 1446 1.601 rillig 1447 1.709 rillig *nameEnd = savedNameEnd; 1448 1.601 rillig return true; 1449 1.601 rillig } 1450 1.601 rillig 1451 1.601 rillig static bool 1452 1.689 rillig ParseDependencyTargets(char **pp, 1453 1.556 rillig const char *lstart, 1454 1.587 rillig ParseSpecial *inout_special, 1455 1.590 rillig GNodeType *inout_targetAttr, 1456 1.706 rillig SearchPathList **inout_paths, 1457 1.706 rillig const char *unexpanded_line) 1458 1.368 rillig { 1459 1.689 rillig char *p = *pp; 1460 1.469 rillig 1461 1.469 rillig for (;;) { 1462 1.689 rillig char *tgt = p; 1463 1.625 rillig 1464 1.689 rillig ParseDependencyTargetWord(&p, lstart); 1465 1.469 rillig 1466 1.469 rillig /* 1467 1.469 rillig * If the word is followed by a left parenthesis, it's the 1468 1.596 rillig * name of one or more files inside an archive. 1469 1.469 rillig */ 1470 1.689 rillig if (!IsEscaped(lstart, p) && *p == '(') { 1471 1.689 rillig p = tgt; 1472 1.689 rillig if (!Arch_ParseArchive(&p, targets, SCOPE_CMDLINE)) { 1473 1.469 rillig Parse_Error(PARSE_FATAL, 1474 1.469 rillig "Error in archive specification: \"%s\"", 1475 1.469 rillig tgt); 1476 1.553 rillig return false; 1477 1.469 rillig } 1478 1.469 rillig continue; 1479 1.469 rillig } 1480 1.444 rillig 1481 1.689 rillig if (*p == '\0') { 1482 1.706 rillig InvalidLineType(lstart, unexpanded_line); 1483 1.553 rillig return false; 1484 1.469 rillig } 1485 1.27 christos 1486 1.689 rillig if (!ApplyDependencyTarget(tgt, p, inout_special, 1487 1.590 rillig inout_targetAttr, inout_paths)) 1488 1.553 rillig return false; 1489 1.118 dsl 1490 1.587 rillig if (*inout_special != SP_NOT && *inout_special != SP_PATH) 1491 1.689 rillig SkipExtraTargets(&p, lstart); 1492 1.469 rillig else 1493 1.689 rillig pp_skip_whitespace(&p); 1494 1.368 rillig 1495 1.689 rillig if (*p == '\0') 1496 1.469 rillig break; 1497 1.689 rillig if ((*p == '!' || *p == ':') && !IsEscaped(lstart, p)) 1498 1.469 rillig break; 1499 1.469 rillig } 1500 1.430 rillig 1501 1.689 rillig *pp = p; 1502 1.553 rillig return true; 1503 1.368 rillig } 1504 1.27 christos 1505 1.368 rillig static void 1506 1.597 rillig ParseDependencySourcesSpecial(char *start, 1507 1.587 rillig ParseSpecial special, SearchPathList *paths) 1508 1.368 rillig { 1509 1.204 dholland 1510 1.469 rillig while (*start != '\0') { 1511 1.709 rillig char savedEnd; 1512 1.597 rillig char *end = start; 1513 1.469 rillig while (*end != '\0' && !ch_isspace(*end)) 1514 1.469 rillig end++; 1515 1.709 rillig savedEnd = *end; 1516 1.469 rillig *end = '\0'; 1517 1.587 rillig ParseDependencySourceSpecial(special, start, paths); 1518 1.709 rillig *end = savedEnd; 1519 1.709 rillig if (savedEnd != '\0') 1520 1.469 rillig end++; 1521 1.469 rillig pp_skip_whitespace(&end); 1522 1.469 rillig start = end; 1523 1.469 rillig } 1524 1.368 rillig } 1525 1.368 rillig 1526 1.656 sjg static void 1527 1.656 sjg LinkVarToTargets(VarAssign *var) 1528 1.656 sjg { 1529 1.656 sjg GNodeListNode *ln; 1530 1.656 sjg 1531 1.656 sjg for (ln = targets->first; ln != NULL; ln = ln->next) 1532 1.658 rillig Parse_Var(var, ln->datum); 1533 1.656 sjg } 1534 1.656 sjg 1535 1.553 rillig static bool 1536 1.597 rillig ParseDependencySourcesMundane(char *start, 1537 1.590 rillig ParseSpecial special, GNodeType targetAttr) 1538 1.368 rillig { 1539 1.469 rillig while (*start != '\0') { 1540 1.597 rillig char *end = start; 1541 1.656 sjg VarAssign var; 1542 1.656 sjg 1543 1.656 sjg /* 1544 1.656 sjg * Check for local variable assignment, 1545 1.656 sjg * rest of the line is the value. 1546 1.656 sjg */ 1547 1.656 sjg if (Parse_IsVar(start, &var)) { 1548 1.709 rillig bool targetVarsEnabled = GetBooleanExpr( 1549 1.657 rillig "${.MAKE.TARGET_LOCAL_VARIABLES}", true); 1550 1.656 sjg 1551 1.709 rillig if (targetVarsEnabled) 1552 1.656 sjg LinkVarToTargets(&var); 1553 1.656 sjg free(var.varname); 1554 1.709 rillig if (targetVarsEnabled) 1555 1.656 sjg return true; 1556 1.656 sjg } 1557 1.657 rillig 1558 1.367 rillig /* 1559 1.469 rillig * The targets take real sources, so we must beware of archive 1560 1.469 rillig * specifications (i.e. things with left parentheses in them) 1561 1.469 rillig * and handle them accordingly. 1562 1.367 rillig */ 1563 1.469 rillig for (; *end != '\0' && !ch_isspace(*end); end++) { 1564 1.469 rillig if (*end == '(' && end > start && end[-1] != '$') { 1565 1.469 rillig /* 1566 1.469 rillig * Only stop for a left parenthesis if it 1567 1.469 rillig * isn't at the start of a word (that'll be 1568 1.469 rillig * for variable changes later) and isn't 1569 1.469 rillig * preceded by a dollar sign (a dynamic 1570 1.469 rillig * source). 1571 1.469 rillig */ 1572 1.469 rillig break; 1573 1.469 rillig } 1574 1.469 rillig } 1575 1.368 rillig 1576 1.469 rillig if (*end == '(') { 1577 1.469 rillig GNodeList sources = LST_INIT; 1578 1.545 rillig if (!Arch_ParseArchive(&start, &sources, 1579 1.545 rillig SCOPE_CMDLINE)) { 1580 1.469 rillig Parse_Error(PARSE_FATAL, 1581 1.469 rillig "Error in source archive spec \"%s\"", 1582 1.469 rillig start); 1583 1.553 rillig return false; 1584 1.469 rillig } 1585 1.368 rillig 1586 1.469 rillig while (!Lst_IsEmpty(&sources)) { 1587 1.469 rillig GNode *gn = Lst_Dequeue(&sources); 1588 1.593 rillig ApplyDependencySource(targetAttr, gn->name, 1589 1.590 rillig special); 1590 1.469 rillig } 1591 1.469 rillig Lst_Done(&sources); 1592 1.469 rillig end = start; 1593 1.469 rillig } else { 1594 1.469 rillig if (*end != '\0') { 1595 1.469 rillig *end = '\0'; 1596 1.469 rillig end++; 1597 1.469 rillig } 1598 1.368 rillig 1599 1.593 rillig ApplyDependencySource(targetAttr, start, special); 1600 1.469 rillig } 1601 1.469 rillig pp_skip_whitespace(&end); 1602 1.469 rillig start = end; 1603 1.368 rillig } 1604 1.553 rillig return true; 1605 1.368 rillig } 1606 1.1 cgd 1607 1.559 rillig /* 1608 1.626 rillig * From a dependency line like 'targets: sources', parse the sources. 1609 1.559 rillig * 1610 1.559 rillig * See the tests depsrc-*.mk. 1611 1.559 rillig */ 1612 1.558 rillig static void 1613 1.597 rillig ParseDependencySources(char *p, GNodeType targetAttr, 1614 1.587 rillig ParseSpecial special, SearchPathList **inout_paths) 1615 1.558 rillig { 1616 1.597 rillig if (*p == '\0') { 1617 1.630 rillig HandleDependencySourcesEmpty(special, *inout_paths); 1618 1.587 rillig } else if (special == SP_MFLAGS) { 1619 1.597 rillig Main_ParseArgLine(p); 1620 1.626 rillig return; 1621 1.587 rillig } else if (special == SP_SHELL) { 1622 1.597 rillig if (!Job_ParseShell(p)) { 1623 1.558 rillig Parse_Error(PARSE_FATAL, 1624 1.558 rillig "improper shell specification"); 1625 1.558 rillig return; 1626 1.558 rillig } 1627 1.626 rillig return; 1628 1.587 rillig } else if (special == SP_NOTPARALLEL || special == SP_SINGLESHELL || 1629 1.587 rillig special == SP_DELETE_ON_ERROR) { 1630 1.626 rillig return; 1631 1.558 rillig } 1632 1.558 rillig 1633 1.691 sjg switch (special) { 1634 1.691 sjg case SP_INCLUDES: 1635 1.691 sjg case SP_LIBS: 1636 1.691 sjg case SP_NOREADONLY: 1637 1.691 sjg case SP_NULL: 1638 1.691 sjg case SP_OBJDIR: 1639 1.691 sjg case SP_PATH: 1640 1.691 sjg case SP_READONLY: 1641 1.691 sjg case SP_SUFFIXES: 1642 1.692 sjg case SP_SYSPATH: 1643 1.597 rillig ParseDependencySourcesSpecial(p, special, *inout_paths); 1644 1.558 rillig if (*inout_paths != NULL) { 1645 1.558 rillig Lst_Free(*inout_paths); 1646 1.558 rillig *inout_paths = NULL; 1647 1.558 rillig } 1648 1.587 rillig if (special == SP_PATH) 1649 1.558 rillig Dir_SetPATH(); 1650 1.692 sjg if (special == SP_SYSPATH) 1651 1.692 sjg Dir_SetSYSPATH(); 1652 1.691 sjg break; 1653 1.691 sjg default: 1654 1.558 rillig assert(*inout_paths == NULL); 1655 1.597 rillig if (!ParseDependencySourcesMundane(p, special, targetAttr)) 1656 1.558 rillig return; 1657 1.691 sjg break; 1658 1.558 rillig } 1659 1.558 rillig 1660 1.630 rillig MaybeUpdateMainTarget(); 1661 1.558 rillig } 1662 1.558 rillig 1663 1.524 rillig /* 1664 1.524 rillig * Parse a dependency line consisting of targets, followed by a dependency 1665 1.368 rillig * operator, optionally followed by sources. 1666 1.368 rillig * 1667 1.368 rillig * The nodes of the sources are linked as children to the nodes of the 1668 1.368 rillig * targets. Nodes are created as necessary. 1669 1.368 rillig * 1670 1.368 rillig * The operator is applied to each node in the global 'targets' list, 1671 1.585 rillig * which is where the nodes found for the targets are kept. 1672 1.368 rillig * 1673 1.368 rillig * The sources are parsed in much the same way as the targets, except 1674 1.368 rillig * that they are expanded using the wildcarding scheme of the C-Shell, 1675 1.441 rillig * and a target is created for each expanded word. Each of the resulting 1676 1.441 rillig * nodes is then linked to each of the targets as one of its children. 1677 1.368 rillig * 1678 1.368 rillig * Certain targets and sources such as .PHONY or .PRECIOUS are handled 1679 1.585 rillig * specially, see ParseSpecial. 1680 1.368 rillig * 1681 1.585 rillig * Transformation rules such as '.c.o' are also handled here, see 1682 1.585 rillig * Suff_AddTransform. 1683 1.441 rillig * 1684 1.721 rillig * Upon return, the value of expandedLine is unspecified. 1685 1.368 rillig */ 1686 1.368 rillig static void 1687 1.721 rillig ParseDependency(char *expandedLine, const char *unexpandedLine) 1688 1.368 rillig { 1689 1.600 rillig char *p; 1690 1.583 rillig SearchPathList *paths; /* search paths to alter when parsing a list 1691 1.583 rillig * of .PATH targets */ 1692 1.590 rillig GNodeType targetAttr; /* from special sources */ 1693 1.600 rillig ParseSpecial special; /* in special targets, the children are 1694 1.600 rillig * linked as children of the parent but not 1695 1.600 rillig * vice versa */ 1696 1.681 rillig GNodeType op; 1697 1.469 rillig 1698 1.721 rillig DEBUG1(PARSE, "ParseDependency(%s)\n", expandedLine); 1699 1.721 rillig p = expandedLine; 1700 1.600 rillig paths = NULL; 1701 1.590 rillig targetAttr = OP_NONE; 1702 1.600 rillig special = SP_NOT; 1703 1.469 rillig 1704 1.721 rillig if (!ParseDependencyTargets(&p, expandedLine, &special, &targetAttr, 1705 1.721 rillig &paths, unexpandedLine)) 1706 1.469 rillig goto out; 1707 1.469 rillig 1708 1.469 rillig if (!Lst_IsEmpty(targets)) 1709 1.628 rillig CheckSpecialMundaneMixture(special); 1710 1.469 rillig 1711 1.681 rillig op = ParseDependencyOp(&p); 1712 1.681 rillig if (op == OP_NONE) { 1713 1.721 rillig InvalidLineType(expandedLine, unexpandedLine); 1714 1.681 rillig goto out; 1715 1.681 rillig } 1716 1.681 rillig ApplyDependencyOperator(op); 1717 1.469 rillig 1718 1.600 rillig pp_skip_whitespace(&p); 1719 1.469 rillig 1720 1.600 rillig ParseDependencySources(p, targetAttr, special, &paths); 1721 1.1 cgd 1722 1.112 christos out: 1723 1.469 rillig if (paths != NULL) 1724 1.469 rillig Lst_Free(paths); 1725 1.1 cgd } 1726 1.1 cgd 1727 1.469 rillig /* 1728 1.469 rillig * Determine the assignment operator and adjust the end of the variable 1729 1.469 rillig * name accordingly. 1730 1.469 rillig */ 1731 1.606 rillig static VarAssign 1732 1.606 rillig AdjustVarassignOp(const char *name, const char *nameEnd, const char *op, 1733 1.606 rillig const char *value) 1734 1.388 rillig { 1735 1.469 rillig VarAssignOp type; 1736 1.606 rillig VarAssign va; 1737 1.469 rillig 1738 1.469 rillig if (op > name && op[-1] == '+') { 1739 1.579 rillig op--; 1740 1.469 rillig type = VAR_APPEND; 1741 1.469 rillig 1742 1.469 rillig } else if (op > name && op[-1] == '?') { 1743 1.469 rillig op--; 1744 1.469 rillig type = VAR_DEFAULT; 1745 1.469 rillig 1746 1.469 rillig } else if (op > name && op[-1] == ':') { 1747 1.469 rillig op--; 1748 1.469 rillig type = VAR_SUBST; 1749 1.469 rillig 1750 1.469 rillig } else if (op > name && op[-1] == '!') { 1751 1.469 rillig op--; 1752 1.469 rillig type = VAR_SHELL; 1753 1.388 rillig 1754 1.469 rillig } else { 1755 1.469 rillig type = VAR_NORMAL; 1756 1.469 rillig while (op > name && ch_isspace(op[-1])) 1757 1.469 rillig op--; 1758 1.388 rillig 1759 1.608 rillig if (op - name >= 3 && memcmp(op - 3, ":sh", 3) == 0) { 1760 1.579 rillig op -= 3; 1761 1.469 rillig type = VAR_SHELL; 1762 1.469 rillig } 1763 1.388 rillig } 1764 1.388 rillig 1765 1.606 rillig va.varname = bmake_strsedup(name, nameEnd < op ? nameEnd : op); 1766 1.606 rillig va.op = type; 1767 1.606 rillig va.value = value; 1768 1.606 rillig return va; 1769 1.388 rillig } 1770 1.388 rillig 1771 1.469 rillig /* 1772 1.469 rillig * Parse a variable assignment, consisting of a single-word variable name, 1773 1.368 rillig * optional whitespace, an assignment operator, optional whitespace and the 1774 1.368 rillig * variable value. 1775 1.84 wiz * 1776 1.410 rillig * Note: There is a lexical ambiguity with assignment modifier characters 1777 1.410 rillig * in variable names. This routine interprets the character before the = 1778 1.410 rillig * as a modifier. Therefore, an assignment like 1779 1.410 rillig * C++=/usr/bin/CC 1780 1.410 rillig * is interpreted as "C+ +=" instead of "C++ =". 1781 1.410 rillig * 1782 1.469 rillig * Used for both lines in a file and command line arguments. 1783 1.469 rillig */ 1784 1.605 rillig static bool 1785 1.368 rillig Parse_IsVar(const char *p, VarAssign *out_var) 1786 1.1 cgd { 1787 1.652 rillig const char *nameStart, *nameEnd, *firstSpace, *eq; 1788 1.469 rillig int level = 0; 1789 1.469 rillig 1790 1.469 rillig cpp_skip_hspace(&p); /* Skip to variable name */ 1791 1.469 rillig 1792 1.469 rillig /* 1793 1.665 rillig * During parsing, the '+' of the operator '+=' is initially parsed 1794 1.469 rillig * as part of the variable name. It is later corrected, as is the 1795 1.652 rillig * ':sh' modifier. Of these two (nameEnd and eq), the earlier one 1796 1.469 rillig * determines the actual end of the variable name. 1797 1.469 rillig */ 1798 1.652 rillig 1799 1.606 rillig nameStart = p; 1800 1.652 rillig firstSpace = NULL; 1801 1.356 rillig 1802 1.712 rillig /* Scan for one of the assignment operators outside an expression. */ 1803 1.469 rillig while (*p != '\0') { 1804 1.469 rillig char ch = *p++; 1805 1.469 rillig if (ch == '(' || ch == '{') { 1806 1.469 rillig level++; 1807 1.469 rillig continue; 1808 1.469 rillig } 1809 1.469 rillig if (ch == ')' || ch == '}') { 1810 1.469 rillig level--; 1811 1.469 rillig continue; 1812 1.469 rillig } 1813 1.469 rillig 1814 1.469 rillig if (level != 0) 1815 1.469 rillig continue; 1816 1.469 rillig 1817 1.652 rillig if ((ch == ' ' || ch == '\t') && firstSpace == NULL) 1818 1.652 rillig firstSpace = p - 1; 1819 1.469 rillig while (ch == ' ' || ch == '\t') 1820 1.469 rillig ch = *p++; 1821 1.368 rillig 1822 1.662 sjg if (ch == '\0') 1823 1.662 sjg return false; 1824 1.469 rillig if (ch == ':' && p[0] == 's' && p[1] == 'h') { 1825 1.469 rillig p += 2; 1826 1.469 rillig continue; 1827 1.469 rillig } 1828 1.607 rillig if (ch == '=') 1829 1.606 rillig eq = p - 1; 1830 1.607 rillig else if (*p == '=' && 1831 1.607 rillig (ch == '+' || ch == ':' || ch == '?' || ch == '!')) 1832 1.606 rillig eq = p; 1833 1.607 rillig else if (firstSpace != NULL) 1834 1.553 rillig return false; 1835 1.607 rillig else 1836 1.607 rillig continue; 1837 1.607 rillig 1838 1.607 rillig nameEnd = firstSpace != NULL ? firstSpace : eq; 1839 1.607 rillig p = eq + 1; 1840 1.607 rillig cpp_skip_whitespace(&p); 1841 1.607 rillig *out_var = AdjustVarassignOp(nameStart, nameEnd, eq, p); 1842 1.607 rillig return true; 1843 1.191 sjg } 1844 1.1 cgd 1845 1.553 rillig return false; 1846 1.1 cgd } 1847 1.1 cgd 1848 1.469 rillig /* 1849 1.469 rillig * Check for syntax errors such as unclosed expressions or unknown modifiers. 1850 1.469 rillig */ 1851 1.368 rillig static void 1852 1.709 rillig VarCheckSyntax(VarAssignOp op, const char *uvalue, GNode *scope) 1853 1.368 rillig { 1854 1.515 rillig if (opts.strict) { 1855 1.709 rillig if (op != VAR_SUBST && strchr(uvalue, '$') != NULL) { 1856 1.709 rillig char *parsedValue = Var_Subst(uvalue, 1857 1.730 rillig scope, VARE_PARSE); 1858 1.469 rillig /* TODO: handle errors */ 1859 1.709 rillig free(parsedValue); 1860 1.469 rillig } 1861 1.243 sjg } 1862 1.368 rillig } 1863 1.368 rillig 1864 1.630 rillig /* Perform a variable assignment that uses the operator ':='. */ 1865 1.390 rillig static void 1866 1.548 rillig VarAssign_EvalSubst(GNode *scope, const char *name, const char *uvalue, 1867 1.506 rillig FStr *out_avalue) 1868 1.390 rillig { 1869 1.469 rillig char *evalue; 1870 1.469 rillig 1871 1.469 rillig /* 1872 1.708 rillig * Make sure that we set the variable the first time to nothing 1873 1.538 rillig * so that it gets substituted. 1874 1.538 rillig * 1875 1.538 rillig * TODO: Add a test that demonstrates why this code is needed, 1876 1.538 rillig * apart from making the debug log longer. 1877 1.633 rillig * 1878 1.630 rillig * XXX: The variable name is expanded up to 3 times. 1879 1.469 rillig */ 1880 1.548 rillig if (!Var_ExistsExpand(scope, name)) 1881 1.548 rillig Var_SetExpand(scope, name, ""); 1882 1.469 rillig 1883 1.730 rillig evalue = Var_Subst(uvalue, scope, 1884 1.730 rillig VARE_EVAL_KEEP_DOLLAR_AND_UNDEFINED); 1885 1.469 rillig /* TODO: handle errors */ 1886 1.520 rillig 1887 1.548 rillig Var_SetExpand(scope, name, evalue); 1888 1.390 rillig 1889 1.536 rillig *out_avalue = FStr_InitOwn(evalue); 1890 1.390 rillig } 1891 1.390 rillig 1892 1.630 rillig /* Perform a variable assignment that uses the operator '!='. */ 1893 1.390 rillig static void 1894 1.546 rillig VarAssign_EvalShell(const char *name, const char *uvalue, GNode *scope, 1895 1.506 rillig FStr *out_avalue) 1896 1.390 rillig { 1897 1.507 rillig FStr cmd; 1898 1.648 rillig char *output, *error; 1899 1.469 rillig 1900 1.507 rillig cmd = FStr_InitRefer(uvalue); 1901 1.738 rillig Var_Expand(&cmd, SCOPE_CMDLINE, VARE_EVAL); 1902 1.469 rillig 1903 1.648 rillig output = Cmd_Exec(cmd.str, &error); 1904 1.648 rillig Var_SetExpand(scope, name, output); 1905 1.648 rillig *out_avalue = FStr_InitOwn(output); 1906 1.648 rillig if (error != NULL) { 1907 1.648 rillig Parse_Error(PARSE_WARNING, "%s", error); 1908 1.648 rillig free(error); 1909 1.648 rillig } 1910 1.390 rillig 1911 1.507 rillig FStr_Done(&cmd); 1912 1.390 rillig } 1913 1.390 rillig 1914 1.524 rillig /* 1915 1.524 rillig * Perform a variable assignment. 1916 1.391 rillig * 1917 1.554 rillig * The actual value of the variable is returned in *out_true_avalue. 1918 1.538 rillig * Especially for VAR_SUBST and VAR_SHELL this can differ from the literal 1919 1.538 rillig * value. 1920 1.538 rillig * 1921 1.538 rillig * Return whether the assignment was actually performed, which is usually 1922 1.538 rillig * the case. It is only skipped if the operator is '?=' and the variable 1923 1.538 rillig * already exists. 1924 1.524 rillig */ 1925 1.553 rillig static bool 1926 1.391 rillig VarAssign_Eval(const char *name, VarAssignOp op, const char *uvalue, 1927 1.554 rillig GNode *scope, FStr *out_true_avalue) 1928 1.368 rillig { 1929 1.506 rillig FStr avalue = FStr_InitRefer(uvalue); 1930 1.469 rillig 1931 1.469 rillig if (op == VAR_APPEND) 1932 1.548 rillig Var_AppendExpand(scope, name, uvalue); 1933 1.469 rillig else if (op == VAR_SUBST) 1934 1.548 rillig VarAssign_EvalSubst(scope, name, uvalue, &avalue); 1935 1.469 rillig else if (op == VAR_SHELL) 1936 1.546 rillig VarAssign_EvalShell(name, uvalue, scope, &avalue); 1937 1.469 rillig else { 1938 1.630 rillig /* XXX: The variable name is expanded up to 2 times. */ 1939 1.548 rillig if (op == VAR_DEFAULT && Var_ExistsExpand(scope, name)) 1940 1.553 rillig return false; 1941 1.353 rillig 1942 1.469 rillig /* Normal assignment -- just do it. */ 1943 1.548 rillig Var_SetExpand(scope, name, uvalue); 1944 1.469 rillig } 1945 1.469 rillig 1946 1.554 rillig *out_true_avalue = avalue; 1947 1.553 rillig return true; 1948 1.368 rillig } 1949 1.368 rillig 1950 1.368 rillig static void 1951 1.368 rillig VarAssignSpecial(const char *name, const char *avalue) 1952 1.368 rillig { 1953 1.696 rillig if (strcmp(name, ".MAKEOVERRIDES") == 0) 1954 1.583 rillig Main_ExportMAKEFLAGS(false); /* re-export MAKEFLAGS */ 1955 1.469 rillig else if (strcmp(name, ".CURDIR") == 0) { 1956 1.469 rillig /* 1957 1.469 rillig * Someone is being (too?) clever... 1958 1.469 rillig * Let's pretend they know what they are doing and 1959 1.469 rillig * re-initialize the 'cur' CachedDir. 1960 1.469 rillig */ 1961 1.469 rillig Dir_InitCur(avalue); 1962 1.469 rillig Dir_SetPATH(); 1963 1.696 rillig } else if (strcmp(name, ".MAKE.JOB.PREFIX") == 0) 1964 1.469 rillig Job_SetPrefix(); 1965 1.695 rillig else if (strcmp(name, ".MAKE.EXPORTED") == 0) 1966 1.473 rillig Var_ExportVars(avalue); 1967 1.368 rillig } 1968 1.368 rillig 1969 1.579 rillig /* Perform the variable assignment in the given scope. */ 1970 1.605 rillig static void 1971 1.658 rillig Parse_Var(VarAssign *var, GNode *scope) 1972 1.368 rillig { 1973 1.583 rillig FStr avalue; /* actual value (maybe expanded) */ 1974 1.368 rillig 1975 1.546 rillig VarCheckSyntax(var->op, var->value, scope); 1976 1.546 rillig if (VarAssign_Eval(var->varname, var->op, var->value, scope, &avalue)) { 1977 1.506 rillig VarAssignSpecial(var->varname, avalue.str); 1978 1.506 rillig FStr_Done(&avalue); 1979 1.506 rillig } 1980 1.656 sjg } 1981 1.657 rillig 1982 1.200 christos 1983 1.524 rillig /* 1984 1.710 rillig * See if the command possibly calls a sub-make by using the 1985 1.524 rillig * expressions ${.MAKE}, ${MAKE} or the plain word "make". 1986 1.524 rillig */ 1987 1.553 rillig static bool 1988 1.432 rillig MaybeSubMake(const char *cmd) 1989 1.195 christos { 1990 1.469 rillig const char *start; 1991 1.432 rillig 1992 1.469 rillig for (start = cmd; *start != '\0'; start++) { 1993 1.469 rillig const char *p = start; 1994 1.469 rillig char endc; 1995 1.469 rillig 1996 1.469 rillig /* XXX: What if progname != "make"? */ 1997 1.579 rillig if (strncmp(p, "make", 4) == 0) 1998 1.469 rillig if (start == cmd || !ch_isalnum(p[-1])) 1999 1.469 rillig if (!ch_isalnum(p[4])) 2000 1.553 rillig return true; 2001 1.469 rillig 2002 1.469 rillig if (*p != '$') 2003 1.469 rillig continue; 2004 1.469 rillig p++; 2005 1.469 rillig 2006 1.469 rillig if (*p == '{') 2007 1.469 rillig endc = '}'; 2008 1.469 rillig else if (*p == '(') 2009 1.469 rillig endc = ')'; 2010 1.469 rillig else 2011 1.469 rillig continue; 2012 1.469 rillig p++; 2013 1.432 rillig 2014 1.469 rillig if (*p == '.') /* Accept either ${.MAKE} or ${MAKE}. */ 2015 1.469 rillig p++; 2016 1.432 rillig 2017 1.619 rillig if (strncmp(p, "MAKE", 4) == 0 && p[4] == endc) 2018 1.619 rillig return true; 2019 1.469 rillig } 2020 1.553 rillig return false; 2021 1.195 christos } 2022 1.195 christos 2023 1.708 rillig /* Append the command to the target node. */ 2024 1.327 rillig static void 2025 1.593 rillig GNode_AddCommand(GNode *gn, char *cmd) 2026 1.9 jtc { 2027 1.469 rillig if ((gn->type & OP_DOUBLEDEP) && gn->cohorts.last != NULL) 2028 1.469 rillig gn = gn->cohorts.last->datum; 2029 1.469 rillig 2030 1.469 rillig /* if target already supplied, ignore commands */ 2031 1.469 rillig if (!(gn->type & OP_HAS_COMMANDS)) { 2032 1.469 rillig Lst_Append(&gn->commands, cmd); 2033 1.469 rillig if (MaybeSubMake(cmd)) 2034 1.469 rillig gn->type |= OP_SUBMAKE; 2035 1.562 rillig RememberLocation(gn); 2036 1.469 rillig } else { 2037 1.469 rillig Parse_Error(PARSE_WARNING, 2038 1.374 rillig "duplicate script for target \"%s\" ignored", 2039 1.374 rillig gn->name); 2040 1.680 rillig ParseErrorInternal(gn, PARSE_WARNING, 2041 1.469 rillig "using previous script for \"%s\" defined here", 2042 1.469 rillig gn->name); 2043 1.469 rillig } 2044 1.1 cgd } 2045 1.1 cgd 2046 1.469 rillig /* 2047 1.566 rillig * Parse a directive like '.include' or '.-include'. 2048 1.566 rillig * 2049 1.566 rillig * .include "user-makefile.mk" 2050 1.566 rillig * .include <system-makefile.mk> 2051 1.566 rillig */ 2052 1.123 dsl static void 2053 1.556 rillig ParseInclude(char *directive) 2054 1.123 dsl { 2055 1.567 rillig char endc; /* '>' or '"' */ 2056 1.567 rillig char *p; 2057 1.553 rillig bool silent = directive[0] != 'i'; 2058 1.566 rillig FStr file; 2059 1.123 dsl 2060 1.566 rillig p = directive + (silent ? 8 : 7); 2061 1.566 rillig pp_skip_hspace(&p); 2062 1.123 dsl 2063 1.566 rillig if (*p != '"' && *p != '<') { 2064 1.469 rillig Parse_Error(PARSE_FATAL, 2065 1.753 rillig ".include filename must be delimited by \"\" or <>"); 2066 1.469 rillig return; 2067 1.469 rillig } 2068 1.123 dsl 2069 1.709 rillig endc = *p++ == '<' ? '>' : '"'; 2070 1.566 rillig file = FStr_InitRefer(p); 2071 1.469 rillig 2072 1.566 rillig while (*p != '\0' && *p != endc) 2073 1.566 rillig p++; 2074 1.123 dsl 2075 1.566 rillig if (*p != endc) { 2076 1.469 rillig Parse_Error(PARSE_FATAL, 2077 1.753 rillig "Unclosed .include filename, \"%c\" expected", endc); 2078 1.469 rillig return; 2079 1.469 rillig } 2080 1.430 rillig 2081 1.566 rillig *p = '\0'; 2082 1.123 dsl 2083 1.730 rillig Var_Expand(&file, SCOPE_CMDLINE, VARE_EVAL); 2084 1.567 rillig IncludeFile(file.str, endc == '>', directive[0] == 'd', silent); 2085 1.567 rillig FStr_Done(&file); 2086 1.1 cgd } 2087 1.1 cgd 2088 1.524 rillig /* 2089 1.524 rillig * Split filename into dirname + basename, then assign these to the 2090 1.524 rillig * given variables. 2091 1.524 rillig */ 2092 1.193 christos static void 2093 1.281 rillig SetFilenameVars(const char *filename, const char *dirvar, const char *filevar) 2094 1.193 christos { 2095 1.550 rillig const char *slash, *basename; 2096 1.550 rillig FStr dirname; 2097 1.469 rillig 2098 1.469 rillig slash = strrchr(filename, '/'); 2099 1.469 rillig if (slash == NULL) { 2100 1.550 rillig dirname = FStr_InitRefer(curdir); 2101 1.469 rillig basename = filename; 2102 1.469 rillig } else { 2103 1.550 rillig dirname = FStr_InitOwn(bmake_strsedup(filename, slash)); 2104 1.469 rillig basename = slash + 1; 2105 1.469 rillig } 2106 1.281 rillig 2107 1.568 rillig Global_Set(dirvar, dirname.str); 2108 1.568 rillig Global_Set(filevar, basename); 2109 1.469 rillig 2110 1.586 rillig DEBUG4(PARSE, "SetFilenameVars: ${%s} = `%s' ${%s} = `%s'\n", 2111 1.586 rillig dirvar, dirname.str, filevar, basename); 2112 1.550 rillig FStr_Done(&dirname); 2113 1.281 rillig } 2114 1.281 rillig 2115 1.469 rillig /* 2116 1.469 rillig * Return the immediately including file. 2117 1.281 rillig * 2118 1.281 rillig * This is made complicated since the .for loop is implemented as a special 2119 1.469 rillig * kind of .include; see For_Run. 2120 1.469 rillig */ 2121 1.281 rillig static const char * 2122 1.281 rillig GetActuallyIncludingFile(void) 2123 1.281 rillig { 2124 1.469 rillig size_t i; 2125 1.627 rillig const IncludedFile *incs = GetInclude(0); 2126 1.193 christos 2127 1.469 rillig for (i = includes.len; i >= 2; i--) 2128 1.617 rillig if (incs[i - 1].forLoop == NULL) 2129 1.576 rillig return incs[i - 2].name.str; 2130 1.469 rillig return NULL; 2131 1.193 christos } 2132 1.281 rillig 2133 1.285 rillig /* Set .PARSEDIR, .PARSEFILE, .INCLUDEDFROMDIR and .INCLUDEDFROMFILE. */ 2134 1.44 aidan static void 2135 1.593 rillig SetParseFile(const char *filename) 2136 1.44 aidan { 2137 1.469 rillig const char *including; 2138 1.44 aidan 2139 1.469 rillig SetFilenameVars(filename, ".PARSEDIR", ".PARSEFILE"); 2140 1.281 rillig 2141 1.469 rillig including = GetActuallyIncludingFile(); 2142 1.469 rillig if (including != NULL) { 2143 1.469 rillig SetFilenameVars(including, 2144 1.469 rillig ".INCLUDEDFROMDIR", ".INCLUDEDFROMFILE"); 2145 1.469 rillig } else { 2146 1.547 rillig Global_Delete(".INCLUDEDFROMDIR"); 2147 1.547 rillig Global_Delete(".INCLUDEDFROMFILE"); 2148 1.469 rillig } 2149 1.44 aidan } 2150 1.44 aidan 2151 1.553 rillig static bool 2152 1.418 rillig StrContainsWord(const char *str, const char *word) 2153 1.418 rillig { 2154 1.469 rillig size_t strLen = strlen(str); 2155 1.469 rillig size_t wordLen = strlen(word); 2156 1.588 rillig const char *p; 2157 1.469 rillig 2158 1.469 rillig if (strLen < wordLen) 2159 1.585 rillig return false; 2160 1.469 rillig 2161 1.469 rillig for (p = str; p != NULL; p = strchr(p, ' ')) { 2162 1.469 rillig if (*p == ' ') 2163 1.469 rillig p++; 2164 1.588 rillig if (p > str + strLen - wordLen) 2165 1.585 rillig return false; 2166 1.469 rillig 2167 1.469 rillig if (memcmp(p, word, wordLen) == 0 && 2168 1.469 rillig (p[wordLen] == '\0' || p[wordLen] == ' ')) 2169 1.553 rillig return true; 2170 1.469 rillig } 2171 1.553 rillig return false; 2172 1.469 rillig } 2173 1.469 rillig 2174 1.469 rillig /* 2175 1.469 rillig * XXX: Searching through a set of words with this linear search is 2176 1.469 rillig * inefficient for variables that contain thousands of words. 2177 1.469 rillig * 2178 1.469 rillig * XXX: The paths in this list don't seem to be normalized in any way. 2179 1.469 rillig */ 2180 1.553 rillig static bool 2181 1.418 rillig VarContainsWord(const char *varname, const char *word) 2182 1.418 rillig { 2183 1.548 rillig FStr val = Var_Value(SCOPE_GLOBAL, varname); 2184 1.553 rillig bool found = val.str != NULL && StrContainsWord(val.str, word); 2185 1.505 rillig FStr_Done(&val); 2186 1.469 rillig return found; 2187 1.418 rillig } 2188 1.418 rillig 2189 1.524 rillig /* 2190 1.524 rillig * Track the makefiles we read - so makefiles can set dependencies on them. 2191 1.441 rillig * Avoid adding anything more than once. 2192 1.441 rillig * 2193 1.441 rillig * Time complexity: O(n) per call, in total O(n^2), where n is the number 2194 1.524 rillig * of makefiles that have been loaded. 2195 1.524 rillig */ 2196 1.184 sjg static void 2197 1.593 rillig TrackInput(const char *name) 2198 1.184 sjg { 2199 1.696 rillig if (!VarContainsWord(".MAKE.MAKEFILES", name)) 2200 1.696 rillig Global_Append(".MAKE.MAKEFILES", name); 2201 1.184 sjg } 2202 1.137 sjg 2203 1.44 aidan 2204 1.630 rillig /* Parse from the given buffer, later return to the current file. */ 2205 1.5 cgd void 2206 1.661 rillig Parse_PushInput(const char *name, unsigned lineno, unsigned readLines, 2207 1.661 rillig Buffer buf, struct ForLoop *forLoop) 2208 1.5 cgd { 2209 1.627 rillig IncludedFile *curFile; 2210 1.469 rillig 2211 1.617 rillig if (forLoop != NULL) 2212 1.576 rillig name = CurFile()->name.str; 2213 1.469 rillig else 2214 1.593 rillig TrackInput(name); 2215 1.469 rillig 2216 1.742 rillig DEBUG3(PARSE, "Parse_PushInput: %s%s:%u\n", 2217 1.742 rillig forLoop != NULL ? ".for loop in ": "", name, lineno); 2218 1.5 cgd 2219 1.469 rillig curFile = Vector_Push(&includes); 2220 1.576 rillig curFile->name = FStr_InitOwn(bmake_strdup(name)); 2221 1.639 rillig curFile->lineno = lineno; 2222 1.639 rillig curFile->readLines = readLines; 2223 1.639 rillig curFile->forHeadLineno = lineno; 2224 1.639 rillig curFile->forBodyReadLines = readLines; 2225 1.616 rillig curFile->buf = buf; 2226 1.469 rillig curFile->depending = doing_depend; /* restore this on EOF */ 2227 1.702 rillig curFile->guardState = forLoop == NULL ? GS_START : GS_NO; 2228 1.702 rillig curFile->guard = NULL; 2229 1.616 rillig curFile->forLoop = forLoop; 2230 1.469 rillig 2231 1.616 rillig if (forLoop != NULL && !For_NextIteration(forLoop, &curFile->buf)) 2232 1.616 rillig abort(); /* see For_Run */ 2233 1.469 rillig 2234 1.616 rillig curFile->buf_ptr = curFile->buf.data; 2235 1.616 rillig curFile->buf_end = curFile->buf.data + curFile->buf.len; 2236 1.687 rillig curFile->condMinDepth = cond_depth; 2237 1.593 rillig SetParseFile(name); 2238 1.5 cgd } 2239 1.5 cgd 2240 1.375 rillig /* Check if the directive is an include directive. */ 2241 1.553 rillig static bool 2242 1.553 rillig IsInclude(const char *dir, bool sysv) 2243 1.228 christos { 2244 1.298 rillig if (dir[0] == 's' || dir[0] == '-' || (dir[0] == 'd' && !sysv)) 2245 1.298 rillig dir++; 2246 1.228 christos 2247 1.298 rillig if (strncmp(dir, "include", 7) != 0) 2248 1.553 rillig return false; 2249 1.228 christos 2250 1.248 rillig /* Space is not mandatory for BSD .include */ 2251 1.298 rillig return !sysv || ch_isspace(dir[7]); 2252 1.228 christos } 2253 1.228 christos 2254 1.228 christos 2255 1.284 rillig /* Check if the line is a SYSV include directive. */ 2256 1.553 rillig static bool 2257 1.228 christos IsSysVInclude(const char *line) 2258 1.228 christos { 2259 1.228 christos const char *p; 2260 1.228 christos 2261 1.553 rillig if (!IsInclude(line, true)) 2262 1.553 rillig return false; 2263 1.228 christos 2264 1.375 rillig /* Avoid interpreting a dependency line as an include */ 2265 1.228 christos for (p = line; (p = strchr(p, ':')) != NULL;) { 2266 1.430 rillig 2267 1.430 rillig /* end of line -> it's a dependency */ 2268 1.430 rillig if (*++p == '\0') 2269 1.553 rillig return false; 2270 1.430 rillig 2271 1.430 rillig /* '::' operator or ': ' -> it's a dependency */ 2272 1.430 rillig if (*p == ':' || ch_isspace(*p)) 2273 1.553 rillig return false; 2274 1.228 christos } 2275 1.553 rillig return true; 2276 1.228 christos } 2277 1.228 christos 2278 1.284 rillig /* Push to another file. The line points to the word "include". */ 2279 1.5 cgd static void 2280 1.84 wiz ParseTraditionalInclude(char *line) 2281 1.5 cgd { 2282 1.711 rillig char *p; /* current position in file spec */ 2283 1.553 rillig bool done = false; 2284 1.553 rillig bool silent = line[0] != 'i'; 2285 1.469 rillig char *file = line + (silent ? 8 : 7); 2286 1.469 rillig char *all_files; 2287 1.469 rillig 2288 1.586 rillig DEBUG1(PARSE, "ParseTraditionalInclude: %s\n", file); 2289 1.469 rillig 2290 1.469 rillig pp_skip_whitespace(&file); 2291 1.469 rillig 2292 1.730 rillig all_files = Var_Subst(file, SCOPE_CMDLINE, VARE_EVAL); 2293 1.469 rillig /* TODO: handle errors */ 2294 1.469 rillig 2295 1.711 rillig for (file = all_files; !done; file = p + 1) { 2296 1.469 rillig /* Skip to end of line or next whitespace */ 2297 1.711 rillig for (p = file; *p != '\0' && !ch_isspace(*p); p++) 2298 1.469 rillig continue; 2299 1.469 rillig 2300 1.711 rillig if (*p != '\0') 2301 1.711 rillig *p = '\0'; 2302 1.469 rillig else 2303 1.553 rillig done = true; 2304 1.38 christos 2305 1.553 rillig IncludeFile(file, false, false, silent); 2306 1.469 rillig } 2307 1.580 rillig 2308 1.469 rillig free(all_files); 2309 1.5 cgd } 2310 1.5 cgd 2311 1.375 rillig /* Parse "export <variable>=<value>", and actually export it. */ 2312 1.182 christos static void 2313 1.182 christos ParseGmakeExport(char *line) 2314 1.182 christos { 2315 1.469 rillig char *variable = line + 6; 2316 1.469 rillig char *value; 2317 1.182 christos 2318 1.586 rillig DEBUG1(PARSE, "ParseGmakeExport: %s\n", variable); 2319 1.182 christos 2320 1.469 rillig pp_skip_whitespace(&variable); 2321 1.182 christos 2322 1.526 rillig for (value = variable; *value != '\0' && *value != '='; value++) 2323 1.469 rillig continue; 2324 1.182 christos 2325 1.469 rillig if (*value != '=') { 2326 1.469 rillig Parse_Error(PARSE_FATAL, 2327 1.284 rillig "Variable/Value missing from \"export\""); 2328 1.469 rillig return; 2329 1.469 rillig } 2330 1.469 rillig *value++ = '\0'; /* terminate variable */ 2331 1.323 rillig 2332 1.469 rillig /* 2333 1.469 rillig * Expand the value before putting it in the environment. 2334 1.469 rillig */ 2335 1.730 rillig value = Var_Subst(value, SCOPE_CMDLINE, VARE_EVAL); 2336 1.469 rillig /* TODO: handle errors */ 2337 1.469 rillig 2338 1.469 rillig setenv(variable, value, 1); 2339 1.469 rillig free(value); 2340 1.182 christos } 2341 1.182 christos 2342 1.469 rillig /* 2343 1.708 rillig * When the end of the current file or .for loop is reached, continue reading 2344 1.708 rillig * the previous file at the previous location. 2345 1.1 cgd * 2346 1.1 cgd * Results: 2347 1.553 rillig * true to continue parsing, i.e. it had only reached the end of an 2348 1.553 rillig * included file, false if the main file has been parsed completely. 2349 1.1 cgd */ 2350 1.553 rillig static bool 2351 1.123 dsl ParseEOF(void) 2352 1.1 cgd { 2353 1.627 rillig IncludedFile *curFile = CurFile(); 2354 1.469 rillig 2355 1.616 rillig doing_depend = curFile->depending; 2356 1.616 rillig if (curFile->forLoop != NULL && 2357 1.616 rillig For_NextIteration(curFile->forLoop, &curFile->buf)) { 2358 1.616 rillig curFile->buf_ptr = curFile->buf.data; 2359 1.616 rillig curFile->buf_end = curFile->buf.data + curFile->buf.len; 2360 1.627 rillig curFile->readLines = curFile->forBodyReadLines; 2361 1.616 rillig return true; 2362 1.615 rillig } 2363 1.469 rillig 2364 1.687 rillig Cond_EndFile(); 2365 1.469 rillig 2366 1.725 rillig if (curFile->guardState == GS_DONE) { 2367 1.725 rillig HashEntry *he = HashTable_CreateEntry(&guards, 2368 1.725 rillig curFile->name.str, NULL); 2369 1.725 rillig if (he->value != NULL) { 2370 1.725 rillig free(((Guard *)he->value)->name); 2371 1.725 rillig free(he->value); 2372 1.725 rillig } 2373 1.725 rillig HashEntry_Set(he, curFile->guard); 2374 1.725 rillig } else if (curFile->guard != NULL) { 2375 1.702 rillig free(curFile->guard->name); 2376 1.702 rillig free(curFile->guard); 2377 1.700 rillig } 2378 1.700 rillig 2379 1.576 rillig FStr_Done(&curFile->name); 2380 1.616 rillig Buf_Done(&curFile->buf); 2381 1.647 rillig if (curFile->forLoop != NULL) 2382 1.647 rillig ForLoop_Free(curFile->forLoop); 2383 1.469 rillig Vector_Pop(&includes); 2384 1.155 dsl 2385 1.469 rillig if (includes.len == 0) { 2386 1.469 rillig /* We've run out of input */ 2387 1.547 rillig Global_Delete(".PARSEDIR"); 2388 1.547 rillig Global_Delete(".PARSEFILE"); 2389 1.547 rillig Global_Delete(".INCLUDEDFROMDIR"); 2390 1.547 rillig Global_Delete(".INCLUDEDFROMFILE"); 2391 1.553 rillig return false; 2392 1.469 rillig } 2393 1.170 dholland 2394 1.469 rillig curFile = CurFile(); 2395 1.742 rillig DEBUG2(PARSE, "ParseEOF: returning to %s:%u\n", 2396 1.641 rillig curFile->name.str, curFile->readLines + 1); 2397 1.1 cgd 2398 1.593 rillig SetParseFile(curFile->name.str); 2399 1.553 rillig return true; 2400 1.1 cgd } 2401 1.1 cgd 2402 1.493 rillig typedef enum ParseRawLineResult { 2403 1.493 rillig PRLR_LINE, 2404 1.493 rillig PRLR_EOF, 2405 1.493 rillig PRLR_ERROR 2406 1.493 rillig } ParseRawLineResult; 2407 1.493 rillig 2408 1.489 rillig /* 2409 1.492 rillig * Parse until the end of a line, taking into account lines that end with 2410 1.571 rillig * backslash-newline. The resulting line goes from out_line to out_line_end; 2411 1.571 rillig * the line is not null-terminated. 2412 1.489 rillig */ 2413 1.493 rillig static ParseRawLineResult 2414 1.627 rillig ParseRawLine(IncludedFile *curFile, char **out_line, char **out_line_end, 2415 1.636 rillig char **out_firstBackslash, char **out_commentLineEnd) 2416 1.489 rillig { 2417 1.493 rillig char *line = curFile->buf_ptr; 2418 1.570 rillig char *buf_end = curFile->buf_end; 2419 1.492 rillig char *p = line; 2420 1.489 rillig char *line_end = line; 2421 1.492 rillig char *firstBackslash = NULL; 2422 1.636 rillig char *commentLineEnd = NULL; 2423 1.493 rillig ParseRawLineResult res = PRLR_LINE; 2424 1.489 rillig 2425 1.627 rillig curFile->readLines++; 2426 1.490 rillig 2427 1.489 rillig for (;;) { 2428 1.492 rillig char ch; 2429 1.492 rillig 2430 1.570 rillig if (p == buf_end) { 2431 1.493 rillig res = PRLR_EOF; 2432 1.489 rillig break; 2433 1.489 rillig } 2434 1.489 rillig 2435 1.492 rillig ch = *p; 2436 1.637 rillig if (ch == '\0' || (ch == '\\' && p[1] == '\0')) { 2437 1.492 rillig Parse_Error(PARSE_FATAL, "Zero byte read from file"); 2438 1.718 rillig exit(2); 2439 1.489 rillig } 2440 1.489 rillig 2441 1.492 rillig /* Treat next character after '\' as literal. */ 2442 1.489 rillig if (ch == '\\') { 2443 1.492 rillig if (firstBackslash == NULL) 2444 1.492 rillig firstBackslash = p; 2445 1.511 rillig if (p[1] == '\n') { 2446 1.627 rillig curFile->readLines++; 2447 1.570 rillig if (p + 2 == buf_end) { 2448 1.511 rillig line_end = p; 2449 1.511 rillig *line_end = '\n'; 2450 1.511 rillig p += 2; 2451 1.511 rillig continue; 2452 1.511 rillig } 2453 1.511 rillig } 2454 1.492 rillig p += 2; 2455 1.492 rillig line_end = p; 2456 1.570 rillig assert(p <= buf_end); 2457 1.489 rillig continue; 2458 1.489 rillig } 2459 1.489 rillig 2460 1.489 rillig /* 2461 1.492 rillig * Remember the first '#' for comment stripping, unless 2462 1.492 rillig * the previous char was '[', as in the modifier ':[#]'. 2463 1.492 rillig */ 2464 1.636 rillig if (ch == '#' && commentLineEnd == NULL && 2465 1.492 rillig !(p > line && p[-1] == '[')) 2466 1.636 rillig commentLineEnd = line_end; 2467 1.489 rillig 2468 1.492 rillig p++; 2469 1.489 rillig if (ch == '\n') 2470 1.489 rillig break; 2471 1.489 rillig 2472 1.489 rillig /* We are not interested in trailing whitespace. */ 2473 1.489 rillig if (!ch_isspace(ch)) 2474 1.492 rillig line_end = p; 2475 1.489 rillig } 2476 1.489 rillig 2477 1.635 rillig curFile->buf_ptr = p; 2478 1.490 rillig *out_line = line; 2479 1.489 rillig *out_line_end = line_end; 2480 1.492 rillig *out_firstBackslash = firstBackslash; 2481 1.636 rillig *out_commentLineEnd = commentLineEnd; 2482 1.493 rillig return res; 2483 1.489 rillig } 2484 1.489 rillig 2485 1.491 rillig /* 2486 1.491 rillig * Beginning at start, unescape '\#' to '#' and replace backslash-newline 2487 1.491 rillig * with a single space. 2488 1.491 rillig */ 2489 1.485 rillig static void 2490 1.508 rillig UnescapeBackslash(char *line, char *start) 2491 1.487 rillig { 2492 1.638 rillig const char *src = start; 2493 1.491 rillig char *dst = start; 2494 1.491 rillig char *spaceStart = line; 2495 1.485 rillig 2496 1.485 rillig for (;;) { 2497 1.491 rillig char ch = *src++; 2498 1.485 rillig if (ch != '\\') { 2499 1.485 rillig if (ch == '\0') 2500 1.485 rillig break; 2501 1.491 rillig *dst++ = ch; 2502 1.485 rillig continue; 2503 1.485 rillig } 2504 1.485 rillig 2505 1.491 rillig ch = *src++; 2506 1.485 rillig if (ch == '\0') { 2507 1.635 rillig /* Delete '\\' at the end of the buffer. */ 2508 1.491 rillig dst--; 2509 1.485 rillig break; 2510 1.485 rillig } 2511 1.485 rillig 2512 1.635 rillig /* Delete '\\' from before '#' on non-command lines. */ 2513 1.635 rillig if (ch == '#' && line[0] != '\t') 2514 1.491 rillig *dst++ = ch; 2515 1.635 rillig else if (ch == '\n') { 2516 1.638 rillig cpp_skip_hspace(&src); 2517 1.635 rillig *dst++ = ' '; 2518 1.635 rillig } else { 2519 1.635 rillig /* Leave '\\' in the buffer for later. */ 2520 1.491 rillig *dst++ = '\\'; 2521 1.491 rillig *dst++ = ch; 2522 1.635 rillig /* Keep an escaped ' ' at the line end. */ 2523 1.635 rillig spaceStart = dst; 2524 1.485 rillig } 2525 1.485 rillig } 2526 1.485 rillig 2527 1.487 rillig /* Delete any trailing spaces - eg from empty continuations */ 2528 1.491 rillig while (dst > spaceStart && ch_isspace(dst[-1])) 2529 1.491 rillig dst--; 2530 1.491 rillig *dst = '\0'; 2531 1.485 rillig } 2532 1.485 rillig 2533 1.593 rillig typedef enum LineKind { 2534 1.495 rillig /* 2535 1.498 rillig * Return the next line that is neither empty nor a comment. 2536 1.495 rillig * Backslash line continuations are folded into a single space. 2537 1.495 rillig * A trailing comment, if any, is discarded. 2538 1.495 rillig */ 2539 1.593 rillig LK_NONEMPTY, 2540 1.495 rillig 2541 1.495 rillig /* 2542 1.498 rillig * Return the next line, even if it is empty or a comment. 2543 1.499 rillig * Preserve backslash-newline to keep the line numbers correct. 2544 1.495 rillig * 2545 1.495 rillig * Used in .for loops to collect the body of the loop while waiting 2546 1.495 rillig * for the corresponding .endfor. 2547 1.495 rillig */ 2548 1.593 rillig LK_FOR_BODY, 2549 1.495 rillig 2550 1.495 rillig /* 2551 1.499 rillig * Return the next line that starts with a dot. 2552 1.495 rillig * Backslash line continuations are folded into a single space. 2553 1.495 rillig * A trailing comment, if any, is discarded. 2554 1.495 rillig * 2555 1.495 rillig * Used in .if directives to skip over irrelevant branches while 2556 1.495 rillig * waiting for the corresponding .endif. 2557 1.495 rillig */ 2558 1.593 rillig LK_DOT 2559 1.593 rillig } LineKind; 2560 1.127 dsl 2561 1.640 rillig /* 2562 1.640 rillig * Return the next "interesting" logical line from the current file. The 2563 1.640 rillig * returned string will be freed at the end of including the file. 2564 1.640 rillig */ 2565 1.127 dsl static char * 2566 1.593 rillig ReadLowLevelLine(LineKind kind) 2567 1.5 cgd { 2568 1.627 rillig IncludedFile *curFile = CurFile(); 2569 1.639 rillig ParseRawLineResult res; 2570 1.469 rillig char *line; 2571 1.469 rillig char *line_end; 2572 1.492 rillig char *firstBackslash; 2573 1.636 rillig char *commentLineEnd; 2574 1.469 rillig 2575 1.127 dsl for (;;) { 2576 1.639 rillig curFile->lineno = curFile->readLines + 1; 2577 1.639 rillig res = ParseRawLine(curFile, 2578 1.636 rillig &line, &line_end, &firstBackslash, &commentLineEnd); 2579 1.493 rillig if (res == PRLR_ERROR) 2580 1.489 rillig return NULL; 2581 1.27 christos 2582 1.636 rillig if (line == line_end || line == commentLineEnd) { 2583 1.493 rillig if (res == PRLR_EOF) 2584 1.469 rillig return NULL; 2585 1.593 rillig if (kind != LK_FOR_BODY) 2586 1.494 rillig continue; 2587 1.469 rillig } 2588 1.5 cgd 2589 1.469 rillig /* We now have a line of data */ 2590 1.514 rillig assert(ch_isspace(*line_end)); 2591 1.469 rillig *line_end = '\0'; 2592 1.5 cgd 2593 1.593 rillig if (kind == LK_FOR_BODY) 2594 1.499 rillig return line; /* Don't join the physical lines. */ 2595 1.5 cgd 2596 1.593 rillig if (kind == LK_DOT && line[0] != '.') 2597 1.499 rillig continue; 2598 1.127 dsl break; 2599 1.127 dsl } 2600 1.5 cgd 2601 1.636 rillig if (commentLineEnd != NULL && line[0] != '\t') 2602 1.636 rillig *commentLineEnd = '\0'; 2603 1.637 rillig if (firstBackslash != NULL) 2604 1.637 rillig UnescapeBackslash(line, firstBackslash); 2605 1.469 rillig return line; 2606 1.5 cgd } 2607 1.1 cgd 2608 1.553 rillig static bool 2609 1.593 rillig SkipIrrelevantBranches(void) 2610 1.501 rillig { 2611 1.640 rillig const char *line; 2612 1.501 rillig 2613 1.708 rillig while ((line = ReadLowLevelLine(LK_DOT)) != NULL) 2614 1.604 rillig if (Cond_EvalLine(line) == CR_TRUE) 2615 1.640 rillig return true; 2616 1.640 rillig return false; 2617 1.501 rillig } 2618 1.501 rillig 2619 1.553 rillig static bool 2620 1.500 rillig ParseForLoop(const char *line) 2621 1.500 rillig { 2622 1.500 rillig int rval; 2623 1.661 rillig unsigned forHeadLineno; 2624 1.661 rillig unsigned bodyReadLines; 2625 1.629 rillig int forLevel; 2626 1.500 rillig 2627 1.500 rillig rval = For_Eval(line); 2628 1.500 rillig if (rval == 0) 2629 1.553 rillig return false; /* Not a .for line */ 2630 1.500 rillig if (rval < 0) 2631 1.553 rillig return true; /* Syntax error - error printed, ignore line */ 2632 1.500 rillig 2633 1.642 rillig forHeadLineno = CurFile()->lineno; 2634 1.642 rillig bodyReadLines = CurFile()->readLines; 2635 1.642 rillig 2636 1.616 rillig /* Accumulate the loop body until the matching '.endfor'. */ 2637 1.629 rillig forLevel = 1; 2638 1.500 rillig do { 2639 1.593 rillig line = ReadLowLevelLine(LK_FOR_BODY); 2640 1.500 rillig if (line == NULL) { 2641 1.500 rillig Parse_Error(PARSE_FATAL, 2642 1.572 rillig "Unexpected end of file in .for loop"); 2643 1.500 rillig break; 2644 1.500 rillig } 2645 1.629 rillig } while (For_Accum(line, &forLevel)); 2646 1.500 rillig 2647 1.639 rillig For_Run(forHeadLineno, bodyReadLines); 2648 1.616 rillig return true; 2649 1.500 rillig } 2650 1.500 rillig 2651 1.469 rillig /* 2652 1.482 rillig * Read an entire line from the input file. 2653 1.482 rillig * 2654 1.708 rillig * Empty lines, .if and .for are handled by this function, while variable 2655 1.708 rillig * assignments, other directives, dependency lines and shell commands are 2656 1.708 rillig * handled by the caller. 2657 1.1 cgd * 2658 1.638 rillig * Return a line without trailing whitespace, or NULL for EOF. The returned 2659 1.638 rillig * string will be freed at the end of including the file. 2660 1.1 cgd */ 2661 1.1 cgd static char * 2662 1.593 rillig ReadHighLevelLine(void) 2663 1.1 cgd { 2664 1.500 rillig char *line; 2665 1.700 rillig CondResult condResult; 2666 1.469 rillig 2667 1.469 rillig for (;;) { 2668 1.700 rillig IncludedFile *curFile = CurFile(); 2669 1.593 rillig line = ReadLowLevelLine(LK_NONEMPTY); 2670 1.669 rillig if (posix_state == PS_MAYBE_NEXT_LINE) 2671 1.669 rillig posix_state = PS_NOW_OR_NEVER; 2672 1.743 rillig else if (posix_state != PS_SET) 2673 1.669 rillig posix_state = PS_TOO_LATE; 2674 1.469 rillig if (line == NULL) 2675 1.469 rillig return NULL; 2676 1.469 rillig 2677 1.736 rillig DEBUG3(PARSE, "Parsing %s:%u: %s\n", 2678 1.736 rillig curFile->name.str, curFile->lineno, line); 2679 1.702 rillig if (curFile->guardState != GS_NO 2680 1.702 rillig && ((curFile->guardState == GS_START && line[0] != '.') 2681 1.702 rillig || curFile->guardState == GS_DONE)) 2682 1.702 rillig curFile->guardState = GS_NO; 2683 1.469 rillig if (line[0] != '.') 2684 1.469 rillig return line; 2685 1.469 rillig 2686 1.700 rillig condResult = Cond_EvalLine(line); 2687 1.702 rillig if (curFile->guardState == GS_START) { 2688 1.702 rillig Guard *guard; 2689 1.703 rillig if (condResult != CR_ERROR 2690 1.702 rillig && (guard = Cond_ExtractGuard(line)) != NULL) { 2691 1.702 rillig curFile->guardState = GS_COND; 2692 1.702 rillig curFile->guard = guard; 2693 1.700 rillig } else 2694 1.702 rillig curFile->guardState = GS_NO; 2695 1.700 rillig } 2696 1.700 rillig switch (condResult) { 2697 1.604 rillig case CR_FALSE: /* May also mean a syntax error. */ 2698 1.593 rillig if (!SkipIrrelevantBranches()) 2699 1.482 rillig return NULL; 2700 1.469 rillig continue; 2701 1.604 rillig case CR_TRUE: 2702 1.469 rillig continue; 2703 1.604 rillig case CR_ERROR: /* Not a conditional line */ 2704 1.500 rillig if (ParseForLoop(line)) 2705 1.469 rillig continue; 2706 1.500 rillig break; 2707 1.469 rillig } 2708 1.469 rillig return line; 2709 1.1 cgd } 2710 1.1 cgd } 2711 1.1 cgd 2712 1.331 rillig static void 2713 1.329 rillig FinishDependencyGroup(void) 2714 1.1 cgd { 2715 1.469 rillig GNodeListNode *ln; 2716 1.430 rillig 2717 1.469 rillig if (targets == NULL) 2718 1.469 rillig return; 2719 1.371 rillig 2720 1.469 rillig for (ln = targets->first; ln != NULL; ln = ln->next) { 2721 1.469 rillig GNode *gn = ln->datum; 2722 1.371 rillig 2723 1.469 rillig Suff_EndTransform(gn); 2724 1.371 rillig 2725 1.469 rillig /* 2726 1.469 rillig * Mark the target as already having commands if it does, to 2727 1.469 rillig * keep from having shell commands on multiple dependency 2728 1.469 rillig * lines. 2729 1.469 rillig */ 2730 1.469 rillig if (!Lst_IsEmpty(&gn->commands)) 2731 1.469 rillig gn->type |= OP_HAS_COMMANDS; 2732 1.469 rillig } 2733 1.430 rillig 2734 1.469 rillig Lst_Free(targets); 2735 1.469 rillig targets = NULL; 2736 1.1 cgd } 2737 1.27 christos 2738 1.726 rillig #ifdef CLEANUP 2739 1.726 rillig void Parse_RegisterCommand(char *cmd) 2740 1.726 rillig { 2741 1.726 rillig Lst_Append(&targCmds, cmd); 2742 1.726 rillig } 2743 1.726 rillig #endif 2744 1.726 rillig 2745 1.327 rillig /* Add the command to each target from the current dependency spec. */ 2746 1.326 rillig static void 2747 1.375 rillig ParseLine_ShellCommand(const char *p) 2748 1.326 rillig { 2749 1.469 rillig cpp_skip_whitespace(&p); 2750 1.469 rillig if (*p == '\0') 2751 1.469 rillig return; /* skip empty commands */ 2752 1.327 rillig 2753 1.469 rillig if (targets == NULL) { 2754 1.469 rillig Parse_Error(PARSE_FATAL, 2755 1.469 rillig "Unassociated shell command \"%s\"", p); 2756 1.469 rillig return; 2757 1.469 rillig } 2758 1.327 rillig 2759 1.469 rillig { 2760 1.469 rillig char *cmd = bmake_strdup(p); 2761 1.469 rillig GNodeListNode *ln; 2762 1.469 rillig 2763 1.469 rillig for (ln = targets->first; ln != NULL; ln = ln->next) { 2764 1.469 rillig GNode *gn = ln->datum; 2765 1.593 rillig GNode_AddCommand(gn, cmd); 2766 1.469 rillig } 2767 1.726 rillig Parse_RegisterCommand(cmd); 2768 1.469 rillig } 2769 1.326 rillig } 2770 1.1 cgd 2771 1.683 rillig static void 2772 1.699 rillig HandleBreak(const char *arg) 2773 1.683 rillig { 2774 1.683 rillig IncludedFile *curFile = CurFile(); 2775 1.683 rillig 2776 1.699 rillig if (arg[0] != '\0') 2777 1.699 rillig Parse_Error(PARSE_FATAL, 2778 1.699 rillig "The .break directive does not take arguments"); 2779 1.699 rillig 2780 1.683 rillig if (curFile->forLoop != NULL) { 2781 1.683 rillig /* pretend we reached EOF */ 2782 1.683 rillig For_Break(curFile->forLoop); 2783 1.687 rillig cond_depth = CurFile_CondMinDepth(); 2784 1.683 rillig ParseEOF(); 2785 1.683 rillig } else 2786 1.683 rillig Parse_Error(PARSE_FATAL, "break outside of for loop"); 2787 1.683 rillig } 2788 1.683 rillig 2789 1.474 rillig /* 2790 1.477 rillig * See if the line starts with one of the known directives, and if so, handle 2791 1.477 rillig * the directive. 2792 1.474 rillig */ 2793 1.553 rillig static bool 2794 1.379 rillig ParseDirective(char *line) 2795 1.379 rillig { 2796 1.711 rillig char *p = line + 1; 2797 1.569 rillig const char *arg; 2798 1.569 rillig Substring dir; 2799 1.474 rillig 2800 1.711 rillig pp_skip_whitespace(&p); 2801 1.711 rillig if (IsInclude(p, false)) { 2802 1.711 rillig ParseInclude(p); 2803 1.553 rillig return true; 2804 1.474 rillig } 2805 1.379 rillig 2806 1.711 rillig dir.start = p; 2807 1.711 rillig while (ch_islower(*p) || *p == '-') 2808 1.711 rillig p++; 2809 1.711 rillig dir.end = p; 2810 1.475 rillig 2811 1.711 rillig if (*p != '\0' && !ch_isspace(*p)) 2812 1.553 rillig return false; 2813 1.475 rillig 2814 1.711 rillig pp_skip_whitespace(&p); 2815 1.711 rillig arg = p; 2816 1.475 rillig 2817 1.683 rillig if (Substring_Equals(dir, "break")) 2818 1.699 rillig HandleBreak(arg); 2819 1.683 rillig else if (Substring_Equals(dir, "undef")) 2820 1.569 rillig Var_Undef(arg); 2821 1.581 rillig else if (Substring_Equals(dir, "export")) 2822 1.517 rillig Var_Export(VEM_PLAIN, arg); 2823 1.729 sjg else if (Substring_Equals(dir, "export-all")) 2824 1.729 sjg Var_Export(VEM_ALL, arg); 2825 1.581 rillig else if (Substring_Equals(dir, "export-env")) 2826 1.517 rillig Var_Export(VEM_ENV, arg); 2827 1.581 rillig else if (Substring_Equals(dir, "export-literal")) 2828 1.476 rillig Var_Export(VEM_LITERAL, arg); 2829 1.581 rillig else if (Substring_Equals(dir, "unexport")) 2830 1.553 rillig Var_UnExport(false, arg); 2831 1.581 rillig else if (Substring_Equals(dir, "unexport-env")) 2832 1.553 rillig Var_UnExport(true, arg); 2833 1.581 rillig else if (Substring_Equals(dir, "info")) 2834 1.602 rillig HandleMessage(PARSE_INFO, "info", arg); 2835 1.581 rillig else if (Substring_Equals(dir, "warning")) 2836 1.602 rillig HandleMessage(PARSE_WARNING, "warning", arg); 2837 1.581 rillig else if (Substring_Equals(dir, "error")) 2838 1.602 rillig HandleMessage(PARSE_FATAL, "error", arg); 2839 1.581 rillig else 2840 1.581 rillig return false; 2841 1.581 rillig return true; 2842 1.379 rillig } 2843 1.379 rillig 2844 1.605 rillig bool 2845 1.605 rillig Parse_VarAssign(const char *line, bool finishDependencyGroup, GNode *scope) 2846 1.379 rillig { 2847 1.469 rillig VarAssign var; 2848 1.430 rillig 2849 1.469 rillig if (!Parse_IsVar(line, &var)) 2850 1.553 rillig return false; 2851 1.605 rillig if (finishDependencyGroup) 2852 1.605 rillig FinishDependencyGroup(); 2853 1.605 rillig Parse_Var(&var, scope); 2854 1.658 rillig free(var.varname); 2855 1.553 rillig return true; 2856 1.379 rillig } 2857 1.379 rillig 2858 1.700 rillig void 2859 1.700 rillig Parse_GuardElse(void) 2860 1.700 rillig { 2861 1.700 rillig IncludedFile *curFile = CurFile(); 2862 1.700 rillig if (cond_depth == curFile->condMinDepth + 1) 2863 1.702 rillig curFile->guardState = GS_NO; 2864 1.700 rillig } 2865 1.700 rillig 2866 1.700 rillig void 2867 1.700 rillig Parse_GuardEndif(void) 2868 1.700 rillig { 2869 1.700 rillig IncludedFile *curFile = CurFile(); 2870 1.702 rillig if (cond_depth == curFile->condMinDepth 2871 1.702 rillig && curFile->guardState == GS_COND) 2872 1.702 rillig curFile->guardState = GS_DONE; 2873 1.700 rillig } 2874 1.700 rillig 2875 1.380 rillig static char * 2876 1.380 rillig FindSemicolon(char *p) 2877 1.380 rillig { 2878 1.711 rillig int depth = 0; 2879 1.469 rillig 2880 1.469 rillig for (; *p != '\0'; p++) { 2881 1.469 rillig if (*p == '\\' && p[1] != '\0') { 2882 1.469 rillig p++; 2883 1.469 rillig continue; 2884 1.469 rillig } 2885 1.380 rillig 2886 1.469 rillig if (*p == '$' && (p[1] == '(' || p[1] == '{')) 2887 1.711 rillig depth++; 2888 1.711 rillig else if (depth > 0 && (*p == ')' || *p == '}')) 2889 1.711 rillig depth--; 2890 1.711 rillig else if (depth == 0 && *p == ';') 2891 1.469 rillig break; 2892 1.469 rillig } 2893 1.469 rillig return p; 2894 1.380 rillig } 2895 1.380 rillig 2896 1.379 rillig static void 2897 1.555 rillig ParseDependencyLine(char *line) 2898 1.379 rillig { 2899 1.469 rillig char *expanded_line; 2900 1.469 rillig const char *shellcmd = NULL; 2901 1.469 rillig 2902 1.469 rillig { 2903 1.469 rillig char *semicolon = FindSemicolon(line); 2904 1.469 rillig if (*semicolon != '\0') { 2905 1.469 rillig /* Terminate the dependency list at the ';' */ 2906 1.469 rillig *semicolon = '\0'; 2907 1.469 rillig shellcmd = semicolon + 1; 2908 1.469 rillig } 2909 1.469 rillig } 2910 1.379 rillig 2911 1.737 rillig expanded_line = Var_Subst(line, SCOPE_CMDLINE, VARE_EVAL); 2912 1.469 rillig /* TODO: handle errors */ 2913 1.469 rillig 2914 1.469 rillig /* Need a fresh list for the target nodes */ 2915 1.469 rillig if (targets != NULL) 2916 1.469 rillig Lst_Free(targets); 2917 1.469 rillig targets = Lst_New(); 2918 1.379 rillig 2919 1.706 rillig ParseDependency(expanded_line, line); 2920 1.469 rillig free(expanded_line); 2921 1.380 rillig 2922 1.469 rillig if (shellcmd != NULL) 2923 1.469 rillig ParseLine_ShellCommand(shellcmd); 2924 1.379 rillig } 2925 1.379 rillig 2926 1.381 rillig static void 2927 1.381 rillig ParseLine(char *line) 2928 1.381 rillig { 2929 1.474 rillig if (line[0] == '.' && ParseDirective(line)) 2930 1.469 rillig return; 2931 1.381 rillig 2932 1.478 rillig if (line[0] == '\t') { 2933 1.469 rillig ParseLine_ShellCommand(line + 1); 2934 1.469 rillig return; 2935 1.469 rillig } 2936 1.381 rillig 2937 1.469 rillig if (IsSysVInclude(line)) { 2938 1.469 rillig ParseTraditionalInclude(line); 2939 1.469 rillig return; 2940 1.469 rillig } 2941 1.381 rillig 2942 1.469 rillig if (strncmp(line, "export", 6) == 0 && ch_isspace(line[6]) && 2943 1.469 rillig strchr(line, ':') == NULL) { 2944 1.469 rillig ParseGmakeExport(line); 2945 1.469 rillig return; 2946 1.469 rillig } 2947 1.381 rillig 2948 1.605 rillig if (Parse_VarAssign(line, true, SCOPE_GLOBAL)) 2949 1.469 rillig return; 2950 1.381 rillig 2951 1.469 rillig FinishDependencyGroup(); 2952 1.381 rillig 2953 1.555 rillig ParseDependencyLine(line); 2954 1.381 rillig } 2955 1.381 rillig 2956 1.708 rillig /* Interpret a top-level makefile. */ 2957 1.1 cgd void 2958 1.125 dsl Parse_File(const char *name, int fd) 2959 1.1 cgd { 2960 1.613 rillig char *line; 2961 1.616 rillig Buffer buf; 2962 1.170 dholland 2963 1.675 rillig buf = LoadFile(name, fd != -1 ? fd : STDIN_FILENO); 2964 1.613 rillig if (fd != -1) 2965 1.613 rillig (void)close(fd); 2966 1.1 cgd 2967 1.469 rillig assert(targets == NULL); 2968 1.44 aidan 2969 1.639 rillig Parse_PushInput(name, 1, 0, buf, NULL); 2970 1.1 cgd 2971 1.469 rillig do { 2972 1.593 rillig while ((line = ReadHighLevelLine()) != NULL) { 2973 1.469 rillig ParseLine(line); 2974 1.469 rillig } 2975 1.469 rillig } while (ParseEOF()); 2976 1.1 cgd 2977 1.469 rillig FinishDependencyGroup(); 2978 1.328 rillig 2979 1.561 rillig if (parseErrors != 0) { 2980 1.469 rillig (void)fflush(stdout); 2981 1.469 rillig (void)fprintf(stderr, 2982 1.655 rillig "%s: Fatal errors encountered -- cannot continue\n", 2983 1.469 rillig progname); 2984 1.655 rillig PrintOnError(NULL, ""); 2985 1.469 rillig exit(1); 2986 1.469 rillig } 2987 1.1 cgd } 2988 1.1 cgd 2989 1.383 rillig /* Initialize the parsing module. */ 2990 1.5 cgd void 2991 1.84 wiz Parse_Init(void) 2992 1.1 cgd { 2993 1.469 rillig mainNode = NULL; 2994 1.469 rillig parseIncPath = SearchPath_New(); 2995 1.469 rillig sysIncPath = SearchPath_New(); 2996 1.469 rillig defSysIncPath = SearchPath_New(); 2997 1.627 rillig Vector_Init(&includes, sizeof(IncludedFile)); 2998 1.700 rillig HashTable_Init(&guards); 2999 1.1 cgd } 3000 1.9 jtc 3001 1.733 rillig #ifdef CLEANUP 3002 1.383 rillig /* Clean up the parsing module. */ 3003 1.9 jtc void 3004 1.84 wiz Parse_End(void) 3005 1.9 jtc { 3006 1.700 rillig HashIter hi; 3007 1.700 rillig 3008 1.722 rillig Lst_DoneFree(&targCmds); 3009 1.469 rillig assert(targets == NULL); 3010 1.469 rillig SearchPath_Free(defSysIncPath); 3011 1.469 rillig SearchPath_Free(sysIncPath); 3012 1.469 rillig SearchPath_Free(parseIncPath); 3013 1.469 rillig assert(includes.len == 0); 3014 1.469 rillig Vector_Done(&includes); 3015 1.700 rillig HashIter_Init(&hi, &guards); 3016 1.728 rillig while (HashIter_Next(&hi)) { 3017 1.702 rillig Guard *guard = hi.entry->value; 3018 1.702 rillig free(guard->name); 3019 1.702 rillig free(guard); 3020 1.702 rillig } 3021 1.700 rillig HashTable_Done(&guards); 3022 1.733 rillig } 3023 1.45 mycroft #endif 3024 1.27 christos 3025 1.1 cgd 3026 1.697 rillig /* Populate the list with the single main target to create, or error out. */ 3027 1.461 rillig void 3028 1.461 rillig Parse_MainName(GNodeList *mainList) 3029 1.1 cgd { 3030 1.469 rillig if (mainNode == NULL) 3031 1.469 rillig Punt("no target to make."); 3032 1.430 rillig 3033 1.527 rillig Lst_Append(mainList, mainNode); 3034 1.527 rillig if (mainNode->type & OP_DOUBLEDEP) 3035 1.469 rillig Lst_AppendAll(mainList, &mainNode->cohorts); 3036 1.441 rillig 3037 1.542 rillig Global_Append(".TARGETS", mainNode->name); 3038 1.59 christos } 3039