parse.c revision 300313
1300313Ssjg/* $NetBSD: parse.c,v 1.214 2016/04/06 09:57:00 gson Exp $ */ 2236769Sobrien 3236769Sobrien/* 4236769Sobrien * Copyright (c) 1988, 1989, 1990, 1993 5236769Sobrien * The Regents of the University of California. All rights reserved. 6236769Sobrien * 7236769Sobrien * This code is derived from software contributed to Berkeley by 8236769Sobrien * Adam de Boor. 9236769Sobrien * 10236769Sobrien * Redistribution and use in source and binary forms, with or without 11236769Sobrien * modification, are permitted provided that the following conditions 12236769Sobrien * are met: 13236769Sobrien * 1. Redistributions of source code must retain the above copyright 14236769Sobrien * notice, this list of conditions and the following disclaimer. 15236769Sobrien * 2. Redistributions in binary form must reproduce the above copyright 16236769Sobrien * notice, this list of conditions and the following disclaimer in the 17236769Sobrien * documentation and/or other materials provided with the distribution. 18236769Sobrien * 3. Neither the name of the University nor the names of its contributors 19236769Sobrien * may be used to endorse or promote products derived from this software 20236769Sobrien * without specific prior written permission. 21236769Sobrien * 22236769Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23236769Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24236769Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25236769Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26236769Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27236769Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28236769Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29236769Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30236769Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31236769Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32236769Sobrien * SUCH DAMAGE. 33236769Sobrien */ 34236769Sobrien 35236769Sobrien/* 36236769Sobrien * Copyright (c) 1989 by Berkeley Softworks 37236769Sobrien * All rights reserved. 38236769Sobrien * 39236769Sobrien * This code is derived from software contributed to Berkeley by 40236769Sobrien * Adam de Boor. 41236769Sobrien * 42236769Sobrien * Redistribution and use in source and binary forms, with or without 43236769Sobrien * modification, are permitted provided that the following conditions 44236769Sobrien * are met: 45236769Sobrien * 1. Redistributions of source code must retain the above copyright 46236769Sobrien * notice, this list of conditions and the following disclaimer. 47236769Sobrien * 2. Redistributions in binary form must reproduce the above copyright 48236769Sobrien * notice, this list of conditions and the following disclaimer in the 49236769Sobrien * documentation and/or other materials provided with the distribution. 50236769Sobrien * 3. All advertising materials mentioning features or use of this software 51236769Sobrien * must display the following acknowledgement: 52236769Sobrien * This product includes software developed by the University of 53236769Sobrien * California, Berkeley and its contributors. 54236769Sobrien * 4. Neither the name of the University nor the names of its contributors 55236769Sobrien * may be used to endorse or promote products derived from this software 56236769Sobrien * without specific prior written permission. 57236769Sobrien * 58236769Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59236769Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60236769Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61236769Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62236769Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63236769Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64236769Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65236769Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66236769Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67236769Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68236769Sobrien * SUCH DAMAGE. 69236769Sobrien */ 70236769Sobrien 71236769Sobrien#ifndef MAKE_NATIVE 72300313Ssjgstatic char rcsid[] = "$NetBSD: parse.c,v 1.214 2016/04/06 09:57:00 gson Exp $"; 73236769Sobrien#else 74236769Sobrien#include <sys/cdefs.h> 75236769Sobrien#ifndef lint 76236769Sobrien#if 0 77236769Sobrienstatic char sccsid[] = "@(#)parse.c 8.3 (Berkeley) 3/19/94"; 78236769Sobrien#else 79300313Ssjg__RCSID("$NetBSD: parse.c,v 1.214 2016/04/06 09:57:00 gson Exp $"); 80236769Sobrien#endif 81236769Sobrien#endif /* not lint */ 82236769Sobrien#endif 83236769Sobrien 84236769Sobrien/*- 85236769Sobrien * parse.c -- 86236769Sobrien * Functions to parse a makefile. 87236769Sobrien * 88236769Sobrien * One function, Parse_Init, must be called before any functions 89236769Sobrien * in this module are used. After that, the function Parse_File is the 90236769Sobrien * main entry point and controls most of the other functions in this 91236769Sobrien * module. 92236769Sobrien * 93236769Sobrien * Most important structures are kept in Lsts. Directories for 94236769Sobrien * the .include "..." function are kept in the 'parseIncPath' Lst, while 95236769Sobrien * those for the .include <...> are kept in the 'sysIncPath' Lst. The 96236769Sobrien * targets currently being defined are kept in the 'targets' Lst. 97236769Sobrien * 98236769Sobrien * The variables 'fname' and 'lineno' are used to track the name 99236769Sobrien * of the current file and the line number in that file so that error 100236769Sobrien * messages can be more meaningful. 101236769Sobrien * 102236769Sobrien * Interface: 103236769Sobrien * Parse_Init Initialization function which must be 104236769Sobrien * called before anything else in this module 105236769Sobrien * is used. 106236769Sobrien * 107236769Sobrien * Parse_End Cleanup the module 108236769Sobrien * 109236769Sobrien * Parse_File Function used to parse a makefile. It must 110236769Sobrien * be given the name of the file, which should 111236769Sobrien * already have been opened, and a function 112236769Sobrien * to call to read a character from the file. 113236769Sobrien * 114236769Sobrien * Parse_IsVar Returns TRUE if the given line is a 115236769Sobrien * variable assignment. Used by MainParseArgs 116236769Sobrien * to determine if an argument is a target 117236769Sobrien * or a variable assignment. Used internally 118236769Sobrien * for pretty much the same thing... 119236769Sobrien * 120236769Sobrien * Parse_Error Function called when an error occurs in 121236769Sobrien * parsing. Used by the variable and 122236769Sobrien * conditional modules. 123236769Sobrien * Parse_MainName Returns a Lst of the main target to create. 124236769Sobrien */ 125236769Sobrien 126236769Sobrien#include <sys/types.h> 127236769Sobrien#include <sys/stat.h> 128236769Sobrien#include <assert.h> 129236769Sobrien#include <ctype.h> 130236769Sobrien#include <errno.h> 131236769Sobrien#include <stdarg.h> 132236769Sobrien#include <stdio.h> 133236769Sobrien 134236769Sobrien#include "make.h" 135236769Sobrien#include "hash.h" 136236769Sobrien#include "dir.h" 137236769Sobrien#include "job.h" 138236769Sobrien#include "buf.h" 139236769Sobrien#include "pathnames.h" 140236769Sobrien 141236769Sobrien#ifdef HAVE_MMAP 142236769Sobrien#include <sys/mman.h> 143236769Sobrien 144236769Sobrien#ifndef MAP_COPY 145236769Sobrien#define MAP_COPY MAP_PRIVATE 146236769Sobrien#endif 147236769Sobrien#ifndef MAP_FILE 148236769Sobrien#define MAP_FILE 0 149236769Sobrien#endif 150236769Sobrien#endif 151236769Sobrien 152236769Sobrien//////////////////////////////////////////////////////////// 153236769Sobrien// types and constants 154236769Sobrien 155236769Sobrien/* 156236769Sobrien * Structure for a file being read ("included file") 157236769Sobrien */ 158236769Sobrientypedef struct IFile { 159251958Ssjg char *fname; /* name of file */ 160236769Sobrien int lineno; /* current line number in file */ 161236769Sobrien int first_lineno; /* line number of start of text */ 162236769Sobrien int cond_depth; /* 'if' nesting when file opened */ 163296637Ssjg Boolean depending; /* state of doing_depend on EOF */ 164236769Sobrien char *P_str; /* point to base of string buffer */ 165236769Sobrien char *P_ptr; /* point to next char of string buffer */ 166236769Sobrien char *P_end; /* point to the end of string buffer */ 167236769Sobrien char *(*nextbuf)(void *, size_t *); /* Function to get more data */ 168236769Sobrien void *nextbuf_arg; /* Opaque arg for nextbuf() */ 169236769Sobrien struct loadedfile *lf; /* loadedfile object, if any */ 170236769Sobrien} IFile; 171236769Sobrien 172236769Sobrien 173236769Sobrien/* 174236769Sobrien * These values are returned by ParseEOF to tell Parse_File whether to 175236769Sobrien * CONTINUE parsing, i.e. it had only reached the end of an include file, 176236769Sobrien * or if it's DONE. 177236769Sobrien */ 178236769Sobrien#define CONTINUE 1 179236769Sobrien#define DONE 0 180236769Sobrien 181236769Sobrien/* 182236769Sobrien * Tokens for target attributes 183236769Sobrien */ 184236769Sobrientypedef enum { 185236769Sobrien Begin, /* .BEGIN */ 186236769Sobrien Default, /* .DEFAULT */ 187236769Sobrien End, /* .END */ 188236769Sobrien dotError, /* .ERROR */ 189236769Sobrien Ignore, /* .IGNORE */ 190236769Sobrien Includes, /* .INCLUDES */ 191236769Sobrien Interrupt, /* .INTERRUPT */ 192236769Sobrien Libs, /* .LIBS */ 193236769Sobrien Meta, /* .META */ 194236769Sobrien MFlags, /* .MFLAGS or .MAKEFLAGS */ 195236769Sobrien Main, /* .MAIN and we don't have anything user-specified to 196236769Sobrien * make */ 197236769Sobrien NoExport, /* .NOEXPORT */ 198236769Sobrien NoMeta, /* .NOMETA */ 199236769Sobrien NoMetaCmp, /* .NOMETA_CMP */ 200236769Sobrien NoPath, /* .NOPATH */ 201236769Sobrien Not, /* Not special */ 202236769Sobrien NotParallel, /* .NOTPARALLEL */ 203236769Sobrien Null, /* .NULL */ 204236769Sobrien ExObjdir, /* .OBJDIR */ 205236769Sobrien Order, /* .ORDER */ 206236769Sobrien Parallel, /* .PARALLEL */ 207236769Sobrien ExPath, /* .PATH */ 208236769Sobrien Phony, /* .PHONY */ 209236769Sobrien#ifdef POSIX 210236769Sobrien Posix, /* .POSIX */ 211236769Sobrien#endif 212236769Sobrien Precious, /* .PRECIOUS */ 213236769Sobrien ExShell, /* .SHELL */ 214236769Sobrien Silent, /* .SILENT */ 215236769Sobrien SingleShell, /* .SINGLESHELL */ 216249033Ssjg Stale, /* .STALE */ 217236769Sobrien Suffixes, /* .SUFFIXES */ 218236769Sobrien Wait, /* .WAIT */ 219236769Sobrien Attribute /* Generic attribute */ 220236769Sobrien} ParseSpecial; 221236769Sobrien 222236769Sobrien/* 223236769Sobrien * Other tokens 224236769Sobrien */ 225236769Sobrien#define LPAREN '(' 226236769Sobrien#define RPAREN ')' 227236769Sobrien 228236769Sobrien 229236769Sobrien//////////////////////////////////////////////////////////// 230236769Sobrien// result data 231236769Sobrien 232236769Sobrien/* 233236769Sobrien * The main target to create. This is the first target on the first 234236769Sobrien * dependency line in the first makefile. 235236769Sobrien */ 236236769Sobrienstatic GNode *mainNode; 237236769Sobrien 238236769Sobrien//////////////////////////////////////////////////////////// 239236769Sobrien// eval state 240236769Sobrien 241236769Sobrien/* targets we're working on */ 242236769Sobrienstatic Lst targets; 243236769Sobrien 244236769Sobrien#ifdef CLEANUP 245236769Sobrien/* command lines for targets */ 246236769Sobrienstatic Lst targCmds; 247236769Sobrien#endif 248236769Sobrien 249236769Sobrien/* 250236769Sobrien * specType contains the SPECial TYPE of the current target. It is 251236769Sobrien * Not if the target is unspecial. If it *is* special, however, the children 252236769Sobrien * are linked as children of the parent but not vice versa. This variable is 253236769Sobrien * set in ParseDoDependency 254236769Sobrien */ 255236769Sobrienstatic ParseSpecial specType; 256236769Sobrien 257236769Sobrien/* 258236769Sobrien * Predecessor node for handling .ORDER. Initialized to NULL when .ORDER 259236769Sobrien * seen, then set to each successive source on the line. 260236769Sobrien */ 261236769Sobrienstatic GNode *predecessor; 262236769Sobrien 263236769Sobrien//////////////////////////////////////////////////////////// 264236769Sobrien// parser state 265236769Sobrien 266236769Sobrien/* true if currently in a dependency line or its commands */ 267236769Sobrienstatic Boolean inLine; 268236769Sobrien 269236769Sobrien/* number of fatal errors */ 270236769Sobrienstatic int fatals = 0; 271236769Sobrien 272236769Sobrien/* 273236769Sobrien * Variables for doing includes 274236769Sobrien */ 275236769Sobrien 276236769Sobrien/* current file being read */ 277236769Sobrienstatic IFile *curFile; 278236769Sobrien 279236769Sobrien/* stack of IFiles generated by .includes */ 280236769Sobrienstatic Lst includes; 281236769Sobrien 282236769Sobrien/* include paths (lists of directories) */ 283236769SobrienLst parseIncPath; /* dirs for "..." includes */ 284236769SobrienLst sysIncPath; /* dirs for <...> includes */ 285236769SobrienLst defIncPath; /* default for sysIncPath */ 286236769Sobrien 287236769Sobrien//////////////////////////////////////////////////////////// 288236769Sobrien// parser tables 289236769Sobrien 290236769Sobrien/* 291236769Sobrien * The parseKeywords table is searched using binary search when deciding 292236769Sobrien * if a target or source is special. The 'spec' field is the ParseSpecial 293236769Sobrien * type of the keyword ("Not" if the keyword isn't special as a target) while 294236769Sobrien * the 'op' field is the operator to apply to the list of targets if the 295236769Sobrien * keyword is used as a source ("0" if the keyword isn't special as a source) 296236769Sobrien */ 297236769Sobrienstatic const struct { 298236769Sobrien const char *name; /* Name of keyword */ 299236769Sobrien ParseSpecial spec; /* Type when used as a target */ 300236769Sobrien int op; /* Operator when used as a source */ 301236769Sobrien} parseKeywords[] = { 302236769Sobrien{ ".BEGIN", Begin, 0 }, 303236769Sobrien{ ".DEFAULT", Default, 0 }, 304236769Sobrien{ ".END", End, 0 }, 305236769Sobrien{ ".ERROR", dotError, 0 }, 306236769Sobrien{ ".EXEC", Attribute, OP_EXEC }, 307236769Sobrien{ ".IGNORE", Ignore, OP_IGNORE }, 308236769Sobrien{ ".INCLUDES", Includes, 0 }, 309236769Sobrien{ ".INTERRUPT", Interrupt, 0 }, 310236769Sobrien{ ".INVISIBLE", Attribute, OP_INVISIBLE }, 311236769Sobrien{ ".JOIN", Attribute, OP_JOIN }, 312236769Sobrien{ ".LIBS", Libs, 0 }, 313236769Sobrien{ ".MADE", Attribute, OP_MADE }, 314236769Sobrien{ ".MAIN", Main, 0 }, 315236769Sobrien{ ".MAKE", Attribute, OP_MAKE }, 316236769Sobrien{ ".MAKEFLAGS", MFlags, 0 }, 317236769Sobrien{ ".META", Meta, OP_META }, 318236769Sobrien{ ".MFLAGS", MFlags, 0 }, 319236769Sobrien{ ".NOMETA", NoMeta, OP_NOMETA }, 320236769Sobrien{ ".NOMETA_CMP", NoMetaCmp, OP_NOMETA_CMP }, 321236769Sobrien{ ".NOPATH", NoPath, OP_NOPATH }, 322236769Sobrien{ ".NOTMAIN", Attribute, OP_NOTMAIN }, 323236769Sobrien{ ".NOTPARALLEL", NotParallel, 0 }, 324236769Sobrien{ ".NO_PARALLEL", NotParallel, 0 }, 325236769Sobrien{ ".NULL", Null, 0 }, 326236769Sobrien{ ".OBJDIR", ExObjdir, 0 }, 327236769Sobrien{ ".OPTIONAL", Attribute, OP_OPTIONAL }, 328236769Sobrien{ ".ORDER", Order, 0 }, 329236769Sobrien{ ".PARALLEL", Parallel, 0 }, 330236769Sobrien{ ".PATH", ExPath, 0 }, 331236769Sobrien{ ".PHONY", Phony, OP_PHONY }, 332236769Sobrien#ifdef POSIX 333236769Sobrien{ ".POSIX", Posix, 0 }, 334236769Sobrien#endif 335236769Sobrien{ ".PRECIOUS", Precious, OP_PRECIOUS }, 336236769Sobrien{ ".RECURSIVE", Attribute, OP_MAKE }, 337236769Sobrien{ ".SHELL", ExShell, 0 }, 338236769Sobrien{ ".SILENT", Silent, OP_SILENT }, 339236769Sobrien{ ".SINGLESHELL", SingleShell, 0 }, 340249033Ssjg{ ".STALE", Stale, 0 }, 341236769Sobrien{ ".SUFFIXES", Suffixes, 0 }, 342236769Sobrien{ ".USE", Attribute, OP_USE }, 343236769Sobrien{ ".USEBEFORE", Attribute, OP_USEBEFORE }, 344236769Sobrien{ ".WAIT", Wait, 0 }, 345236769Sobrien}; 346236769Sobrien 347236769Sobrien//////////////////////////////////////////////////////////// 348236769Sobrien// local functions 349236769Sobrien 350236769Sobrienstatic int ParseIsEscaped(const char *, const char *); 351236769Sobrienstatic void ParseErrorInternal(const char *, size_t, int, const char *, ...) 352237578Sobrien MAKE_ATTR_PRINTFLIKE(4,5); 353236769Sobrienstatic void ParseVErrorInternal(FILE *, const char *, size_t, int, const char *, va_list) 354237578Sobrien MAKE_ATTR_PRINTFLIKE(5, 0); 355236769Sobrienstatic int ParseFindKeyword(const char *); 356236769Sobrienstatic int ParseLinkSrc(void *, void *); 357236769Sobrienstatic int ParseDoOp(void *, void *); 358236769Sobrienstatic void ParseDoSrc(int, const char *); 359236769Sobrienstatic int ParseFindMain(void *, void *); 360236769Sobrienstatic int ParseAddDir(void *, void *); 361236769Sobrienstatic int ParseClearPath(void *, void *); 362236769Sobrienstatic void ParseDoDependency(char *); 363236769Sobrienstatic int ParseAddCmd(void *, void *); 364236769Sobrienstatic void ParseHasCommands(void *); 365236769Sobrienstatic void ParseDoInclude(char *); 366236769Sobrienstatic void ParseSetParseFile(const char *); 367268437Ssjgstatic void ParseSetIncludedFile(void); 368236769Sobrien#ifdef SYSVINCLUDE 369236769Sobrienstatic void ParseTraditionalInclude(char *); 370236769Sobrien#endif 371236769Sobrien#ifdef GMAKEEXPORT 372236769Sobrienstatic void ParseGmakeExport(char *); 373236769Sobrien#endif 374236769Sobrienstatic int ParseEOF(void); 375236769Sobrienstatic char *ParseReadLine(void); 376236769Sobrienstatic void ParseFinishLine(void); 377236769Sobrienstatic void ParseMark(GNode *); 378236769Sobrien 379236769Sobrien//////////////////////////////////////////////////////////// 380236769Sobrien// file loader 381236769Sobrien 382236769Sobrienstruct loadedfile { 383236769Sobrien const char *path; /* name, for error reports */ 384236769Sobrien char *buf; /* contents buffer */ 385236769Sobrien size_t len; /* length of contents */ 386236769Sobrien size_t maplen; /* length of mmap area, or 0 */ 387236769Sobrien Boolean used; /* XXX: have we used the data yet */ 388236769Sobrien}; 389236769Sobrien 390236769Sobrien/* 391236769Sobrien * Constructor/destructor for loadedfile 392236769Sobrien */ 393236769Sobrienstatic struct loadedfile * 394236769Sobrienloadedfile_create(const char *path) 395236769Sobrien{ 396236769Sobrien struct loadedfile *lf; 397236769Sobrien 398236769Sobrien lf = bmake_malloc(sizeof(*lf)); 399236769Sobrien lf->path = (path == NULL ? "(stdin)" : path); 400236769Sobrien lf->buf = NULL; 401236769Sobrien lf->len = 0; 402236769Sobrien lf->maplen = 0; 403236769Sobrien lf->used = FALSE; 404236769Sobrien return lf; 405236769Sobrien} 406236769Sobrien 407236769Sobrienstatic void 408236769Sobrienloadedfile_destroy(struct loadedfile *lf) 409236769Sobrien{ 410236769Sobrien if (lf->buf != NULL) { 411236769Sobrien if (lf->maplen > 0) { 412236769Sobrien#ifdef HAVE_MMAP 413236769Sobrien munmap(lf->buf, lf->maplen); 414236769Sobrien#endif 415236769Sobrien } else { 416236769Sobrien free(lf->buf); 417236769Sobrien } 418236769Sobrien } 419236769Sobrien free(lf); 420236769Sobrien} 421236769Sobrien 422236769Sobrien/* 423236769Sobrien * nextbuf() operation for loadedfile, as needed by the weird and twisted 424236769Sobrien * logic below. Once that's cleaned up, we can get rid of lf->used... 425236769Sobrien */ 426236769Sobrienstatic char * 427236769Sobrienloadedfile_nextbuf(void *x, size_t *len) 428236769Sobrien{ 429236769Sobrien struct loadedfile *lf = x; 430236769Sobrien 431236769Sobrien if (lf->used) { 432236769Sobrien return NULL; 433236769Sobrien } 434236769Sobrien lf->used = TRUE; 435236769Sobrien *len = lf->len; 436236769Sobrien return lf->buf; 437236769Sobrien} 438236769Sobrien 439236769Sobrien/* 440236769Sobrien * Try to get the size of a file. 441236769Sobrien */ 442236769Sobrienstatic ReturnStatus 443236769Sobrienload_getsize(int fd, size_t *ret) 444236769Sobrien{ 445236769Sobrien struct stat st; 446236769Sobrien 447236769Sobrien if (fstat(fd, &st) < 0) { 448236769Sobrien return FAILURE; 449236769Sobrien } 450236769Sobrien 451236769Sobrien if (!S_ISREG(st.st_mode)) { 452236769Sobrien return FAILURE; 453236769Sobrien } 454236769Sobrien 455236769Sobrien /* 456236769Sobrien * st_size is an off_t, which is 64 bits signed; *ret is 457236769Sobrien * size_t, which might be 32 bits unsigned or 64 bits 458236769Sobrien * unsigned. Rather than being elaborate, just punt on 459236769Sobrien * files that are more than 2^31 bytes. We should never 460236769Sobrien * see a makefile that size in practice... 461236769Sobrien * 462236769Sobrien * While we're at it reject negative sizes too, just in case. 463236769Sobrien */ 464236769Sobrien if (st.st_size < 0 || st.st_size > 0x7fffffff) { 465236769Sobrien return FAILURE; 466236769Sobrien } 467236769Sobrien 468236769Sobrien *ret = (size_t) st.st_size; 469236769Sobrien return SUCCESS; 470236769Sobrien} 471236769Sobrien 472236769Sobrien/* 473236769Sobrien * Read in a file. 474236769Sobrien * 475236769Sobrien * Until the path search logic can be moved under here instead of 476236769Sobrien * being in the caller in another source file, we need to have the fd 477236769Sobrien * passed in already open. Bleh. 478236769Sobrien * 479236769Sobrien * If the path is NULL use stdin and (to insure against fd leaks) 480236769Sobrien * assert that the caller passed in -1. 481236769Sobrien */ 482236769Sobrienstatic struct loadedfile * 483236769Sobrienloadfile(const char *path, int fd) 484236769Sobrien{ 485236769Sobrien struct loadedfile *lf; 486236769Sobrien#ifdef HAVE_MMAP 487236769Sobrien long pagesize; 488236769Sobrien#endif 489236769Sobrien ssize_t result; 490236769Sobrien size_t bufpos; 491236769Sobrien 492236769Sobrien lf = loadedfile_create(path); 493236769Sobrien 494236769Sobrien if (path == NULL) { 495236769Sobrien assert(fd == -1); 496236769Sobrien fd = STDIN_FILENO; 497236769Sobrien } else { 498236769Sobrien#if 0 /* notyet */ 499236769Sobrien fd = open(path, O_RDONLY); 500236769Sobrien if (fd < 0) { 501236769Sobrien ... 502236769Sobrien Error("%s: %s", path, strerror(errno)); 503236769Sobrien exit(1); 504236769Sobrien } 505236769Sobrien#endif 506236769Sobrien } 507236769Sobrien 508236769Sobrien#ifdef HAVE_MMAP 509236769Sobrien if (load_getsize(fd, &lf->len) == SUCCESS) { 510236769Sobrien /* found a size, try mmap */ 511291978Ssjg#ifdef _SC_PAGESIZE 512236769Sobrien pagesize = sysconf(_SC_PAGESIZE); 513291978Ssjg#else 514291978Ssjg pagesize = 0; 515291978Ssjg#endif 516236769Sobrien if (pagesize <= 0) { 517236769Sobrien pagesize = 0x1000; 518236769Sobrien } 519236769Sobrien /* round size up to a page */ 520236769Sobrien lf->maplen = pagesize * ((lf->len + pagesize - 1)/pagesize); 521236769Sobrien 522236769Sobrien /* 523236769Sobrien * XXX hack for dealing with empty files; remove when 524236769Sobrien * we're no longer limited by interfacing to the old 525236769Sobrien * logic elsewhere in this file. 526236769Sobrien */ 527236769Sobrien if (lf->maplen == 0) { 528236769Sobrien lf->maplen = pagesize; 529236769Sobrien } 530236769Sobrien 531236769Sobrien /* 532236769Sobrien * FUTURE: remove PROT_WRITE when the parser no longer 533236769Sobrien * needs to scribble on the input. 534236769Sobrien */ 535236769Sobrien lf->buf = mmap(NULL, lf->maplen, PROT_READ|PROT_WRITE, 536236769Sobrien MAP_FILE|MAP_COPY, fd, 0); 537236769Sobrien if (lf->buf != MAP_FAILED) { 538236769Sobrien /* succeeded */ 539236769Sobrien if (lf->len == lf->maplen && lf->buf[lf->len - 1] != '\n') { 540236769Sobrien char *b = malloc(lf->len + 1); 541236769Sobrien b[lf->len] = '\n'; 542236769Sobrien memcpy(b, lf->buf, lf->len++); 543236769Sobrien munmap(lf->buf, lf->maplen); 544236769Sobrien lf->maplen = 0; 545236769Sobrien lf->buf = b; 546236769Sobrien } 547236769Sobrien goto done; 548236769Sobrien } 549236769Sobrien } 550236769Sobrien#endif 551236769Sobrien /* cannot mmap; load the traditional way */ 552236769Sobrien 553236769Sobrien lf->maplen = 0; 554236769Sobrien lf->len = 1024; 555236769Sobrien lf->buf = bmake_malloc(lf->len); 556236769Sobrien 557236769Sobrien bufpos = 0; 558236769Sobrien while (1) { 559236769Sobrien assert(bufpos <= lf->len); 560236769Sobrien if (bufpos == lf->len) { 561236769Sobrien lf->len *= 2; 562236769Sobrien lf->buf = bmake_realloc(lf->buf, lf->len); 563236769Sobrien } 564236769Sobrien result = read(fd, lf->buf + bufpos, lf->len - bufpos); 565236769Sobrien if (result < 0) { 566236769Sobrien Error("%s: read error: %s", path, strerror(errno)); 567236769Sobrien exit(1); 568236769Sobrien } 569236769Sobrien if (result == 0) { 570236769Sobrien break; 571236769Sobrien } 572236769Sobrien bufpos += result; 573236769Sobrien } 574236769Sobrien assert(bufpos <= lf->len); 575236769Sobrien lf->len = bufpos; 576236769Sobrien 577236769Sobrien /* truncate malloc region to actual length (maybe not useful) */ 578236769Sobrien if (lf->len > 0) { 579236769Sobrien lf->buf = bmake_realloc(lf->buf, lf->len); 580236769Sobrien } 581236769Sobrien 582236769Sobrien#ifdef HAVE_MMAP 583236769Sobriendone: 584236769Sobrien#endif 585236769Sobrien if (path != NULL) { 586236769Sobrien close(fd); 587236769Sobrien } 588236769Sobrien return lf; 589236769Sobrien} 590236769Sobrien 591236769Sobrien//////////////////////////////////////////////////////////// 592236769Sobrien// old code 593236769Sobrien 594236769Sobrien/*- 595236769Sobrien *---------------------------------------------------------------------- 596236769Sobrien * ParseIsEscaped -- 597236769Sobrien * Check if the current character is escaped on the current line 598236769Sobrien * 599236769Sobrien * Results: 600236769Sobrien * 0 if the character is not backslash escaped, 1 otherwise 601236769Sobrien * 602236769Sobrien * Side Effects: 603236769Sobrien * None 604236769Sobrien *---------------------------------------------------------------------- 605236769Sobrien */ 606236769Sobrienstatic int 607236769SobrienParseIsEscaped(const char *line, const char *c) 608236769Sobrien{ 609236769Sobrien int active = 0; 610236769Sobrien for (;;) { 611236769Sobrien if (line == c) 612236769Sobrien return active; 613236769Sobrien if (*--c != '\\') 614236769Sobrien return active; 615236769Sobrien active = !active; 616236769Sobrien } 617236769Sobrien} 618236769Sobrien 619236769Sobrien/*- 620236769Sobrien *---------------------------------------------------------------------- 621236769Sobrien * ParseFindKeyword -- 622236769Sobrien * Look in the table of keywords for one matching the given string. 623236769Sobrien * 624236769Sobrien * Input: 625236769Sobrien * str String to find 626236769Sobrien * 627236769Sobrien * Results: 628236769Sobrien * The index of the keyword, or -1 if it isn't there. 629236769Sobrien * 630236769Sobrien * Side Effects: 631236769Sobrien * None 632236769Sobrien *---------------------------------------------------------------------- 633236769Sobrien */ 634236769Sobrienstatic int 635236769SobrienParseFindKeyword(const char *str) 636236769Sobrien{ 637236769Sobrien int start, end, cur; 638236769Sobrien int diff; 639236769Sobrien 640236769Sobrien start = 0; 641236769Sobrien end = (sizeof(parseKeywords)/sizeof(parseKeywords[0])) - 1; 642236769Sobrien 643236769Sobrien do { 644236769Sobrien cur = start + ((end - start) / 2); 645236769Sobrien diff = strcmp(str, parseKeywords[cur].name); 646236769Sobrien 647236769Sobrien if (diff == 0) { 648236769Sobrien return (cur); 649236769Sobrien } else if (diff < 0) { 650236769Sobrien end = cur - 1; 651236769Sobrien } else { 652236769Sobrien start = cur + 1; 653236769Sobrien } 654236769Sobrien } while (start <= end); 655236769Sobrien return (-1); 656236769Sobrien} 657236769Sobrien 658236769Sobrien/*- 659236769Sobrien * ParseVErrorInternal -- 660236769Sobrien * Error message abort function for parsing. Prints out the context 661236769Sobrien * of the error (line number and file) as well as the message with 662236769Sobrien * two optional arguments. 663236769Sobrien * 664236769Sobrien * Results: 665236769Sobrien * None 666236769Sobrien * 667236769Sobrien * Side Effects: 668236769Sobrien * "fatals" is incremented if the level is PARSE_FATAL. 669236769Sobrien */ 670236769Sobrien/* VARARGS */ 671236769Sobrienstatic void 672236769SobrienParseVErrorInternal(FILE *f, const char *cfname, size_t clineno, int type, 673236769Sobrien const char *fmt, va_list ap) 674236769Sobrien{ 675236769Sobrien static Boolean fatal_warning_error_printed = FALSE; 676236769Sobrien 677236769Sobrien (void)fprintf(f, "%s: ", progname); 678236769Sobrien 679236769Sobrien if (cfname != NULL) { 680236769Sobrien (void)fprintf(f, "\""); 681236769Sobrien if (*cfname != '/' && strcmp(cfname, "(stdin)") != 0) { 682236769Sobrien char *cp; 683236769Sobrien const char *dir; 684236769Sobrien 685236769Sobrien /* 686236769Sobrien * Nothing is more annoying than not knowing 687236769Sobrien * which Makefile is the culprit. 688236769Sobrien */ 689236769Sobrien dir = Var_Value(".PARSEDIR", VAR_GLOBAL, &cp); 690236769Sobrien if (dir == NULL || *dir == '\0' || 691236769Sobrien (*dir == '.' && dir[1] == '\0')) 692236769Sobrien dir = Var_Value(".CURDIR", VAR_GLOBAL, &cp); 693236769Sobrien if (dir == NULL) 694236769Sobrien dir = "."; 695236769Sobrien 696236769Sobrien (void)fprintf(f, "%s/%s", dir, cfname); 697236769Sobrien } else 698236769Sobrien (void)fprintf(f, "%s", cfname); 699236769Sobrien 700236769Sobrien (void)fprintf(f, "\" line %d: ", (int)clineno); 701236769Sobrien } 702236769Sobrien if (type == PARSE_WARNING) 703236769Sobrien (void)fprintf(f, "warning: "); 704236769Sobrien (void)vfprintf(f, fmt, ap); 705236769Sobrien (void)fprintf(f, "\n"); 706236769Sobrien (void)fflush(f); 707236769Sobrien if (type == PARSE_FATAL || parseWarnFatal) 708236769Sobrien fatals += 1; 709236769Sobrien if (parseWarnFatal && !fatal_warning_error_printed) { 710236769Sobrien Error("parsing warnings being treated as errors"); 711236769Sobrien fatal_warning_error_printed = TRUE; 712236769Sobrien } 713236769Sobrien} 714236769Sobrien 715236769Sobrien/*- 716236769Sobrien * ParseErrorInternal -- 717236769Sobrien * Error function 718236769Sobrien * 719236769Sobrien * Results: 720236769Sobrien * None 721236769Sobrien * 722236769Sobrien * Side Effects: 723236769Sobrien * None 724236769Sobrien */ 725236769Sobrien/* VARARGS */ 726236769Sobrienstatic void 727236769SobrienParseErrorInternal(const char *cfname, size_t clineno, int type, 728236769Sobrien const char *fmt, ...) 729236769Sobrien{ 730236769Sobrien va_list ap; 731236769Sobrien 732236769Sobrien va_start(ap, fmt); 733236769Sobrien (void)fflush(stdout); 734236769Sobrien ParseVErrorInternal(stderr, cfname, clineno, type, fmt, ap); 735236769Sobrien va_end(ap); 736236769Sobrien 737236769Sobrien if (debug_file != stderr && debug_file != stdout) { 738236769Sobrien va_start(ap, fmt); 739236769Sobrien ParseVErrorInternal(debug_file, cfname, clineno, type, fmt, ap); 740236769Sobrien va_end(ap); 741236769Sobrien } 742236769Sobrien} 743236769Sobrien 744236769Sobrien/*- 745236769Sobrien * Parse_Error -- 746236769Sobrien * External interface to ParseErrorInternal; uses the default filename 747236769Sobrien * Line number. 748236769Sobrien * 749236769Sobrien * Results: 750236769Sobrien * None 751236769Sobrien * 752236769Sobrien * Side Effects: 753236769Sobrien * None 754236769Sobrien */ 755236769Sobrien/* VARARGS */ 756236769Sobrienvoid 757236769SobrienParse_Error(int type, const char *fmt, ...) 758236769Sobrien{ 759236769Sobrien va_list ap; 760236769Sobrien const char *fname; 761236769Sobrien size_t lineno; 762236769Sobrien 763236769Sobrien if (curFile == NULL) { 764236769Sobrien fname = NULL; 765236769Sobrien lineno = 0; 766236769Sobrien } else { 767236769Sobrien fname = curFile->fname; 768236769Sobrien lineno = curFile->lineno; 769236769Sobrien } 770236769Sobrien 771236769Sobrien va_start(ap, fmt); 772236769Sobrien (void)fflush(stdout); 773236769Sobrien ParseVErrorInternal(stderr, fname, lineno, type, fmt, ap); 774236769Sobrien va_end(ap); 775236769Sobrien 776236769Sobrien if (debug_file != stderr && debug_file != stdout) { 777236769Sobrien va_start(ap, fmt); 778236769Sobrien ParseVErrorInternal(debug_file, fname, lineno, type, fmt, ap); 779236769Sobrien va_end(ap); 780236769Sobrien } 781236769Sobrien} 782236769Sobrien 783236769Sobrien 784236769Sobrien/* 785236769Sobrien * ParseMessage 786236769Sobrien * Parse a .info .warning or .error directive 787236769Sobrien * 788236769Sobrien * The input is the line minus the ".". We substitute 789236769Sobrien * variables, print the message and exit(1) (for .error) or just print 790236769Sobrien * a warning if the directive is malformed. 791236769Sobrien */ 792236769Sobrienstatic Boolean 793236769SobrienParseMessage(char *line) 794236769Sobrien{ 795236769Sobrien int mtype; 796236769Sobrien 797236769Sobrien switch(*line) { 798236769Sobrien case 'i': 799236769Sobrien mtype = 0; 800236769Sobrien break; 801236769Sobrien case 'w': 802236769Sobrien mtype = PARSE_WARNING; 803236769Sobrien break; 804236769Sobrien case 'e': 805236769Sobrien mtype = PARSE_FATAL; 806236769Sobrien break; 807236769Sobrien default: 808236769Sobrien Parse_Error(PARSE_WARNING, "invalid syntax: \".%s\"", line); 809236769Sobrien return FALSE; 810236769Sobrien } 811236769Sobrien 812300313Ssjg while (isalpha((unsigned char)*line)) 813236769Sobrien line++; 814300313Ssjg if (!isspace((unsigned char)*line)) 815236769Sobrien return FALSE; /* not for us */ 816300313Ssjg while (isspace((unsigned char)*line)) 817236769Sobrien line++; 818236769Sobrien 819296637Ssjg line = Var_Subst(NULL, line, VAR_CMD, VARF_WANTRES); 820236769Sobrien Parse_Error(mtype, "%s", line); 821236769Sobrien free(line); 822236769Sobrien 823236769Sobrien if (mtype == PARSE_FATAL) { 824236769Sobrien /* Terminate immediately. */ 825236769Sobrien exit(1); 826236769Sobrien } 827236769Sobrien return TRUE; 828236769Sobrien} 829236769Sobrien 830236769Sobrien/*- 831236769Sobrien *--------------------------------------------------------------------- 832236769Sobrien * ParseLinkSrc -- 833236769Sobrien * Link the parent node to its new child. Used in a Lst_ForEach by 834236769Sobrien * ParseDoDependency. If the specType isn't 'Not', the parent 835236769Sobrien * isn't linked as a parent of the child. 836236769Sobrien * 837236769Sobrien * Input: 838236769Sobrien * pgnp The parent node 839236769Sobrien * cgpn The child node 840236769Sobrien * 841236769Sobrien * Results: 842236769Sobrien * Always = 0 843236769Sobrien * 844236769Sobrien * Side Effects: 845236769Sobrien * New elements are added to the parents list of cgn and the 846236769Sobrien * children list of cgn. the unmade field of pgn is updated 847236769Sobrien * to reflect the additional child. 848236769Sobrien *--------------------------------------------------------------------- 849236769Sobrien */ 850236769Sobrienstatic int 851236769SobrienParseLinkSrc(void *pgnp, void *cgnp) 852236769Sobrien{ 853236769Sobrien GNode *pgn = (GNode *)pgnp; 854236769Sobrien GNode *cgn = (GNode *)cgnp; 855236769Sobrien 856236769Sobrien if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (pgn->cohorts)) 857236769Sobrien pgn = (GNode *)Lst_Datum(Lst_Last(pgn->cohorts)); 858236769Sobrien (void)Lst_AtEnd(pgn->children, cgn); 859236769Sobrien if (specType == Not) 860236769Sobrien (void)Lst_AtEnd(cgn->parents, pgn); 861236769Sobrien pgn->unmade += 1; 862236769Sobrien if (DEBUG(PARSE)) { 863268437Ssjg fprintf(debug_file, "# %s: added child %s - %s\n", __func__, 864268437Ssjg pgn->name, cgn->name); 865236769Sobrien Targ_PrintNode(pgn, 0); 866236769Sobrien Targ_PrintNode(cgn, 0); 867236769Sobrien } 868236769Sobrien return (0); 869236769Sobrien} 870236769Sobrien 871236769Sobrien/*- 872236769Sobrien *--------------------------------------------------------------------- 873236769Sobrien * ParseDoOp -- 874236769Sobrien * Apply the parsed operator to the given target node. Used in a 875236769Sobrien * Lst_ForEach call by ParseDoDependency once all targets have 876236769Sobrien * been found and their operator parsed. If the previous and new 877236769Sobrien * operators are incompatible, a major error is taken. 878236769Sobrien * 879236769Sobrien * Input: 880236769Sobrien * gnp The node to which the operator is to be applied 881236769Sobrien * opp The operator to apply 882236769Sobrien * 883236769Sobrien * Results: 884236769Sobrien * Always 0 885236769Sobrien * 886236769Sobrien * Side Effects: 887236769Sobrien * The type field of the node is altered to reflect any new bits in 888236769Sobrien * the op. 889236769Sobrien *--------------------------------------------------------------------- 890236769Sobrien */ 891236769Sobrienstatic int 892236769SobrienParseDoOp(void *gnp, void *opp) 893236769Sobrien{ 894236769Sobrien GNode *gn = (GNode *)gnp; 895236769Sobrien int op = *(int *)opp; 896236769Sobrien /* 897236769Sobrien * If the dependency mask of the operator and the node don't match and 898236769Sobrien * the node has actually had an operator applied to it before, and 899236769Sobrien * the operator actually has some dependency information in it, complain. 900236769Sobrien */ 901236769Sobrien if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) && 902236769Sobrien !OP_NOP(gn->type) && !OP_NOP(op)) 903236769Sobrien { 904236769Sobrien Parse_Error(PARSE_FATAL, "Inconsistent operator for %s", gn->name); 905236769Sobrien return (1); 906236769Sobrien } 907236769Sobrien 908236769Sobrien if ((op == OP_DOUBLEDEP) && ((gn->type & OP_OPMASK) == OP_DOUBLEDEP)) { 909236769Sobrien /* 910236769Sobrien * If the node was the object of a :: operator, we need to create a 911236769Sobrien * new instance of it for the children and commands on this dependency 912236769Sobrien * line. The new instance is placed on the 'cohorts' list of the 913236769Sobrien * initial one (note the initial one is not on its own cohorts list) 914236769Sobrien * and the new instance is linked to all parents of the initial 915236769Sobrien * instance. 916236769Sobrien */ 917236769Sobrien GNode *cohort; 918236769Sobrien 919236769Sobrien /* 920236769Sobrien * Propagate copied bits to the initial node. They'll be propagated 921236769Sobrien * back to the rest of the cohorts later. 922236769Sobrien */ 923236769Sobrien gn->type |= op & ~OP_OPMASK; 924236769Sobrien 925236769Sobrien cohort = Targ_FindNode(gn->name, TARG_NOHASH); 926249033Ssjg if (doing_depend) 927249033Ssjg ParseMark(cohort); 928236769Sobrien /* 929236769Sobrien * Make the cohort invisible as well to avoid duplicating it into 930236769Sobrien * other variables. True, parents of this target won't tend to do 931236769Sobrien * anything with their local variables, but better safe than 932236769Sobrien * sorry. (I think this is pointless now, since the relevant list 933236769Sobrien * traversals will no longer see this node anyway. -mycroft) 934236769Sobrien */ 935236769Sobrien cohort->type = op | OP_INVISIBLE; 936236769Sobrien (void)Lst_AtEnd(gn->cohorts, cohort); 937236769Sobrien cohort->centurion = gn; 938236769Sobrien gn->unmade_cohorts += 1; 939236769Sobrien snprintf(cohort->cohort_num, sizeof cohort->cohort_num, "#%d", 940236769Sobrien gn->unmade_cohorts); 941236769Sobrien } else { 942236769Sobrien /* 943236769Sobrien * We don't want to nuke any previous flags (whatever they were) so we 944236769Sobrien * just OR the new operator into the old 945236769Sobrien */ 946236769Sobrien gn->type |= op; 947236769Sobrien } 948236769Sobrien 949236769Sobrien return (0); 950236769Sobrien} 951236769Sobrien 952236769Sobrien/*- 953236769Sobrien *--------------------------------------------------------------------- 954236769Sobrien * ParseDoSrc -- 955236769Sobrien * Given the name of a source, figure out if it is an attribute 956236769Sobrien * and apply it to the targets if it is. Else decide if there is 957236769Sobrien * some attribute which should be applied *to* the source because 958236769Sobrien * of some special target and apply it if so. Otherwise, make the 959236769Sobrien * source be a child of the targets in the list 'targets' 960236769Sobrien * 961236769Sobrien * Input: 962236769Sobrien * tOp operator (if any) from special targets 963236769Sobrien * src name of the source to handle 964236769Sobrien * 965236769Sobrien * Results: 966236769Sobrien * None 967236769Sobrien * 968236769Sobrien * Side Effects: 969236769Sobrien * Operator bits may be added to the list of targets or to the source. 970236769Sobrien * The targets may have a new source added to their lists of children. 971236769Sobrien *--------------------------------------------------------------------- 972236769Sobrien */ 973236769Sobrienstatic void 974236769SobrienParseDoSrc(int tOp, const char *src) 975236769Sobrien{ 976236769Sobrien GNode *gn = NULL; 977236769Sobrien static int wait_number = 0; 978236769Sobrien char wait_src[16]; 979236769Sobrien 980236769Sobrien if (*src == '.' && isupper ((unsigned char)src[1])) { 981236769Sobrien int keywd = ParseFindKeyword(src); 982236769Sobrien if (keywd != -1) { 983236769Sobrien int op = parseKeywords[keywd].op; 984236769Sobrien if (op != 0) { 985236769Sobrien Lst_ForEach(targets, ParseDoOp, &op); 986236769Sobrien return; 987236769Sobrien } 988236769Sobrien if (parseKeywords[keywd].spec == Wait) { 989236769Sobrien /* 990236769Sobrien * We add a .WAIT node in the dependency list. 991236769Sobrien * After any dynamic dependencies (and filename globbing) 992236769Sobrien * have happened, it is given a dependency on the each 993236769Sobrien * previous child back to and previous .WAIT node. 994236769Sobrien * The next child won't be scheduled until the .WAIT node 995236769Sobrien * is built. 996236769Sobrien * We give each .WAIT node a unique name (mainly for diag). 997236769Sobrien */ 998236769Sobrien snprintf(wait_src, sizeof wait_src, ".WAIT_%u", ++wait_number); 999236769Sobrien gn = Targ_FindNode(wait_src, TARG_NOHASH); 1000249033Ssjg if (doing_depend) 1001249033Ssjg ParseMark(gn); 1002236769Sobrien gn->type = OP_WAIT | OP_PHONY | OP_DEPENDS | OP_NOTMAIN; 1003236769Sobrien Lst_ForEach(targets, ParseLinkSrc, gn); 1004236769Sobrien return; 1005236769Sobrien } 1006236769Sobrien } 1007236769Sobrien } 1008236769Sobrien 1009236769Sobrien switch (specType) { 1010236769Sobrien case Main: 1011236769Sobrien /* 1012236769Sobrien * If we have noted the existence of a .MAIN, it means we need 1013236769Sobrien * to add the sources of said target to the list of things 1014236769Sobrien * to create. The string 'src' is likely to be free, so we 1015236769Sobrien * must make a new copy of it. Note that this will only be 1016236769Sobrien * invoked if the user didn't specify a target on the command 1017236769Sobrien * line. This is to allow #ifmake's to succeed, or something... 1018236769Sobrien */ 1019236769Sobrien (void)Lst_AtEnd(create, bmake_strdup(src)); 1020236769Sobrien /* 1021236769Sobrien * Add the name to the .TARGETS variable as well, so the user can 1022236769Sobrien * employ that, if desired. 1023236769Sobrien */ 1024236769Sobrien Var_Append(".TARGETS", src, VAR_GLOBAL); 1025236769Sobrien return; 1026236769Sobrien 1027236769Sobrien case Order: 1028236769Sobrien /* 1029236769Sobrien * Create proper predecessor/successor links between the previous 1030236769Sobrien * source and the current one. 1031236769Sobrien */ 1032236769Sobrien gn = Targ_FindNode(src, TARG_CREATE); 1033249033Ssjg if (doing_depend) 1034249033Ssjg ParseMark(gn); 1035236769Sobrien if (predecessor != NULL) { 1036236769Sobrien (void)Lst_AtEnd(predecessor->order_succ, gn); 1037236769Sobrien (void)Lst_AtEnd(gn->order_pred, predecessor); 1038236769Sobrien if (DEBUG(PARSE)) { 1039268437Ssjg fprintf(debug_file, "# %s: added Order dependency %s - %s\n", 1040268437Ssjg __func__, predecessor->name, gn->name); 1041236769Sobrien Targ_PrintNode(predecessor, 0); 1042236769Sobrien Targ_PrintNode(gn, 0); 1043236769Sobrien } 1044236769Sobrien } 1045236769Sobrien /* 1046236769Sobrien * The current source now becomes the predecessor for the next one. 1047236769Sobrien */ 1048236769Sobrien predecessor = gn; 1049236769Sobrien break; 1050236769Sobrien 1051236769Sobrien default: 1052236769Sobrien /* 1053236769Sobrien * If the source is not an attribute, we need to find/create 1054236769Sobrien * a node for it. After that we can apply any operator to it 1055236769Sobrien * from a special target or link it to its parents, as 1056236769Sobrien * appropriate. 1057236769Sobrien * 1058236769Sobrien * In the case of a source that was the object of a :: operator, 1059236769Sobrien * the attribute is applied to all of its instances (as kept in 1060236769Sobrien * the 'cohorts' list of the node) or all the cohorts are linked 1061236769Sobrien * to all the targets. 1062236769Sobrien */ 1063236769Sobrien 1064236769Sobrien /* Find/create the 'src' node and attach to all targets */ 1065236769Sobrien gn = Targ_FindNode(src, TARG_CREATE); 1066249033Ssjg if (doing_depend) 1067249033Ssjg ParseMark(gn); 1068236769Sobrien if (tOp) { 1069236769Sobrien gn->type |= tOp; 1070236769Sobrien } else { 1071236769Sobrien Lst_ForEach(targets, ParseLinkSrc, gn); 1072236769Sobrien } 1073236769Sobrien break; 1074236769Sobrien } 1075236769Sobrien} 1076236769Sobrien 1077236769Sobrien/*- 1078236769Sobrien *----------------------------------------------------------------------- 1079236769Sobrien * ParseFindMain -- 1080236769Sobrien * Find a real target in the list and set it to be the main one. 1081236769Sobrien * Called by ParseDoDependency when a main target hasn't been found 1082236769Sobrien * yet. 1083236769Sobrien * 1084236769Sobrien * Input: 1085236769Sobrien * gnp Node to examine 1086236769Sobrien * 1087236769Sobrien * Results: 1088236769Sobrien * 0 if main not found yet, 1 if it is. 1089236769Sobrien * 1090236769Sobrien * Side Effects: 1091236769Sobrien * mainNode is changed and Targ_SetMain is called. 1092236769Sobrien * 1093236769Sobrien *----------------------------------------------------------------------- 1094236769Sobrien */ 1095236769Sobrienstatic int 1096236769SobrienParseFindMain(void *gnp, void *dummy) 1097236769Sobrien{ 1098236769Sobrien GNode *gn = (GNode *)gnp; 1099236769Sobrien if ((gn->type & OP_NOTARGET) == 0) { 1100236769Sobrien mainNode = gn; 1101236769Sobrien Targ_SetMain(gn); 1102236769Sobrien return (dummy ? 1 : 1); 1103236769Sobrien } else { 1104236769Sobrien return (dummy ? 0 : 0); 1105236769Sobrien } 1106236769Sobrien} 1107236769Sobrien 1108236769Sobrien/*- 1109236769Sobrien *----------------------------------------------------------------------- 1110236769Sobrien * ParseAddDir -- 1111236769Sobrien * Front-end for Dir_AddDir to make sure Lst_ForEach keeps going 1112236769Sobrien * 1113236769Sobrien * Results: 1114236769Sobrien * === 0 1115236769Sobrien * 1116236769Sobrien * Side Effects: 1117236769Sobrien * See Dir_AddDir. 1118236769Sobrien * 1119236769Sobrien *----------------------------------------------------------------------- 1120236769Sobrien */ 1121236769Sobrienstatic int 1122236769SobrienParseAddDir(void *path, void *name) 1123236769Sobrien{ 1124236769Sobrien (void)Dir_AddDir((Lst) path, (char *)name); 1125236769Sobrien return(0); 1126236769Sobrien} 1127236769Sobrien 1128236769Sobrien/*- 1129236769Sobrien *----------------------------------------------------------------------- 1130236769Sobrien * ParseClearPath -- 1131236769Sobrien * Front-end for Dir_ClearPath to make sure Lst_ForEach keeps going 1132236769Sobrien * 1133236769Sobrien * Results: 1134236769Sobrien * === 0 1135236769Sobrien * 1136236769Sobrien * Side Effects: 1137236769Sobrien * See Dir_ClearPath 1138236769Sobrien * 1139236769Sobrien *----------------------------------------------------------------------- 1140236769Sobrien */ 1141236769Sobrienstatic int 1142236769SobrienParseClearPath(void *path, void *dummy) 1143236769Sobrien{ 1144236769Sobrien Dir_ClearPath((Lst) path); 1145236769Sobrien return(dummy ? 0 : 0); 1146236769Sobrien} 1147236769Sobrien 1148236769Sobrien/*- 1149236769Sobrien *--------------------------------------------------------------------- 1150236769Sobrien * ParseDoDependency -- 1151236769Sobrien * Parse the dependency line in line. 1152236769Sobrien * 1153236769Sobrien * Input: 1154236769Sobrien * line the line to parse 1155236769Sobrien * 1156236769Sobrien * Results: 1157236769Sobrien * None 1158236769Sobrien * 1159236769Sobrien * Side Effects: 1160236769Sobrien * The nodes of the sources are linked as children to the nodes of the 1161236769Sobrien * targets. Some nodes may be created. 1162236769Sobrien * 1163236769Sobrien * We parse a dependency line by first extracting words from the line and 1164236769Sobrien * finding nodes in the list of all targets with that name. This is done 1165236769Sobrien * until a character is encountered which is an operator character. Currently 1166236769Sobrien * these are only ! and :. At this point the operator is parsed and the 1167236769Sobrien * pointer into the line advanced until the first source is encountered. 1168236769Sobrien * The parsed operator is applied to each node in the 'targets' list, 1169236769Sobrien * which is where the nodes found for the targets are kept, by means of 1170236769Sobrien * the ParseDoOp function. 1171236769Sobrien * The sources are read in much the same way as the targets were except 1172236769Sobrien * that now they are expanded using the wildcarding scheme of the C-Shell 1173236769Sobrien * and all instances of the resulting words in the list of all targets 1174236769Sobrien * are found. Each of the resulting nodes is then linked to each of the 1175236769Sobrien * targets as one of its children. 1176236769Sobrien * Certain targets are handled specially. These are the ones detailed 1177236769Sobrien * by the specType variable. 1178236769Sobrien * The storing of transformation rules is also taken care of here. 1179236769Sobrien * A target is recognized as a transformation rule by calling 1180236769Sobrien * Suff_IsTransform. If it is a transformation rule, its node is gotten 1181236769Sobrien * from the suffix module via Suff_AddTransform rather than the standard 1182236769Sobrien * Targ_FindNode in the target module. 1183236769Sobrien *--------------------------------------------------------------------- 1184236769Sobrien */ 1185236769Sobrienstatic void 1186236769SobrienParseDoDependency(char *line) 1187236769Sobrien{ 1188236769Sobrien char *cp; /* our current position */ 1189236769Sobrien GNode *gn = NULL; /* a general purpose temporary node */ 1190236769Sobrien int op; /* the operator on the line */ 1191236769Sobrien char savec; /* a place to save a character */ 1192236769Sobrien Lst paths; /* List of search paths to alter when parsing 1193236769Sobrien * a list of .PATH targets */ 1194236769Sobrien int tOp; /* operator from special target */ 1195236769Sobrien Lst sources; /* list of archive source names after 1196236769Sobrien * expansion */ 1197236769Sobrien Lst curTargs; /* list of target names to be found and added 1198236769Sobrien * to the targets list */ 1199236769Sobrien char *lstart = line; 1200236769Sobrien 1201236769Sobrien if (DEBUG(PARSE)) 1202236769Sobrien fprintf(debug_file, "ParseDoDependency(%s)\n", line); 1203236769Sobrien tOp = 0; 1204236769Sobrien 1205236769Sobrien specType = Not; 1206236769Sobrien paths = NULL; 1207236769Sobrien 1208236769Sobrien curTargs = Lst_Init(FALSE); 1209236769Sobrien 1210281812Ssjg /* 1211281812Ssjg * First, grind through the targets. 1212281812Ssjg */ 1213281812Ssjg 1214236769Sobrien do { 1215281812Ssjg /* 1216281812Ssjg * Here LINE points to the beginning of the next word, and 1217281812Ssjg * LSTART points to the actual beginning of the line. 1218281812Ssjg */ 1219281812Ssjg 1220281812Ssjg /* Find the end of the next word. */ 1221236769Sobrien for (cp = line; *cp && (ParseIsEscaped(lstart, cp) || 1222236769Sobrien !(isspace((unsigned char)*cp) || 1223236769Sobrien *cp == '!' || *cp == ':' || *cp == LPAREN)); 1224236769Sobrien cp++) { 1225236769Sobrien if (*cp == '$') { 1226236769Sobrien /* 1227236769Sobrien * Must be a dynamic source (would have been expanded 1228236769Sobrien * otherwise), so call the Var module to parse the puppy 1229236769Sobrien * so we can safely advance beyond it...There should be 1230236769Sobrien * no errors in this, as they would have been discovered 1231236769Sobrien * in the initial Var_Subst and we wouldn't be here. 1232236769Sobrien */ 1233236769Sobrien int length; 1234236769Sobrien void *freeIt; 1235236769Sobrien 1236296637Ssjg (void)Var_Parse(cp, VAR_CMD, VARF_UNDEFERR|VARF_WANTRES, 1237296637Ssjg &length, &freeIt); 1238296637Ssjg free(freeIt); 1239236769Sobrien cp += length-1; 1240236769Sobrien } 1241236769Sobrien } 1242236769Sobrien 1243281812Ssjg /* 1244281812Ssjg * If the word is followed by a left parenthesis, it's the 1245281812Ssjg * name of an object file inside an archive (ar file). 1246281812Ssjg */ 1247236769Sobrien if (!ParseIsEscaped(lstart, cp) && *cp == LPAREN) { 1248236769Sobrien /* 1249236769Sobrien * Archives must be handled specially to make sure the OP_ARCHV 1250236769Sobrien * flag is set in their 'type' field, for one thing, and because 1251236769Sobrien * things like "archive(file1.o file2.o file3.o)" are permissible. 1252236769Sobrien * Arch_ParseArchive will set 'line' to be the first non-blank 1253236769Sobrien * after the archive-spec. It creates/finds nodes for the members 1254236769Sobrien * and places them on the given list, returning SUCCESS if all 1255236769Sobrien * went well and FAILURE if there was an error in the 1256236769Sobrien * specification. On error, line should remain untouched. 1257236769Sobrien */ 1258236769Sobrien if (Arch_ParseArchive(&line, targets, VAR_CMD) != SUCCESS) { 1259236769Sobrien Parse_Error(PARSE_FATAL, 1260236769Sobrien "Error in archive specification: \"%s\"", line); 1261236769Sobrien goto out; 1262236769Sobrien } else { 1263281812Ssjg /* Done with this word; on to the next. */ 1264297040Ssjg cp = line; 1265236769Sobrien continue; 1266236769Sobrien } 1267236769Sobrien } 1268236769Sobrien 1269236769Sobrien if (!*cp) { 1270236769Sobrien /* 1271281812Ssjg * We got to the end of the line while we were still 1272281812Ssjg * looking at targets. 1273281812Ssjg * 1274236769Sobrien * Ending a dependency line without an operator is a Bozo 1275236769Sobrien * no-no. As a heuristic, this is also often triggered by 1276236769Sobrien * undetected conflicts from cvs/rcs merges. 1277236769Sobrien */ 1278236769Sobrien if ((strncmp(line, "<<<<<<", 6) == 0) || 1279236769Sobrien (strncmp(line, "======", 6) == 0) || 1280236769Sobrien (strncmp(line, ">>>>>>", 6) == 0)) 1281236769Sobrien Parse_Error(PARSE_FATAL, 1282236769Sobrien "Makefile appears to contain unresolved cvs/rcs/??? merge conflicts"); 1283236769Sobrien else 1284236769Sobrien Parse_Error(PARSE_FATAL, lstart[0] == '.' ? "Unknown directive" 1285236769Sobrien : "Need an operator"); 1286236769Sobrien goto out; 1287236769Sobrien } 1288281812Ssjg 1289281812Ssjg /* Insert a null terminator. */ 1290281812Ssjg savec = *cp; 1291236769Sobrien *cp = '\0'; 1292236769Sobrien 1293236769Sobrien /* 1294281812Ssjg * Got the word. See if it's a special target and if so set 1295236769Sobrien * specType to match it. 1296236769Sobrien */ 1297236769Sobrien if (*line == '.' && isupper ((unsigned char)line[1])) { 1298236769Sobrien /* 1299236769Sobrien * See if the target is a special target that must have it 1300236769Sobrien * or its sources handled specially. 1301236769Sobrien */ 1302236769Sobrien int keywd = ParseFindKeyword(line); 1303236769Sobrien if (keywd != -1) { 1304236769Sobrien if (specType == ExPath && parseKeywords[keywd].spec != ExPath) { 1305236769Sobrien Parse_Error(PARSE_FATAL, "Mismatched special targets"); 1306236769Sobrien goto out; 1307236769Sobrien } 1308236769Sobrien 1309236769Sobrien specType = parseKeywords[keywd].spec; 1310236769Sobrien tOp = parseKeywords[keywd].op; 1311236769Sobrien 1312236769Sobrien /* 1313236769Sobrien * Certain special targets have special semantics: 1314236769Sobrien * .PATH Have to set the dirSearchPath 1315236769Sobrien * variable too 1316236769Sobrien * .MAIN Its sources are only used if 1317236769Sobrien * nothing has been specified to 1318236769Sobrien * create. 1319236769Sobrien * .DEFAULT Need to create a node to hang 1320236769Sobrien * commands on, but we don't want 1321236769Sobrien * it in the graph, nor do we want 1322236769Sobrien * it to be the Main Target, so we 1323236769Sobrien * create it, set OP_NOTMAIN and 1324236769Sobrien * add it to the list, setting 1325236769Sobrien * DEFAULT to the new node for 1326236769Sobrien * later use. We claim the node is 1327236769Sobrien * A transformation rule to make 1328236769Sobrien * life easier later, when we'll 1329236769Sobrien * use Make_HandleUse to actually 1330236769Sobrien * apply the .DEFAULT commands. 1331236769Sobrien * .PHONY The list of targets 1332236769Sobrien * .NOPATH Don't search for file in the path 1333249033Ssjg * .STALE 1334236769Sobrien * .BEGIN 1335236769Sobrien * .END 1336236769Sobrien * .ERROR 1337236769Sobrien * .INTERRUPT Are not to be considered the 1338236769Sobrien * main target. 1339236769Sobrien * .NOTPARALLEL Make only one target at a time. 1340236769Sobrien * .SINGLESHELL Create a shell for each command. 1341236769Sobrien * .ORDER Must set initial predecessor to NULL 1342236769Sobrien */ 1343236769Sobrien switch (specType) { 1344249033Ssjg case ExPath: 1345249033Ssjg if (paths == NULL) { 1346249033Ssjg paths = Lst_Init(FALSE); 1347249033Ssjg } 1348249033Ssjg (void)Lst_AtEnd(paths, dirSearchPath); 1349249033Ssjg break; 1350249033Ssjg case Main: 1351249033Ssjg if (!Lst_IsEmpty(create)) { 1352249033Ssjg specType = Not; 1353249033Ssjg } 1354249033Ssjg break; 1355249033Ssjg case Begin: 1356249033Ssjg case End: 1357249033Ssjg case Stale: 1358249033Ssjg case dotError: 1359249033Ssjg case Interrupt: 1360249033Ssjg gn = Targ_FindNode(line, TARG_CREATE); 1361249033Ssjg if (doing_depend) 1362249033Ssjg ParseMark(gn); 1363249033Ssjg gn->type |= OP_NOTMAIN|OP_SPECIAL; 1364249033Ssjg (void)Lst_AtEnd(targets, gn); 1365249033Ssjg break; 1366249033Ssjg case Default: 1367249033Ssjg gn = Targ_NewGN(".DEFAULT"); 1368249033Ssjg gn->type |= (OP_NOTMAIN|OP_TRANSFORM); 1369249033Ssjg (void)Lst_AtEnd(targets, gn); 1370249033Ssjg DEFAULT = gn; 1371249033Ssjg break; 1372249033Ssjg case NotParallel: 1373249033Ssjg maxJobs = 1; 1374249033Ssjg break; 1375249033Ssjg case SingleShell: 1376249033Ssjg compatMake = TRUE; 1377249033Ssjg break; 1378249033Ssjg case Order: 1379249033Ssjg predecessor = NULL; 1380249033Ssjg break; 1381249033Ssjg default: 1382249033Ssjg break; 1383236769Sobrien } 1384236769Sobrien } else if (strncmp(line, ".PATH", 5) == 0) { 1385236769Sobrien /* 1386236769Sobrien * .PATH<suffix> has to be handled specially. 1387236769Sobrien * Call on the suffix module to give us a path to 1388236769Sobrien * modify. 1389236769Sobrien */ 1390236769Sobrien Lst path; 1391236769Sobrien 1392236769Sobrien specType = ExPath; 1393236769Sobrien path = Suff_GetPath(&line[5]); 1394236769Sobrien if (path == NULL) { 1395236769Sobrien Parse_Error(PARSE_FATAL, 1396236769Sobrien "Suffix '%s' not defined (yet)", 1397236769Sobrien &line[5]); 1398236769Sobrien goto out; 1399236769Sobrien } else { 1400236769Sobrien if (paths == NULL) { 1401236769Sobrien paths = Lst_Init(FALSE); 1402236769Sobrien } 1403236769Sobrien (void)Lst_AtEnd(paths, path); 1404236769Sobrien } 1405236769Sobrien } 1406236769Sobrien } 1407236769Sobrien 1408236769Sobrien /* 1409236769Sobrien * Have word in line. Get or create its node and stick it at 1410236769Sobrien * the end of the targets list 1411236769Sobrien */ 1412236769Sobrien if ((specType == Not) && (*line != '\0')) { 1413236769Sobrien if (Dir_HasWildcards(line)) { 1414236769Sobrien /* 1415236769Sobrien * Targets are to be sought only in the current directory, 1416236769Sobrien * so create an empty path for the thing. Note we need to 1417236769Sobrien * use Dir_Destroy in the destruction of the path as the 1418236769Sobrien * Dir module could have added a directory to the path... 1419236769Sobrien */ 1420236769Sobrien Lst emptyPath = Lst_Init(FALSE); 1421236769Sobrien 1422236769Sobrien Dir_Expand(line, emptyPath, curTargs); 1423236769Sobrien 1424236769Sobrien Lst_Destroy(emptyPath, Dir_Destroy); 1425236769Sobrien } else { 1426236769Sobrien /* 1427236769Sobrien * No wildcards, but we want to avoid code duplication, 1428236769Sobrien * so create a list with the word on it. 1429236769Sobrien */ 1430236769Sobrien (void)Lst_AtEnd(curTargs, line); 1431236769Sobrien } 1432236769Sobrien 1433281812Ssjg /* Apply the targets. */ 1434281812Ssjg 1435236769Sobrien while(!Lst_IsEmpty(curTargs)) { 1436236769Sobrien char *targName = (char *)Lst_DeQueue(curTargs); 1437236769Sobrien 1438236769Sobrien if (!Suff_IsTransform (targName)) { 1439236769Sobrien gn = Targ_FindNode(targName, TARG_CREATE); 1440236769Sobrien } else { 1441236769Sobrien gn = Suff_AddTransform(targName); 1442236769Sobrien } 1443249033Ssjg if (doing_depend) 1444249033Ssjg ParseMark(gn); 1445236769Sobrien 1446236769Sobrien (void)Lst_AtEnd(targets, gn); 1447236769Sobrien } 1448236769Sobrien } else if (specType == ExPath && *line != '.' && *line != '\0') { 1449236769Sobrien Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line); 1450236769Sobrien } 1451236769Sobrien 1452281812Ssjg /* Don't need the inserted null terminator any more. */ 1453236769Sobrien *cp = savec; 1454281812Ssjg 1455236769Sobrien /* 1456236769Sobrien * If it is a special type and not .PATH, it's the only target we 1457236769Sobrien * allow on this line... 1458236769Sobrien */ 1459236769Sobrien if (specType != Not && specType != ExPath) { 1460236769Sobrien Boolean warning = FALSE; 1461236769Sobrien 1462236769Sobrien while (*cp && (ParseIsEscaped(lstart, cp) || 1463236769Sobrien ((*cp != '!') && (*cp != ':')))) { 1464236769Sobrien if (ParseIsEscaped(lstart, cp) || 1465236769Sobrien (*cp != ' ' && *cp != '\t')) { 1466236769Sobrien warning = TRUE; 1467236769Sobrien } 1468236769Sobrien cp++; 1469236769Sobrien } 1470236769Sobrien if (warning) { 1471236769Sobrien Parse_Error(PARSE_WARNING, "Extra target ignored"); 1472236769Sobrien } 1473236769Sobrien } else { 1474236769Sobrien while (*cp && isspace ((unsigned char)*cp)) { 1475236769Sobrien cp++; 1476236769Sobrien } 1477236769Sobrien } 1478236769Sobrien line = cp; 1479236769Sobrien } while (*line && (ParseIsEscaped(lstart, line) || 1480236769Sobrien ((*line != '!') && (*line != ':')))); 1481236769Sobrien 1482236769Sobrien /* 1483236769Sobrien * Don't need the list of target names anymore... 1484236769Sobrien */ 1485236769Sobrien Lst_Destroy(curTargs, NULL); 1486236769Sobrien curTargs = NULL; 1487236769Sobrien 1488236769Sobrien if (!Lst_IsEmpty(targets)) { 1489236769Sobrien switch(specType) { 1490236769Sobrien default: 1491236769Sobrien Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. Mundane ones ignored"); 1492236769Sobrien break; 1493236769Sobrien case Default: 1494249033Ssjg case Stale: 1495236769Sobrien case Begin: 1496236769Sobrien case End: 1497236769Sobrien case dotError: 1498236769Sobrien case Interrupt: 1499236769Sobrien /* 1500236769Sobrien * These four create nodes on which to hang commands, so 1501236769Sobrien * targets shouldn't be empty... 1502236769Sobrien */ 1503236769Sobrien case Not: 1504236769Sobrien /* 1505236769Sobrien * Nothing special here -- targets can be empty if it wants. 1506236769Sobrien */ 1507236769Sobrien break; 1508236769Sobrien } 1509236769Sobrien } 1510236769Sobrien 1511236769Sobrien /* 1512236769Sobrien * Have now parsed all the target names. Must parse the operator next. The 1513236769Sobrien * result is left in op . 1514236769Sobrien */ 1515236769Sobrien if (*cp == '!') { 1516236769Sobrien op = OP_FORCE; 1517236769Sobrien } else if (*cp == ':') { 1518236769Sobrien if (cp[1] == ':') { 1519236769Sobrien op = OP_DOUBLEDEP; 1520236769Sobrien cp++; 1521236769Sobrien } else { 1522236769Sobrien op = OP_DEPENDS; 1523236769Sobrien } 1524236769Sobrien } else { 1525236769Sobrien Parse_Error(PARSE_FATAL, lstart[0] == '.' ? "Unknown directive" 1526236769Sobrien : "Missing dependency operator"); 1527236769Sobrien goto out; 1528236769Sobrien } 1529236769Sobrien 1530281812Ssjg /* Advance beyond the operator */ 1531281812Ssjg cp++; 1532236769Sobrien 1533281812Ssjg /* 1534281812Ssjg * Apply the operator to the target. This is how we remember which 1535281812Ssjg * operator a target was defined with. It fails if the operator 1536281812Ssjg * used isn't consistent across all references. 1537281812Ssjg */ 1538236769Sobrien Lst_ForEach(targets, ParseDoOp, &op); 1539236769Sobrien 1540236769Sobrien /* 1541281812Ssjg * Onward to the sources. 1542281812Ssjg * 1543281812Ssjg * LINE will now point to the first source word, if any, or the 1544281812Ssjg * end of the string if not. 1545236769Sobrien */ 1546236769Sobrien while (*cp && isspace ((unsigned char)*cp)) { 1547236769Sobrien cp++; 1548236769Sobrien } 1549236769Sobrien line = cp; 1550236769Sobrien 1551236769Sobrien /* 1552236769Sobrien * Several special targets take different actions if present with no 1553236769Sobrien * sources: 1554236769Sobrien * a .SUFFIXES line with no sources clears out all old suffixes 1555236769Sobrien * a .PRECIOUS line makes all targets precious 1556236769Sobrien * a .IGNORE line ignores errors for all targets 1557236769Sobrien * a .SILENT line creates silence when making all targets 1558236769Sobrien * a .PATH removes all directories from the search path(s). 1559236769Sobrien */ 1560236769Sobrien if (!*line) { 1561236769Sobrien switch (specType) { 1562236769Sobrien case Suffixes: 1563236769Sobrien Suff_ClearSuffixes(); 1564236769Sobrien break; 1565236769Sobrien case Precious: 1566236769Sobrien allPrecious = TRUE; 1567236769Sobrien break; 1568236769Sobrien case Ignore: 1569236769Sobrien ignoreErrors = TRUE; 1570236769Sobrien break; 1571236769Sobrien case Silent: 1572236769Sobrien beSilent = TRUE; 1573236769Sobrien break; 1574236769Sobrien case ExPath: 1575236769Sobrien Lst_ForEach(paths, ParseClearPath, NULL); 1576236769Sobrien Dir_SetPATH(); 1577236769Sobrien break; 1578236769Sobrien#ifdef POSIX 1579236769Sobrien case Posix: 1580236769Sobrien Var_Set("%POSIX", "1003.2", VAR_GLOBAL, 0); 1581236769Sobrien break; 1582236769Sobrien#endif 1583236769Sobrien default: 1584236769Sobrien break; 1585236769Sobrien } 1586236769Sobrien } else if (specType == MFlags) { 1587236769Sobrien /* 1588236769Sobrien * Call on functions in main.c to deal with these arguments and 1589236769Sobrien * set the initial character to a null-character so the loop to 1590236769Sobrien * get sources won't get anything 1591236769Sobrien */ 1592236769Sobrien Main_ParseArgLine(line); 1593236769Sobrien *line = '\0'; 1594236769Sobrien } else if (specType == ExShell) { 1595236769Sobrien if (Job_ParseShell(line) != SUCCESS) { 1596236769Sobrien Parse_Error(PARSE_FATAL, "improper shell specification"); 1597236769Sobrien goto out; 1598236769Sobrien } 1599236769Sobrien *line = '\0'; 1600236769Sobrien } else if ((specType == NotParallel) || (specType == SingleShell)) { 1601236769Sobrien *line = '\0'; 1602236769Sobrien } 1603236769Sobrien 1604236769Sobrien /* 1605236769Sobrien * NOW GO FOR THE SOURCES 1606236769Sobrien */ 1607236769Sobrien if ((specType == Suffixes) || (specType == ExPath) || 1608236769Sobrien (specType == Includes) || (specType == Libs) || 1609236769Sobrien (specType == Null) || (specType == ExObjdir)) 1610236769Sobrien { 1611236769Sobrien while (*line) { 1612236769Sobrien /* 1613236769Sobrien * If the target was one that doesn't take files as its sources 1614236769Sobrien * but takes something like suffixes, we take each 1615236769Sobrien * space-separated word on the line as a something and deal 1616236769Sobrien * with it accordingly. 1617236769Sobrien * 1618236769Sobrien * If the target was .SUFFIXES, we take each source as a 1619236769Sobrien * suffix and add it to the list of suffixes maintained by the 1620236769Sobrien * Suff module. 1621236769Sobrien * 1622236769Sobrien * If the target was a .PATH, we add the source as a directory 1623236769Sobrien * to search on the search path. 1624236769Sobrien * 1625236769Sobrien * If it was .INCLUDES, the source is taken to be the suffix of 1626236769Sobrien * files which will be #included and whose search path should 1627236769Sobrien * be present in the .INCLUDES variable. 1628236769Sobrien * 1629236769Sobrien * If it was .LIBS, the source is taken to be the suffix of 1630236769Sobrien * files which are considered libraries and whose search path 1631236769Sobrien * should be present in the .LIBS variable. 1632236769Sobrien * 1633236769Sobrien * If it was .NULL, the source is the suffix to use when a file 1634236769Sobrien * has no valid suffix. 1635236769Sobrien * 1636236769Sobrien * If it was .OBJDIR, the source is a new definition for .OBJDIR, 1637236769Sobrien * and will cause make to do a new chdir to that path. 1638236769Sobrien */ 1639236769Sobrien while (*cp && !isspace ((unsigned char)*cp)) { 1640236769Sobrien cp++; 1641236769Sobrien } 1642236769Sobrien savec = *cp; 1643236769Sobrien *cp = '\0'; 1644236769Sobrien switch (specType) { 1645236769Sobrien case Suffixes: 1646236769Sobrien Suff_AddSuffix(line, &mainNode); 1647236769Sobrien break; 1648236769Sobrien case ExPath: 1649236769Sobrien Lst_ForEach(paths, ParseAddDir, line); 1650236769Sobrien break; 1651236769Sobrien case Includes: 1652236769Sobrien Suff_AddInclude(line); 1653236769Sobrien break; 1654236769Sobrien case Libs: 1655236769Sobrien Suff_AddLib(line); 1656236769Sobrien break; 1657236769Sobrien case Null: 1658236769Sobrien Suff_SetNull(line); 1659236769Sobrien break; 1660236769Sobrien case ExObjdir: 1661236769Sobrien Main_SetObjdir(line); 1662236769Sobrien break; 1663236769Sobrien default: 1664236769Sobrien break; 1665236769Sobrien } 1666236769Sobrien *cp = savec; 1667236769Sobrien if (savec != '\0') { 1668236769Sobrien cp++; 1669236769Sobrien } 1670236769Sobrien while (*cp && isspace ((unsigned char)*cp)) { 1671236769Sobrien cp++; 1672236769Sobrien } 1673236769Sobrien line = cp; 1674236769Sobrien } 1675236769Sobrien if (paths) { 1676236769Sobrien Lst_Destroy(paths, NULL); 1677236769Sobrien } 1678236769Sobrien if (specType == ExPath) 1679236769Sobrien Dir_SetPATH(); 1680236769Sobrien } else { 1681236769Sobrien while (*line) { 1682236769Sobrien /* 1683236769Sobrien * The targets take real sources, so we must beware of archive 1684236769Sobrien * specifications (i.e. things with left parentheses in them) 1685236769Sobrien * and handle them accordingly. 1686236769Sobrien */ 1687236769Sobrien for (; *cp && !isspace ((unsigned char)*cp); cp++) { 1688236769Sobrien if ((*cp == LPAREN) && (cp > line) && (cp[-1] != '$')) { 1689236769Sobrien /* 1690236769Sobrien * Only stop for a left parenthesis if it isn't at the 1691236769Sobrien * start of a word (that'll be for variable changes 1692236769Sobrien * later) and isn't preceded by a dollar sign (a dynamic 1693236769Sobrien * source). 1694236769Sobrien */ 1695236769Sobrien break; 1696236769Sobrien } 1697236769Sobrien } 1698236769Sobrien 1699236769Sobrien if (*cp == LPAREN) { 1700236769Sobrien sources = Lst_Init(FALSE); 1701236769Sobrien if (Arch_ParseArchive(&line, sources, VAR_CMD) != SUCCESS) { 1702236769Sobrien Parse_Error(PARSE_FATAL, 1703236769Sobrien "Error in source archive spec \"%s\"", line); 1704236769Sobrien goto out; 1705236769Sobrien } 1706236769Sobrien 1707236769Sobrien while (!Lst_IsEmpty (sources)) { 1708236769Sobrien gn = (GNode *)Lst_DeQueue(sources); 1709236769Sobrien ParseDoSrc(tOp, gn->name); 1710236769Sobrien } 1711236769Sobrien Lst_Destroy(sources, NULL); 1712236769Sobrien cp = line; 1713236769Sobrien } else { 1714236769Sobrien if (*cp) { 1715236769Sobrien *cp = '\0'; 1716236769Sobrien cp += 1; 1717236769Sobrien } 1718236769Sobrien 1719236769Sobrien ParseDoSrc(tOp, line); 1720236769Sobrien } 1721236769Sobrien while (*cp && isspace ((unsigned char)*cp)) { 1722236769Sobrien cp++; 1723236769Sobrien } 1724236769Sobrien line = cp; 1725236769Sobrien } 1726236769Sobrien } 1727236769Sobrien 1728236769Sobrien if (mainNode == NULL) { 1729236769Sobrien /* 1730236769Sobrien * If we have yet to decide on a main target to make, in the 1731236769Sobrien * absence of any user input, we want the first target on 1732236769Sobrien * the first dependency line that is actually a real target 1733236769Sobrien * (i.e. isn't a .USE or .EXEC rule) to be made. 1734236769Sobrien */ 1735236769Sobrien Lst_ForEach(targets, ParseFindMain, NULL); 1736236769Sobrien } 1737236769Sobrien 1738236769Sobrienout: 1739236769Sobrien if (curTargs) 1740236769Sobrien Lst_Destroy(curTargs, NULL); 1741236769Sobrien} 1742236769Sobrien 1743236769Sobrien/*- 1744236769Sobrien *--------------------------------------------------------------------- 1745236769Sobrien * Parse_IsVar -- 1746236769Sobrien * Return TRUE if the passed line is a variable assignment. A variable 1747236769Sobrien * assignment consists of a single word followed by optional whitespace 1748236769Sobrien * followed by either a += or an = operator. 1749236769Sobrien * This function is used both by the Parse_File function and main when 1750236769Sobrien * parsing the command-line arguments. 1751236769Sobrien * 1752236769Sobrien * Input: 1753236769Sobrien * line the line to check 1754236769Sobrien * 1755236769Sobrien * Results: 1756236769Sobrien * TRUE if it is. FALSE if it ain't 1757236769Sobrien * 1758236769Sobrien * Side Effects: 1759236769Sobrien * none 1760236769Sobrien *--------------------------------------------------------------------- 1761236769Sobrien */ 1762236769SobrienBoolean 1763236769SobrienParse_IsVar(char *line) 1764236769Sobrien{ 1765236769Sobrien Boolean wasSpace = FALSE; /* set TRUE if found a space */ 1766236769Sobrien char ch; 1767236769Sobrien int level = 0; 1768236769Sobrien#define ISEQOPERATOR(c) \ 1769236769Sobrien (((c) == '+') || ((c) == ':') || ((c) == '?') || ((c) == '!')) 1770236769Sobrien 1771236769Sobrien /* 1772236769Sobrien * Skip to variable name 1773236769Sobrien */ 1774236769Sobrien for (;(*line == ' ') || (*line == '\t'); line++) 1775236769Sobrien continue; 1776236769Sobrien 1777236769Sobrien /* Scan for one of the assignment operators outside a variable expansion */ 1778236769Sobrien while ((ch = *line++) != 0) { 1779236769Sobrien if (ch == '(' || ch == '{') { 1780236769Sobrien level++; 1781236769Sobrien continue; 1782236769Sobrien } 1783236769Sobrien if (ch == ')' || ch == '}') { 1784236769Sobrien level--; 1785236769Sobrien continue; 1786236769Sobrien } 1787236769Sobrien if (level != 0) 1788236769Sobrien continue; 1789236769Sobrien while (ch == ' ' || ch == '\t') { 1790236769Sobrien ch = *line++; 1791236769Sobrien wasSpace = TRUE; 1792236769Sobrien } 1793255253Ssjg#ifdef SUNSHCMD 1794255253Ssjg if (ch == ':' && strncmp(line, "sh", 2) == 0) { 1795255253Ssjg line += 2; 1796255253Ssjg continue; 1797255253Ssjg } 1798255253Ssjg#endif 1799236769Sobrien if (ch == '=') 1800236769Sobrien return TRUE; 1801236769Sobrien if (*line == '=' && ISEQOPERATOR(ch)) 1802236769Sobrien return TRUE; 1803236769Sobrien if (wasSpace) 1804236769Sobrien return FALSE; 1805236769Sobrien } 1806236769Sobrien 1807236769Sobrien return FALSE; 1808236769Sobrien} 1809236769Sobrien 1810236769Sobrien/*- 1811236769Sobrien *--------------------------------------------------------------------- 1812236769Sobrien * Parse_DoVar -- 1813236769Sobrien * Take the variable assignment in the passed line and do it in the 1814236769Sobrien * global context. 1815236769Sobrien * 1816236769Sobrien * Note: There is a lexical ambiguity with assignment modifier characters 1817236769Sobrien * in variable names. This routine interprets the character before the = 1818236769Sobrien * as a modifier. Therefore, an assignment like 1819236769Sobrien * C++=/usr/bin/CC 1820236769Sobrien * is interpreted as "C+ +=" instead of "C++ =". 1821236769Sobrien * 1822236769Sobrien * Input: 1823236769Sobrien * line a line guaranteed to be a variable assignment. 1824236769Sobrien * This reduces error checks 1825236769Sobrien * ctxt Context in which to do the assignment 1826236769Sobrien * 1827236769Sobrien * Results: 1828236769Sobrien * none 1829236769Sobrien * 1830236769Sobrien * Side Effects: 1831236769Sobrien * the variable structure of the given variable name is altered in the 1832236769Sobrien * global context. 1833236769Sobrien *--------------------------------------------------------------------- 1834236769Sobrien */ 1835236769Sobrienvoid 1836236769SobrienParse_DoVar(char *line, GNode *ctxt) 1837236769Sobrien{ 1838236769Sobrien char *cp; /* pointer into line */ 1839236769Sobrien enum { 1840236769Sobrien VAR_SUBST, VAR_APPEND, VAR_SHELL, VAR_NORMAL 1841236769Sobrien } type; /* Type of assignment */ 1842236769Sobrien char *opc; /* ptr to operator character to 1843236769Sobrien * null-terminate the variable name */ 1844236769Sobrien Boolean freeCp = FALSE; /* TRUE if cp needs to be freed, 1845236769Sobrien * i.e. if any variable expansion was 1846236769Sobrien * performed */ 1847236769Sobrien int depth; 1848236769Sobrien 1849236769Sobrien /* 1850236769Sobrien * Skip to variable name 1851236769Sobrien */ 1852236769Sobrien while ((*line == ' ') || (*line == '\t')) { 1853236769Sobrien line++; 1854236769Sobrien } 1855236769Sobrien 1856236769Sobrien /* 1857236769Sobrien * Skip to operator character, nulling out whitespace as we go 1858236769Sobrien * XXX Rather than counting () and {} we should look for $ and 1859236769Sobrien * then expand the variable. 1860236769Sobrien */ 1861236769Sobrien for (depth = 0, cp = line + 1; depth != 0 || *cp != '='; cp++) { 1862236769Sobrien if (*cp == '(' || *cp == '{') { 1863236769Sobrien depth++; 1864236769Sobrien continue; 1865236769Sobrien } 1866236769Sobrien if (*cp == ')' || *cp == '}') { 1867236769Sobrien depth--; 1868236769Sobrien continue; 1869236769Sobrien } 1870236769Sobrien if (depth == 0 && isspace ((unsigned char)*cp)) { 1871236769Sobrien *cp = '\0'; 1872236769Sobrien } 1873236769Sobrien } 1874236769Sobrien opc = cp-1; /* operator is the previous character */ 1875236769Sobrien *cp++ = '\0'; /* nuke the = */ 1876236769Sobrien 1877236769Sobrien /* 1878236769Sobrien * Check operator type 1879236769Sobrien */ 1880236769Sobrien switch (*opc) { 1881236769Sobrien case '+': 1882236769Sobrien type = VAR_APPEND; 1883236769Sobrien *opc = '\0'; 1884236769Sobrien break; 1885236769Sobrien 1886236769Sobrien case '?': 1887236769Sobrien /* 1888236769Sobrien * If the variable already has a value, we don't do anything. 1889236769Sobrien */ 1890236769Sobrien *opc = '\0'; 1891236769Sobrien if (Var_Exists(line, ctxt)) { 1892236769Sobrien return; 1893236769Sobrien } else { 1894236769Sobrien type = VAR_NORMAL; 1895236769Sobrien } 1896236769Sobrien break; 1897236769Sobrien 1898236769Sobrien case ':': 1899236769Sobrien type = VAR_SUBST; 1900236769Sobrien *opc = '\0'; 1901236769Sobrien break; 1902236769Sobrien 1903236769Sobrien case '!': 1904236769Sobrien type = VAR_SHELL; 1905236769Sobrien *opc = '\0'; 1906236769Sobrien break; 1907236769Sobrien 1908236769Sobrien default: 1909236769Sobrien#ifdef SUNSHCMD 1910236769Sobrien while (opc > line && *opc != ':') 1911236769Sobrien opc--; 1912236769Sobrien 1913236769Sobrien if (strncmp(opc, ":sh", 3) == 0) { 1914236769Sobrien type = VAR_SHELL; 1915236769Sobrien *opc = '\0'; 1916236769Sobrien break; 1917236769Sobrien } 1918236769Sobrien#endif 1919236769Sobrien type = VAR_NORMAL; 1920236769Sobrien break; 1921236769Sobrien } 1922236769Sobrien 1923236769Sobrien while (isspace ((unsigned char)*cp)) { 1924236769Sobrien cp++; 1925236769Sobrien } 1926236769Sobrien 1927236769Sobrien if (type == VAR_APPEND) { 1928236769Sobrien Var_Append(line, cp, ctxt); 1929236769Sobrien } else if (type == VAR_SUBST) { 1930236769Sobrien /* 1931236769Sobrien * Allow variables in the old value to be undefined, but leave their 1932236769Sobrien * invocation alone -- this is done by forcing oldVars to be false. 1933236769Sobrien * XXX: This can cause recursive variables, but that's not hard to do, 1934236769Sobrien * and this allows someone to do something like 1935236769Sobrien * 1936236769Sobrien * CFLAGS = $(.INCLUDES) 1937236769Sobrien * CFLAGS := -I.. $(CFLAGS) 1938236769Sobrien * 1939236769Sobrien * And not get an error. 1940236769Sobrien */ 1941236769Sobrien Boolean oldOldVars = oldVars; 1942236769Sobrien 1943236769Sobrien oldVars = FALSE; 1944236769Sobrien 1945236769Sobrien /* 1946236769Sobrien * make sure that we set the variable the first time to nothing 1947236769Sobrien * so that it gets substituted! 1948236769Sobrien */ 1949236769Sobrien if (!Var_Exists(line, ctxt)) 1950236769Sobrien Var_Set(line, "", ctxt, 0); 1951236769Sobrien 1952296637Ssjg cp = Var_Subst(NULL, cp, ctxt, VARF_WANTRES|VARF_ASSIGN); 1953236769Sobrien oldVars = oldOldVars; 1954236769Sobrien freeCp = TRUE; 1955236769Sobrien 1956236769Sobrien Var_Set(line, cp, ctxt, 0); 1957236769Sobrien } else if (type == VAR_SHELL) { 1958236769Sobrien char *res; 1959236769Sobrien const char *error; 1960236769Sobrien 1961236769Sobrien if (strchr(cp, '$') != NULL) { 1962236769Sobrien /* 1963236769Sobrien * There's a dollar sign in the command, so perform variable 1964236769Sobrien * expansion on the whole thing. The resulting string will need 1965236769Sobrien * freeing when we're done, so set freeCmd to TRUE. 1966236769Sobrien */ 1967296637Ssjg cp = Var_Subst(NULL, cp, VAR_CMD, VARF_UNDEFERR|VARF_WANTRES); 1968236769Sobrien freeCp = TRUE; 1969236769Sobrien } 1970236769Sobrien 1971236769Sobrien res = Cmd_Exec(cp, &error); 1972236769Sobrien Var_Set(line, res, ctxt, 0); 1973236769Sobrien free(res); 1974236769Sobrien 1975236769Sobrien if (error) 1976236769Sobrien Parse_Error(PARSE_WARNING, error, cp); 1977236769Sobrien } else { 1978236769Sobrien /* 1979236769Sobrien * Normal assignment -- just do it. 1980236769Sobrien */ 1981236769Sobrien Var_Set(line, cp, ctxt, 0); 1982236769Sobrien } 1983236769Sobrien if (strcmp(line, MAKEOVERRIDES) == 0) 1984236769Sobrien Main_ExportMAKEFLAGS(FALSE); /* re-export MAKEFLAGS */ 1985236769Sobrien else if (strcmp(line, ".CURDIR") == 0) { 1986236769Sobrien /* 1987236769Sobrien * Somone is being (too?) clever... 1988236769Sobrien * Let's pretend they know what they are doing and 1989236769Sobrien * re-initialize the 'cur' Path. 1990236769Sobrien */ 1991236769Sobrien Dir_InitCur(cp); 1992236769Sobrien Dir_SetPATH(); 1993236769Sobrien } else if (strcmp(line, MAKE_JOB_PREFIX) == 0) { 1994236769Sobrien Job_SetPrefix(); 1995236769Sobrien } else if (strcmp(line, MAKE_EXPORTED) == 0) { 1996236769Sobrien Var_Export(cp, 0); 1997236769Sobrien } 1998236769Sobrien if (freeCp) 1999236769Sobrien free(cp); 2000236769Sobrien} 2001236769Sobrien 2002236769Sobrien 2003281812Ssjg/* 2004281812Ssjg * ParseMaybeSubMake -- 2005281812Ssjg * Scan the command string to see if it a possible submake node 2006281812Ssjg * Input: 2007281812Ssjg * cmd the command to scan 2008281812Ssjg * Results: 2009281812Ssjg * TRUE if the command is possibly a submake, FALSE if not. 2010281812Ssjg */ 2011281812Ssjgstatic Boolean 2012281812SsjgParseMaybeSubMake(const char *cmd) 2013281812Ssjg{ 2014281812Ssjg size_t i; 2015281812Ssjg static struct { 2016281812Ssjg const char *name; 2017281812Ssjg size_t len; 2018281812Ssjg } vals[] = { 2019281812Ssjg#define MKV(A) { A, sizeof(A) - 1 } 2020281812Ssjg MKV("${MAKE}"), 2021281812Ssjg MKV("${.MAKE}"), 2022281812Ssjg MKV("$(MAKE)"), 2023281812Ssjg MKV("$(.MAKE)"), 2024281812Ssjg MKV("make"), 2025281812Ssjg }; 2026281812Ssjg for (i = 0; i < sizeof(vals)/sizeof(vals[0]); i++) { 2027281812Ssjg char *ptr; 2028281812Ssjg if ((ptr = strstr(cmd, vals[i].name)) == NULL) 2029281812Ssjg continue; 2030281812Ssjg if ((ptr == cmd || !isalnum((unsigned char)ptr[-1])) 2031281812Ssjg && !isalnum((unsigned char)ptr[vals[i].len])) 2032281812Ssjg return TRUE; 2033281812Ssjg } 2034281812Ssjg return FALSE; 2035281812Ssjg} 2036281812Ssjg 2037236769Sobrien/*- 2038236769Sobrien * ParseAddCmd -- 2039236769Sobrien * Lst_ForEach function to add a command line to all targets 2040236769Sobrien * 2041236769Sobrien * Input: 2042236769Sobrien * gnp the node to which the command is to be added 2043236769Sobrien * cmd the command to add 2044236769Sobrien * 2045236769Sobrien * Results: 2046236769Sobrien * Always 0 2047236769Sobrien * 2048236769Sobrien * Side Effects: 2049281812Ssjg * A new element is added to the commands list of the node, 2050281812Ssjg * and the node can be marked as a submake node if the command is 2051281812Ssjg * determined to be that. 2052236769Sobrien */ 2053236769Sobrienstatic int 2054236769SobrienParseAddCmd(void *gnp, void *cmd) 2055236769Sobrien{ 2056236769Sobrien GNode *gn = (GNode *)gnp; 2057236769Sobrien 2058236769Sobrien /* Add to last (ie current) cohort for :: targets */ 2059236769Sobrien if ((gn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (gn->cohorts)) 2060236769Sobrien gn = (GNode *)Lst_Datum(Lst_Last(gn->cohorts)); 2061236769Sobrien 2062236769Sobrien /* if target already supplied, ignore commands */ 2063236769Sobrien if (!(gn->type & OP_HAS_COMMANDS)) { 2064236769Sobrien (void)Lst_AtEnd(gn->commands, cmd); 2065281812Ssjg if (ParseMaybeSubMake(cmd)) 2066281812Ssjg gn->type |= OP_SUBMAKE; 2067236769Sobrien ParseMark(gn); 2068236769Sobrien } else { 2069236769Sobrien#ifdef notyet 2070236769Sobrien /* XXX: We cannot do this until we fix the tree */ 2071236769Sobrien (void)Lst_AtEnd(gn->commands, cmd); 2072236769Sobrien Parse_Error(PARSE_WARNING, 2073236769Sobrien "overriding commands for target \"%s\"; " 2074236769Sobrien "previous commands defined at %s: %d ignored", 2075236769Sobrien gn->name, gn->fname, gn->lineno); 2076236769Sobrien#else 2077236769Sobrien Parse_Error(PARSE_WARNING, 2078236769Sobrien "duplicate script for target \"%s\" ignored", 2079236769Sobrien gn->name); 2080236769Sobrien ParseErrorInternal(gn->fname, gn->lineno, PARSE_WARNING, 2081236769Sobrien "using previous script for \"%s\" defined here", 2082236769Sobrien gn->name); 2083236769Sobrien#endif 2084236769Sobrien } 2085236769Sobrien return(0); 2086236769Sobrien} 2087236769Sobrien 2088236769Sobrien/*- 2089236769Sobrien *----------------------------------------------------------------------- 2090236769Sobrien * ParseHasCommands -- 2091236769Sobrien * Callback procedure for Parse_File when destroying the list of 2092236769Sobrien * targets on the last dependency line. Marks a target as already 2093236769Sobrien * having commands if it does, to keep from having shell commands 2094236769Sobrien * on multiple dependency lines. 2095236769Sobrien * 2096236769Sobrien * Input: 2097236769Sobrien * gnp Node to examine 2098236769Sobrien * 2099236769Sobrien * Results: 2100236769Sobrien * None 2101236769Sobrien * 2102236769Sobrien * Side Effects: 2103236769Sobrien * OP_HAS_COMMANDS may be set for the target. 2104236769Sobrien * 2105236769Sobrien *----------------------------------------------------------------------- 2106236769Sobrien */ 2107236769Sobrienstatic void 2108236769SobrienParseHasCommands(void *gnp) 2109236769Sobrien{ 2110236769Sobrien GNode *gn = (GNode *)gnp; 2111236769Sobrien if (!Lst_IsEmpty(gn->commands)) { 2112236769Sobrien gn->type |= OP_HAS_COMMANDS; 2113236769Sobrien } 2114236769Sobrien} 2115236769Sobrien 2116236769Sobrien/*- 2117236769Sobrien *----------------------------------------------------------------------- 2118236769Sobrien * Parse_AddIncludeDir -- 2119236769Sobrien * Add a directory to the path searched for included makefiles 2120236769Sobrien * bracketed by double-quotes. Used by functions in main.c 2121236769Sobrien * 2122236769Sobrien * Input: 2123236769Sobrien * dir The name of the directory to add 2124236769Sobrien * 2125236769Sobrien * Results: 2126236769Sobrien * None. 2127236769Sobrien * 2128236769Sobrien * Side Effects: 2129236769Sobrien * The directory is appended to the list. 2130236769Sobrien * 2131236769Sobrien *----------------------------------------------------------------------- 2132236769Sobrien */ 2133236769Sobrienvoid 2134236769SobrienParse_AddIncludeDir(char *dir) 2135236769Sobrien{ 2136236769Sobrien (void)Dir_AddDir(parseIncPath, dir); 2137236769Sobrien} 2138236769Sobrien 2139236769Sobrien/*- 2140236769Sobrien *--------------------------------------------------------------------- 2141236769Sobrien * ParseDoInclude -- 2142236769Sobrien * Push to another file. 2143236769Sobrien * 2144236769Sobrien * The input is the line minus the `.'. A file spec is a string 2145236769Sobrien * enclosed in <> or "". The former is looked for only in sysIncPath. 2146236769Sobrien * The latter in . and the directories specified by -I command line 2147236769Sobrien * options 2148236769Sobrien * 2149236769Sobrien * Results: 2150236769Sobrien * None 2151236769Sobrien * 2152236769Sobrien * Side Effects: 2153236769Sobrien * A structure is added to the includes Lst and readProc, lineno, 2154236769Sobrien * fname and curFILE are altered for the new file 2155236769Sobrien *--------------------------------------------------------------------- 2156236769Sobrien */ 2157236769Sobrien 2158236769Sobrienstatic void 2159296637SsjgParse_include_file(char *file, Boolean isSystem, Boolean depinc, int silent) 2160236769Sobrien{ 2161236769Sobrien struct loadedfile *lf; 2162236769Sobrien char *fullname; /* full pathname of file */ 2163236769Sobrien char *newName; 2164236769Sobrien char *prefEnd, *incdir; 2165236769Sobrien int fd; 2166236769Sobrien int i; 2167236769Sobrien 2168236769Sobrien /* 2169236769Sobrien * Now we know the file's name and its search path, we attempt to 2170236769Sobrien * find the durn thing. A return of NULL indicates the file don't 2171236769Sobrien * exist. 2172236769Sobrien */ 2173236769Sobrien fullname = file[0] == '/' ? bmake_strdup(file) : NULL; 2174236769Sobrien 2175236769Sobrien if (fullname == NULL && !isSystem) { 2176236769Sobrien /* 2177236769Sobrien * Include files contained in double-quotes are first searched for 2178236769Sobrien * relative to the including file's location. We don't want to 2179236769Sobrien * cd there, of course, so we just tack on the old file's 2180236769Sobrien * leading path components and call Dir_FindFile to see if 2181236769Sobrien * we can locate the beast. 2182236769Sobrien */ 2183236769Sobrien 2184236769Sobrien incdir = bmake_strdup(curFile->fname); 2185236769Sobrien prefEnd = strrchr(incdir, '/'); 2186236769Sobrien if (prefEnd != NULL) { 2187236769Sobrien *prefEnd = '\0'; 2188236769Sobrien /* Now do lexical processing of leading "../" on the filename */ 2189236769Sobrien for (i = 0; strncmp(file + i, "../", 3) == 0; i += 3) { 2190236769Sobrien prefEnd = strrchr(incdir + 1, '/'); 2191236769Sobrien if (prefEnd == NULL || strcmp(prefEnd, "/..") == 0) 2192236769Sobrien break; 2193236769Sobrien *prefEnd = '\0'; 2194236769Sobrien } 2195236769Sobrien newName = str_concat(incdir, file + i, STR_ADDSLASH); 2196236769Sobrien fullname = Dir_FindFile(newName, parseIncPath); 2197236769Sobrien if (fullname == NULL) 2198236769Sobrien fullname = Dir_FindFile(newName, dirSearchPath); 2199236769Sobrien free(newName); 2200236769Sobrien } 2201236769Sobrien free(incdir); 2202236769Sobrien 2203236769Sobrien if (fullname == NULL) { 2204236769Sobrien /* 2205236769Sobrien * Makefile wasn't found in same directory as included makefile. 2206236769Sobrien * Search for it first on the -I search path, 2207236769Sobrien * then on the .PATH search path, if not found in a -I directory. 2208236769Sobrien * If we have a suffix specific path we should use that. 2209236769Sobrien */ 2210236769Sobrien char *suff; 2211236769Sobrien Lst suffPath = NULL; 2212236769Sobrien 2213236769Sobrien if ((suff = strrchr(file, '.'))) { 2214236769Sobrien suffPath = Suff_GetPath(suff); 2215236769Sobrien if (suffPath != NULL) { 2216236769Sobrien fullname = Dir_FindFile(file, suffPath); 2217236769Sobrien } 2218236769Sobrien } 2219236769Sobrien if (fullname == NULL) { 2220236769Sobrien fullname = Dir_FindFile(file, parseIncPath); 2221236769Sobrien if (fullname == NULL) { 2222236769Sobrien fullname = Dir_FindFile(file, dirSearchPath); 2223236769Sobrien } 2224236769Sobrien } 2225236769Sobrien } 2226236769Sobrien } 2227236769Sobrien 2228236769Sobrien /* Looking for a system file or file still not found */ 2229236769Sobrien if (fullname == NULL) { 2230236769Sobrien /* 2231236769Sobrien * Look for it on the system path 2232236769Sobrien */ 2233236769Sobrien fullname = Dir_FindFile(file, 2234236769Sobrien Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath); 2235236769Sobrien } 2236236769Sobrien 2237236769Sobrien if (fullname == NULL) { 2238236769Sobrien if (!silent) 2239236769Sobrien Parse_Error(PARSE_FATAL, "Could not find %s", file); 2240236769Sobrien return; 2241236769Sobrien } 2242236769Sobrien 2243236769Sobrien /* Actually open the file... */ 2244236769Sobrien fd = open(fullname, O_RDONLY); 2245236769Sobrien if (fd == -1) { 2246236769Sobrien if (!silent) 2247236769Sobrien Parse_Error(PARSE_FATAL, "Cannot open %s", fullname); 2248236769Sobrien free(fullname); 2249236769Sobrien return; 2250236769Sobrien } 2251236769Sobrien 2252236769Sobrien /* load it */ 2253236769Sobrien lf = loadfile(fullname, fd); 2254236769Sobrien 2255268437Ssjg ParseSetIncludedFile(); 2256236769Sobrien /* Start reading from this file next */ 2257236769Sobrien Parse_SetInput(fullname, 0, -1, loadedfile_nextbuf, lf); 2258236769Sobrien curFile->lf = lf; 2259296637Ssjg if (depinc) 2260296637Ssjg doing_depend = depinc; /* only turn it on */ 2261236769Sobrien} 2262236769Sobrien 2263236769Sobrienstatic void 2264236769SobrienParseDoInclude(char *line) 2265236769Sobrien{ 2266236769Sobrien char endc; /* the character which ends the file spec */ 2267236769Sobrien char *cp; /* current position in file spec */ 2268236769Sobrien int silent = (*line != 'i') ? 1 : 0; 2269236769Sobrien char *file = &line[7 + silent]; 2270236769Sobrien 2271236769Sobrien /* Skip to delimiter character so we know where to look */ 2272236769Sobrien while (*file == ' ' || *file == '\t') 2273236769Sobrien file++; 2274236769Sobrien 2275236769Sobrien if (*file != '"' && *file != '<') { 2276236769Sobrien Parse_Error(PARSE_FATAL, 2277236769Sobrien ".include filename must be delimited by '\"' or '<'"); 2278236769Sobrien return; 2279236769Sobrien } 2280236769Sobrien 2281236769Sobrien /* 2282236769Sobrien * Set the search path on which to find the include file based on the 2283236769Sobrien * characters which bracket its name. Angle-brackets imply it's 2284236769Sobrien * a system Makefile while double-quotes imply it's a user makefile 2285236769Sobrien */ 2286236769Sobrien if (*file == '<') { 2287236769Sobrien endc = '>'; 2288236769Sobrien } else { 2289236769Sobrien endc = '"'; 2290236769Sobrien } 2291236769Sobrien 2292236769Sobrien /* Skip to matching delimiter */ 2293236769Sobrien for (cp = ++file; *cp && *cp != endc; cp++) 2294236769Sobrien continue; 2295236769Sobrien 2296236769Sobrien if (*cp != endc) { 2297236769Sobrien Parse_Error(PARSE_FATAL, 2298236769Sobrien "Unclosed %cinclude filename. '%c' expected", 2299236769Sobrien '.', endc); 2300236769Sobrien return; 2301236769Sobrien } 2302236769Sobrien *cp = '\0'; 2303236769Sobrien 2304236769Sobrien /* 2305236769Sobrien * Substitute for any variables in the file name before trying to 2306236769Sobrien * find the thing. 2307236769Sobrien */ 2308296637Ssjg file = Var_Subst(NULL, file, VAR_CMD, VARF_WANTRES); 2309236769Sobrien 2310296637Ssjg Parse_include_file(file, endc == '>', (*line == 'd'), silent); 2311236769Sobrien free(file); 2312236769Sobrien} 2313236769Sobrien 2314236769Sobrien 2315236769Sobrien/*- 2316236769Sobrien *--------------------------------------------------------------------- 2317268437Ssjg * ParseSetIncludedFile -- 2318268437Ssjg * Set the .INCLUDEDFROMFILE variable to the contents of .PARSEFILE 2319268437Ssjg * and the .INCLUDEDFROMDIR variable to the contents of .PARSEDIR 2320268437Ssjg * 2321268437Ssjg * Results: 2322268437Ssjg * None 2323268437Ssjg * 2324268437Ssjg * Side Effects: 2325268437Ssjg * The .INCLUDEDFROMFILE variable is overwritten by the contents 2326268437Ssjg * of .PARSEFILE and the .INCLUDEDFROMDIR variable is overwriten 2327268437Ssjg * by the contents of .PARSEDIR 2328268437Ssjg *--------------------------------------------------------------------- 2329268437Ssjg */ 2330268437Ssjgstatic void 2331268437SsjgParseSetIncludedFile(void) 2332268437Ssjg{ 2333268437Ssjg char *pf, *fp = NULL; 2334268437Ssjg char *pd, *dp = NULL; 2335268437Ssjg 2336268437Ssjg pf = Var_Value(".PARSEFILE", VAR_GLOBAL, &fp); 2337268437Ssjg Var_Set(".INCLUDEDFROMFILE", pf, VAR_GLOBAL, 0); 2338268437Ssjg pd = Var_Value(".PARSEDIR", VAR_GLOBAL, &dp); 2339268437Ssjg Var_Set(".INCLUDEDFROMDIR", pd, VAR_GLOBAL, 0); 2340268437Ssjg 2341268437Ssjg if (DEBUG(PARSE)) 2342268437Ssjg fprintf(debug_file, "%s: ${.INCLUDEDFROMDIR} = `%s' " 2343268437Ssjg "${.INCLUDEDFROMFILE} = `%s'\n", __func__, pd, pf); 2344268437Ssjg 2345296637Ssjg free(fp); 2346296637Ssjg free(dp); 2347268437Ssjg} 2348268437Ssjg/*- 2349268437Ssjg *--------------------------------------------------------------------- 2350236769Sobrien * ParseSetParseFile -- 2351236769Sobrien * Set the .PARSEDIR and .PARSEFILE variables to the dirname and 2352236769Sobrien * basename of the given filename 2353236769Sobrien * 2354236769Sobrien * Results: 2355236769Sobrien * None 2356236769Sobrien * 2357236769Sobrien * Side Effects: 2358236769Sobrien * The .PARSEDIR and .PARSEFILE variables are overwritten by the 2359236769Sobrien * dirname and basename of the given filename. 2360236769Sobrien *--------------------------------------------------------------------- 2361236769Sobrien */ 2362236769Sobrienstatic void 2363236769SobrienParseSetParseFile(const char *filename) 2364236769Sobrien{ 2365236769Sobrien char *slash, *dirname; 2366236769Sobrien const char *pd, *pf; 2367236769Sobrien int len; 2368236769Sobrien 2369236769Sobrien slash = strrchr(filename, '/'); 2370236769Sobrien if (slash == NULL) { 2371236769Sobrien Var_Set(".PARSEDIR", pd = curdir, VAR_GLOBAL, 0); 2372236769Sobrien Var_Set(".PARSEFILE", pf = filename, VAR_GLOBAL, 0); 2373236769Sobrien dirname= NULL; 2374236769Sobrien } else { 2375236769Sobrien len = slash - filename; 2376236769Sobrien dirname = bmake_malloc(len + 1); 2377236769Sobrien memcpy(dirname, filename, len); 2378236769Sobrien dirname[len] = '\0'; 2379236769Sobrien Var_Set(".PARSEDIR", pd = dirname, VAR_GLOBAL, 0); 2380236769Sobrien Var_Set(".PARSEFILE", pf = slash + 1, VAR_GLOBAL, 0); 2381236769Sobrien } 2382236769Sobrien if (DEBUG(PARSE)) 2383268437Ssjg fprintf(debug_file, "%s: ${.PARSEDIR} = `%s' ${.PARSEFILE} = `%s'\n", 2384268437Ssjg __func__, pd, pf); 2385236769Sobrien free(dirname); 2386236769Sobrien} 2387236769Sobrien 2388236769Sobrien/* 2389236769Sobrien * Track the makefiles we read - so makefiles can 2390236769Sobrien * set dependencies on them. 2391236769Sobrien * Avoid adding anything more than once. 2392236769Sobrien */ 2393236769Sobrien 2394236769Sobrienstatic void 2395236769SobrienParseTrackInput(const char *name) 2396236769Sobrien{ 2397236769Sobrien char *old; 2398291342Ssjg char *ep; 2399236769Sobrien char *fp = NULL; 2400236769Sobrien size_t name_len = strlen(name); 2401236769Sobrien 2402236769Sobrien old = Var_Value(MAKE_MAKEFILES, VAR_GLOBAL, &fp); 2403236769Sobrien if (old) { 2404291342Ssjg ep = old + strlen(old) - name_len; 2405236769Sobrien /* does it contain name? */ 2406236769Sobrien for (; old != NULL; old = strchr(old, ' ')) { 2407236769Sobrien if (*old == ' ') 2408236769Sobrien old++; 2409291342Ssjg if (old >= ep) 2410291342Ssjg break; /* cannot contain name */ 2411236769Sobrien if (memcmp(old, name, name_len) == 0 2412236769Sobrien && (old[name_len] == 0 || old[name_len] == ' ')) 2413236769Sobrien goto cleanup; 2414236769Sobrien } 2415236769Sobrien } 2416236769Sobrien Var_Append (MAKE_MAKEFILES, name, VAR_GLOBAL); 2417236769Sobrien cleanup: 2418236769Sobrien if (fp) { 2419236769Sobrien free(fp); 2420236769Sobrien } 2421236769Sobrien} 2422236769Sobrien 2423236769Sobrien 2424236769Sobrien/*- 2425236769Sobrien *--------------------------------------------------------------------- 2426236769Sobrien * Parse_setInput -- 2427236769Sobrien * Start Parsing from the given source 2428236769Sobrien * 2429236769Sobrien * Results: 2430236769Sobrien * None 2431236769Sobrien * 2432236769Sobrien * Side Effects: 2433236769Sobrien * A structure is added to the includes Lst and readProc, lineno, 2434236769Sobrien * fname and curFile are altered for the new file 2435236769Sobrien *--------------------------------------------------------------------- 2436236769Sobrien */ 2437236769Sobrienvoid 2438236769SobrienParse_SetInput(const char *name, int line, int fd, 2439236769Sobrien char *(*nextbuf)(void *, size_t *), void *arg) 2440236769Sobrien{ 2441236769Sobrien char *buf; 2442236769Sobrien size_t len; 2443236769Sobrien 2444236769Sobrien if (name == NULL) 2445236769Sobrien name = curFile->fname; 2446236769Sobrien else 2447236769Sobrien ParseTrackInput(name); 2448236769Sobrien 2449236769Sobrien if (DEBUG(PARSE)) 2450268437Ssjg fprintf(debug_file, "%s: file %s, line %d, fd %d, nextbuf %p, arg %p\n", 2451268437Ssjg __func__, name, line, fd, nextbuf, arg); 2452236769Sobrien 2453236769Sobrien if (fd == -1 && nextbuf == NULL) 2454236769Sobrien /* sanity */ 2455236769Sobrien return; 2456236769Sobrien 2457236769Sobrien if (curFile != NULL) 2458236769Sobrien /* Save exiting file info */ 2459236769Sobrien Lst_AtFront(includes, curFile); 2460236769Sobrien 2461236769Sobrien /* Allocate and fill in new structure */ 2462236769Sobrien curFile = bmake_malloc(sizeof *curFile); 2463236769Sobrien 2464236769Sobrien /* 2465236769Sobrien * Once the previous state has been saved, we can get down to reading 2466236769Sobrien * the new file. We set up the name of the file to be the absolute 2467236769Sobrien * name of the include file so error messages refer to the right 2468236769Sobrien * place. 2469236769Sobrien */ 2470251958Ssjg curFile->fname = bmake_strdup(name); 2471236769Sobrien curFile->lineno = line; 2472236769Sobrien curFile->first_lineno = line; 2473236769Sobrien curFile->nextbuf = nextbuf; 2474236769Sobrien curFile->nextbuf_arg = arg; 2475236769Sobrien curFile->lf = NULL; 2476296637Ssjg curFile->depending = doing_depend; /* restore this on EOF */ 2477236769Sobrien 2478236769Sobrien assert(nextbuf != NULL); 2479236769Sobrien 2480236769Sobrien /* Get first block of input data */ 2481236769Sobrien buf = curFile->nextbuf(curFile->nextbuf_arg, &len); 2482236769Sobrien if (buf == NULL) { 2483236769Sobrien /* Was all a waste of time ... */ 2484251958Ssjg if (curFile->fname) 2485251958Ssjg free(curFile->fname); 2486236769Sobrien free(curFile); 2487236769Sobrien return; 2488236769Sobrien } 2489236769Sobrien curFile->P_str = buf; 2490236769Sobrien curFile->P_ptr = buf; 2491236769Sobrien curFile->P_end = buf+len; 2492236769Sobrien 2493236769Sobrien curFile->cond_depth = Cond_save_depth(); 2494236769Sobrien ParseSetParseFile(name); 2495236769Sobrien} 2496236769Sobrien 2497236769Sobrien#ifdef SYSVINCLUDE 2498236769Sobrien/*- 2499236769Sobrien *--------------------------------------------------------------------- 2500236769Sobrien * ParseTraditionalInclude -- 2501236769Sobrien * Push to another file. 2502236769Sobrien * 2503236769Sobrien * The input is the current line. The file name(s) are 2504236769Sobrien * following the "include". 2505236769Sobrien * 2506236769Sobrien * Results: 2507236769Sobrien * None 2508236769Sobrien * 2509236769Sobrien * Side Effects: 2510236769Sobrien * A structure is added to the includes Lst and readProc, lineno, 2511236769Sobrien * fname and curFILE are altered for the new file 2512236769Sobrien *--------------------------------------------------------------------- 2513236769Sobrien */ 2514236769Sobrienstatic void 2515236769SobrienParseTraditionalInclude(char *line) 2516236769Sobrien{ 2517236769Sobrien char *cp; /* current position in file spec */ 2518236769Sobrien int done = 0; 2519236769Sobrien int silent = (line[0] != 'i') ? 1 : 0; 2520236769Sobrien char *file = &line[silent + 7]; 2521236769Sobrien char *all_files; 2522236769Sobrien 2523236769Sobrien if (DEBUG(PARSE)) { 2524268437Ssjg fprintf(debug_file, "%s: %s\n", __func__, file); 2525236769Sobrien } 2526236769Sobrien 2527236769Sobrien /* 2528236769Sobrien * Skip over whitespace 2529236769Sobrien */ 2530236769Sobrien while (isspace((unsigned char)*file)) 2531236769Sobrien file++; 2532236769Sobrien 2533236769Sobrien /* 2534236769Sobrien * Substitute for any variables in the file name before trying to 2535236769Sobrien * find the thing. 2536236769Sobrien */ 2537296637Ssjg all_files = Var_Subst(NULL, file, VAR_CMD, VARF_WANTRES); 2538236769Sobrien 2539236769Sobrien if (*file == '\0') { 2540236769Sobrien Parse_Error(PARSE_FATAL, 2541236769Sobrien "Filename missing from \"include\""); 2542236769Sobrien return; 2543236769Sobrien } 2544236769Sobrien 2545236769Sobrien for (file = all_files; !done; file = cp + 1) { 2546236769Sobrien /* Skip to end of line or next whitespace */ 2547236769Sobrien for (cp = file; *cp && !isspace((unsigned char) *cp); cp++) 2548236769Sobrien continue; 2549236769Sobrien 2550236769Sobrien if (*cp) 2551236769Sobrien *cp = '\0'; 2552236769Sobrien else 2553236769Sobrien done = 1; 2554236769Sobrien 2555296637Ssjg Parse_include_file(file, FALSE, FALSE, silent); 2556236769Sobrien } 2557236769Sobrien free(all_files); 2558236769Sobrien} 2559236769Sobrien#endif 2560236769Sobrien 2561236769Sobrien#ifdef GMAKEEXPORT 2562236769Sobrien/*- 2563236769Sobrien *--------------------------------------------------------------------- 2564236769Sobrien * ParseGmakeExport -- 2565236769Sobrien * Parse export <variable>=<value> 2566236769Sobrien * 2567236769Sobrien * And set the environment with it. 2568236769Sobrien * 2569236769Sobrien * Results: 2570236769Sobrien * None 2571236769Sobrien * 2572236769Sobrien * Side Effects: 2573236769Sobrien * None 2574236769Sobrien *--------------------------------------------------------------------- 2575236769Sobrien */ 2576236769Sobrienstatic void 2577236769SobrienParseGmakeExport(char *line) 2578236769Sobrien{ 2579236769Sobrien char *variable = &line[6]; 2580236769Sobrien char *value; 2581236769Sobrien 2582236769Sobrien if (DEBUG(PARSE)) { 2583268437Ssjg fprintf(debug_file, "%s: %s\n", __func__, variable); 2584236769Sobrien } 2585236769Sobrien 2586236769Sobrien /* 2587236769Sobrien * Skip over whitespace 2588236769Sobrien */ 2589236769Sobrien while (isspace((unsigned char)*variable)) 2590236769Sobrien variable++; 2591236769Sobrien 2592236769Sobrien for (value = variable; *value && *value != '='; value++) 2593236769Sobrien continue; 2594236769Sobrien 2595236769Sobrien if (*value != '=') { 2596236769Sobrien Parse_Error(PARSE_FATAL, 2597236769Sobrien "Variable/Value missing from \"export\""); 2598236769Sobrien return; 2599236769Sobrien } 2600249033Ssjg *value++ = '\0'; /* terminate variable */ 2601236769Sobrien 2602236769Sobrien /* 2603236769Sobrien * Expand the value before putting it in the environment. 2604236769Sobrien */ 2605296637Ssjg value = Var_Subst(NULL, value, VAR_CMD, VARF_WANTRES); 2606236769Sobrien setenv(variable, value, 1); 2607236769Sobrien} 2608236769Sobrien#endif 2609236769Sobrien 2610236769Sobrien/*- 2611236769Sobrien *--------------------------------------------------------------------- 2612236769Sobrien * ParseEOF -- 2613236769Sobrien * Called when EOF is reached in the current file. If we were reading 2614236769Sobrien * an include file, the includes stack is popped and things set up 2615236769Sobrien * to go back to reading the previous file at the previous location. 2616236769Sobrien * 2617236769Sobrien * Results: 2618236769Sobrien * CONTINUE if there's more to do. DONE if not. 2619236769Sobrien * 2620236769Sobrien * Side Effects: 2621236769Sobrien * The old curFILE, is closed. The includes list is shortened. 2622236769Sobrien * lineno, curFILE, and fname are changed if CONTINUE is returned. 2623236769Sobrien *--------------------------------------------------------------------- 2624236769Sobrien */ 2625236769Sobrienstatic int 2626236769SobrienParseEOF(void) 2627236769Sobrien{ 2628236769Sobrien char *ptr; 2629236769Sobrien size_t len; 2630236769Sobrien 2631236769Sobrien assert(curFile->nextbuf != NULL); 2632236769Sobrien 2633296637Ssjg doing_depend = curFile->depending; /* restore this */ 2634236769Sobrien /* get next input buffer, if any */ 2635236769Sobrien ptr = curFile->nextbuf(curFile->nextbuf_arg, &len); 2636236769Sobrien curFile->P_ptr = ptr; 2637236769Sobrien curFile->P_str = ptr; 2638236769Sobrien curFile->P_end = ptr + len; 2639236769Sobrien curFile->lineno = curFile->first_lineno; 2640236769Sobrien if (ptr != NULL) { 2641236769Sobrien /* Iterate again */ 2642236769Sobrien return CONTINUE; 2643236769Sobrien } 2644236769Sobrien 2645236769Sobrien /* Ensure the makefile (or loop) didn't have mismatched conditionals */ 2646236769Sobrien Cond_restore_depth(curFile->cond_depth); 2647236769Sobrien 2648236769Sobrien if (curFile->lf != NULL) { 2649236769Sobrien loadedfile_destroy(curFile->lf); 2650236769Sobrien curFile->lf = NULL; 2651236769Sobrien } 2652236769Sobrien 2653236769Sobrien /* Dispose of curFile info */ 2654236769Sobrien /* Leak curFile->fname because all the gnodes have pointers to it */ 2655236769Sobrien free(curFile->P_str); 2656236769Sobrien free(curFile); 2657236769Sobrien 2658236769Sobrien curFile = Lst_DeQueue(includes); 2659236769Sobrien 2660236769Sobrien if (curFile == NULL) { 2661236769Sobrien /* We've run out of input */ 2662236769Sobrien Var_Delete(".PARSEDIR", VAR_GLOBAL); 2663236769Sobrien Var_Delete(".PARSEFILE", VAR_GLOBAL); 2664268437Ssjg Var_Delete(".INCLUDEDFROMDIR", VAR_GLOBAL); 2665268437Ssjg Var_Delete(".INCLUDEDFROMFILE", VAR_GLOBAL); 2666236769Sobrien return DONE; 2667236769Sobrien } 2668236769Sobrien 2669236769Sobrien if (DEBUG(PARSE)) 2670236769Sobrien fprintf(debug_file, "ParseEOF: returning to file %s, line %d\n", 2671236769Sobrien curFile->fname, curFile->lineno); 2672236769Sobrien 2673236769Sobrien /* Restore the PARSEDIR/PARSEFILE variables */ 2674236769Sobrien ParseSetParseFile(curFile->fname); 2675236769Sobrien return (CONTINUE); 2676236769Sobrien} 2677236769Sobrien 2678236769Sobrien#define PARSE_RAW 1 2679236769Sobrien#define PARSE_SKIP 2 2680236769Sobrien 2681236769Sobrienstatic char * 2682236769SobrienParseGetLine(int flags, int *length) 2683236769Sobrien{ 2684236769Sobrien IFile *cf = curFile; 2685236769Sobrien char *ptr; 2686236769Sobrien char ch; 2687236769Sobrien char *line; 2688236769Sobrien char *line_end; 2689236769Sobrien char *escaped; 2690236769Sobrien char *comment; 2691236769Sobrien char *tp; 2692236769Sobrien 2693236769Sobrien /* Loop through blank lines and comment lines */ 2694236769Sobrien for (;;) { 2695236769Sobrien cf->lineno++; 2696236769Sobrien line = cf->P_ptr; 2697236769Sobrien ptr = line; 2698236769Sobrien line_end = line; 2699236769Sobrien escaped = NULL; 2700236769Sobrien comment = NULL; 2701236769Sobrien for (;;) { 2702236769Sobrien if (cf->P_end != NULL && ptr == cf->P_end) { 2703236769Sobrien /* end of buffer */ 2704236769Sobrien ch = 0; 2705236769Sobrien break; 2706236769Sobrien } 2707236769Sobrien ch = *ptr; 2708236769Sobrien if (ch == 0 || (ch == '\\' && ptr[1] == 0)) { 2709236769Sobrien if (cf->P_end == NULL) 2710236769Sobrien /* End of string (aka for loop) data */ 2711236769Sobrien break; 2712254194Ssjg /* see if there is more we can parse */ 2713254194Ssjg while (ptr++ < cf->P_end) { 2714254194Ssjg if ((ch = *ptr) == '\n') { 2715254194Ssjg if (ptr > line && ptr[-1] == '\\') 2716254194Ssjg continue; 2717254194Ssjg Parse_Error(PARSE_WARNING, 2718254194Ssjg "Zero byte read from file, skipping rest of line."); 2719254194Ssjg break; 2720254194Ssjg } 2721254194Ssjg } 2722236769Sobrien if (cf->nextbuf != NULL) { 2723236769Sobrien /* 2724236769Sobrien * End of this buffer; return EOF and outer logic 2725236769Sobrien * will get the next one. (eww) 2726236769Sobrien */ 2727236769Sobrien break; 2728236769Sobrien } 2729236769Sobrien Parse_Error(PARSE_FATAL, "Zero byte read from file"); 2730236769Sobrien return NULL; 2731236769Sobrien } 2732236769Sobrien 2733236769Sobrien if (ch == '\\') { 2734236769Sobrien /* Don't treat next character as special, remember first one */ 2735236769Sobrien if (escaped == NULL) 2736236769Sobrien escaped = ptr; 2737236769Sobrien if (ptr[1] == '\n') 2738236769Sobrien cf->lineno++; 2739236769Sobrien ptr += 2; 2740236769Sobrien line_end = ptr; 2741236769Sobrien continue; 2742236769Sobrien } 2743236769Sobrien if (ch == '#' && comment == NULL) { 2744236769Sobrien /* Remember first '#' for comment stripping */ 2745236769Sobrien /* Unless previous char was '[', as in modifier :[#] */ 2746236769Sobrien if (!(ptr > line && ptr[-1] == '[')) 2747236769Sobrien comment = line_end; 2748236769Sobrien } 2749236769Sobrien ptr++; 2750236769Sobrien if (ch == '\n') 2751236769Sobrien break; 2752236769Sobrien if (!isspace((unsigned char)ch)) 2753236769Sobrien /* We are not interested in trailing whitespace */ 2754236769Sobrien line_end = ptr; 2755236769Sobrien } 2756236769Sobrien 2757236769Sobrien /* Save next 'to be processed' location */ 2758236769Sobrien cf->P_ptr = ptr; 2759236769Sobrien 2760236769Sobrien /* Check we have a non-comment, non-blank line */ 2761236769Sobrien if (line_end == line || comment == line) { 2762236769Sobrien if (ch == 0) 2763236769Sobrien /* At end of file */ 2764236769Sobrien return NULL; 2765236769Sobrien /* Parse another line */ 2766236769Sobrien continue; 2767236769Sobrien } 2768236769Sobrien 2769236769Sobrien /* We now have a line of data */ 2770236769Sobrien *line_end = 0; 2771236769Sobrien 2772236769Sobrien if (flags & PARSE_RAW) { 2773236769Sobrien /* Leave '\' (etc) in line buffer (eg 'for' lines) */ 2774236769Sobrien *length = line_end - line; 2775236769Sobrien return line; 2776236769Sobrien } 2777236769Sobrien 2778236769Sobrien if (flags & PARSE_SKIP) { 2779236769Sobrien /* Completely ignore non-directives */ 2780236769Sobrien if (line[0] != '.') 2781236769Sobrien continue; 2782236769Sobrien /* We could do more of the .else/.elif/.endif checks here */ 2783236769Sobrien } 2784236769Sobrien break; 2785236769Sobrien } 2786236769Sobrien 2787236769Sobrien /* Brutally ignore anything after a non-escaped '#' in non-commands */ 2788236769Sobrien if (comment != NULL && line[0] != '\t') { 2789236769Sobrien line_end = comment; 2790236769Sobrien *line_end = 0; 2791236769Sobrien } 2792236769Sobrien 2793236769Sobrien /* If we didn't see a '\\' then the in-situ data is fine */ 2794236769Sobrien if (escaped == NULL) { 2795236769Sobrien *length = line_end - line; 2796236769Sobrien return line; 2797236769Sobrien } 2798236769Sobrien 2799236769Sobrien /* Remove escapes from '\n' and '#' */ 2800236769Sobrien tp = ptr = escaped; 2801236769Sobrien escaped = line; 2802236769Sobrien for (; ; *tp++ = ch) { 2803236769Sobrien ch = *ptr++; 2804236769Sobrien if (ch != '\\') { 2805236769Sobrien if (ch == 0) 2806236769Sobrien break; 2807236769Sobrien continue; 2808236769Sobrien } 2809236769Sobrien 2810236769Sobrien ch = *ptr++; 2811236769Sobrien if (ch == 0) { 2812236769Sobrien /* Delete '\\' at end of buffer */ 2813236769Sobrien tp--; 2814236769Sobrien break; 2815236769Sobrien } 2816236769Sobrien 2817236769Sobrien if (ch == '#' && line[0] != '\t') 2818236769Sobrien /* Delete '\\' from before '#' on non-command lines */ 2819236769Sobrien continue; 2820236769Sobrien 2821236769Sobrien if (ch != '\n') { 2822236769Sobrien /* Leave '\\' in buffer for later */ 2823236769Sobrien *tp++ = '\\'; 2824236769Sobrien /* Make sure we don't delete an escaped ' ' from the line end */ 2825236769Sobrien escaped = tp + 1; 2826236769Sobrien continue; 2827236769Sobrien } 2828236769Sobrien 2829236769Sobrien /* Escaped '\n' replace following whitespace with a single ' ' */ 2830236769Sobrien while (ptr[0] == ' ' || ptr[0] == '\t') 2831236769Sobrien ptr++; 2832236769Sobrien ch = ' '; 2833236769Sobrien } 2834236769Sobrien 2835236769Sobrien /* Delete any trailing spaces - eg from empty continuations */ 2836236769Sobrien while (tp > escaped && isspace((unsigned char)tp[-1])) 2837236769Sobrien tp--; 2838236769Sobrien 2839236769Sobrien *tp = 0; 2840236769Sobrien *length = tp - line; 2841236769Sobrien return line; 2842236769Sobrien} 2843236769Sobrien 2844236769Sobrien/*- 2845236769Sobrien *--------------------------------------------------------------------- 2846236769Sobrien * ParseReadLine -- 2847236769Sobrien * Read an entire line from the input file. Called only by Parse_File. 2848236769Sobrien * 2849236769Sobrien * Results: 2850236769Sobrien * A line w/o its newline 2851236769Sobrien * 2852236769Sobrien * Side Effects: 2853236769Sobrien * Only those associated with reading a character 2854236769Sobrien *--------------------------------------------------------------------- 2855236769Sobrien */ 2856236769Sobrienstatic char * 2857236769SobrienParseReadLine(void) 2858236769Sobrien{ 2859236769Sobrien char *line; /* Result */ 2860236769Sobrien int lineLength; /* Length of result */ 2861236769Sobrien int lineno; /* Saved line # */ 2862236769Sobrien int rval; 2863236769Sobrien 2864236769Sobrien for (;;) { 2865236769Sobrien line = ParseGetLine(0, &lineLength); 2866236769Sobrien if (line == NULL) 2867236769Sobrien return NULL; 2868236769Sobrien 2869236769Sobrien if (line[0] != '.') 2870236769Sobrien return line; 2871236769Sobrien 2872236769Sobrien /* 2873236769Sobrien * The line might be a conditional. Ask the conditional module 2874236769Sobrien * about it and act accordingly 2875236769Sobrien */ 2876236769Sobrien switch (Cond_Eval(line)) { 2877236769Sobrien case COND_SKIP: 2878236769Sobrien /* Skip to next conditional that evaluates to COND_PARSE. */ 2879236769Sobrien do { 2880236769Sobrien line = ParseGetLine(PARSE_SKIP, &lineLength); 2881236769Sobrien } while (line && Cond_Eval(line) != COND_PARSE); 2882236769Sobrien if (line == NULL) 2883236769Sobrien break; 2884236769Sobrien continue; 2885236769Sobrien case COND_PARSE: 2886236769Sobrien continue; 2887236769Sobrien case COND_INVALID: /* Not a conditional line */ 2888236769Sobrien /* Check for .for loops */ 2889236769Sobrien rval = For_Eval(line); 2890236769Sobrien if (rval == 0) 2891236769Sobrien /* Not a .for line */ 2892236769Sobrien break; 2893236769Sobrien if (rval < 0) 2894236769Sobrien /* Syntax error - error printed, ignore line */ 2895236769Sobrien continue; 2896236769Sobrien /* Start of a .for loop */ 2897236769Sobrien lineno = curFile->lineno; 2898236769Sobrien /* Accumulate loop lines until matching .endfor */ 2899236769Sobrien do { 2900236769Sobrien line = ParseGetLine(PARSE_RAW, &lineLength); 2901236769Sobrien if (line == NULL) { 2902236769Sobrien Parse_Error(PARSE_FATAL, 2903236769Sobrien "Unexpected end of file in for loop."); 2904236769Sobrien break; 2905236769Sobrien } 2906236769Sobrien } while (For_Accum(line)); 2907236769Sobrien /* Stash each iteration as a new 'input file' */ 2908236769Sobrien For_Run(lineno); 2909236769Sobrien /* Read next line from for-loop buffer */ 2910236769Sobrien continue; 2911236769Sobrien } 2912236769Sobrien return (line); 2913236769Sobrien } 2914236769Sobrien} 2915236769Sobrien 2916236769Sobrien/*- 2917236769Sobrien *----------------------------------------------------------------------- 2918236769Sobrien * ParseFinishLine -- 2919236769Sobrien * Handle the end of a dependency group. 2920236769Sobrien * 2921236769Sobrien * Results: 2922236769Sobrien * Nothing. 2923236769Sobrien * 2924236769Sobrien * Side Effects: 2925236769Sobrien * inLine set FALSE. 'targets' list destroyed. 2926236769Sobrien * 2927236769Sobrien *----------------------------------------------------------------------- 2928236769Sobrien */ 2929236769Sobrienstatic void 2930236769SobrienParseFinishLine(void) 2931236769Sobrien{ 2932236769Sobrien if (inLine) { 2933236769Sobrien Lst_ForEach(targets, Suff_EndTransform, NULL); 2934236769Sobrien Lst_Destroy(targets, ParseHasCommands); 2935236769Sobrien targets = NULL; 2936236769Sobrien inLine = FALSE; 2937236769Sobrien } 2938236769Sobrien} 2939236769Sobrien 2940236769Sobrien 2941236769Sobrien/*- 2942236769Sobrien *--------------------------------------------------------------------- 2943236769Sobrien * Parse_File -- 2944236769Sobrien * Parse a file into its component parts, incorporating it into the 2945236769Sobrien * current dependency graph. This is the main function and controls 2946236769Sobrien * almost every other function in this module 2947236769Sobrien * 2948236769Sobrien * Input: 2949236769Sobrien * name the name of the file being read 2950236769Sobrien * fd Open file to makefile to parse 2951236769Sobrien * 2952236769Sobrien * Results: 2953236769Sobrien * None 2954236769Sobrien * 2955236769Sobrien * Side Effects: 2956236769Sobrien * closes fd. 2957236769Sobrien * Loads. Nodes are added to the list of all targets, nodes and links 2958236769Sobrien * are added to the dependency graph. etc. etc. etc. 2959236769Sobrien *--------------------------------------------------------------------- 2960236769Sobrien */ 2961236769Sobrienvoid 2962236769SobrienParse_File(const char *name, int fd) 2963236769Sobrien{ 2964236769Sobrien char *cp; /* pointer into the line */ 2965236769Sobrien char *line; /* the line we're working on */ 2966236769Sobrien struct loadedfile *lf; 2967236769Sobrien 2968236769Sobrien lf = loadfile(name, fd); 2969236769Sobrien 2970236769Sobrien inLine = FALSE; 2971236769Sobrien fatals = 0; 2972236769Sobrien 2973236769Sobrien if (name == NULL) { 2974236769Sobrien name = "(stdin)"; 2975236769Sobrien } 2976236769Sobrien 2977236769Sobrien Parse_SetInput(name, 0, -1, loadedfile_nextbuf, lf); 2978236769Sobrien curFile->lf = lf; 2979236769Sobrien 2980236769Sobrien do { 2981236769Sobrien for (; (line = ParseReadLine()) != NULL; ) { 2982236769Sobrien if (DEBUG(PARSE)) 2983236769Sobrien fprintf(debug_file, "ParseReadLine (%d): '%s'\n", 2984236769Sobrien curFile->lineno, line); 2985236769Sobrien if (*line == '.') { 2986236769Sobrien /* 2987236769Sobrien * Lines that begin with the special character may be 2988236769Sobrien * include or undef directives. 2989236769Sobrien * On the other hand they can be suffix rules (.c.o: ...) 2990236769Sobrien * or just dependencies for filenames that start '.'. 2991236769Sobrien */ 2992236769Sobrien for (cp = line + 1; isspace((unsigned char)*cp); cp++) { 2993236769Sobrien continue; 2994236769Sobrien } 2995236769Sobrien if (strncmp(cp, "include", 7) == 0 || 2996296637Ssjg ((cp[0] == 'd' || cp[0] == 's' || cp[0] == '-') && 2997236769Sobrien strncmp(&cp[1], "include", 7) == 0)) { 2998236769Sobrien ParseDoInclude(cp); 2999236769Sobrien continue; 3000236769Sobrien } 3001236769Sobrien if (strncmp(cp, "undef", 5) == 0) { 3002236769Sobrien char *cp2; 3003236769Sobrien for (cp += 5; isspace((unsigned char) *cp); cp++) 3004236769Sobrien continue; 3005236769Sobrien for (cp2 = cp; !isspace((unsigned char) *cp2) && 3006236769Sobrien (*cp2 != '\0'); cp2++) 3007236769Sobrien continue; 3008236769Sobrien *cp2 = '\0'; 3009236769Sobrien Var_Delete(cp, VAR_GLOBAL); 3010236769Sobrien continue; 3011236769Sobrien } else if (strncmp(cp, "export", 6) == 0) { 3012236769Sobrien for (cp += 6; isspace((unsigned char) *cp); cp++) 3013236769Sobrien continue; 3014236769Sobrien Var_Export(cp, 1); 3015236769Sobrien continue; 3016236769Sobrien } else if (strncmp(cp, "unexport", 8) == 0) { 3017236769Sobrien Var_UnExport(cp); 3018236769Sobrien continue; 3019236769Sobrien } else if (strncmp(cp, "info", 4) == 0 || 3020236769Sobrien strncmp(cp, "error", 5) == 0 || 3021236769Sobrien strncmp(cp, "warning", 7) == 0) { 3022236769Sobrien if (ParseMessage(cp)) 3023236769Sobrien continue; 3024236769Sobrien } 3025236769Sobrien } 3026236769Sobrien 3027236769Sobrien if (*line == '\t') { 3028236769Sobrien /* 3029236769Sobrien * If a line starts with a tab, it can only hope to be 3030236769Sobrien * a creation command. 3031236769Sobrien */ 3032236769Sobrien cp = line + 1; 3033236769Sobrien shellCommand: 3034236769Sobrien for (; isspace ((unsigned char)*cp); cp++) { 3035236769Sobrien continue; 3036236769Sobrien } 3037236769Sobrien if (*cp) { 3038236769Sobrien if (!inLine) 3039236769Sobrien Parse_Error(PARSE_FATAL, 3040236769Sobrien "Unassociated shell command \"%s\"", 3041236769Sobrien cp); 3042236769Sobrien /* 3043236769Sobrien * So long as it's not a blank line and we're actually 3044236769Sobrien * in a dependency spec, add the command to the list of 3045236769Sobrien * commands of all targets in the dependency spec 3046236769Sobrien */ 3047236769Sobrien if (targets) { 3048236769Sobrien cp = bmake_strdup(cp); 3049236769Sobrien Lst_ForEach(targets, ParseAddCmd, cp); 3050236769Sobrien#ifdef CLEANUP 3051236769Sobrien Lst_AtEnd(targCmds, cp); 3052236769Sobrien#endif 3053236769Sobrien } 3054236769Sobrien } 3055236769Sobrien continue; 3056236769Sobrien } 3057236769Sobrien 3058236769Sobrien#ifdef SYSVINCLUDE 3059236769Sobrien if (((strncmp(line, "include", 7) == 0 && 3060236769Sobrien isspace((unsigned char) line[7])) || 3061236769Sobrien ((line[0] == 's' || line[0] == '-') && 3062236769Sobrien strncmp(&line[1], "include", 7) == 0 && 3063236769Sobrien isspace((unsigned char) line[8]))) && 3064236769Sobrien strchr(line, ':') == NULL) { 3065236769Sobrien /* 3066236769Sobrien * It's an S3/S5-style "include". 3067236769Sobrien */ 3068236769Sobrien ParseTraditionalInclude(line); 3069236769Sobrien continue; 3070236769Sobrien } 3071236769Sobrien#endif 3072236769Sobrien#ifdef GMAKEEXPORT 3073236769Sobrien if (strncmp(line, "export", 6) == 0 && 3074236769Sobrien isspace((unsigned char) line[6]) && 3075236769Sobrien strchr(line, ':') == NULL) { 3076236769Sobrien /* 3077236769Sobrien * It's a Gmake "export". 3078236769Sobrien */ 3079236769Sobrien ParseGmakeExport(line); 3080236769Sobrien continue; 3081236769Sobrien } 3082236769Sobrien#endif 3083236769Sobrien if (Parse_IsVar(line)) { 3084236769Sobrien ParseFinishLine(); 3085236769Sobrien Parse_DoVar(line, VAR_GLOBAL); 3086236769Sobrien continue; 3087236769Sobrien } 3088236769Sobrien 3089236769Sobrien#ifndef POSIX 3090236769Sobrien /* 3091236769Sobrien * To make life easier on novices, if the line is indented we 3092236769Sobrien * first make sure the line has a dependency operator in it. 3093236769Sobrien * If it doesn't have an operator and we're in a dependency 3094236769Sobrien * line's script, we assume it's actually a shell command 3095236769Sobrien * and add it to the current list of targets. 3096236769Sobrien */ 3097236769Sobrien cp = line; 3098236769Sobrien if (isspace((unsigned char) line[0])) { 3099236769Sobrien while ((*cp != '\0') && isspace((unsigned char) *cp)) 3100236769Sobrien cp++; 3101236769Sobrien while (*cp && (ParseIsEscaped(line, cp) || 3102236769Sobrien (*cp != ':') && (*cp != '!'))) { 3103236769Sobrien cp++; 3104236769Sobrien } 3105236769Sobrien if (*cp == '\0') { 3106236769Sobrien if (inLine) { 3107236769Sobrien Parse_Error(PARSE_WARNING, 3108236769Sobrien "Shell command needs a leading tab"); 3109236769Sobrien goto shellCommand; 3110236769Sobrien } 3111236769Sobrien } 3112236769Sobrien } 3113236769Sobrien#endif 3114236769Sobrien ParseFinishLine(); 3115236769Sobrien 3116236769Sobrien /* 3117236769Sobrien * For some reason - probably to make the parser impossible - 3118236769Sobrien * a ';' can be used to separate commands from dependencies. 3119236769Sobrien * Attempt to avoid ';' inside substitution patterns. 3120236769Sobrien */ 3121236769Sobrien { 3122236769Sobrien int level = 0; 3123236769Sobrien 3124236769Sobrien for (cp = line; *cp != 0; cp++) { 3125236769Sobrien if (*cp == '\\' && cp[1] != 0) { 3126236769Sobrien cp++; 3127236769Sobrien continue; 3128236769Sobrien } 3129236769Sobrien if (*cp == '$' && 3130236769Sobrien (cp[1] == '(' || cp[1] == '{')) { 3131236769Sobrien level++; 3132236769Sobrien continue; 3133236769Sobrien } 3134236769Sobrien if (level > 0) { 3135236769Sobrien if (*cp == ')' || *cp == '}') { 3136236769Sobrien level--; 3137236769Sobrien continue; 3138236769Sobrien } 3139236769Sobrien } else if (*cp == ';') { 3140236769Sobrien break; 3141236769Sobrien } 3142236769Sobrien } 3143236769Sobrien } 3144236769Sobrien if (*cp != 0) 3145236769Sobrien /* Terminate the dependency list at the ';' */ 3146236769Sobrien *cp++ = 0; 3147236769Sobrien else 3148236769Sobrien cp = NULL; 3149236769Sobrien 3150236769Sobrien /* 3151236769Sobrien * We now know it's a dependency line so it needs to have all 3152236769Sobrien * variables expanded before being parsed. Tell the variable 3153236769Sobrien * module to complain if some variable is undefined... 3154236769Sobrien */ 3155296637Ssjg line = Var_Subst(NULL, line, VAR_CMD, VARF_UNDEFERR|VARF_WANTRES); 3156236769Sobrien 3157236769Sobrien /* 3158236769Sobrien * Need a non-circular list for the target nodes 3159236769Sobrien */ 3160236769Sobrien if (targets) 3161236769Sobrien Lst_Destroy(targets, NULL); 3162236769Sobrien 3163236769Sobrien targets = Lst_Init(FALSE); 3164236769Sobrien inLine = TRUE; 3165236769Sobrien 3166236769Sobrien ParseDoDependency(line); 3167236769Sobrien free(line); 3168236769Sobrien 3169236769Sobrien /* If there were commands after a ';', add them now */ 3170236769Sobrien if (cp != NULL) { 3171236769Sobrien goto shellCommand; 3172236769Sobrien } 3173236769Sobrien } 3174236769Sobrien /* 3175236769Sobrien * Reached EOF, but it may be just EOF of an include file... 3176236769Sobrien */ 3177236769Sobrien } while (ParseEOF() == CONTINUE); 3178236769Sobrien 3179236769Sobrien if (fatals) { 3180236769Sobrien (void)fflush(stdout); 3181236769Sobrien (void)fprintf(stderr, 3182236769Sobrien "%s: Fatal errors encountered -- cannot continue", 3183236769Sobrien progname); 3184236769Sobrien PrintOnError(NULL, NULL); 3185236769Sobrien exit(1); 3186236769Sobrien } 3187236769Sobrien} 3188236769Sobrien 3189236769Sobrien/*- 3190236769Sobrien *--------------------------------------------------------------------- 3191236769Sobrien * Parse_Init -- 3192236769Sobrien * initialize the parsing module 3193236769Sobrien * 3194236769Sobrien * Results: 3195236769Sobrien * none 3196236769Sobrien * 3197236769Sobrien * Side Effects: 3198236769Sobrien * the parseIncPath list is initialized... 3199236769Sobrien *--------------------------------------------------------------------- 3200236769Sobrien */ 3201236769Sobrienvoid 3202236769SobrienParse_Init(void) 3203236769Sobrien{ 3204236769Sobrien mainNode = NULL; 3205236769Sobrien parseIncPath = Lst_Init(FALSE); 3206236769Sobrien sysIncPath = Lst_Init(FALSE); 3207236769Sobrien defIncPath = Lst_Init(FALSE); 3208236769Sobrien includes = Lst_Init(FALSE); 3209236769Sobrien#ifdef CLEANUP 3210236769Sobrien targCmds = Lst_Init(FALSE); 3211236769Sobrien#endif 3212236769Sobrien} 3213236769Sobrien 3214236769Sobrienvoid 3215236769SobrienParse_End(void) 3216236769Sobrien{ 3217236769Sobrien#ifdef CLEANUP 3218236769Sobrien Lst_Destroy(targCmds, (FreeProc *)free); 3219236769Sobrien if (targets) 3220236769Sobrien Lst_Destroy(targets, NULL); 3221236769Sobrien Lst_Destroy(defIncPath, Dir_Destroy); 3222236769Sobrien Lst_Destroy(sysIncPath, Dir_Destroy); 3223236769Sobrien Lst_Destroy(parseIncPath, Dir_Destroy); 3224236769Sobrien Lst_Destroy(includes, NULL); /* Should be empty now */ 3225236769Sobrien#endif 3226236769Sobrien} 3227236769Sobrien 3228236769Sobrien 3229236769Sobrien/*- 3230236769Sobrien *----------------------------------------------------------------------- 3231236769Sobrien * Parse_MainName -- 3232236769Sobrien * Return a Lst of the main target to create for main()'s sake. If 3233236769Sobrien * no such target exists, we Punt with an obnoxious error message. 3234236769Sobrien * 3235236769Sobrien * Results: 3236236769Sobrien * A Lst of the single node to create. 3237236769Sobrien * 3238236769Sobrien * Side Effects: 3239236769Sobrien * None. 3240236769Sobrien * 3241236769Sobrien *----------------------------------------------------------------------- 3242236769Sobrien */ 3243236769SobrienLst 3244236769SobrienParse_MainName(void) 3245236769Sobrien{ 3246236769Sobrien Lst mainList; /* result list */ 3247236769Sobrien 3248236769Sobrien mainList = Lst_Init(FALSE); 3249236769Sobrien 3250236769Sobrien if (mainNode == NULL) { 3251236769Sobrien Punt("no target to make."); 3252236769Sobrien /*NOTREACHED*/ 3253236769Sobrien } else if (mainNode->type & OP_DOUBLEDEP) { 3254236769Sobrien (void)Lst_AtEnd(mainList, mainNode); 3255236769Sobrien Lst_Concat(mainList, mainNode->cohorts, LST_CONCNEW); 3256236769Sobrien } 3257236769Sobrien else 3258236769Sobrien (void)Lst_AtEnd(mainList, mainNode); 3259236769Sobrien Var_Append(".TARGETS", mainNode->name, VAR_GLOBAL); 3260236769Sobrien return (mainList); 3261236769Sobrien} 3262236769Sobrien 3263236769Sobrien/*- 3264236769Sobrien *----------------------------------------------------------------------- 3265236769Sobrien * ParseMark -- 3266236769Sobrien * Add the filename and lineno to the GNode so that we remember 3267236769Sobrien * where it was first defined. 3268236769Sobrien * 3269236769Sobrien * Side Effects: 3270236769Sobrien * None. 3271236769Sobrien * 3272236769Sobrien *----------------------------------------------------------------------- 3273236769Sobrien */ 3274236769Sobrienstatic void 3275236769SobrienParseMark(GNode *gn) 3276236769Sobrien{ 3277236769Sobrien gn->fname = curFile->fname; 3278236769Sobrien gn->lineno = curFile->lineno; 3279236769Sobrien} 3280