parse.c revision 319884
1319884Ssjg/* $NetBSD: parse.c,v 1.225 2017/04/17 13:29:07 maya 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 72319884Ssjgstatic char rcsid[] = "$NetBSD: parse.c,v 1.225 2017/04/17 13:29:07 maya 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 79319884Ssjg__RCSID("$NetBSD: parse.c,v 1.225 2017/04/17 13:29:07 maya 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 141319884Ssjg#ifdef HAVE_STDINT_H 142319884Ssjg#include <stdint.h> 143319884Ssjg#endif 144319884Ssjg 145236769Sobrien#ifdef HAVE_MMAP 146236769Sobrien#include <sys/mman.h> 147236769Sobrien 148236769Sobrien#ifndef MAP_COPY 149236769Sobrien#define MAP_COPY MAP_PRIVATE 150236769Sobrien#endif 151236769Sobrien#ifndef MAP_FILE 152236769Sobrien#define MAP_FILE 0 153236769Sobrien#endif 154236769Sobrien#endif 155236769Sobrien 156236769Sobrien//////////////////////////////////////////////////////////// 157236769Sobrien// types and constants 158236769Sobrien 159236769Sobrien/* 160236769Sobrien * Structure for a file being read ("included file") 161236769Sobrien */ 162236769Sobrientypedef struct IFile { 163251958Ssjg char *fname; /* name of file */ 164236769Sobrien int lineno; /* current line number in file */ 165236769Sobrien int first_lineno; /* line number of start of text */ 166236769Sobrien int cond_depth; /* 'if' nesting when file opened */ 167296637Ssjg Boolean depending; /* state of doing_depend on EOF */ 168236769Sobrien char *P_str; /* point to base of string buffer */ 169236769Sobrien char *P_ptr; /* point to next char of string buffer */ 170236769Sobrien char *P_end; /* point to the end of string buffer */ 171236769Sobrien char *(*nextbuf)(void *, size_t *); /* Function to get more data */ 172236769Sobrien void *nextbuf_arg; /* Opaque arg for nextbuf() */ 173236769Sobrien struct loadedfile *lf; /* loadedfile object, if any */ 174236769Sobrien} IFile; 175236769Sobrien 176236769Sobrien 177236769Sobrien/* 178236769Sobrien * These values are returned by ParseEOF to tell Parse_File whether to 179236769Sobrien * CONTINUE parsing, i.e. it had only reached the end of an include file, 180236769Sobrien * or if it's DONE. 181236769Sobrien */ 182236769Sobrien#define CONTINUE 1 183236769Sobrien#define DONE 0 184236769Sobrien 185236769Sobrien/* 186236769Sobrien * Tokens for target attributes 187236769Sobrien */ 188236769Sobrientypedef enum { 189236769Sobrien Begin, /* .BEGIN */ 190236769Sobrien Default, /* .DEFAULT */ 191319884Ssjg DeleteOnError, /* .DELETE_ON_ERROR */ 192236769Sobrien End, /* .END */ 193236769Sobrien dotError, /* .ERROR */ 194236769Sobrien Ignore, /* .IGNORE */ 195236769Sobrien Includes, /* .INCLUDES */ 196236769Sobrien Interrupt, /* .INTERRUPT */ 197236769Sobrien Libs, /* .LIBS */ 198236769Sobrien Meta, /* .META */ 199236769Sobrien MFlags, /* .MFLAGS or .MAKEFLAGS */ 200236769Sobrien Main, /* .MAIN and we don't have anything user-specified to 201236769Sobrien * make */ 202236769Sobrien NoExport, /* .NOEXPORT */ 203236769Sobrien NoMeta, /* .NOMETA */ 204236769Sobrien NoMetaCmp, /* .NOMETA_CMP */ 205236769Sobrien NoPath, /* .NOPATH */ 206236769Sobrien Not, /* Not special */ 207236769Sobrien NotParallel, /* .NOTPARALLEL */ 208236769Sobrien Null, /* .NULL */ 209236769Sobrien ExObjdir, /* .OBJDIR */ 210236769Sobrien Order, /* .ORDER */ 211236769Sobrien Parallel, /* .PARALLEL */ 212236769Sobrien ExPath, /* .PATH */ 213236769Sobrien Phony, /* .PHONY */ 214236769Sobrien#ifdef POSIX 215236769Sobrien Posix, /* .POSIX */ 216236769Sobrien#endif 217236769Sobrien Precious, /* .PRECIOUS */ 218236769Sobrien ExShell, /* .SHELL */ 219236769Sobrien Silent, /* .SILENT */ 220236769Sobrien SingleShell, /* .SINGLESHELL */ 221249033Ssjg Stale, /* .STALE */ 222236769Sobrien Suffixes, /* .SUFFIXES */ 223236769Sobrien Wait, /* .WAIT */ 224236769Sobrien Attribute /* Generic attribute */ 225236769Sobrien} ParseSpecial; 226236769Sobrien 227236769Sobrien/* 228236769Sobrien * Other tokens 229236769Sobrien */ 230236769Sobrien#define LPAREN '(' 231236769Sobrien#define RPAREN ')' 232236769Sobrien 233236769Sobrien 234236769Sobrien//////////////////////////////////////////////////////////// 235236769Sobrien// result data 236236769Sobrien 237236769Sobrien/* 238236769Sobrien * The main target to create. This is the first target on the first 239236769Sobrien * dependency line in the first makefile. 240236769Sobrien */ 241236769Sobrienstatic GNode *mainNode; 242236769Sobrien 243236769Sobrien//////////////////////////////////////////////////////////// 244236769Sobrien// eval state 245236769Sobrien 246236769Sobrien/* targets we're working on */ 247236769Sobrienstatic Lst targets; 248236769Sobrien 249236769Sobrien#ifdef CLEANUP 250236769Sobrien/* command lines for targets */ 251236769Sobrienstatic Lst targCmds; 252236769Sobrien#endif 253236769Sobrien 254236769Sobrien/* 255236769Sobrien * specType contains the SPECial TYPE of the current target. It is 256236769Sobrien * Not if the target is unspecial. If it *is* special, however, the children 257236769Sobrien * are linked as children of the parent but not vice versa. This variable is 258236769Sobrien * set in ParseDoDependency 259236769Sobrien */ 260236769Sobrienstatic ParseSpecial specType; 261236769Sobrien 262236769Sobrien/* 263236769Sobrien * Predecessor node for handling .ORDER. Initialized to NULL when .ORDER 264236769Sobrien * seen, then set to each successive source on the line. 265236769Sobrien */ 266236769Sobrienstatic GNode *predecessor; 267236769Sobrien 268236769Sobrien//////////////////////////////////////////////////////////// 269236769Sobrien// parser state 270236769Sobrien 271236769Sobrien/* true if currently in a dependency line or its commands */ 272236769Sobrienstatic Boolean inLine; 273236769Sobrien 274236769Sobrien/* number of fatal errors */ 275236769Sobrienstatic int fatals = 0; 276236769Sobrien 277236769Sobrien/* 278236769Sobrien * Variables for doing includes 279236769Sobrien */ 280236769Sobrien 281236769Sobrien/* current file being read */ 282236769Sobrienstatic IFile *curFile; 283236769Sobrien 284236769Sobrien/* stack of IFiles generated by .includes */ 285236769Sobrienstatic Lst includes; 286236769Sobrien 287236769Sobrien/* include paths (lists of directories) */ 288236769SobrienLst parseIncPath; /* dirs for "..." includes */ 289236769SobrienLst sysIncPath; /* dirs for <...> includes */ 290236769SobrienLst defIncPath; /* default for sysIncPath */ 291236769Sobrien 292236769Sobrien//////////////////////////////////////////////////////////// 293236769Sobrien// parser tables 294236769Sobrien 295236769Sobrien/* 296236769Sobrien * The parseKeywords table is searched using binary search when deciding 297236769Sobrien * if a target or source is special. The 'spec' field is the ParseSpecial 298236769Sobrien * type of the keyword ("Not" if the keyword isn't special as a target) while 299236769Sobrien * the 'op' field is the operator to apply to the list of targets if the 300236769Sobrien * keyword is used as a source ("0" if the keyword isn't special as a source) 301236769Sobrien */ 302236769Sobrienstatic const struct { 303236769Sobrien const char *name; /* Name of keyword */ 304236769Sobrien ParseSpecial spec; /* Type when used as a target */ 305236769Sobrien int op; /* Operator when used as a source */ 306236769Sobrien} parseKeywords[] = { 307236769Sobrien{ ".BEGIN", Begin, 0 }, 308236769Sobrien{ ".DEFAULT", Default, 0 }, 309319884Ssjg{ ".DELETE_ON_ERROR", DeleteOnError, 0 }, 310236769Sobrien{ ".END", End, 0 }, 311236769Sobrien{ ".ERROR", dotError, 0 }, 312236769Sobrien{ ".EXEC", Attribute, OP_EXEC }, 313236769Sobrien{ ".IGNORE", Ignore, OP_IGNORE }, 314236769Sobrien{ ".INCLUDES", Includes, 0 }, 315236769Sobrien{ ".INTERRUPT", Interrupt, 0 }, 316236769Sobrien{ ".INVISIBLE", Attribute, OP_INVISIBLE }, 317236769Sobrien{ ".JOIN", Attribute, OP_JOIN }, 318236769Sobrien{ ".LIBS", Libs, 0 }, 319236769Sobrien{ ".MADE", Attribute, OP_MADE }, 320236769Sobrien{ ".MAIN", Main, 0 }, 321236769Sobrien{ ".MAKE", Attribute, OP_MAKE }, 322236769Sobrien{ ".MAKEFLAGS", MFlags, 0 }, 323236769Sobrien{ ".META", Meta, OP_META }, 324236769Sobrien{ ".MFLAGS", MFlags, 0 }, 325236769Sobrien{ ".NOMETA", NoMeta, OP_NOMETA }, 326236769Sobrien{ ".NOMETA_CMP", NoMetaCmp, OP_NOMETA_CMP }, 327236769Sobrien{ ".NOPATH", NoPath, OP_NOPATH }, 328236769Sobrien{ ".NOTMAIN", Attribute, OP_NOTMAIN }, 329236769Sobrien{ ".NOTPARALLEL", NotParallel, 0 }, 330236769Sobrien{ ".NO_PARALLEL", NotParallel, 0 }, 331236769Sobrien{ ".NULL", Null, 0 }, 332236769Sobrien{ ".OBJDIR", ExObjdir, 0 }, 333236769Sobrien{ ".OPTIONAL", Attribute, OP_OPTIONAL }, 334236769Sobrien{ ".ORDER", Order, 0 }, 335236769Sobrien{ ".PARALLEL", Parallel, 0 }, 336236769Sobrien{ ".PATH", ExPath, 0 }, 337236769Sobrien{ ".PHONY", Phony, OP_PHONY }, 338236769Sobrien#ifdef POSIX 339236769Sobrien{ ".POSIX", Posix, 0 }, 340236769Sobrien#endif 341236769Sobrien{ ".PRECIOUS", Precious, OP_PRECIOUS }, 342236769Sobrien{ ".RECURSIVE", Attribute, OP_MAKE }, 343236769Sobrien{ ".SHELL", ExShell, 0 }, 344236769Sobrien{ ".SILENT", Silent, OP_SILENT }, 345236769Sobrien{ ".SINGLESHELL", SingleShell, 0 }, 346249033Ssjg{ ".STALE", Stale, 0 }, 347236769Sobrien{ ".SUFFIXES", Suffixes, 0 }, 348236769Sobrien{ ".USE", Attribute, OP_USE }, 349236769Sobrien{ ".USEBEFORE", Attribute, OP_USEBEFORE }, 350236769Sobrien{ ".WAIT", Wait, 0 }, 351236769Sobrien}; 352236769Sobrien 353236769Sobrien//////////////////////////////////////////////////////////// 354236769Sobrien// local functions 355236769Sobrien 356236769Sobrienstatic int ParseIsEscaped(const char *, const char *); 357236769Sobrienstatic void ParseErrorInternal(const char *, size_t, int, const char *, ...) 358237578Sobrien MAKE_ATTR_PRINTFLIKE(4,5); 359236769Sobrienstatic void ParseVErrorInternal(FILE *, const char *, size_t, int, const char *, va_list) 360237578Sobrien MAKE_ATTR_PRINTFLIKE(5, 0); 361236769Sobrienstatic int ParseFindKeyword(const char *); 362236769Sobrienstatic int ParseLinkSrc(void *, void *); 363236769Sobrienstatic int ParseDoOp(void *, void *); 364236769Sobrienstatic void ParseDoSrc(int, const char *); 365236769Sobrienstatic int ParseFindMain(void *, void *); 366236769Sobrienstatic int ParseAddDir(void *, void *); 367236769Sobrienstatic int ParseClearPath(void *, void *); 368236769Sobrienstatic void ParseDoDependency(char *); 369236769Sobrienstatic int ParseAddCmd(void *, void *); 370236769Sobrienstatic void ParseHasCommands(void *); 371236769Sobrienstatic void ParseDoInclude(char *); 372236769Sobrienstatic void ParseSetParseFile(const char *); 373268437Ssjgstatic void ParseSetIncludedFile(void); 374236769Sobrien#ifdef SYSVINCLUDE 375236769Sobrienstatic void ParseTraditionalInclude(char *); 376236769Sobrien#endif 377236769Sobrien#ifdef GMAKEEXPORT 378236769Sobrienstatic void ParseGmakeExport(char *); 379236769Sobrien#endif 380236769Sobrienstatic int ParseEOF(void); 381236769Sobrienstatic char *ParseReadLine(void); 382236769Sobrienstatic void ParseFinishLine(void); 383236769Sobrienstatic void ParseMark(GNode *); 384236769Sobrien 385236769Sobrien//////////////////////////////////////////////////////////// 386236769Sobrien// file loader 387236769Sobrien 388236769Sobrienstruct loadedfile { 389236769Sobrien const char *path; /* name, for error reports */ 390236769Sobrien char *buf; /* contents buffer */ 391236769Sobrien size_t len; /* length of contents */ 392236769Sobrien size_t maplen; /* length of mmap area, or 0 */ 393236769Sobrien Boolean used; /* XXX: have we used the data yet */ 394236769Sobrien}; 395236769Sobrien 396236769Sobrien/* 397236769Sobrien * Constructor/destructor for loadedfile 398236769Sobrien */ 399236769Sobrienstatic struct loadedfile * 400236769Sobrienloadedfile_create(const char *path) 401236769Sobrien{ 402236769Sobrien struct loadedfile *lf; 403236769Sobrien 404236769Sobrien lf = bmake_malloc(sizeof(*lf)); 405236769Sobrien lf->path = (path == NULL ? "(stdin)" : path); 406236769Sobrien lf->buf = NULL; 407236769Sobrien lf->len = 0; 408236769Sobrien lf->maplen = 0; 409236769Sobrien lf->used = FALSE; 410236769Sobrien return lf; 411236769Sobrien} 412236769Sobrien 413236769Sobrienstatic void 414236769Sobrienloadedfile_destroy(struct loadedfile *lf) 415236769Sobrien{ 416236769Sobrien if (lf->buf != NULL) { 417236769Sobrien if (lf->maplen > 0) { 418236769Sobrien#ifdef HAVE_MMAP 419236769Sobrien munmap(lf->buf, lf->maplen); 420236769Sobrien#endif 421236769Sobrien } else { 422236769Sobrien free(lf->buf); 423236769Sobrien } 424236769Sobrien } 425236769Sobrien free(lf); 426236769Sobrien} 427236769Sobrien 428236769Sobrien/* 429236769Sobrien * nextbuf() operation for loadedfile, as needed by the weird and twisted 430236769Sobrien * logic below. Once that's cleaned up, we can get rid of lf->used... 431236769Sobrien */ 432236769Sobrienstatic char * 433236769Sobrienloadedfile_nextbuf(void *x, size_t *len) 434236769Sobrien{ 435236769Sobrien struct loadedfile *lf = x; 436236769Sobrien 437236769Sobrien if (lf->used) { 438236769Sobrien return NULL; 439236769Sobrien } 440236769Sobrien lf->used = TRUE; 441236769Sobrien *len = lf->len; 442236769Sobrien return lf->buf; 443236769Sobrien} 444236769Sobrien 445236769Sobrien/* 446236769Sobrien * Try to get the size of a file. 447236769Sobrien */ 448236769Sobrienstatic ReturnStatus 449236769Sobrienload_getsize(int fd, size_t *ret) 450236769Sobrien{ 451236769Sobrien struct stat st; 452236769Sobrien 453236769Sobrien if (fstat(fd, &st) < 0) { 454236769Sobrien return FAILURE; 455236769Sobrien } 456236769Sobrien 457236769Sobrien if (!S_ISREG(st.st_mode)) { 458236769Sobrien return FAILURE; 459236769Sobrien } 460236769Sobrien 461236769Sobrien /* 462236769Sobrien * st_size is an off_t, which is 64 bits signed; *ret is 463236769Sobrien * size_t, which might be 32 bits unsigned or 64 bits 464236769Sobrien * unsigned. Rather than being elaborate, just punt on 465236769Sobrien * files that are more than 2^31 bytes. We should never 466236769Sobrien * see a makefile that size in practice... 467236769Sobrien * 468236769Sobrien * While we're at it reject negative sizes too, just in case. 469236769Sobrien */ 470236769Sobrien if (st.st_size < 0 || st.st_size > 0x7fffffff) { 471236769Sobrien return FAILURE; 472236769Sobrien } 473236769Sobrien 474236769Sobrien *ret = (size_t) st.st_size; 475236769Sobrien return SUCCESS; 476236769Sobrien} 477236769Sobrien 478236769Sobrien/* 479236769Sobrien * Read in a file. 480236769Sobrien * 481236769Sobrien * Until the path search logic can be moved under here instead of 482236769Sobrien * being in the caller in another source file, we need to have the fd 483236769Sobrien * passed in already open. Bleh. 484236769Sobrien * 485236769Sobrien * If the path is NULL use stdin and (to insure against fd leaks) 486236769Sobrien * assert that the caller passed in -1. 487236769Sobrien */ 488236769Sobrienstatic struct loadedfile * 489236769Sobrienloadfile(const char *path, int fd) 490236769Sobrien{ 491236769Sobrien struct loadedfile *lf; 492236769Sobrien#ifdef HAVE_MMAP 493236769Sobrien long pagesize; 494236769Sobrien#endif 495236769Sobrien ssize_t result; 496236769Sobrien size_t bufpos; 497236769Sobrien 498236769Sobrien lf = loadedfile_create(path); 499236769Sobrien 500236769Sobrien if (path == NULL) { 501236769Sobrien assert(fd == -1); 502236769Sobrien fd = STDIN_FILENO; 503236769Sobrien } else { 504236769Sobrien#if 0 /* notyet */ 505236769Sobrien fd = open(path, O_RDONLY); 506236769Sobrien if (fd < 0) { 507236769Sobrien ... 508236769Sobrien Error("%s: %s", path, strerror(errno)); 509236769Sobrien exit(1); 510236769Sobrien } 511236769Sobrien#endif 512236769Sobrien } 513236769Sobrien 514236769Sobrien#ifdef HAVE_MMAP 515236769Sobrien if (load_getsize(fd, &lf->len) == SUCCESS) { 516236769Sobrien /* found a size, try mmap */ 517291978Ssjg#ifdef _SC_PAGESIZE 518236769Sobrien pagesize = sysconf(_SC_PAGESIZE); 519291978Ssjg#else 520291978Ssjg pagesize = 0; 521291978Ssjg#endif 522236769Sobrien if (pagesize <= 0) { 523236769Sobrien pagesize = 0x1000; 524236769Sobrien } 525236769Sobrien /* round size up to a page */ 526236769Sobrien lf->maplen = pagesize * ((lf->len + pagesize - 1)/pagesize); 527236769Sobrien 528236769Sobrien /* 529236769Sobrien * XXX hack for dealing with empty files; remove when 530236769Sobrien * we're no longer limited by interfacing to the old 531236769Sobrien * logic elsewhere in this file. 532236769Sobrien */ 533236769Sobrien if (lf->maplen == 0) { 534236769Sobrien lf->maplen = pagesize; 535236769Sobrien } 536236769Sobrien 537236769Sobrien /* 538236769Sobrien * FUTURE: remove PROT_WRITE when the parser no longer 539236769Sobrien * needs to scribble on the input. 540236769Sobrien */ 541236769Sobrien lf->buf = mmap(NULL, lf->maplen, PROT_READ|PROT_WRITE, 542236769Sobrien MAP_FILE|MAP_COPY, fd, 0); 543236769Sobrien if (lf->buf != MAP_FAILED) { 544236769Sobrien /* succeeded */ 545236769Sobrien if (lf->len == lf->maplen && lf->buf[lf->len - 1] != '\n') { 546319884Ssjg char *b = bmake_malloc(lf->len + 1); 547236769Sobrien b[lf->len] = '\n'; 548236769Sobrien memcpy(b, lf->buf, lf->len++); 549236769Sobrien munmap(lf->buf, lf->maplen); 550236769Sobrien lf->maplen = 0; 551236769Sobrien lf->buf = b; 552236769Sobrien } 553236769Sobrien goto done; 554236769Sobrien } 555236769Sobrien } 556236769Sobrien#endif 557236769Sobrien /* cannot mmap; load the traditional way */ 558236769Sobrien 559236769Sobrien lf->maplen = 0; 560236769Sobrien lf->len = 1024; 561236769Sobrien lf->buf = bmake_malloc(lf->len); 562236769Sobrien 563236769Sobrien bufpos = 0; 564236769Sobrien while (1) { 565236769Sobrien assert(bufpos <= lf->len); 566236769Sobrien if (bufpos == lf->len) { 567319884Ssjg if (lf->len > SIZE_MAX/2) { 568319884Ssjg errno = EFBIG; 569319884Ssjg Error("%s: file too large", path); 570319884Ssjg exit(1); 571319884Ssjg } 572236769Sobrien lf->len *= 2; 573236769Sobrien lf->buf = bmake_realloc(lf->buf, lf->len); 574236769Sobrien } 575319884Ssjg assert(bufpos < lf->len); 576236769Sobrien result = read(fd, lf->buf + bufpos, lf->len - bufpos); 577236769Sobrien if (result < 0) { 578236769Sobrien Error("%s: read error: %s", path, strerror(errno)); 579236769Sobrien exit(1); 580236769Sobrien } 581236769Sobrien if (result == 0) { 582236769Sobrien break; 583236769Sobrien } 584236769Sobrien bufpos += result; 585236769Sobrien } 586236769Sobrien assert(bufpos <= lf->len); 587236769Sobrien lf->len = bufpos; 588236769Sobrien 589236769Sobrien /* truncate malloc region to actual length (maybe not useful) */ 590236769Sobrien if (lf->len > 0) { 591319884Ssjg /* as for mmap case, ensure trailing \n */ 592319884Ssjg if (lf->buf[lf->len - 1] != '\n') 593319884Ssjg lf->len++; 594236769Sobrien lf->buf = bmake_realloc(lf->buf, lf->len); 595319884Ssjg lf->buf[lf->len - 1] = '\n'; 596236769Sobrien } 597236769Sobrien 598236769Sobrien#ifdef HAVE_MMAP 599236769Sobriendone: 600236769Sobrien#endif 601236769Sobrien if (path != NULL) { 602236769Sobrien close(fd); 603236769Sobrien } 604236769Sobrien return lf; 605236769Sobrien} 606236769Sobrien 607236769Sobrien//////////////////////////////////////////////////////////// 608236769Sobrien// old code 609236769Sobrien 610236769Sobrien/*- 611236769Sobrien *---------------------------------------------------------------------- 612236769Sobrien * ParseIsEscaped -- 613236769Sobrien * Check if the current character is escaped on the current line 614236769Sobrien * 615236769Sobrien * Results: 616236769Sobrien * 0 if the character is not backslash escaped, 1 otherwise 617236769Sobrien * 618236769Sobrien * Side Effects: 619236769Sobrien * None 620236769Sobrien *---------------------------------------------------------------------- 621236769Sobrien */ 622236769Sobrienstatic int 623236769SobrienParseIsEscaped(const char *line, const char *c) 624236769Sobrien{ 625236769Sobrien int active = 0; 626236769Sobrien for (;;) { 627236769Sobrien if (line == c) 628236769Sobrien return active; 629236769Sobrien if (*--c != '\\') 630236769Sobrien return active; 631236769Sobrien active = !active; 632236769Sobrien } 633236769Sobrien} 634236769Sobrien 635236769Sobrien/*- 636236769Sobrien *---------------------------------------------------------------------- 637236769Sobrien * ParseFindKeyword -- 638236769Sobrien * Look in the table of keywords for one matching the given string. 639236769Sobrien * 640236769Sobrien * Input: 641236769Sobrien * str String to find 642236769Sobrien * 643236769Sobrien * Results: 644236769Sobrien * The index of the keyword, or -1 if it isn't there. 645236769Sobrien * 646236769Sobrien * Side Effects: 647236769Sobrien * None 648236769Sobrien *---------------------------------------------------------------------- 649236769Sobrien */ 650236769Sobrienstatic int 651236769SobrienParseFindKeyword(const char *str) 652236769Sobrien{ 653236769Sobrien int start, end, cur; 654236769Sobrien int diff; 655236769Sobrien 656236769Sobrien start = 0; 657236769Sobrien end = (sizeof(parseKeywords)/sizeof(parseKeywords[0])) - 1; 658236769Sobrien 659236769Sobrien do { 660236769Sobrien cur = start + ((end - start) / 2); 661236769Sobrien diff = strcmp(str, parseKeywords[cur].name); 662236769Sobrien 663236769Sobrien if (diff == 0) { 664236769Sobrien return (cur); 665236769Sobrien } else if (diff < 0) { 666236769Sobrien end = cur - 1; 667236769Sobrien } else { 668236769Sobrien start = cur + 1; 669236769Sobrien } 670236769Sobrien } while (start <= end); 671236769Sobrien return (-1); 672236769Sobrien} 673236769Sobrien 674236769Sobrien/*- 675236769Sobrien * ParseVErrorInternal -- 676236769Sobrien * Error message abort function for parsing. Prints out the context 677236769Sobrien * of the error (line number and file) as well as the message with 678236769Sobrien * two optional arguments. 679236769Sobrien * 680236769Sobrien * Results: 681236769Sobrien * None 682236769Sobrien * 683236769Sobrien * Side Effects: 684236769Sobrien * "fatals" is incremented if the level is PARSE_FATAL. 685236769Sobrien */ 686236769Sobrien/* VARARGS */ 687236769Sobrienstatic void 688236769SobrienParseVErrorInternal(FILE *f, const char *cfname, size_t clineno, int type, 689236769Sobrien const char *fmt, va_list ap) 690236769Sobrien{ 691236769Sobrien static Boolean fatal_warning_error_printed = FALSE; 692236769Sobrien 693236769Sobrien (void)fprintf(f, "%s: ", progname); 694236769Sobrien 695236769Sobrien if (cfname != NULL) { 696236769Sobrien (void)fprintf(f, "\""); 697236769Sobrien if (*cfname != '/' && strcmp(cfname, "(stdin)") != 0) { 698236769Sobrien char *cp; 699236769Sobrien const char *dir; 700236769Sobrien 701236769Sobrien /* 702236769Sobrien * Nothing is more annoying than not knowing 703236769Sobrien * which Makefile is the culprit. 704236769Sobrien */ 705236769Sobrien dir = Var_Value(".PARSEDIR", VAR_GLOBAL, &cp); 706236769Sobrien if (dir == NULL || *dir == '\0' || 707236769Sobrien (*dir == '.' && dir[1] == '\0')) 708236769Sobrien dir = Var_Value(".CURDIR", VAR_GLOBAL, &cp); 709236769Sobrien if (dir == NULL) 710236769Sobrien dir = "."; 711236769Sobrien 712236769Sobrien (void)fprintf(f, "%s/%s", dir, cfname); 713236769Sobrien } else 714236769Sobrien (void)fprintf(f, "%s", cfname); 715236769Sobrien 716236769Sobrien (void)fprintf(f, "\" line %d: ", (int)clineno); 717236769Sobrien } 718236769Sobrien if (type == PARSE_WARNING) 719236769Sobrien (void)fprintf(f, "warning: "); 720236769Sobrien (void)vfprintf(f, fmt, ap); 721236769Sobrien (void)fprintf(f, "\n"); 722236769Sobrien (void)fflush(f); 723236769Sobrien if (type == PARSE_FATAL || parseWarnFatal) 724236769Sobrien fatals += 1; 725236769Sobrien if (parseWarnFatal && !fatal_warning_error_printed) { 726236769Sobrien Error("parsing warnings being treated as errors"); 727236769Sobrien fatal_warning_error_printed = TRUE; 728236769Sobrien } 729236769Sobrien} 730236769Sobrien 731236769Sobrien/*- 732236769Sobrien * ParseErrorInternal -- 733236769Sobrien * Error function 734236769Sobrien * 735236769Sobrien * Results: 736236769Sobrien * None 737236769Sobrien * 738236769Sobrien * Side Effects: 739236769Sobrien * None 740236769Sobrien */ 741236769Sobrien/* VARARGS */ 742236769Sobrienstatic void 743236769SobrienParseErrorInternal(const char *cfname, size_t clineno, int type, 744236769Sobrien const char *fmt, ...) 745236769Sobrien{ 746236769Sobrien va_list ap; 747236769Sobrien 748236769Sobrien va_start(ap, fmt); 749236769Sobrien (void)fflush(stdout); 750236769Sobrien ParseVErrorInternal(stderr, cfname, clineno, type, fmt, ap); 751236769Sobrien va_end(ap); 752236769Sobrien 753236769Sobrien if (debug_file != stderr && debug_file != stdout) { 754236769Sobrien va_start(ap, fmt); 755236769Sobrien ParseVErrorInternal(debug_file, cfname, clineno, type, fmt, ap); 756236769Sobrien va_end(ap); 757236769Sobrien } 758236769Sobrien} 759236769Sobrien 760236769Sobrien/*- 761236769Sobrien * Parse_Error -- 762236769Sobrien * External interface to ParseErrorInternal; uses the default filename 763236769Sobrien * Line number. 764236769Sobrien * 765236769Sobrien * Results: 766236769Sobrien * None 767236769Sobrien * 768236769Sobrien * Side Effects: 769236769Sobrien * None 770236769Sobrien */ 771236769Sobrien/* VARARGS */ 772236769Sobrienvoid 773236769SobrienParse_Error(int type, const char *fmt, ...) 774236769Sobrien{ 775236769Sobrien va_list ap; 776236769Sobrien const char *fname; 777236769Sobrien size_t lineno; 778236769Sobrien 779236769Sobrien if (curFile == NULL) { 780236769Sobrien fname = NULL; 781236769Sobrien lineno = 0; 782236769Sobrien } else { 783236769Sobrien fname = curFile->fname; 784236769Sobrien lineno = curFile->lineno; 785236769Sobrien } 786236769Sobrien 787236769Sobrien va_start(ap, fmt); 788236769Sobrien (void)fflush(stdout); 789236769Sobrien ParseVErrorInternal(stderr, fname, lineno, type, fmt, ap); 790236769Sobrien va_end(ap); 791236769Sobrien 792236769Sobrien if (debug_file != stderr && debug_file != stdout) { 793236769Sobrien va_start(ap, fmt); 794236769Sobrien ParseVErrorInternal(debug_file, fname, lineno, type, fmt, ap); 795236769Sobrien va_end(ap); 796236769Sobrien } 797236769Sobrien} 798236769Sobrien 799236769Sobrien 800236769Sobrien/* 801236769Sobrien * ParseMessage 802236769Sobrien * Parse a .info .warning or .error directive 803236769Sobrien * 804236769Sobrien * The input is the line minus the ".". We substitute 805236769Sobrien * variables, print the message and exit(1) (for .error) or just print 806236769Sobrien * a warning if the directive is malformed. 807236769Sobrien */ 808236769Sobrienstatic Boolean 809236769SobrienParseMessage(char *line) 810236769Sobrien{ 811236769Sobrien int mtype; 812236769Sobrien 813236769Sobrien switch(*line) { 814236769Sobrien case 'i': 815236769Sobrien mtype = 0; 816236769Sobrien break; 817236769Sobrien case 'w': 818236769Sobrien mtype = PARSE_WARNING; 819236769Sobrien break; 820236769Sobrien case 'e': 821236769Sobrien mtype = PARSE_FATAL; 822236769Sobrien break; 823236769Sobrien default: 824236769Sobrien Parse_Error(PARSE_WARNING, "invalid syntax: \".%s\"", line); 825236769Sobrien return FALSE; 826236769Sobrien } 827236769Sobrien 828300313Ssjg while (isalpha((unsigned char)*line)) 829236769Sobrien line++; 830300313Ssjg if (!isspace((unsigned char)*line)) 831236769Sobrien return FALSE; /* not for us */ 832300313Ssjg while (isspace((unsigned char)*line)) 833236769Sobrien line++; 834236769Sobrien 835296637Ssjg line = Var_Subst(NULL, line, VAR_CMD, VARF_WANTRES); 836236769Sobrien Parse_Error(mtype, "%s", line); 837236769Sobrien free(line); 838236769Sobrien 839236769Sobrien if (mtype == PARSE_FATAL) { 840236769Sobrien /* Terminate immediately. */ 841236769Sobrien exit(1); 842236769Sobrien } 843236769Sobrien return TRUE; 844236769Sobrien} 845236769Sobrien 846236769Sobrien/*- 847236769Sobrien *--------------------------------------------------------------------- 848236769Sobrien * ParseLinkSrc -- 849236769Sobrien * Link the parent node to its new child. Used in a Lst_ForEach by 850236769Sobrien * ParseDoDependency. If the specType isn't 'Not', the parent 851236769Sobrien * isn't linked as a parent of the child. 852236769Sobrien * 853236769Sobrien * Input: 854236769Sobrien * pgnp The parent node 855236769Sobrien * cgpn The child node 856236769Sobrien * 857236769Sobrien * Results: 858236769Sobrien * Always = 0 859236769Sobrien * 860236769Sobrien * Side Effects: 861236769Sobrien * New elements are added to the parents list of cgn and the 862236769Sobrien * children list of cgn. the unmade field of pgn is updated 863236769Sobrien * to reflect the additional child. 864236769Sobrien *--------------------------------------------------------------------- 865236769Sobrien */ 866236769Sobrienstatic int 867236769SobrienParseLinkSrc(void *pgnp, void *cgnp) 868236769Sobrien{ 869236769Sobrien GNode *pgn = (GNode *)pgnp; 870236769Sobrien GNode *cgn = (GNode *)cgnp; 871236769Sobrien 872236769Sobrien if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (pgn->cohorts)) 873236769Sobrien pgn = (GNode *)Lst_Datum(Lst_Last(pgn->cohorts)); 874236769Sobrien (void)Lst_AtEnd(pgn->children, cgn); 875236769Sobrien if (specType == Not) 876236769Sobrien (void)Lst_AtEnd(cgn->parents, pgn); 877236769Sobrien pgn->unmade += 1; 878236769Sobrien if (DEBUG(PARSE)) { 879268437Ssjg fprintf(debug_file, "# %s: added child %s - %s\n", __func__, 880268437Ssjg pgn->name, cgn->name); 881236769Sobrien Targ_PrintNode(pgn, 0); 882236769Sobrien Targ_PrintNode(cgn, 0); 883236769Sobrien } 884236769Sobrien return (0); 885236769Sobrien} 886236769Sobrien 887236769Sobrien/*- 888236769Sobrien *--------------------------------------------------------------------- 889236769Sobrien * ParseDoOp -- 890236769Sobrien * Apply the parsed operator to the given target node. Used in a 891236769Sobrien * Lst_ForEach call by ParseDoDependency once all targets have 892236769Sobrien * been found and their operator parsed. If the previous and new 893236769Sobrien * operators are incompatible, a major error is taken. 894236769Sobrien * 895236769Sobrien * Input: 896236769Sobrien * gnp The node to which the operator is to be applied 897236769Sobrien * opp The operator to apply 898236769Sobrien * 899236769Sobrien * Results: 900236769Sobrien * Always 0 901236769Sobrien * 902236769Sobrien * Side Effects: 903236769Sobrien * The type field of the node is altered to reflect any new bits in 904236769Sobrien * the op. 905236769Sobrien *--------------------------------------------------------------------- 906236769Sobrien */ 907236769Sobrienstatic int 908236769SobrienParseDoOp(void *gnp, void *opp) 909236769Sobrien{ 910236769Sobrien GNode *gn = (GNode *)gnp; 911236769Sobrien int op = *(int *)opp; 912236769Sobrien /* 913236769Sobrien * If the dependency mask of the operator and the node don't match and 914236769Sobrien * the node has actually had an operator applied to it before, and 915236769Sobrien * the operator actually has some dependency information in it, complain. 916236769Sobrien */ 917236769Sobrien if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) && 918236769Sobrien !OP_NOP(gn->type) && !OP_NOP(op)) 919236769Sobrien { 920236769Sobrien Parse_Error(PARSE_FATAL, "Inconsistent operator for %s", gn->name); 921236769Sobrien return (1); 922236769Sobrien } 923236769Sobrien 924236769Sobrien if ((op == OP_DOUBLEDEP) && ((gn->type & OP_OPMASK) == OP_DOUBLEDEP)) { 925236769Sobrien /* 926236769Sobrien * If the node was the object of a :: operator, we need to create a 927236769Sobrien * new instance of it for the children and commands on this dependency 928236769Sobrien * line. The new instance is placed on the 'cohorts' list of the 929236769Sobrien * initial one (note the initial one is not on its own cohorts list) 930236769Sobrien * and the new instance is linked to all parents of the initial 931236769Sobrien * instance. 932236769Sobrien */ 933236769Sobrien GNode *cohort; 934236769Sobrien 935236769Sobrien /* 936236769Sobrien * Propagate copied bits to the initial node. They'll be propagated 937236769Sobrien * back to the rest of the cohorts later. 938236769Sobrien */ 939236769Sobrien gn->type |= op & ~OP_OPMASK; 940236769Sobrien 941236769Sobrien cohort = Targ_FindNode(gn->name, TARG_NOHASH); 942249033Ssjg if (doing_depend) 943249033Ssjg ParseMark(cohort); 944236769Sobrien /* 945236769Sobrien * Make the cohort invisible as well to avoid duplicating it into 946236769Sobrien * other variables. True, parents of this target won't tend to do 947236769Sobrien * anything with their local variables, but better safe than 948236769Sobrien * sorry. (I think this is pointless now, since the relevant list 949236769Sobrien * traversals will no longer see this node anyway. -mycroft) 950236769Sobrien */ 951236769Sobrien cohort->type = op | OP_INVISIBLE; 952236769Sobrien (void)Lst_AtEnd(gn->cohorts, cohort); 953236769Sobrien cohort->centurion = gn; 954236769Sobrien gn->unmade_cohorts += 1; 955236769Sobrien snprintf(cohort->cohort_num, sizeof cohort->cohort_num, "#%d", 956236769Sobrien gn->unmade_cohorts); 957236769Sobrien } else { 958236769Sobrien /* 959236769Sobrien * We don't want to nuke any previous flags (whatever they were) so we 960236769Sobrien * just OR the new operator into the old 961236769Sobrien */ 962236769Sobrien gn->type |= op; 963236769Sobrien } 964236769Sobrien 965236769Sobrien return (0); 966236769Sobrien} 967236769Sobrien 968236769Sobrien/*- 969236769Sobrien *--------------------------------------------------------------------- 970236769Sobrien * ParseDoSrc -- 971236769Sobrien * Given the name of a source, figure out if it is an attribute 972236769Sobrien * and apply it to the targets if it is. Else decide if there is 973236769Sobrien * some attribute which should be applied *to* the source because 974236769Sobrien * of some special target and apply it if so. Otherwise, make the 975236769Sobrien * source be a child of the targets in the list 'targets' 976236769Sobrien * 977236769Sobrien * Input: 978236769Sobrien * tOp operator (if any) from special targets 979236769Sobrien * src name of the source to handle 980236769Sobrien * 981236769Sobrien * Results: 982236769Sobrien * None 983236769Sobrien * 984236769Sobrien * Side Effects: 985236769Sobrien * Operator bits may be added to the list of targets or to the source. 986236769Sobrien * The targets may have a new source added to their lists of children. 987236769Sobrien *--------------------------------------------------------------------- 988236769Sobrien */ 989236769Sobrienstatic void 990236769SobrienParseDoSrc(int tOp, const char *src) 991236769Sobrien{ 992236769Sobrien GNode *gn = NULL; 993236769Sobrien static int wait_number = 0; 994236769Sobrien char wait_src[16]; 995236769Sobrien 996236769Sobrien if (*src == '.' && isupper ((unsigned char)src[1])) { 997236769Sobrien int keywd = ParseFindKeyword(src); 998236769Sobrien if (keywd != -1) { 999236769Sobrien int op = parseKeywords[keywd].op; 1000236769Sobrien if (op != 0) { 1001236769Sobrien Lst_ForEach(targets, ParseDoOp, &op); 1002236769Sobrien return; 1003236769Sobrien } 1004236769Sobrien if (parseKeywords[keywd].spec == Wait) { 1005236769Sobrien /* 1006236769Sobrien * We add a .WAIT node in the dependency list. 1007236769Sobrien * After any dynamic dependencies (and filename globbing) 1008236769Sobrien * have happened, it is given a dependency on the each 1009236769Sobrien * previous child back to and previous .WAIT node. 1010236769Sobrien * The next child won't be scheduled until the .WAIT node 1011236769Sobrien * is built. 1012236769Sobrien * We give each .WAIT node a unique name (mainly for diag). 1013236769Sobrien */ 1014236769Sobrien snprintf(wait_src, sizeof wait_src, ".WAIT_%u", ++wait_number); 1015236769Sobrien gn = Targ_FindNode(wait_src, TARG_NOHASH); 1016249033Ssjg if (doing_depend) 1017249033Ssjg ParseMark(gn); 1018236769Sobrien gn->type = OP_WAIT | OP_PHONY | OP_DEPENDS | OP_NOTMAIN; 1019236769Sobrien Lst_ForEach(targets, ParseLinkSrc, gn); 1020236769Sobrien return; 1021236769Sobrien } 1022236769Sobrien } 1023236769Sobrien } 1024236769Sobrien 1025236769Sobrien switch (specType) { 1026236769Sobrien case Main: 1027236769Sobrien /* 1028236769Sobrien * If we have noted the existence of a .MAIN, it means we need 1029236769Sobrien * to add the sources of said target to the list of things 1030236769Sobrien * to create. The string 'src' is likely to be free, so we 1031236769Sobrien * must make a new copy of it. Note that this will only be 1032236769Sobrien * invoked if the user didn't specify a target on the command 1033236769Sobrien * line. This is to allow #ifmake's to succeed, or something... 1034236769Sobrien */ 1035236769Sobrien (void)Lst_AtEnd(create, bmake_strdup(src)); 1036236769Sobrien /* 1037236769Sobrien * Add the name to the .TARGETS variable as well, so the user can 1038236769Sobrien * employ that, if desired. 1039236769Sobrien */ 1040236769Sobrien Var_Append(".TARGETS", src, VAR_GLOBAL); 1041236769Sobrien return; 1042236769Sobrien 1043236769Sobrien case Order: 1044236769Sobrien /* 1045236769Sobrien * Create proper predecessor/successor links between the previous 1046236769Sobrien * source and the current one. 1047236769Sobrien */ 1048236769Sobrien gn = Targ_FindNode(src, TARG_CREATE); 1049249033Ssjg if (doing_depend) 1050249033Ssjg ParseMark(gn); 1051236769Sobrien if (predecessor != NULL) { 1052236769Sobrien (void)Lst_AtEnd(predecessor->order_succ, gn); 1053236769Sobrien (void)Lst_AtEnd(gn->order_pred, predecessor); 1054236769Sobrien if (DEBUG(PARSE)) { 1055268437Ssjg fprintf(debug_file, "# %s: added Order dependency %s - %s\n", 1056268437Ssjg __func__, predecessor->name, gn->name); 1057236769Sobrien Targ_PrintNode(predecessor, 0); 1058236769Sobrien Targ_PrintNode(gn, 0); 1059236769Sobrien } 1060236769Sobrien } 1061236769Sobrien /* 1062236769Sobrien * The current source now becomes the predecessor for the next one. 1063236769Sobrien */ 1064236769Sobrien predecessor = gn; 1065236769Sobrien break; 1066236769Sobrien 1067236769Sobrien default: 1068236769Sobrien /* 1069236769Sobrien * If the source is not an attribute, we need to find/create 1070236769Sobrien * a node for it. After that we can apply any operator to it 1071236769Sobrien * from a special target or link it to its parents, as 1072236769Sobrien * appropriate. 1073236769Sobrien * 1074236769Sobrien * In the case of a source that was the object of a :: operator, 1075236769Sobrien * the attribute is applied to all of its instances (as kept in 1076236769Sobrien * the 'cohorts' list of the node) or all the cohorts are linked 1077236769Sobrien * to all the targets. 1078236769Sobrien */ 1079236769Sobrien 1080236769Sobrien /* Find/create the 'src' node and attach to all targets */ 1081236769Sobrien gn = Targ_FindNode(src, TARG_CREATE); 1082249033Ssjg if (doing_depend) 1083249033Ssjg ParseMark(gn); 1084236769Sobrien if (tOp) { 1085236769Sobrien gn->type |= tOp; 1086236769Sobrien } else { 1087236769Sobrien Lst_ForEach(targets, ParseLinkSrc, gn); 1088236769Sobrien } 1089236769Sobrien break; 1090236769Sobrien } 1091236769Sobrien} 1092236769Sobrien 1093236769Sobrien/*- 1094236769Sobrien *----------------------------------------------------------------------- 1095236769Sobrien * ParseFindMain -- 1096236769Sobrien * Find a real target in the list and set it to be the main one. 1097236769Sobrien * Called by ParseDoDependency when a main target hasn't been found 1098236769Sobrien * yet. 1099236769Sobrien * 1100236769Sobrien * Input: 1101236769Sobrien * gnp Node to examine 1102236769Sobrien * 1103236769Sobrien * Results: 1104236769Sobrien * 0 if main not found yet, 1 if it is. 1105236769Sobrien * 1106236769Sobrien * Side Effects: 1107236769Sobrien * mainNode is changed and Targ_SetMain is called. 1108236769Sobrien * 1109236769Sobrien *----------------------------------------------------------------------- 1110236769Sobrien */ 1111236769Sobrienstatic int 1112319884SsjgParseFindMain(void *gnp, void *dummy MAKE_ATTR_UNUSED) 1113236769Sobrien{ 1114236769Sobrien GNode *gn = (GNode *)gnp; 1115236769Sobrien if ((gn->type & OP_NOTARGET) == 0) { 1116236769Sobrien mainNode = gn; 1117236769Sobrien Targ_SetMain(gn); 1118319884Ssjg return 1; 1119236769Sobrien } else { 1120319884Ssjg return 0; 1121236769Sobrien } 1122236769Sobrien} 1123236769Sobrien 1124236769Sobrien/*- 1125236769Sobrien *----------------------------------------------------------------------- 1126236769Sobrien * ParseAddDir -- 1127236769Sobrien * Front-end for Dir_AddDir to make sure Lst_ForEach keeps going 1128236769Sobrien * 1129236769Sobrien * Results: 1130236769Sobrien * === 0 1131236769Sobrien * 1132236769Sobrien * Side Effects: 1133236769Sobrien * See Dir_AddDir. 1134236769Sobrien * 1135236769Sobrien *----------------------------------------------------------------------- 1136236769Sobrien */ 1137236769Sobrienstatic int 1138236769SobrienParseAddDir(void *path, void *name) 1139236769Sobrien{ 1140236769Sobrien (void)Dir_AddDir((Lst) path, (char *)name); 1141236769Sobrien return(0); 1142236769Sobrien} 1143236769Sobrien 1144236769Sobrien/*- 1145236769Sobrien *----------------------------------------------------------------------- 1146236769Sobrien * ParseClearPath -- 1147236769Sobrien * Front-end for Dir_ClearPath to make sure Lst_ForEach keeps going 1148236769Sobrien * 1149236769Sobrien * Results: 1150236769Sobrien * === 0 1151236769Sobrien * 1152236769Sobrien * Side Effects: 1153236769Sobrien * See Dir_ClearPath 1154236769Sobrien * 1155236769Sobrien *----------------------------------------------------------------------- 1156236769Sobrien */ 1157236769Sobrienstatic int 1158319884SsjgParseClearPath(void *path, void *dummy MAKE_ATTR_UNUSED) 1159236769Sobrien{ 1160236769Sobrien Dir_ClearPath((Lst) path); 1161319884Ssjg return 0; 1162236769Sobrien} 1163236769Sobrien 1164236769Sobrien/*- 1165236769Sobrien *--------------------------------------------------------------------- 1166236769Sobrien * ParseDoDependency -- 1167236769Sobrien * Parse the dependency line in line. 1168236769Sobrien * 1169236769Sobrien * Input: 1170236769Sobrien * line the line to parse 1171236769Sobrien * 1172236769Sobrien * Results: 1173236769Sobrien * None 1174236769Sobrien * 1175236769Sobrien * Side Effects: 1176236769Sobrien * The nodes of the sources are linked as children to the nodes of the 1177236769Sobrien * targets. Some nodes may be created. 1178236769Sobrien * 1179236769Sobrien * We parse a dependency line by first extracting words from the line and 1180236769Sobrien * finding nodes in the list of all targets with that name. This is done 1181236769Sobrien * until a character is encountered which is an operator character. Currently 1182236769Sobrien * these are only ! and :. At this point the operator is parsed and the 1183236769Sobrien * pointer into the line advanced until the first source is encountered. 1184236769Sobrien * The parsed operator is applied to each node in the 'targets' list, 1185236769Sobrien * which is where the nodes found for the targets are kept, by means of 1186236769Sobrien * the ParseDoOp function. 1187236769Sobrien * The sources are read in much the same way as the targets were except 1188236769Sobrien * that now they are expanded using the wildcarding scheme of the C-Shell 1189236769Sobrien * and all instances of the resulting words in the list of all targets 1190236769Sobrien * are found. Each of the resulting nodes is then linked to each of the 1191236769Sobrien * targets as one of its children. 1192236769Sobrien * Certain targets are handled specially. These are the ones detailed 1193236769Sobrien * by the specType variable. 1194236769Sobrien * The storing of transformation rules is also taken care of here. 1195236769Sobrien * A target is recognized as a transformation rule by calling 1196236769Sobrien * Suff_IsTransform. If it is a transformation rule, its node is gotten 1197236769Sobrien * from the suffix module via Suff_AddTransform rather than the standard 1198236769Sobrien * Targ_FindNode in the target module. 1199236769Sobrien *--------------------------------------------------------------------- 1200236769Sobrien */ 1201236769Sobrienstatic void 1202236769SobrienParseDoDependency(char *line) 1203236769Sobrien{ 1204236769Sobrien char *cp; /* our current position */ 1205236769Sobrien GNode *gn = NULL; /* a general purpose temporary node */ 1206236769Sobrien int op; /* the operator on the line */ 1207236769Sobrien char savec; /* a place to save a character */ 1208236769Sobrien Lst paths; /* List of search paths to alter when parsing 1209236769Sobrien * a list of .PATH targets */ 1210236769Sobrien int tOp; /* operator from special target */ 1211236769Sobrien Lst sources; /* list of archive source names after 1212236769Sobrien * expansion */ 1213236769Sobrien Lst curTargs; /* list of target names to be found and added 1214236769Sobrien * to the targets list */ 1215236769Sobrien char *lstart = line; 1216236769Sobrien 1217236769Sobrien if (DEBUG(PARSE)) 1218236769Sobrien fprintf(debug_file, "ParseDoDependency(%s)\n", line); 1219236769Sobrien tOp = 0; 1220236769Sobrien 1221236769Sobrien specType = Not; 1222236769Sobrien paths = NULL; 1223236769Sobrien 1224236769Sobrien curTargs = Lst_Init(FALSE); 1225236769Sobrien 1226281812Ssjg /* 1227281812Ssjg * First, grind through the targets. 1228281812Ssjg */ 1229281812Ssjg 1230236769Sobrien do { 1231281812Ssjg /* 1232281812Ssjg * Here LINE points to the beginning of the next word, and 1233281812Ssjg * LSTART points to the actual beginning of the line. 1234281812Ssjg */ 1235281812Ssjg 1236281812Ssjg /* Find the end of the next word. */ 1237236769Sobrien for (cp = line; *cp && (ParseIsEscaped(lstart, cp) || 1238236769Sobrien !(isspace((unsigned char)*cp) || 1239236769Sobrien *cp == '!' || *cp == ':' || *cp == LPAREN)); 1240236769Sobrien cp++) { 1241236769Sobrien if (*cp == '$') { 1242236769Sobrien /* 1243236769Sobrien * Must be a dynamic source (would have been expanded 1244236769Sobrien * otherwise), so call the Var module to parse the puppy 1245236769Sobrien * so we can safely advance beyond it...There should be 1246236769Sobrien * no errors in this, as they would have been discovered 1247236769Sobrien * in the initial Var_Subst and we wouldn't be here. 1248236769Sobrien */ 1249236769Sobrien int length; 1250236769Sobrien void *freeIt; 1251236769Sobrien 1252296637Ssjg (void)Var_Parse(cp, VAR_CMD, VARF_UNDEFERR|VARF_WANTRES, 1253296637Ssjg &length, &freeIt); 1254296637Ssjg free(freeIt); 1255236769Sobrien cp += length-1; 1256236769Sobrien } 1257236769Sobrien } 1258236769Sobrien 1259281812Ssjg /* 1260281812Ssjg * If the word is followed by a left parenthesis, it's the 1261281812Ssjg * name of an object file inside an archive (ar file). 1262281812Ssjg */ 1263236769Sobrien if (!ParseIsEscaped(lstart, cp) && *cp == LPAREN) { 1264236769Sobrien /* 1265236769Sobrien * Archives must be handled specially to make sure the OP_ARCHV 1266236769Sobrien * flag is set in their 'type' field, for one thing, and because 1267236769Sobrien * things like "archive(file1.o file2.o file3.o)" are permissible. 1268236769Sobrien * Arch_ParseArchive will set 'line' to be the first non-blank 1269236769Sobrien * after the archive-spec. It creates/finds nodes for the members 1270236769Sobrien * and places them on the given list, returning SUCCESS if all 1271236769Sobrien * went well and FAILURE if there was an error in the 1272236769Sobrien * specification. On error, line should remain untouched. 1273236769Sobrien */ 1274236769Sobrien if (Arch_ParseArchive(&line, targets, VAR_CMD) != SUCCESS) { 1275236769Sobrien Parse_Error(PARSE_FATAL, 1276236769Sobrien "Error in archive specification: \"%s\"", line); 1277236769Sobrien goto out; 1278236769Sobrien } else { 1279281812Ssjg /* Done with this word; on to the next. */ 1280297040Ssjg cp = line; 1281236769Sobrien continue; 1282236769Sobrien } 1283236769Sobrien } 1284236769Sobrien 1285236769Sobrien if (!*cp) { 1286236769Sobrien /* 1287281812Ssjg * We got to the end of the line while we were still 1288281812Ssjg * looking at targets. 1289281812Ssjg * 1290236769Sobrien * Ending a dependency line without an operator is a Bozo 1291236769Sobrien * no-no. As a heuristic, this is also often triggered by 1292236769Sobrien * undetected conflicts from cvs/rcs merges. 1293236769Sobrien */ 1294236769Sobrien if ((strncmp(line, "<<<<<<", 6) == 0) || 1295236769Sobrien (strncmp(line, "======", 6) == 0) || 1296236769Sobrien (strncmp(line, ">>>>>>", 6) == 0)) 1297236769Sobrien Parse_Error(PARSE_FATAL, 1298236769Sobrien "Makefile appears to contain unresolved cvs/rcs/??? merge conflicts"); 1299236769Sobrien else 1300236769Sobrien Parse_Error(PARSE_FATAL, lstart[0] == '.' ? "Unknown directive" 1301236769Sobrien : "Need an operator"); 1302236769Sobrien goto out; 1303236769Sobrien } 1304281812Ssjg 1305281812Ssjg /* Insert a null terminator. */ 1306281812Ssjg savec = *cp; 1307236769Sobrien *cp = '\0'; 1308236769Sobrien 1309236769Sobrien /* 1310281812Ssjg * Got the word. See if it's a special target and if so set 1311236769Sobrien * specType to match it. 1312236769Sobrien */ 1313236769Sobrien if (*line == '.' && isupper ((unsigned char)line[1])) { 1314236769Sobrien /* 1315236769Sobrien * See if the target is a special target that must have it 1316236769Sobrien * or its sources handled specially. 1317236769Sobrien */ 1318236769Sobrien int keywd = ParseFindKeyword(line); 1319236769Sobrien if (keywd != -1) { 1320236769Sobrien if (specType == ExPath && parseKeywords[keywd].spec != ExPath) { 1321236769Sobrien Parse_Error(PARSE_FATAL, "Mismatched special targets"); 1322236769Sobrien goto out; 1323236769Sobrien } 1324236769Sobrien 1325236769Sobrien specType = parseKeywords[keywd].spec; 1326236769Sobrien tOp = parseKeywords[keywd].op; 1327236769Sobrien 1328236769Sobrien /* 1329236769Sobrien * Certain special targets have special semantics: 1330236769Sobrien * .PATH Have to set the dirSearchPath 1331236769Sobrien * variable too 1332236769Sobrien * .MAIN Its sources are only used if 1333236769Sobrien * nothing has been specified to 1334236769Sobrien * create. 1335236769Sobrien * .DEFAULT Need to create a node to hang 1336236769Sobrien * commands on, but we don't want 1337236769Sobrien * it in the graph, nor do we want 1338236769Sobrien * it to be the Main Target, so we 1339236769Sobrien * create it, set OP_NOTMAIN and 1340236769Sobrien * add it to the list, setting 1341236769Sobrien * DEFAULT to the new node for 1342236769Sobrien * later use. We claim the node is 1343236769Sobrien * A transformation rule to make 1344236769Sobrien * life easier later, when we'll 1345236769Sobrien * use Make_HandleUse to actually 1346236769Sobrien * apply the .DEFAULT commands. 1347236769Sobrien * .PHONY The list of targets 1348236769Sobrien * .NOPATH Don't search for file in the path 1349249033Ssjg * .STALE 1350236769Sobrien * .BEGIN 1351236769Sobrien * .END 1352236769Sobrien * .ERROR 1353319884Ssjg * .DELETE_ON_ERROR 1354236769Sobrien * .INTERRUPT Are not to be considered the 1355236769Sobrien * main target. 1356236769Sobrien * .NOTPARALLEL Make only one target at a time. 1357236769Sobrien * .SINGLESHELL Create a shell for each command. 1358236769Sobrien * .ORDER Must set initial predecessor to NULL 1359236769Sobrien */ 1360236769Sobrien switch (specType) { 1361249033Ssjg case ExPath: 1362249033Ssjg if (paths == NULL) { 1363249033Ssjg paths = Lst_Init(FALSE); 1364249033Ssjg } 1365249033Ssjg (void)Lst_AtEnd(paths, dirSearchPath); 1366249033Ssjg break; 1367249033Ssjg case Main: 1368249033Ssjg if (!Lst_IsEmpty(create)) { 1369249033Ssjg specType = Not; 1370249033Ssjg } 1371249033Ssjg break; 1372249033Ssjg case Begin: 1373249033Ssjg case End: 1374249033Ssjg case Stale: 1375249033Ssjg case dotError: 1376249033Ssjg case Interrupt: 1377249033Ssjg gn = Targ_FindNode(line, TARG_CREATE); 1378249033Ssjg if (doing_depend) 1379249033Ssjg ParseMark(gn); 1380249033Ssjg gn->type |= OP_NOTMAIN|OP_SPECIAL; 1381249033Ssjg (void)Lst_AtEnd(targets, gn); 1382249033Ssjg break; 1383249033Ssjg case Default: 1384249033Ssjg gn = Targ_NewGN(".DEFAULT"); 1385249033Ssjg gn->type |= (OP_NOTMAIN|OP_TRANSFORM); 1386249033Ssjg (void)Lst_AtEnd(targets, gn); 1387249033Ssjg DEFAULT = gn; 1388249033Ssjg break; 1389319884Ssjg case DeleteOnError: 1390319884Ssjg deleteOnError = TRUE; 1391319884Ssjg break; 1392249033Ssjg case NotParallel: 1393249033Ssjg maxJobs = 1; 1394249033Ssjg break; 1395249033Ssjg case SingleShell: 1396249033Ssjg compatMake = TRUE; 1397249033Ssjg break; 1398249033Ssjg case Order: 1399249033Ssjg predecessor = NULL; 1400249033Ssjg break; 1401249033Ssjg default: 1402249033Ssjg break; 1403236769Sobrien } 1404236769Sobrien } else if (strncmp(line, ".PATH", 5) == 0) { 1405236769Sobrien /* 1406236769Sobrien * .PATH<suffix> has to be handled specially. 1407236769Sobrien * Call on the suffix module to give us a path to 1408236769Sobrien * modify. 1409236769Sobrien */ 1410236769Sobrien Lst path; 1411236769Sobrien 1412236769Sobrien specType = ExPath; 1413236769Sobrien path = Suff_GetPath(&line[5]); 1414236769Sobrien if (path == NULL) { 1415236769Sobrien Parse_Error(PARSE_FATAL, 1416236769Sobrien "Suffix '%s' not defined (yet)", 1417236769Sobrien &line[5]); 1418236769Sobrien goto out; 1419236769Sobrien } else { 1420236769Sobrien if (paths == NULL) { 1421236769Sobrien paths = Lst_Init(FALSE); 1422236769Sobrien } 1423236769Sobrien (void)Lst_AtEnd(paths, path); 1424236769Sobrien } 1425236769Sobrien } 1426236769Sobrien } 1427236769Sobrien 1428236769Sobrien /* 1429236769Sobrien * Have word in line. Get or create its node and stick it at 1430236769Sobrien * the end of the targets list 1431236769Sobrien */ 1432236769Sobrien if ((specType == Not) && (*line != '\0')) { 1433236769Sobrien if (Dir_HasWildcards(line)) { 1434236769Sobrien /* 1435236769Sobrien * Targets are to be sought only in the current directory, 1436236769Sobrien * so create an empty path for the thing. Note we need to 1437236769Sobrien * use Dir_Destroy in the destruction of the path as the 1438236769Sobrien * Dir module could have added a directory to the path... 1439236769Sobrien */ 1440236769Sobrien Lst emptyPath = Lst_Init(FALSE); 1441236769Sobrien 1442236769Sobrien Dir_Expand(line, emptyPath, curTargs); 1443236769Sobrien 1444236769Sobrien Lst_Destroy(emptyPath, Dir_Destroy); 1445236769Sobrien } else { 1446236769Sobrien /* 1447236769Sobrien * No wildcards, but we want to avoid code duplication, 1448236769Sobrien * so create a list with the word on it. 1449236769Sobrien */ 1450236769Sobrien (void)Lst_AtEnd(curTargs, line); 1451236769Sobrien } 1452236769Sobrien 1453281812Ssjg /* Apply the targets. */ 1454281812Ssjg 1455236769Sobrien while(!Lst_IsEmpty(curTargs)) { 1456236769Sobrien char *targName = (char *)Lst_DeQueue(curTargs); 1457236769Sobrien 1458236769Sobrien if (!Suff_IsTransform (targName)) { 1459236769Sobrien gn = Targ_FindNode(targName, TARG_CREATE); 1460236769Sobrien } else { 1461236769Sobrien gn = Suff_AddTransform(targName); 1462236769Sobrien } 1463249033Ssjg if (doing_depend) 1464249033Ssjg ParseMark(gn); 1465236769Sobrien 1466236769Sobrien (void)Lst_AtEnd(targets, gn); 1467236769Sobrien } 1468236769Sobrien } else if (specType == ExPath && *line != '.' && *line != '\0') { 1469236769Sobrien Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line); 1470236769Sobrien } 1471236769Sobrien 1472281812Ssjg /* Don't need the inserted null terminator any more. */ 1473236769Sobrien *cp = savec; 1474281812Ssjg 1475236769Sobrien /* 1476236769Sobrien * If it is a special type and not .PATH, it's the only target we 1477236769Sobrien * allow on this line... 1478236769Sobrien */ 1479236769Sobrien if (specType != Not && specType != ExPath) { 1480236769Sobrien Boolean warning = FALSE; 1481236769Sobrien 1482236769Sobrien while (*cp && (ParseIsEscaped(lstart, cp) || 1483236769Sobrien ((*cp != '!') && (*cp != ':')))) { 1484236769Sobrien if (ParseIsEscaped(lstart, cp) || 1485236769Sobrien (*cp != ' ' && *cp != '\t')) { 1486236769Sobrien warning = TRUE; 1487236769Sobrien } 1488236769Sobrien cp++; 1489236769Sobrien } 1490236769Sobrien if (warning) { 1491236769Sobrien Parse_Error(PARSE_WARNING, "Extra target ignored"); 1492236769Sobrien } 1493236769Sobrien } else { 1494236769Sobrien while (*cp && isspace ((unsigned char)*cp)) { 1495236769Sobrien cp++; 1496236769Sobrien } 1497236769Sobrien } 1498236769Sobrien line = cp; 1499236769Sobrien } while (*line && (ParseIsEscaped(lstart, line) || 1500236769Sobrien ((*line != '!') && (*line != ':')))); 1501236769Sobrien 1502236769Sobrien /* 1503236769Sobrien * Don't need the list of target names anymore... 1504236769Sobrien */ 1505236769Sobrien Lst_Destroy(curTargs, NULL); 1506236769Sobrien curTargs = NULL; 1507236769Sobrien 1508236769Sobrien if (!Lst_IsEmpty(targets)) { 1509236769Sobrien switch(specType) { 1510236769Sobrien default: 1511236769Sobrien Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. Mundane ones ignored"); 1512236769Sobrien break; 1513236769Sobrien case Default: 1514249033Ssjg case Stale: 1515236769Sobrien case Begin: 1516236769Sobrien case End: 1517236769Sobrien case dotError: 1518236769Sobrien case Interrupt: 1519236769Sobrien /* 1520236769Sobrien * These four create nodes on which to hang commands, so 1521236769Sobrien * targets shouldn't be empty... 1522236769Sobrien */ 1523236769Sobrien case Not: 1524236769Sobrien /* 1525236769Sobrien * Nothing special here -- targets can be empty if it wants. 1526236769Sobrien */ 1527236769Sobrien break; 1528236769Sobrien } 1529236769Sobrien } 1530236769Sobrien 1531236769Sobrien /* 1532236769Sobrien * Have now parsed all the target names. Must parse the operator next. The 1533236769Sobrien * result is left in op . 1534236769Sobrien */ 1535236769Sobrien if (*cp == '!') { 1536236769Sobrien op = OP_FORCE; 1537236769Sobrien } else if (*cp == ':') { 1538236769Sobrien if (cp[1] == ':') { 1539236769Sobrien op = OP_DOUBLEDEP; 1540236769Sobrien cp++; 1541236769Sobrien } else { 1542236769Sobrien op = OP_DEPENDS; 1543236769Sobrien } 1544236769Sobrien } else { 1545236769Sobrien Parse_Error(PARSE_FATAL, lstart[0] == '.' ? "Unknown directive" 1546236769Sobrien : "Missing dependency operator"); 1547236769Sobrien goto out; 1548236769Sobrien } 1549236769Sobrien 1550281812Ssjg /* Advance beyond the operator */ 1551281812Ssjg cp++; 1552236769Sobrien 1553281812Ssjg /* 1554281812Ssjg * Apply the operator to the target. This is how we remember which 1555281812Ssjg * operator a target was defined with. It fails if the operator 1556281812Ssjg * used isn't consistent across all references. 1557281812Ssjg */ 1558236769Sobrien Lst_ForEach(targets, ParseDoOp, &op); 1559236769Sobrien 1560236769Sobrien /* 1561281812Ssjg * Onward to the sources. 1562281812Ssjg * 1563281812Ssjg * LINE will now point to the first source word, if any, or the 1564281812Ssjg * end of the string if not. 1565236769Sobrien */ 1566236769Sobrien while (*cp && isspace ((unsigned char)*cp)) { 1567236769Sobrien cp++; 1568236769Sobrien } 1569236769Sobrien line = cp; 1570236769Sobrien 1571236769Sobrien /* 1572236769Sobrien * Several special targets take different actions if present with no 1573236769Sobrien * sources: 1574236769Sobrien * a .SUFFIXES line with no sources clears out all old suffixes 1575236769Sobrien * a .PRECIOUS line makes all targets precious 1576236769Sobrien * a .IGNORE line ignores errors for all targets 1577236769Sobrien * a .SILENT line creates silence when making all targets 1578236769Sobrien * a .PATH removes all directories from the search path(s). 1579236769Sobrien */ 1580236769Sobrien if (!*line) { 1581236769Sobrien switch (specType) { 1582236769Sobrien case Suffixes: 1583236769Sobrien Suff_ClearSuffixes(); 1584236769Sobrien break; 1585236769Sobrien case Precious: 1586236769Sobrien allPrecious = TRUE; 1587236769Sobrien break; 1588236769Sobrien case Ignore: 1589236769Sobrien ignoreErrors = TRUE; 1590236769Sobrien break; 1591236769Sobrien case Silent: 1592236769Sobrien beSilent = TRUE; 1593236769Sobrien break; 1594236769Sobrien case ExPath: 1595236769Sobrien Lst_ForEach(paths, ParseClearPath, NULL); 1596236769Sobrien Dir_SetPATH(); 1597236769Sobrien break; 1598236769Sobrien#ifdef POSIX 1599236769Sobrien case Posix: 1600236769Sobrien Var_Set("%POSIX", "1003.2", VAR_GLOBAL, 0); 1601236769Sobrien break; 1602236769Sobrien#endif 1603236769Sobrien default: 1604236769Sobrien break; 1605236769Sobrien } 1606236769Sobrien } else if (specType == MFlags) { 1607236769Sobrien /* 1608236769Sobrien * Call on functions in main.c to deal with these arguments and 1609236769Sobrien * set the initial character to a null-character so the loop to 1610236769Sobrien * get sources won't get anything 1611236769Sobrien */ 1612236769Sobrien Main_ParseArgLine(line); 1613236769Sobrien *line = '\0'; 1614236769Sobrien } else if (specType == ExShell) { 1615236769Sobrien if (Job_ParseShell(line) != SUCCESS) { 1616236769Sobrien Parse_Error(PARSE_FATAL, "improper shell specification"); 1617236769Sobrien goto out; 1618236769Sobrien } 1619236769Sobrien *line = '\0'; 1620319884Ssjg } else if ((specType == NotParallel) || (specType == SingleShell) || 1621319884Ssjg (specType == DeleteOnError)) { 1622236769Sobrien *line = '\0'; 1623236769Sobrien } 1624236769Sobrien 1625236769Sobrien /* 1626236769Sobrien * NOW GO FOR THE SOURCES 1627236769Sobrien */ 1628236769Sobrien if ((specType == Suffixes) || (specType == ExPath) || 1629236769Sobrien (specType == Includes) || (specType == Libs) || 1630236769Sobrien (specType == Null) || (specType == ExObjdir)) 1631236769Sobrien { 1632236769Sobrien while (*line) { 1633236769Sobrien /* 1634236769Sobrien * If the target was one that doesn't take files as its sources 1635236769Sobrien * but takes something like suffixes, we take each 1636236769Sobrien * space-separated word on the line as a something and deal 1637236769Sobrien * with it accordingly. 1638236769Sobrien * 1639236769Sobrien * If the target was .SUFFIXES, we take each source as a 1640236769Sobrien * suffix and add it to the list of suffixes maintained by the 1641236769Sobrien * Suff module. 1642236769Sobrien * 1643236769Sobrien * If the target was a .PATH, we add the source as a directory 1644236769Sobrien * to search on the search path. 1645236769Sobrien * 1646236769Sobrien * If it was .INCLUDES, the source is taken to be the suffix of 1647236769Sobrien * files which will be #included and whose search path should 1648236769Sobrien * be present in the .INCLUDES variable. 1649236769Sobrien * 1650236769Sobrien * If it was .LIBS, the source is taken to be the suffix of 1651236769Sobrien * files which are considered libraries and whose search path 1652236769Sobrien * should be present in the .LIBS variable. 1653236769Sobrien * 1654236769Sobrien * If it was .NULL, the source is the suffix to use when a file 1655236769Sobrien * has no valid suffix. 1656236769Sobrien * 1657236769Sobrien * If it was .OBJDIR, the source is a new definition for .OBJDIR, 1658236769Sobrien * and will cause make to do a new chdir to that path. 1659236769Sobrien */ 1660236769Sobrien while (*cp && !isspace ((unsigned char)*cp)) { 1661236769Sobrien cp++; 1662236769Sobrien } 1663236769Sobrien savec = *cp; 1664236769Sobrien *cp = '\0'; 1665236769Sobrien switch (specType) { 1666236769Sobrien case Suffixes: 1667236769Sobrien Suff_AddSuffix(line, &mainNode); 1668236769Sobrien break; 1669236769Sobrien case ExPath: 1670236769Sobrien Lst_ForEach(paths, ParseAddDir, line); 1671236769Sobrien break; 1672236769Sobrien case Includes: 1673236769Sobrien Suff_AddInclude(line); 1674236769Sobrien break; 1675236769Sobrien case Libs: 1676236769Sobrien Suff_AddLib(line); 1677236769Sobrien break; 1678236769Sobrien case Null: 1679236769Sobrien Suff_SetNull(line); 1680236769Sobrien break; 1681236769Sobrien case ExObjdir: 1682319884Ssjg Main_SetObjdir("%s", line); 1683236769Sobrien break; 1684236769Sobrien default: 1685236769Sobrien break; 1686236769Sobrien } 1687236769Sobrien *cp = savec; 1688236769Sobrien if (savec != '\0') { 1689236769Sobrien cp++; 1690236769Sobrien } 1691236769Sobrien while (*cp && isspace ((unsigned char)*cp)) { 1692236769Sobrien cp++; 1693236769Sobrien } 1694236769Sobrien line = cp; 1695236769Sobrien } 1696236769Sobrien if (paths) { 1697236769Sobrien Lst_Destroy(paths, NULL); 1698319884Ssjg paths = NULL; 1699236769Sobrien } 1700236769Sobrien if (specType == ExPath) 1701236769Sobrien Dir_SetPATH(); 1702236769Sobrien } else { 1703319884Ssjg assert(paths == NULL); 1704236769Sobrien while (*line) { 1705236769Sobrien /* 1706236769Sobrien * The targets take real sources, so we must beware of archive 1707236769Sobrien * specifications (i.e. things with left parentheses in them) 1708236769Sobrien * and handle them accordingly. 1709236769Sobrien */ 1710236769Sobrien for (; *cp && !isspace ((unsigned char)*cp); cp++) { 1711236769Sobrien if ((*cp == LPAREN) && (cp > line) && (cp[-1] != '$')) { 1712236769Sobrien /* 1713236769Sobrien * Only stop for a left parenthesis if it isn't at the 1714236769Sobrien * start of a word (that'll be for variable changes 1715236769Sobrien * later) and isn't preceded by a dollar sign (a dynamic 1716236769Sobrien * source). 1717236769Sobrien */ 1718236769Sobrien break; 1719236769Sobrien } 1720236769Sobrien } 1721236769Sobrien 1722236769Sobrien if (*cp == LPAREN) { 1723236769Sobrien sources = Lst_Init(FALSE); 1724236769Sobrien if (Arch_ParseArchive(&line, sources, VAR_CMD) != SUCCESS) { 1725236769Sobrien Parse_Error(PARSE_FATAL, 1726236769Sobrien "Error in source archive spec \"%s\"", line); 1727236769Sobrien goto out; 1728236769Sobrien } 1729236769Sobrien 1730236769Sobrien while (!Lst_IsEmpty (sources)) { 1731236769Sobrien gn = (GNode *)Lst_DeQueue(sources); 1732236769Sobrien ParseDoSrc(tOp, gn->name); 1733236769Sobrien } 1734236769Sobrien Lst_Destroy(sources, NULL); 1735236769Sobrien cp = line; 1736236769Sobrien } else { 1737236769Sobrien if (*cp) { 1738236769Sobrien *cp = '\0'; 1739236769Sobrien cp += 1; 1740236769Sobrien } 1741236769Sobrien 1742236769Sobrien ParseDoSrc(tOp, line); 1743236769Sobrien } 1744236769Sobrien while (*cp && isspace ((unsigned char)*cp)) { 1745236769Sobrien cp++; 1746236769Sobrien } 1747236769Sobrien line = cp; 1748236769Sobrien } 1749236769Sobrien } 1750236769Sobrien 1751236769Sobrien if (mainNode == NULL) { 1752236769Sobrien /* 1753236769Sobrien * If we have yet to decide on a main target to make, in the 1754236769Sobrien * absence of any user input, we want the first target on 1755236769Sobrien * the first dependency line that is actually a real target 1756236769Sobrien * (i.e. isn't a .USE or .EXEC rule) to be made. 1757236769Sobrien */ 1758236769Sobrien Lst_ForEach(targets, ParseFindMain, NULL); 1759236769Sobrien } 1760236769Sobrien 1761236769Sobrienout: 1762319884Ssjg assert(paths == NULL); 1763236769Sobrien if (curTargs) 1764236769Sobrien Lst_Destroy(curTargs, NULL); 1765236769Sobrien} 1766236769Sobrien 1767236769Sobrien/*- 1768236769Sobrien *--------------------------------------------------------------------- 1769236769Sobrien * Parse_IsVar -- 1770236769Sobrien * Return TRUE if the passed line is a variable assignment. A variable 1771236769Sobrien * assignment consists of a single word followed by optional whitespace 1772236769Sobrien * followed by either a += or an = operator. 1773236769Sobrien * This function is used both by the Parse_File function and main when 1774236769Sobrien * parsing the command-line arguments. 1775236769Sobrien * 1776236769Sobrien * Input: 1777236769Sobrien * line the line to check 1778236769Sobrien * 1779236769Sobrien * Results: 1780236769Sobrien * TRUE if it is. FALSE if it ain't 1781236769Sobrien * 1782236769Sobrien * Side Effects: 1783236769Sobrien * none 1784236769Sobrien *--------------------------------------------------------------------- 1785236769Sobrien */ 1786236769SobrienBoolean 1787236769SobrienParse_IsVar(char *line) 1788236769Sobrien{ 1789236769Sobrien Boolean wasSpace = FALSE; /* set TRUE if found a space */ 1790236769Sobrien char ch; 1791236769Sobrien int level = 0; 1792236769Sobrien#define ISEQOPERATOR(c) \ 1793236769Sobrien (((c) == '+') || ((c) == ':') || ((c) == '?') || ((c) == '!')) 1794236769Sobrien 1795236769Sobrien /* 1796236769Sobrien * Skip to variable name 1797236769Sobrien */ 1798236769Sobrien for (;(*line == ' ') || (*line == '\t'); line++) 1799236769Sobrien continue; 1800236769Sobrien 1801236769Sobrien /* Scan for one of the assignment operators outside a variable expansion */ 1802236769Sobrien while ((ch = *line++) != 0) { 1803236769Sobrien if (ch == '(' || ch == '{') { 1804236769Sobrien level++; 1805236769Sobrien continue; 1806236769Sobrien } 1807236769Sobrien if (ch == ')' || ch == '}') { 1808236769Sobrien level--; 1809236769Sobrien continue; 1810236769Sobrien } 1811236769Sobrien if (level != 0) 1812236769Sobrien continue; 1813236769Sobrien while (ch == ' ' || ch == '\t') { 1814236769Sobrien ch = *line++; 1815236769Sobrien wasSpace = TRUE; 1816236769Sobrien } 1817255253Ssjg#ifdef SUNSHCMD 1818255253Ssjg if (ch == ':' && strncmp(line, "sh", 2) == 0) { 1819255253Ssjg line += 2; 1820255253Ssjg continue; 1821255253Ssjg } 1822255253Ssjg#endif 1823236769Sobrien if (ch == '=') 1824236769Sobrien return TRUE; 1825236769Sobrien if (*line == '=' && ISEQOPERATOR(ch)) 1826236769Sobrien return TRUE; 1827236769Sobrien if (wasSpace) 1828236769Sobrien return FALSE; 1829236769Sobrien } 1830236769Sobrien 1831236769Sobrien return FALSE; 1832236769Sobrien} 1833236769Sobrien 1834236769Sobrien/*- 1835236769Sobrien *--------------------------------------------------------------------- 1836236769Sobrien * Parse_DoVar -- 1837236769Sobrien * Take the variable assignment in the passed line and do it in the 1838236769Sobrien * global context. 1839236769Sobrien * 1840236769Sobrien * Note: There is a lexical ambiguity with assignment modifier characters 1841236769Sobrien * in variable names. This routine interprets the character before the = 1842236769Sobrien * as a modifier. Therefore, an assignment like 1843236769Sobrien * C++=/usr/bin/CC 1844236769Sobrien * is interpreted as "C+ +=" instead of "C++ =". 1845236769Sobrien * 1846236769Sobrien * Input: 1847236769Sobrien * line a line guaranteed to be a variable assignment. 1848236769Sobrien * This reduces error checks 1849236769Sobrien * ctxt Context in which to do the assignment 1850236769Sobrien * 1851236769Sobrien * Results: 1852236769Sobrien * none 1853236769Sobrien * 1854236769Sobrien * Side Effects: 1855236769Sobrien * the variable structure of the given variable name is altered in the 1856236769Sobrien * global context. 1857236769Sobrien *--------------------------------------------------------------------- 1858236769Sobrien */ 1859236769Sobrienvoid 1860236769SobrienParse_DoVar(char *line, GNode *ctxt) 1861236769Sobrien{ 1862236769Sobrien char *cp; /* pointer into line */ 1863236769Sobrien enum { 1864236769Sobrien VAR_SUBST, VAR_APPEND, VAR_SHELL, VAR_NORMAL 1865236769Sobrien } type; /* Type of assignment */ 1866236769Sobrien char *opc; /* ptr to operator character to 1867236769Sobrien * null-terminate the variable name */ 1868236769Sobrien Boolean freeCp = FALSE; /* TRUE if cp needs to be freed, 1869236769Sobrien * i.e. if any variable expansion was 1870236769Sobrien * performed */ 1871236769Sobrien int depth; 1872236769Sobrien 1873236769Sobrien /* 1874236769Sobrien * Skip to variable name 1875236769Sobrien */ 1876236769Sobrien while ((*line == ' ') || (*line == '\t')) { 1877236769Sobrien line++; 1878236769Sobrien } 1879236769Sobrien 1880236769Sobrien /* 1881236769Sobrien * Skip to operator character, nulling out whitespace as we go 1882236769Sobrien * XXX Rather than counting () and {} we should look for $ and 1883236769Sobrien * then expand the variable. 1884236769Sobrien */ 1885319884Ssjg for (depth = 0, cp = line + 1; depth > 0 || *cp != '='; cp++) { 1886236769Sobrien if (*cp == '(' || *cp == '{') { 1887236769Sobrien depth++; 1888236769Sobrien continue; 1889236769Sobrien } 1890236769Sobrien if (*cp == ')' || *cp == '}') { 1891236769Sobrien depth--; 1892236769Sobrien continue; 1893236769Sobrien } 1894236769Sobrien if (depth == 0 && isspace ((unsigned char)*cp)) { 1895236769Sobrien *cp = '\0'; 1896236769Sobrien } 1897236769Sobrien } 1898236769Sobrien opc = cp-1; /* operator is the previous character */ 1899236769Sobrien *cp++ = '\0'; /* nuke the = */ 1900236769Sobrien 1901236769Sobrien /* 1902236769Sobrien * Check operator type 1903236769Sobrien */ 1904236769Sobrien switch (*opc) { 1905236769Sobrien case '+': 1906236769Sobrien type = VAR_APPEND; 1907236769Sobrien *opc = '\0'; 1908236769Sobrien break; 1909236769Sobrien 1910236769Sobrien case '?': 1911236769Sobrien /* 1912236769Sobrien * If the variable already has a value, we don't do anything. 1913236769Sobrien */ 1914236769Sobrien *opc = '\0'; 1915236769Sobrien if (Var_Exists(line, ctxt)) { 1916236769Sobrien return; 1917236769Sobrien } else { 1918236769Sobrien type = VAR_NORMAL; 1919236769Sobrien } 1920236769Sobrien break; 1921236769Sobrien 1922236769Sobrien case ':': 1923236769Sobrien type = VAR_SUBST; 1924236769Sobrien *opc = '\0'; 1925236769Sobrien break; 1926236769Sobrien 1927236769Sobrien case '!': 1928236769Sobrien type = VAR_SHELL; 1929236769Sobrien *opc = '\0'; 1930236769Sobrien break; 1931236769Sobrien 1932236769Sobrien default: 1933236769Sobrien#ifdef SUNSHCMD 1934236769Sobrien while (opc > line && *opc != ':') 1935236769Sobrien opc--; 1936236769Sobrien 1937236769Sobrien if (strncmp(opc, ":sh", 3) == 0) { 1938236769Sobrien type = VAR_SHELL; 1939236769Sobrien *opc = '\0'; 1940236769Sobrien break; 1941236769Sobrien } 1942236769Sobrien#endif 1943236769Sobrien type = VAR_NORMAL; 1944236769Sobrien break; 1945236769Sobrien } 1946236769Sobrien 1947236769Sobrien while (isspace ((unsigned char)*cp)) { 1948236769Sobrien cp++; 1949236769Sobrien } 1950236769Sobrien 1951236769Sobrien if (type == VAR_APPEND) { 1952236769Sobrien Var_Append(line, cp, ctxt); 1953236769Sobrien } else if (type == VAR_SUBST) { 1954236769Sobrien /* 1955236769Sobrien * Allow variables in the old value to be undefined, but leave their 1956236769Sobrien * invocation alone -- this is done by forcing oldVars to be false. 1957236769Sobrien * XXX: This can cause recursive variables, but that's not hard to do, 1958236769Sobrien * and this allows someone to do something like 1959236769Sobrien * 1960236769Sobrien * CFLAGS = $(.INCLUDES) 1961236769Sobrien * CFLAGS := -I.. $(CFLAGS) 1962236769Sobrien * 1963236769Sobrien * And not get an error. 1964236769Sobrien */ 1965236769Sobrien Boolean oldOldVars = oldVars; 1966236769Sobrien 1967236769Sobrien oldVars = FALSE; 1968236769Sobrien 1969236769Sobrien /* 1970236769Sobrien * make sure that we set the variable the first time to nothing 1971236769Sobrien * so that it gets substituted! 1972236769Sobrien */ 1973236769Sobrien if (!Var_Exists(line, ctxt)) 1974236769Sobrien Var_Set(line, "", ctxt, 0); 1975236769Sobrien 1976296637Ssjg cp = Var_Subst(NULL, cp, ctxt, VARF_WANTRES|VARF_ASSIGN); 1977236769Sobrien oldVars = oldOldVars; 1978236769Sobrien freeCp = TRUE; 1979236769Sobrien 1980236769Sobrien Var_Set(line, cp, ctxt, 0); 1981236769Sobrien } else if (type == VAR_SHELL) { 1982236769Sobrien char *res; 1983236769Sobrien const char *error; 1984236769Sobrien 1985236769Sobrien if (strchr(cp, '$') != NULL) { 1986236769Sobrien /* 1987236769Sobrien * There's a dollar sign in the command, so perform variable 1988236769Sobrien * expansion on the whole thing. The resulting string will need 1989236769Sobrien * freeing when we're done, so set freeCmd to TRUE. 1990236769Sobrien */ 1991296637Ssjg cp = Var_Subst(NULL, cp, VAR_CMD, VARF_UNDEFERR|VARF_WANTRES); 1992236769Sobrien freeCp = TRUE; 1993236769Sobrien } 1994236769Sobrien 1995236769Sobrien res = Cmd_Exec(cp, &error); 1996236769Sobrien Var_Set(line, res, ctxt, 0); 1997236769Sobrien free(res); 1998236769Sobrien 1999236769Sobrien if (error) 2000236769Sobrien Parse_Error(PARSE_WARNING, error, cp); 2001236769Sobrien } else { 2002236769Sobrien /* 2003236769Sobrien * Normal assignment -- just do it. 2004236769Sobrien */ 2005236769Sobrien Var_Set(line, cp, ctxt, 0); 2006236769Sobrien } 2007236769Sobrien if (strcmp(line, MAKEOVERRIDES) == 0) 2008236769Sobrien Main_ExportMAKEFLAGS(FALSE); /* re-export MAKEFLAGS */ 2009236769Sobrien else if (strcmp(line, ".CURDIR") == 0) { 2010236769Sobrien /* 2011236769Sobrien * Somone is being (too?) clever... 2012236769Sobrien * Let's pretend they know what they are doing and 2013236769Sobrien * re-initialize the 'cur' Path. 2014236769Sobrien */ 2015236769Sobrien Dir_InitCur(cp); 2016236769Sobrien Dir_SetPATH(); 2017236769Sobrien } else if (strcmp(line, MAKE_JOB_PREFIX) == 0) { 2018236769Sobrien Job_SetPrefix(); 2019236769Sobrien } else if (strcmp(line, MAKE_EXPORTED) == 0) { 2020236769Sobrien Var_Export(cp, 0); 2021236769Sobrien } 2022236769Sobrien if (freeCp) 2023236769Sobrien free(cp); 2024236769Sobrien} 2025236769Sobrien 2026236769Sobrien 2027281812Ssjg/* 2028281812Ssjg * ParseMaybeSubMake -- 2029281812Ssjg * Scan the command string to see if it a possible submake node 2030281812Ssjg * Input: 2031281812Ssjg * cmd the command to scan 2032281812Ssjg * Results: 2033281812Ssjg * TRUE if the command is possibly a submake, FALSE if not. 2034281812Ssjg */ 2035281812Ssjgstatic Boolean 2036281812SsjgParseMaybeSubMake(const char *cmd) 2037281812Ssjg{ 2038281812Ssjg size_t i; 2039281812Ssjg static struct { 2040281812Ssjg const char *name; 2041281812Ssjg size_t len; 2042281812Ssjg } vals[] = { 2043281812Ssjg#define MKV(A) { A, sizeof(A) - 1 } 2044281812Ssjg MKV("${MAKE}"), 2045281812Ssjg MKV("${.MAKE}"), 2046281812Ssjg MKV("$(MAKE)"), 2047281812Ssjg MKV("$(.MAKE)"), 2048281812Ssjg MKV("make"), 2049281812Ssjg }; 2050281812Ssjg for (i = 0; i < sizeof(vals)/sizeof(vals[0]); i++) { 2051281812Ssjg char *ptr; 2052281812Ssjg if ((ptr = strstr(cmd, vals[i].name)) == NULL) 2053281812Ssjg continue; 2054281812Ssjg if ((ptr == cmd || !isalnum((unsigned char)ptr[-1])) 2055281812Ssjg && !isalnum((unsigned char)ptr[vals[i].len])) 2056281812Ssjg return TRUE; 2057281812Ssjg } 2058281812Ssjg return FALSE; 2059281812Ssjg} 2060281812Ssjg 2061236769Sobrien/*- 2062236769Sobrien * ParseAddCmd -- 2063236769Sobrien * Lst_ForEach function to add a command line to all targets 2064236769Sobrien * 2065236769Sobrien * Input: 2066236769Sobrien * gnp the node to which the command is to be added 2067236769Sobrien * cmd the command to add 2068236769Sobrien * 2069236769Sobrien * Results: 2070236769Sobrien * Always 0 2071236769Sobrien * 2072236769Sobrien * Side Effects: 2073281812Ssjg * A new element is added to the commands list of the node, 2074281812Ssjg * and the node can be marked as a submake node if the command is 2075281812Ssjg * determined to be that. 2076236769Sobrien */ 2077236769Sobrienstatic int 2078236769SobrienParseAddCmd(void *gnp, void *cmd) 2079236769Sobrien{ 2080236769Sobrien GNode *gn = (GNode *)gnp; 2081236769Sobrien 2082236769Sobrien /* Add to last (ie current) cohort for :: targets */ 2083236769Sobrien if ((gn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (gn->cohorts)) 2084236769Sobrien gn = (GNode *)Lst_Datum(Lst_Last(gn->cohorts)); 2085236769Sobrien 2086236769Sobrien /* if target already supplied, ignore commands */ 2087236769Sobrien if (!(gn->type & OP_HAS_COMMANDS)) { 2088236769Sobrien (void)Lst_AtEnd(gn->commands, cmd); 2089281812Ssjg if (ParseMaybeSubMake(cmd)) 2090281812Ssjg gn->type |= OP_SUBMAKE; 2091236769Sobrien ParseMark(gn); 2092236769Sobrien } else { 2093236769Sobrien#ifdef notyet 2094236769Sobrien /* XXX: We cannot do this until we fix the tree */ 2095236769Sobrien (void)Lst_AtEnd(gn->commands, cmd); 2096236769Sobrien Parse_Error(PARSE_WARNING, 2097236769Sobrien "overriding commands for target \"%s\"; " 2098236769Sobrien "previous commands defined at %s: %d ignored", 2099236769Sobrien gn->name, gn->fname, gn->lineno); 2100236769Sobrien#else 2101236769Sobrien Parse_Error(PARSE_WARNING, 2102236769Sobrien "duplicate script for target \"%s\" ignored", 2103236769Sobrien gn->name); 2104236769Sobrien ParseErrorInternal(gn->fname, gn->lineno, PARSE_WARNING, 2105236769Sobrien "using previous script for \"%s\" defined here", 2106236769Sobrien gn->name); 2107236769Sobrien#endif 2108236769Sobrien } 2109236769Sobrien return(0); 2110236769Sobrien} 2111236769Sobrien 2112236769Sobrien/*- 2113236769Sobrien *----------------------------------------------------------------------- 2114236769Sobrien * ParseHasCommands -- 2115236769Sobrien * Callback procedure for Parse_File when destroying the list of 2116236769Sobrien * targets on the last dependency line. Marks a target as already 2117236769Sobrien * having commands if it does, to keep from having shell commands 2118236769Sobrien * on multiple dependency lines. 2119236769Sobrien * 2120236769Sobrien * Input: 2121236769Sobrien * gnp Node to examine 2122236769Sobrien * 2123236769Sobrien * Results: 2124236769Sobrien * None 2125236769Sobrien * 2126236769Sobrien * Side Effects: 2127236769Sobrien * OP_HAS_COMMANDS may be set for the target. 2128236769Sobrien * 2129236769Sobrien *----------------------------------------------------------------------- 2130236769Sobrien */ 2131236769Sobrienstatic void 2132236769SobrienParseHasCommands(void *gnp) 2133236769Sobrien{ 2134236769Sobrien GNode *gn = (GNode *)gnp; 2135236769Sobrien if (!Lst_IsEmpty(gn->commands)) { 2136236769Sobrien gn->type |= OP_HAS_COMMANDS; 2137236769Sobrien } 2138236769Sobrien} 2139236769Sobrien 2140236769Sobrien/*- 2141236769Sobrien *----------------------------------------------------------------------- 2142236769Sobrien * Parse_AddIncludeDir -- 2143236769Sobrien * Add a directory to the path searched for included makefiles 2144236769Sobrien * bracketed by double-quotes. Used by functions in main.c 2145236769Sobrien * 2146236769Sobrien * Input: 2147236769Sobrien * dir The name of the directory to add 2148236769Sobrien * 2149236769Sobrien * Results: 2150236769Sobrien * None. 2151236769Sobrien * 2152236769Sobrien * Side Effects: 2153236769Sobrien * The directory is appended to the list. 2154236769Sobrien * 2155236769Sobrien *----------------------------------------------------------------------- 2156236769Sobrien */ 2157236769Sobrienvoid 2158236769SobrienParse_AddIncludeDir(char *dir) 2159236769Sobrien{ 2160236769Sobrien (void)Dir_AddDir(parseIncPath, dir); 2161236769Sobrien} 2162236769Sobrien 2163236769Sobrien/*- 2164236769Sobrien *--------------------------------------------------------------------- 2165236769Sobrien * ParseDoInclude -- 2166236769Sobrien * Push to another file. 2167236769Sobrien * 2168236769Sobrien * The input is the line minus the `.'. A file spec is a string 2169236769Sobrien * enclosed in <> or "". The former is looked for only in sysIncPath. 2170236769Sobrien * The latter in . and the directories specified by -I command line 2171236769Sobrien * options 2172236769Sobrien * 2173236769Sobrien * Results: 2174236769Sobrien * None 2175236769Sobrien * 2176236769Sobrien * Side Effects: 2177236769Sobrien * A structure is added to the includes Lst and readProc, lineno, 2178236769Sobrien * fname and curFILE are altered for the new file 2179236769Sobrien *--------------------------------------------------------------------- 2180236769Sobrien */ 2181236769Sobrien 2182236769Sobrienstatic void 2183296637SsjgParse_include_file(char *file, Boolean isSystem, Boolean depinc, int silent) 2184236769Sobrien{ 2185236769Sobrien struct loadedfile *lf; 2186236769Sobrien char *fullname; /* full pathname of file */ 2187236769Sobrien char *newName; 2188236769Sobrien char *prefEnd, *incdir; 2189236769Sobrien int fd; 2190236769Sobrien int i; 2191236769Sobrien 2192236769Sobrien /* 2193236769Sobrien * Now we know the file's name and its search path, we attempt to 2194236769Sobrien * find the durn thing. A return of NULL indicates the file don't 2195236769Sobrien * exist. 2196236769Sobrien */ 2197236769Sobrien fullname = file[0] == '/' ? bmake_strdup(file) : NULL; 2198236769Sobrien 2199236769Sobrien if (fullname == NULL && !isSystem) { 2200236769Sobrien /* 2201236769Sobrien * Include files contained in double-quotes are first searched for 2202236769Sobrien * relative to the including file's location. We don't want to 2203236769Sobrien * cd there, of course, so we just tack on the old file's 2204236769Sobrien * leading path components and call Dir_FindFile to see if 2205236769Sobrien * we can locate the beast. 2206236769Sobrien */ 2207236769Sobrien 2208236769Sobrien incdir = bmake_strdup(curFile->fname); 2209236769Sobrien prefEnd = strrchr(incdir, '/'); 2210236769Sobrien if (prefEnd != NULL) { 2211236769Sobrien *prefEnd = '\0'; 2212236769Sobrien /* Now do lexical processing of leading "../" on the filename */ 2213236769Sobrien for (i = 0; strncmp(file + i, "../", 3) == 0; i += 3) { 2214236769Sobrien prefEnd = strrchr(incdir + 1, '/'); 2215236769Sobrien if (prefEnd == NULL || strcmp(prefEnd, "/..") == 0) 2216236769Sobrien break; 2217236769Sobrien *prefEnd = '\0'; 2218236769Sobrien } 2219236769Sobrien newName = str_concat(incdir, file + i, STR_ADDSLASH); 2220236769Sobrien fullname = Dir_FindFile(newName, parseIncPath); 2221236769Sobrien if (fullname == NULL) 2222236769Sobrien fullname = Dir_FindFile(newName, dirSearchPath); 2223236769Sobrien free(newName); 2224236769Sobrien } 2225236769Sobrien free(incdir); 2226236769Sobrien 2227236769Sobrien if (fullname == NULL) { 2228236769Sobrien /* 2229236769Sobrien * Makefile wasn't found in same directory as included makefile. 2230236769Sobrien * Search for it first on the -I search path, 2231236769Sobrien * then on the .PATH search path, if not found in a -I directory. 2232236769Sobrien * If we have a suffix specific path we should use that. 2233236769Sobrien */ 2234236769Sobrien char *suff; 2235236769Sobrien Lst suffPath = NULL; 2236236769Sobrien 2237236769Sobrien if ((suff = strrchr(file, '.'))) { 2238236769Sobrien suffPath = Suff_GetPath(suff); 2239236769Sobrien if (suffPath != NULL) { 2240236769Sobrien fullname = Dir_FindFile(file, suffPath); 2241236769Sobrien } 2242236769Sobrien } 2243236769Sobrien if (fullname == NULL) { 2244236769Sobrien fullname = Dir_FindFile(file, parseIncPath); 2245236769Sobrien if (fullname == NULL) { 2246236769Sobrien fullname = Dir_FindFile(file, dirSearchPath); 2247236769Sobrien } 2248236769Sobrien } 2249236769Sobrien } 2250236769Sobrien } 2251236769Sobrien 2252236769Sobrien /* Looking for a system file or file still not found */ 2253236769Sobrien if (fullname == NULL) { 2254236769Sobrien /* 2255236769Sobrien * Look for it on the system path 2256236769Sobrien */ 2257236769Sobrien fullname = Dir_FindFile(file, 2258236769Sobrien Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath); 2259236769Sobrien } 2260236769Sobrien 2261236769Sobrien if (fullname == NULL) { 2262236769Sobrien if (!silent) 2263236769Sobrien Parse_Error(PARSE_FATAL, "Could not find %s", file); 2264236769Sobrien return; 2265236769Sobrien } 2266236769Sobrien 2267236769Sobrien /* Actually open the file... */ 2268236769Sobrien fd = open(fullname, O_RDONLY); 2269236769Sobrien if (fd == -1) { 2270236769Sobrien if (!silent) 2271236769Sobrien Parse_Error(PARSE_FATAL, "Cannot open %s", fullname); 2272236769Sobrien free(fullname); 2273236769Sobrien return; 2274236769Sobrien } 2275236769Sobrien 2276236769Sobrien /* load it */ 2277236769Sobrien lf = loadfile(fullname, fd); 2278236769Sobrien 2279268437Ssjg ParseSetIncludedFile(); 2280236769Sobrien /* Start reading from this file next */ 2281236769Sobrien Parse_SetInput(fullname, 0, -1, loadedfile_nextbuf, lf); 2282236769Sobrien curFile->lf = lf; 2283296637Ssjg if (depinc) 2284296637Ssjg doing_depend = depinc; /* only turn it on */ 2285236769Sobrien} 2286236769Sobrien 2287236769Sobrienstatic void 2288236769SobrienParseDoInclude(char *line) 2289236769Sobrien{ 2290236769Sobrien char endc; /* the character which ends the file spec */ 2291236769Sobrien char *cp; /* current position in file spec */ 2292236769Sobrien int silent = (*line != 'i') ? 1 : 0; 2293236769Sobrien char *file = &line[7 + silent]; 2294236769Sobrien 2295236769Sobrien /* Skip to delimiter character so we know where to look */ 2296236769Sobrien while (*file == ' ' || *file == '\t') 2297236769Sobrien file++; 2298236769Sobrien 2299236769Sobrien if (*file != '"' && *file != '<') { 2300236769Sobrien Parse_Error(PARSE_FATAL, 2301236769Sobrien ".include filename must be delimited by '\"' or '<'"); 2302236769Sobrien return; 2303236769Sobrien } 2304236769Sobrien 2305236769Sobrien /* 2306236769Sobrien * Set the search path on which to find the include file based on the 2307236769Sobrien * characters which bracket its name. Angle-brackets imply it's 2308236769Sobrien * a system Makefile while double-quotes imply it's a user makefile 2309236769Sobrien */ 2310236769Sobrien if (*file == '<') { 2311236769Sobrien endc = '>'; 2312236769Sobrien } else { 2313236769Sobrien endc = '"'; 2314236769Sobrien } 2315236769Sobrien 2316236769Sobrien /* Skip to matching delimiter */ 2317236769Sobrien for (cp = ++file; *cp && *cp != endc; cp++) 2318236769Sobrien continue; 2319236769Sobrien 2320236769Sobrien if (*cp != endc) { 2321236769Sobrien Parse_Error(PARSE_FATAL, 2322236769Sobrien "Unclosed %cinclude filename. '%c' expected", 2323236769Sobrien '.', endc); 2324236769Sobrien return; 2325236769Sobrien } 2326236769Sobrien *cp = '\0'; 2327236769Sobrien 2328236769Sobrien /* 2329236769Sobrien * Substitute for any variables in the file name before trying to 2330236769Sobrien * find the thing. 2331236769Sobrien */ 2332296637Ssjg file = Var_Subst(NULL, file, VAR_CMD, VARF_WANTRES); 2333236769Sobrien 2334296637Ssjg Parse_include_file(file, endc == '>', (*line == 'd'), silent); 2335236769Sobrien free(file); 2336236769Sobrien} 2337236769Sobrien 2338236769Sobrien 2339236769Sobrien/*- 2340236769Sobrien *--------------------------------------------------------------------- 2341268437Ssjg * ParseSetIncludedFile -- 2342268437Ssjg * Set the .INCLUDEDFROMFILE variable to the contents of .PARSEFILE 2343268437Ssjg * and the .INCLUDEDFROMDIR variable to the contents of .PARSEDIR 2344268437Ssjg * 2345268437Ssjg * Results: 2346268437Ssjg * None 2347268437Ssjg * 2348268437Ssjg * Side Effects: 2349268437Ssjg * The .INCLUDEDFROMFILE variable is overwritten by the contents 2350268437Ssjg * of .PARSEFILE and the .INCLUDEDFROMDIR variable is overwriten 2351268437Ssjg * by the contents of .PARSEDIR 2352268437Ssjg *--------------------------------------------------------------------- 2353268437Ssjg */ 2354268437Ssjgstatic void 2355268437SsjgParseSetIncludedFile(void) 2356268437Ssjg{ 2357268437Ssjg char *pf, *fp = NULL; 2358268437Ssjg char *pd, *dp = NULL; 2359268437Ssjg 2360268437Ssjg pf = Var_Value(".PARSEFILE", VAR_GLOBAL, &fp); 2361268437Ssjg Var_Set(".INCLUDEDFROMFILE", pf, VAR_GLOBAL, 0); 2362268437Ssjg pd = Var_Value(".PARSEDIR", VAR_GLOBAL, &dp); 2363268437Ssjg Var_Set(".INCLUDEDFROMDIR", pd, VAR_GLOBAL, 0); 2364268437Ssjg 2365268437Ssjg if (DEBUG(PARSE)) 2366268437Ssjg fprintf(debug_file, "%s: ${.INCLUDEDFROMDIR} = `%s' " 2367268437Ssjg "${.INCLUDEDFROMFILE} = `%s'\n", __func__, pd, pf); 2368268437Ssjg 2369296637Ssjg free(fp); 2370296637Ssjg free(dp); 2371268437Ssjg} 2372268437Ssjg/*- 2373268437Ssjg *--------------------------------------------------------------------- 2374236769Sobrien * ParseSetParseFile -- 2375236769Sobrien * Set the .PARSEDIR and .PARSEFILE variables to the dirname and 2376236769Sobrien * basename of the given filename 2377236769Sobrien * 2378236769Sobrien * Results: 2379236769Sobrien * None 2380236769Sobrien * 2381236769Sobrien * Side Effects: 2382236769Sobrien * The .PARSEDIR and .PARSEFILE variables are overwritten by the 2383236769Sobrien * dirname and basename of the given filename. 2384236769Sobrien *--------------------------------------------------------------------- 2385236769Sobrien */ 2386236769Sobrienstatic void 2387236769SobrienParseSetParseFile(const char *filename) 2388236769Sobrien{ 2389236769Sobrien char *slash, *dirname; 2390236769Sobrien const char *pd, *pf; 2391236769Sobrien int len; 2392236769Sobrien 2393236769Sobrien slash = strrchr(filename, '/'); 2394236769Sobrien if (slash == NULL) { 2395236769Sobrien Var_Set(".PARSEDIR", pd = curdir, VAR_GLOBAL, 0); 2396236769Sobrien Var_Set(".PARSEFILE", pf = filename, VAR_GLOBAL, 0); 2397236769Sobrien dirname= NULL; 2398236769Sobrien } else { 2399236769Sobrien len = slash - filename; 2400236769Sobrien dirname = bmake_malloc(len + 1); 2401236769Sobrien memcpy(dirname, filename, len); 2402236769Sobrien dirname[len] = '\0'; 2403236769Sobrien Var_Set(".PARSEDIR", pd = dirname, VAR_GLOBAL, 0); 2404236769Sobrien Var_Set(".PARSEFILE", pf = slash + 1, VAR_GLOBAL, 0); 2405236769Sobrien } 2406236769Sobrien if (DEBUG(PARSE)) 2407268437Ssjg fprintf(debug_file, "%s: ${.PARSEDIR} = `%s' ${.PARSEFILE} = `%s'\n", 2408268437Ssjg __func__, pd, pf); 2409236769Sobrien free(dirname); 2410236769Sobrien} 2411236769Sobrien 2412236769Sobrien/* 2413236769Sobrien * Track the makefiles we read - so makefiles can 2414236769Sobrien * set dependencies on them. 2415236769Sobrien * Avoid adding anything more than once. 2416236769Sobrien */ 2417236769Sobrien 2418236769Sobrienstatic void 2419236769SobrienParseTrackInput(const char *name) 2420236769Sobrien{ 2421236769Sobrien char *old; 2422291342Ssjg char *ep; 2423236769Sobrien char *fp = NULL; 2424236769Sobrien size_t name_len = strlen(name); 2425236769Sobrien 2426236769Sobrien old = Var_Value(MAKE_MAKEFILES, VAR_GLOBAL, &fp); 2427236769Sobrien if (old) { 2428291342Ssjg ep = old + strlen(old) - name_len; 2429236769Sobrien /* does it contain name? */ 2430236769Sobrien for (; old != NULL; old = strchr(old, ' ')) { 2431236769Sobrien if (*old == ' ') 2432236769Sobrien old++; 2433291342Ssjg if (old >= ep) 2434291342Ssjg break; /* cannot contain name */ 2435236769Sobrien if (memcmp(old, name, name_len) == 0 2436236769Sobrien && (old[name_len] == 0 || old[name_len] == ' ')) 2437236769Sobrien goto cleanup; 2438236769Sobrien } 2439236769Sobrien } 2440236769Sobrien Var_Append (MAKE_MAKEFILES, name, VAR_GLOBAL); 2441236769Sobrien cleanup: 2442236769Sobrien if (fp) { 2443236769Sobrien free(fp); 2444236769Sobrien } 2445236769Sobrien} 2446236769Sobrien 2447236769Sobrien 2448236769Sobrien/*- 2449236769Sobrien *--------------------------------------------------------------------- 2450236769Sobrien * Parse_setInput -- 2451236769Sobrien * Start Parsing from the given source 2452236769Sobrien * 2453236769Sobrien * Results: 2454236769Sobrien * None 2455236769Sobrien * 2456236769Sobrien * Side Effects: 2457236769Sobrien * A structure is added to the includes Lst and readProc, lineno, 2458236769Sobrien * fname and curFile are altered for the new file 2459236769Sobrien *--------------------------------------------------------------------- 2460236769Sobrien */ 2461236769Sobrienvoid 2462236769SobrienParse_SetInput(const char *name, int line, int fd, 2463236769Sobrien char *(*nextbuf)(void *, size_t *), void *arg) 2464236769Sobrien{ 2465236769Sobrien char *buf; 2466236769Sobrien size_t len; 2467236769Sobrien 2468236769Sobrien if (name == NULL) 2469236769Sobrien name = curFile->fname; 2470236769Sobrien else 2471236769Sobrien ParseTrackInput(name); 2472236769Sobrien 2473236769Sobrien if (DEBUG(PARSE)) 2474268437Ssjg fprintf(debug_file, "%s: file %s, line %d, fd %d, nextbuf %p, arg %p\n", 2475268437Ssjg __func__, name, line, fd, nextbuf, arg); 2476236769Sobrien 2477236769Sobrien if (fd == -1 && nextbuf == NULL) 2478236769Sobrien /* sanity */ 2479236769Sobrien return; 2480236769Sobrien 2481236769Sobrien if (curFile != NULL) 2482236769Sobrien /* Save exiting file info */ 2483236769Sobrien Lst_AtFront(includes, curFile); 2484236769Sobrien 2485236769Sobrien /* Allocate and fill in new structure */ 2486236769Sobrien curFile = bmake_malloc(sizeof *curFile); 2487236769Sobrien 2488236769Sobrien /* 2489236769Sobrien * Once the previous state has been saved, we can get down to reading 2490236769Sobrien * the new file. We set up the name of the file to be the absolute 2491236769Sobrien * name of the include file so error messages refer to the right 2492236769Sobrien * place. 2493236769Sobrien */ 2494251958Ssjg curFile->fname = bmake_strdup(name); 2495236769Sobrien curFile->lineno = line; 2496236769Sobrien curFile->first_lineno = line; 2497236769Sobrien curFile->nextbuf = nextbuf; 2498236769Sobrien curFile->nextbuf_arg = arg; 2499236769Sobrien curFile->lf = NULL; 2500296637Ssjg curFile->depending = doing_depend; /* restore this on EOF */ 2501236769Sobrien 2502236769Sobrien assert(nextbuf != NULL); 2503236769Sobrien 2504236769Sobrien /* Get first block of input data */ 2505236769Sobrien buf = curFile->nextbuf(curFile->nextbuf_arg, &len); 2506236769Sobrien if (buf == NULL) { 2507236769Sobrien /* Was all a waste of time ... */ 2508251958Ssjg if (curFile->fname) 2509251958Ssjg free(curFile->fname); 2510236769Sobrien free(curFile); 2511236769Sobrien return; 2512236769Sobrien } 2513236769Sobrien curFile->P_str = buf; 2514236769Sobrien curFile->P_ptr = buf; 2515236769Sobrien curFile->P_end = buf+len; 2516236769Sobrien 2517236769Sobrien curFile->cond_depth = Cond_save_depth(); 2518236769Sobrien ParseSetParseFile(name); 2519236769Sobrien} 2520236769Sobrien 2521236769Sobrien#ifdef SYSVINCLUDE 2522236769Sobrien/*- 2523236769Sobrien *--------------------------------------------------------------------- 2524236769Sobrien * ParseTraditionalInclude -- 2525236769Sobrien * Push to another file. 2526236769Sobrien * 2527236769Sobrien * The input is the current line. The file name(s) are 2528236769Sobrien * following the "include". 2529236769Sobrien * 2530236769Sobrien * Results: 2531236769Sobrien * None 2532236769Sobrien * 2533236769Sobrien * Side Effects: 2534236769Sobrien * A structure is added to the includes Lst and readProc, lineno, 2535236769Sobrien * fname and curFILE are altered for the new file 2536236769Sobrien *--------------------------------------------------------------------- 2537236769Sobrien */ 2538236769Sobrienstatic void 2539236769SobrienParseTraditionalInclude(char *line) 2540236769Sobrien{ 2541236769Sobrien char *cp; /* current position in file spec */ 2542236769Sobrien int done = 0; 2543236769Sobrien int silent = (line[0] != 'i') ? 1 : 0; 2544236769Sobrien char *file = &line[silent + 7]; 2545236769Sobrien char *all_files; 2546236769Sobrien 2547236769Sobrien if (DEBUG(PARSE)) { 2548268437Ssjg fprintf(debug_file, "%s: %s\n", __func__, file); 2549236769Sobrien } 2550236769Sobrien 2551236769Sobrien /* 2552236769Sobrien * Skip over whitespace 2553236769Sobrien */ 2554236769Sobrien while (isspace((unsigned char)*file)) 2555236769Sobrien file++; 2556236769Sobrien 2557236769Sobrien /* 2558236769Sobrien * Substitute for any variables in the file name before trying to 2559236769Sobrien * find the thing. 2560236769Sobrien */ 2561296637Ssjg all_files = Var_Subst(NULL, file, VAR_CMD, VARF_WANTRES); 2562236769Sobrien 2563236769Sobrien if (*file == '\0') { 2564236769Sobrien Parse_Error(PARSE_FATAL, 2565236769Sobrien "Filename missing from \"include\""); 2566319884Ssjg goto out; 2567236769Sobrien } 2568236769Sobrien 2569236769Sobrien for (file = all_files; !done; file = cp + 1) { 2570236769Sobrien /* Skip to end of line or next whitespace */ 2571236769Sobrien for (cp = file; *cp && !isspace((unsigned char) *cp); cp++) 2572236769Sobrien continue; 2573236769Sobrien 2574236769Sobrien if (*cp) 2575236769Sobrien *cp = '\0'; 2576236769Sobrien else 2577236769Sobrien done = 1; 2578236769Sobrien 2579296637Ssjg Parse_include_file(file, FALSE, FALSE, silent); 2580236769Sobrien } 2581319884Ssjgout: 2582236769Sobrien free(all_files); 2583236769Sobrien} 2584236769Sobrien#endif 2585236769Sobrien 2586236769Sobrien#ifdef GMAKEEXPORT 2587236769Sobrien/*- 2588236769Sobrien *--------------------------------------------------------------------- 2589236769Sobrien * ParseGmakeExport -- 2590236769Sobrien * Parse export <variable>=<value> 2591236769Sobrien * 2592236769Sobrien * And set the environment with it. 2593236769Sobrien * 2594236769Sobrien * Results: 2595236769Sobrien * None 2596236769Sobrien * 2597236769Sobrien * Side Effects: 2598236769Sobrien * None 2599236769Sobrien *--------------------------------------------------------------------- 2600236769Sobrien */ 2601236769Sobrienstatic void 2602236769SobrienParseGmakeExport(char *line) 2603236769Sobrien{ 2604236769Sobrien char *variable = &line[6]; 2605236769Sobrien char *value; 2606236769Sobrien 2607236769Sobrien if (DEBUG(PARSE)) { 2608268437Ssjg fprintf(debug_file, "%s: %s\n", __func__, variable); 2609236769Sobrien } 2610236769Sobrien 2611236769Sobrien /* 2612236769Sobrien * Skip over whitespace 2613236769Sobrien */ 2614236769Sobrien while (isspace((unsigned char)*variable)) 2615236769Sobrien variable++; 2616236769Sobrien 2617236769Sobrien for (value = variable; *value && *value != '='; value++) 2618236769Sobrien continue; 2619236769Sobrien 2620236769Sobrien if (*value != '=') { 2621236769Sobrien Parse_Error(PARSE_FATAL, 2622236769Sobrien "Variable/Value missing from \"export\""); 2623236769Sobrien return; 2624236769Sobrien } 2625249033Ssjg *value++ = '\0'; /* terminate variable */ 2626236769Sobrien 2627236769Sobrien /* 2628236769Sobrien * Expand the value before putting it in the environment. 2629236769Sobrien */ 2630296637Ssjg value = Var_Subst(NULL, value, VAR_CMD, VARF_WANTRES); 2631236769Sobrien setenv(variable, value, 1); 2632319884Ssjg free(value); 2633236769Sobrien} 2634236769Sobrien#endif 2635236769Sobrien 2636236769Sobrien/*- 2637236769Sobrien *--------------------------------------------------------------------- 2638236769Sobrien * ParseEOF -- 2639236769Sobrien * Called when EOF is reached in the current file. If we were reading 2640236769Sobrien * an include file, the includes stack is popped and things set up 2641236769Sobrien * to go back to reading the previous file at the previous location. 2642236769Sobrien * 2643236769Sobrien * Results: 2644236769Sobrien * CONTINUE if there's more to do. DONE if not. 2645236769Sobrien * 2646236769Sobrien * Side Effects: 2647236769Sobrien * The old curFILE, is closed. The includes list is shortened. 2648236769Sobrien * lineno, curFILE, and fname are changed if CONTINUE is returned. 2649236769Sobrien *--------------------------------------------------------------------- 2650236769Sobrien */ 2651236769Sobrienstatic int 2652236769SobrienParseEOF(void) 2653236769Sobrien{ 2654236769Sobrien char *ptr; 2655236769Sobrien size_t len; 2656236769Sobrien 2657236769Sobrien assert(curFile->nextbuf != NULL); 2658236769Sobrien 2659296637Ssjg doing_depend = curFile->depending; /* restore this */ 2660236769Sobrien /* get next input buffer, if any */ 2661236769Sobrien ptr = curFile->nextbuf(curFile->nextbuf_arg, &len); 2662236769Sobrien curFile->P_ptr = ptr; 2663236769Sobrien curFile->P_str = ptr; 2664236769Sobrien curFile->P_end = ptr + len; 2665236769Sobrien curFile->lineno = curFile->first_lineno; 2666236769Sobrien if (ptr != NULL) { 2667236769Sobrien /* Iterate again */ 2668236769Sobrien return CONTINUE; 2669236769Sobrien } 2670236769Sobrien 2671236769Sobrien /* Ensure the makefile (or loop) didn't have mismatched conditionals */ 2672236769Sobrien Cond_restore_depth(curFile->cond_depth); 2673236769Sobrien 2674236769Sobrien if (curFile->lf != NULL) { 2675236769Sobrien loadedfile_destroy(curFile->lf); 2676236769Sobrien curFile->lf = NULL; 2677236769Sobrien } 2678236769Sobrien 2679236769Sobrien /* Dispose of curFile info */ 2680236769Sobrien /* Leak curFile->fname because all the gnodes have pointers to it */ 2681236769Sobrien free(curFile->P_str); 2682236769Sobrien free(curFile); 2683236769Sobrien 2684236769Sobrien curFile = Lst_DeQueue(includes); 2685236769Sobrien 2686236769Sobrien if (curFile == NULL) { 2687236769Sobrien /* We've run out of input */ 2688236769Sobrien Var_Delete(".PARSEDIR", VAR_GLOBAL); 2689236769Sobrien Var_Delete(".PARSEFILE", VAR_GLOBAL); 2690268437Ssjg Var_Delete(".INCLUDEDFROMDIR", VAR_GLOBAL); 2691268437Ssjg Var_Delete(".INCLUDEDFROMFILE", VAR_GLOBAL); 2692236769Sobrien return DONE; 2693236769Sobrien } 2694236769Sobrien 2695236769Sobrien if (DEBUG(PARSE)) 2696236769Sobrien fprintf(debug_file, "ParseEOF: returning to file %s, line %d\n", 2697236769Sobrien curFile->fname, curFile->lineno); 2698236769Sobrien 2699236769Sobrien /* Restore the PARSEDIR/PARSEFILE variables */ 2700236769Sobrien ParseSetParseFile(curFile->fname); 2701236769Sobrien return (CONTINUE); 2702236769Sobrien} 2703236769Sobrien 2704236769Sobrien#define PARSE_RAW 1 2705236769Sobrien#define PARSE_SKIP 2 2706236769Sobrien 2707236769Sobrienstatic char * 2708236769SobrienParseGetLine(int flags, int *length) 2709236769Sobrien{ 2710236769Sobrien IFile *cf = curFile; 2711236769Sobrien char *ptr; 2712236769Sobrien char ch; 2713236769Sobrien char *line; 2714236769Sobrien char *line_end; 2715236769Sobrien char *escaped; 2716236769Sobrien char *comment; 2717236769Sobrien char *tp; 2718236769Sobrien 2719236769Sobrien /* Loop through blank lines and comment lines */ 2720236769Sobrien for (;;) { 2721236769Sobrien cf->lineno++; 2722236769Sobrien line = cf->P_ptr; 2723236769Sobrien ptr = line; 2724236769Sobrien line_end = line; 2725236769Sobrien escaped = NULL; 2726236769Sobrien comment = NULL; 2727236769Sobrien for (;;) { 2728236769Sobrien if (cf->P_end != NULL && ptr == cf->P_end) { 2729236769Sobrien /* end of buffer */ 2730236769Sobrien ch = 0; 2731236769Sobrien break; 2732236769Sobrien } 2733236769Sobrien ch = *ptr; 2734236769Sobrien if (ch == 0 || (ch == '\\' && ptr[1] == 0)) { 2735236769Sobrien if (cf->P_end == NULL) 2736236769Sobrien /* End of string (aka for loop) data */ 2737236769Sobrien break; 2738254194Ssjg /* see if there is more we can parse */ 2739254194Ssjg while (ptr++ < cf->P_end) { 2740254194Ssjg if ((ch = *ptr) == '\n') { 2741254194Ssjg if (ptr > line && ptr[-1] == '\\') 2742254194Ssjg continue; 2743254194Ssjg Parse_Error(PARSE_WARNING, 2744254194Ssjg "Zero byte read from file, skipping rest of line."); 2745254194Ssjg break; 2746254194Ssjg } 2747254194Ssjg } 2748236769Sobrien if (cf->nextbuf != NULL) { 2749236769Sobrien /* 2750236769Sobrien * End of this buffer; return EOF and outer logic 2751236769Sobrien * will get the next one. (eww) 2752236769Sobrien */ 2753236769Sobrien break; 2754236769Sobrien } 2755236769Sobrien Parse_Error(PARSE_FATAL, "Zero byte read from file"); 2756236769Sobrien return NULL; 2757236769Sobrien } 2758236769Sobrien 2759236769Sobrien if (ch == '\\') { 2760236769Sobrien /* Don't treat next character as special, remember first one */ 2761236769Sobrien if (escaped == NULL) 2762236769Sobrien escaped = ptr; 2763236769Sobrien if (ptr[1] == '\n') 2764236769Sobrien cf->lineno++; 2765236769Sobrien ptr += 2; 2766236769Sobrien line_end = ptr; 2767236769Sobrien continue; 2768236769Sobrien } 2769236769Sobrien if (ch == '#' && comment == NULL) { 2770236769Sobrien /* Remember first '#' for comment stripping */ 2771236769Sobrien /* Unless previous char was '[', as in modifier :[#] */ 2772236769Sobrien if (!(ptr > line && ptr[-1] == '[')) 2773236769Sobrien comment = line_end; 2774236769Sobrien } 2775236769Sobrien ptr++; 2776236769Sobrien if (ch == '\n') 2777236769Sobrien break; 2778236769Sobrien if (!isspace((unsigned char)ch)) 2779236769Sobrien /* We are not interested in trailing whitespace */ 2780236769Sobrien line_end = ptr; 2781236769Sobrien } 2782236769Sobrien 2783236769Sobrien /* Save next 'to be processed' location */ 2784236769Sobrien cf->P_ptr = ptr; 2785236769Sobrien 2786236769Sobrien /* Check we have a non-comment, non-blank line */ 2787236769Sobrien if (line_end == line || comment == line) { 2788236769Sobrien if (ch == 0) 2789236769Sobrien /* At end of file */ 2790236769Sobrien return NULL; 2791236769Sobrien /* Parse another line */ 2792236769Sobrien continue; 2793236769Sobrien } 2794236769Sobrien 2795236769Sobrien /* We now have a line of data */ 2796236769Sobrien *line_end = 0; 2797236769Sobrien 2798236769Sobrien if (flags & PARSE_RAW) { 2799236769Sobrien /* Leave '\' (etc) in line buffer (eg 'for' lines) */ 2800236769Sobrien *length = line_end - line; 2801236769Sobrien return line; 2802236769Sobrien } 2803236769Sobrien 2804236769Sobrien if (flags & PARSE_SKIP) { 2805236769Sobrien /* Completely ignore non-directives */ 2806236769Sobrien if (line[0] != '.') 2807236769Sobrien continue; 2808236769Sobrien /* We could do more of the .else/.elif/.endif checks here */ 2809236769Sobrien } 2810236769Sobrien break; 2811236769Sobrien } 2812236769Sobrien 2813236769Sobrien /* Brutally ignore anything after a non-escaped '#' in non-commands */ 2814236769Sobrien if (comment != NULL && line[0] != '\t') { 2815236769Sobrien line_end = comment; 2816236769Sobrien *line_end = 0; 2817236769Sobrien } 2818236769Sobrien 2819236769Sobrien /* If we didn't see a '\\' then the in-situ data is fine */ 2820236769Sobrien if (escaped == NULL) { 2821236769Sobrien *length = line_end - line; 2822236769Sobrien return line; 2823236769Sobrien } 2824236769Sobrien 2825236769Sobrien /* Remove escapes from '\n' and '#' */ 2826236769Sobrien tp = ptr = escaped; 2827236769Sobrien escaped = line; 2828236769Sobrien for (; ; *tp++ = ch) { 2829236769Sobrien ch = *ptr++; 2830236769Sobrien if (ch != '\\') { 2831236769Sobrien if (ch == 0) 2832236769Sobrien break; 2833236769Sobrien continue; 2834236769Sobrien } 2835236769Sobrien 2836236769Sobrien ch = *ptr++; 2837236769Sobrien if (ch == 0) { 2838236769Sobrien /* Delete '\\' at end of buffer */ 2839236769Sobrien tp--; 2840236769Sobrien break; 2841236769Sobrien } 2842236769Sobrien 2843236769Sobrien if (ch == '#' && line[0] != '\t') 2844236769Sobrien /* Delete '\\' from before '#' on non-command lines */ 2845236769Sobrien continue; 2846236769Sobrien 2847236769Sobrien if (ch != '\n') { 2848236769Sobrien /* Leave '\\' in buffer for later */ 2849236769Sobrien *tp++ = '\\'; 2850236769Sobrien /* Make sure we don't delete an escaped ' ' from the line end */ 2851236769Sobrien escaped = tp + 1; 2852236769Sobrien continue; 2853236769Sobrien } 2854236769Sobrien 2855236769Sobrien /* Escaped '\n' replace following whitespace with a single ' ' */ 2856236769Sobrien while (ptr[0] == ' ' || ptr[0] == '\t') 2857236769Sobrien ptr++; 2858236769Sobrien ch = ' '; 2859236769Sobrien } 2860236769Sobrien 2861236769Sobrien /* Delete any trailing spaces - eg from empty continuations */ 2862236769Sobrien while (tp > escaped && isspace((unsigned char)tp[-1])) 2863236769Sobrien tp--; 2864236769Sobrien 2865236769Sobrien *tp = 0; 2866236769Sobrien *length = tp - line; 2867236769Sobrien return line; 2868236769Sobrien} 2869236769Sobrien 2870236769Sobrien/*- 2871236769Sobrien *--------------------------------------------------------------------- 2872236769Sobrien * ParseReadLine -- 2873236769Sobrien * Read an entire line from the input file. Called only by Parse_File. 2874236769Sobrien * 2875236769Sobrien * Results: 2876236769Sobrien * A line w/o its newline 2877236769Sobrien * 2878236769Sobrien * Side Effects: 2879236769Sobrien * Only those associated with reading a character 2880236769Sobrien *--------------------------------------------------------------------- 2881236769Sobrien */ 2882236769Sobrienstatic char * 2883236769SobrienParseReadLine(void) 2884236769Sobrien{ 2885236769Sobrien char *line; /* Result */ 2886236769Sobrien int lineLength; /* Length of result */ 2887236769Sobrien int lineno; /* Saved line # */ 2888236769Sobrien int rval; 2889236769Sobrien 2890236769Sobrien for (;;) { 2891236769Sobrien line = ParseGetLine(0, &lineLength); 2892236769Sobrien if (line == NULL) 2893236769Sobrien return NULL; 2894236769Sobrien 2895236769Sobrien if (line[0] != '.') 2896236769Sobrien return line; 2897236769Sobrien 2898236769Sobrien /* 2899236769Sobrien * The line might be a conditional. Ask the conditional module 2900236769Sobrien * about it and act accordingly 2901236769Sobrien */ 2902236769Sobrien switch (Cond_Eval(line)) { 2903236769Sobrien case COND_SKIP: 2904236769Sobrien /* Skip to next conditional that evaluates to COND_PARSE. */ 2905236769Sobrien do { 2906236769Sobrien line = ParseGetLine(PARSE_SKIP, &lineLength); 2907236769Sobrien } while (line && Cond_Eval(line) != COND_PARSE); 2908236769Sobrien if (line == NULL) 2909236769Sobrien break; 2910236769Sobrien continue; 2911236769Sobrien case COND_PARSE: 2912236769Sobrien continue; 2913236769Sobrien case COND_INVALID: /* Not a conditional line */ 2914236769Sobrien /* Check for .for loops */ 2915236769Sobrien rval = For_Eval(line); 2916236769Sobrien if (rval == 0) 2917236769Sobrien /* Not a .for line */ 2918236769Sobrien break; 2919236769Sobrien if (rval < 0) 2920236769Sobrien /* Syntax error - error printed, ignore line */ 2921236769Sobrien continue; 2922236769Sobrien /* Start of a .for loop */ 2923236769Sobrien lineno = curFile->lineno; 2924236769Sobrien /* Accumulate loop lines until matching .endfor */ 2925236769Sobrien do { 2926236769Sobrien line = ParseGetLine(PARSE_RAW, &lineLength); 2927236769Sobrien if (line == NULL) { 2928236769Sobrien Parse_Error(PARSE_FATAL, 2929236769Sobrien "Unexpected end of file in for loop."); 2930236769Sobrien break; 2931236769Sobrien } 2932236769Sobrien } while (For_Accum(line)); 2933236769Sobrien /* Stash each iteration as a new 'input file' */ 2934236769Sobrien For_Run(lineno); 2935236769Sobrien /* Read next line from for-loop buffer */ 2936236769Sobrien continue; 2937236769Sobrien } 2938236769Sobrien return (line); 2939236769Sobrien } 2940236769Sobrien} 2941236769Sobrien 2942236769Sobrien/*- 2943236769Sobrien *----------------------------------------------------------------------- 2944236769Sobrien * ParseFinishLine -- 2945236769Sobrien * Handle the end of a dependency group. 2946236769Sobrien * 2947236769Sobrien * Results: 2948236769Sobrien * Nothing. 2949236769Sobrien * 2950236769Sobrien * Side Effects: 2951236769Sobrien * inLine set FALSE. 'targets' list destroyed. 2952236769Sobrien * 2953236769Sobrien *----------------------------------------------------------------------- 2954236769Sobrien */ 2955236769Sobrienstatic void 2956236769SobrienParseFinishLine(void) 2957236769Sobrien{ 2958236769Sobrien if (inLine) { 2959236769Sobrien Lst_ForEach(targets, Suff_EndTransform, NULL); 2960236769Sobrien Lst_Destroy(targets, ParseHasCommands); 2961236769Sobrien targets = NULL; 2962236769Sobrien inLine = FALSE; 2963236769Sobrien } 2964236769Sobrien} 2965236769Sobrien 2966236769Sobrien 2967236769Sobrien/*- 2968236769Sobrien *--------------------------------------------------------------------- 2969236769Sobrien * Parse_File -- 2970236769Sobrien * Parse a file into its component parts, incorporating it into the 2971236769Sobrien * current dependency graph. This is the main function and controls 2972236769Sobrien * almost every other function in this module 2973236769Sobrien * 2974236769Sobrien * Input: 2975236769Sobrien * name the name of the file being read 2976236769Sobrien * fd Open file to makefile to parse 2977236769Sobrien * 2978236769Sobrien * Results: 2979236769Sobrien * None 2980236769Sobrien * 2981236769Sobrien * Side Effects: 2982236769Sobrien * closes fd. 2983236769Sobrien * Loads. Nodes are added to the list of all targets, nodes and links 2984236769Sobrien * are added to the dependency graph. etc. etc. etc. 2985236769Sobrien *--------------------------------------------------------------------- 2986236769Sobrien */ 2987236769Sobrienvoid 2988236769SobrienParse_File(const char *name, int fd) 2989236769Sobrien{ 2990236769Sobrien char *cp; /* pointer into the line */ 2991236769Sobrien char *line; /* the line we're working on */ 2992236769Sobrien struct loadedfile *lf; 2993236769Sobrien 2994236769Sobrien lf = loadfile(name, fd); 2995236769Sobrien 2996236769Sobrien inLine = FALSE; 2997236769Sobrien fatals = 0; 2998236769Sobrien 2999236769Sobrien if (name == NULL) { 3000236769Sobrien name = "(stdin)"; 3001236769Sobrien } 3002236769Sobrien 3003236769Sobrien Parse_SetInput(name, 0, -1, loadedfile_nextbuf, lf); 3004236769Sobrien curFile->lf = lf; 3005236769Sobrien 3006236769Sobrien do { 3007236769Sobrien for (; (line = ParseReadLine()) != NULL; ) { 3008236769Sobrien if (DEBUG(PARSE)) 3009236769Sobrien fprintf(debug_file, "ParseReadLine (%d): '%s'\n", 3010236769Sobrien curFile->lineno, line); 3011236769Sobrien if (*line == '.') { 3012236769Sobrien /* 3013236769Sobrien * Lines that begin with the special character may be 3014236769Sobrien * include or undef directives. 3015236769Sobrien * On the other hand they can be suffix rules (.c.o: ...) 3016236769Sobrien * or just dependencies for filenames that start '.'. 3017236769Sobrien */ 3018236769Sobrien for (cp = line + 1; isspace((unsigned char)*cp); cp++) { 3019236769Sobrien continue; 3020236769Sobrien } 3021236769Sobrien if (strncmp(cp, "include", 7) == 0 || 3022296637Ssjg ((cp[0] == 'd' || cp[0] == 's' || cp[0] == '-') && 3023236769Sobrien strncmp(&cp[1], "include", 7) == 0)) { 3024236769Sobrien ParseDoInclude(cp); 3025236769Sobrien continue; 3026236769Sobrien } 3027236769Sobrien if (strncmp(cp, "undef", 5) == 0) { 3028236769Sobrien char *cp2; 3029236769Sobrien for (cp += 5; isspace((unsigned char) *cp); cp++) 3030236769Sobrien continue; 3031236769Sobrien for (cp2 = cp; !isspace((unsigned char) *cp2) && 3032236769Sobrien (*cp2 != '\0'); cp2++) 3033236769Sobrien continue; 3034236769Sobrien *cp2 = '\0'; 3035236769Sobrien Var_Delete(cp, VAR_GLOBAL); 3036236769Sobrien continue; 3037236769Sobrien } else if (strncmp(cp, "export", 6) == 0) { 3038236769Sobrien for (cp += 6; isspace((unsigned char) *cp); cp++) 3039236769Sobrien continue; 3040236769Sobrien Var_Export(cp, 1); 3041236769Sobrien continue; 3042236769Sobrien } else if (strncmp(cp, "unexport", 8) == 0) { 3043236769Sobrien Var_UnExport(cp); 3044236769Sobrien continue; 3045236769Sobrien } else if (strncmp(cp, "info", 4) == 0 || 3046236769Sobrien strncmp(cp, "error", 5) == 0 || 3047236769Sobrien strncmp(cp, "warning", 7) == 0) { 3048236769Sobrien if (ParseMessage(cp)) 3049236769Sobrien continue; 3050236769Sobrien } 3051236769Sobrien } 3052236769Sobrien 3053236769Sobrien if (*line == '\t') { 3054236769Sobrien /* 3055236769Sobrien * If a line starts with a tab, it can only hope to be 3056236769Sobrien * a creation command. 3057236769Sobrien */ 3058236769Sobrien cp = line + 1; 3059236769Sobrien shellCommand: 3060236769Sobrien for (; isspace ((unsigned char)*cp); cp++) { 3061236769Sobrien continue; 3062236769Sobrien } 3063236769Sobrien if (*cp) { 3064236769Sobrien if (!inLine) 3065236769Sobrien Parse_Error(PARSE_FATAL, 3066236769Sobrien "Unassociated shell command \"%s\"", 3067236769Sobrien cp); 3068236769Sobrien /* 3069236769Sobrien * So long as it's not a blank line and we're actually 3070236769Sobrien * in a dependency spec, add the command to the list of 3071236769Sobrien * commands of all targets in the dependency spec 3072236769Sobrien */ 3073236769Sobrien if (targets) { 3074236769Sobrien cp = bmake_strdup(cp); 3075236769Sobrien Lst_ForEach(targets, ParseAddCmd, cp); 3076236769Sobrien#ifdef CLEANUP 3077236769Sobrien Lst_AtEnd(targCmds, cp); 3078236769Sobrien#endif 3079236769Sobrien } 3080236769Sobrien } 3081236769Sobrien continue; 3082236769Sobrien } 3083236769Sobrien 3084236769Sobrien#ifdef SYSVINCLUDE 3085236769Sobrien if (((strncmp(line, "include", 7) == 0 && 3086236769Sobrien isspace((unsigned char) line[7])) || 3087236769Sobrien ((line[0] == 's' || line[0] == '-') && 3088236769Sobrien strncmp(&line[1], "include", 7) == 0 && 3089236769Sobrien isspace((unsigned char) line[8]))) && 3090236769Sobrien strchr(line, ':') == NULL) { 3091236769Sobrien /* 3092236769Sobrien * It's an S3/S5-style "include". 3093236769Sobrien */ 3094236769Sobrien ParseTraditionalInclude(line); 3095236769Sobrien continue; 3096236769Sobrien } 3097236769Sobrien#endif 3098236769Sobrien#ifdef GMAKEEXPORT 3099236769Sobrien if (strncmp(line, "export", 6) == 0 && 3100236769Sobrien isspace((unsigned char) line[6]) && 3101236769Sobrien strchr(line, ':') == NULL) { 3102236769Sobrien /* 3103236769Sobrien * It's a Gmake "export". 3104236769Sobrien */ 3105236769Sobrien ParseGmakeExport(line); 3106236769Sobrien continue; 3107236769Sobrien } 3108236769Sobrien#endif 3109236769Sobrien if (Parse_IsVar(line)) { 3110236769Sobrien ParseFinishLine(); 3111236769Sobrien Parse_DoVar(line, VAR_GLOBAL); 3112236769Sobrien continue; 3113236769Sobrien } 3114236769Sobrien 3115236769Sobrien#ifndef POSIX 3116236769Sobrien /* 3117236769Sobrien * To make life easier on novices, if the line is indented we 3118236769Sobrien * first make sure the line has a dependency operator in it. 3119236769Sobrien * If it doesn't have an operator and we're in a dependency 3120236769Sobrien * line's script, we assume it's actually a shell command 3121236769Sobrien * and add it to the current list of targets. 3122236769Sobrien */ 3123236769Sobrien cp = line; 3124236769Sobrien if (isspace((unsigned char) line[0])) { 3125236769Sobrien while ((*cp != '\0') && isspace((unsigned char) *cp)) 3126236769Sobrien cp++; 3127236769Sobrien while (*cp && (ParseIsEscaped(line, cp) || 3128236769Sobrien (*cp != ':') && (*cp != '!'))) { 3129236769Sobrien cp++; 3130236769Sobrien } 3131236769Sobrien if (*cp == '\0') { 3132236769Sobrien if (inLine) { 3133236769Sobrien Parse_Error(PARSE_WARNING, 3134236769Sobrien "Shell command needs a leading tab"); 3135236769Sobrien goto shellCommand; 3136236769Sobrien } 3137236769Sobrien } 3138236769Sobrien } 3139236769Sobrien#endif 3140236769Sobrien ParseFinishLine(); 3141236769Sobrien 3142236769Sobrien /* 3143236769Sobrien * For some reason - probably to make the parser impossible - 3144236769Sobrien * a ';' can be used to separate commands from dependencies. 3145236769Sobrien * Attempt to avoid ';' inside substitution patterns. 3146236769Sobrien */ 3147236769Sobrien { 3148236769Sobrien int level = 0; 3149236769Sobrien 3150236769Sobrien for (cp = line; *cp != 0; cp++) { 3151236769Sobrien if (*cp == '\\' && cp[1] != 0) { 3152236769Sobrien cp++; 3153236769Sobrien continue; 3154236769Sobrien } 3155236769Sobrien if (*cp == '$' && 3156236769Sobrien (cp[1] == '(' || cp[1] == '{')) { 3157236769Sobrien level++; 3158236769Sobrien continue; 3159236769Sobrien } 3160236769Sobrien if (level > 0) { 3161236769Sobrien if (*cp == ')' || *cp == '}') { 3162236769Sobrien level--; 3163236769Sobrien continue; 3164236769Sobrien } 3165236769Sobrien } else if (*cp == ';') { 3166236769Sobrien break; 3167236769Sobrien } 3168236769Sobrien } 3169236769Sobrien } 3170236769Sobrien if (*cp != 0) 3171236769Sobrien /* Terminate the dependency list at the ';' */ 3172236769Sobrien *cp++ = 0; 3173236769Sobrien else 3174236769Sobrien cp = NULL; 3175236769Sobrien 3176236769Sobrien /* 3177236769Sobrien * We now know it's a dependency line so it needs to have all 3178236769Sobrien * variables expanded before being parsed. Tell the variable 3179236769Sobrien * module to complain if some variable is undefined... 3180236769Sobrien */ 3181296637Ssjg line = Var_Subst(NULL, line, VAR_CMD, VARF_UNDEFERR|VARF_WANTRES); 3182236769Sobrien 3183236769Sobrien /* 3184236769Sobrien * Need a non-circular list for the target nodes 3185236769Sobrien */ 3186236769Sobrien if (targets) 3187236769Sobrien Lst_Destroy(targets, NULL); 3188236769Sobrien 3189236769Sobrien targets = Lst_Init(FALSE); 3190236769Sobrien inLine = TRUE; 3191236769Sobrien 3192236769Sobrien ParseDoDependency(line); 3193236769Sobrien free(line); 3194236769Sobrien 3195236769Sobrien /* If there were commands after a ';', add them now */ 3196236769Sobrien if (cp != NULL) { 3197236769Sobrien goto shellCommand; 3198236769Sobrien } 3199236769Sobrien } 3200236769Sobrien /* 3201236769Sobrien * Reached EOF, but it may be just EOF of an include file... 3202236769Sobrien */ 3203236769Sobrien } while (ParseEOF() == CONTINUE); 3204236769Sobrien 3205236769Sobrien if (fatals) { 3206236769Sobrien (void)fflush(stdout); 3207236769Sobrien (void)fprintf(stderr, 3208236769Sobrien "%s: Fatal errors encountered -- cannot continue", 3209236769Sobrien progname); 3210236769Sobrien PrintOnError(NULL, NULL); 3211236769Sobrien exit(1); 3212236769Sobrien } 3213236769Sobrien} 3214236769Sobrien 3215236769Sobrien/*- 3216236769Sobrien *--------------------------------------------------------------------- 3217236769Sobrien * Parse_Init -- 3218236769Sobrien * initialize the parsing module 3219236769Sobrien * 3220236769Sobrien * Results: 3221236769Sobrien * none 3222236769Sobrien * 3223236769Sobrien * Side Effects: 3224236769Sobrien * the parseIncPath list is initialized... 3225236769Sobrien *--------------------------------------------------------------------- 3226236769Sobrien */ 3227236769Sobrienvoid 3228236769SobrienParse_Init(void) 3229236769Sobrien{ 3230236769Sobrien mainNode = NULL; 3231236769Sobrien parseIncPath = Lst_Init(FALSE); 3232236769Sobrien sysIncPath = Lst_Init(FALSE); 3233236769Sobrien defIncPath = Lst_Init(FALSE); 3234236769Sobrien includes = Lst_Init(FALSE); 3235236769Sobrien#ifdef CLEANUP 3236236769Sobrien targCmds = Lst_Init(FALSE); 3237236769Sobrien#endif 3238236769Sobrien} 3239236769Sobrien 3240236769Sobrienvoid 3241236769SobrienParse_End(void) 3242236769Sobrien{ 3243236769Sobrien#ifdef CLEANUP 3244236769Sobrien Lst_Destroy(targCmds, (FreeProc *)free); 3245236769Sobrien if (targets) 3246236769Sobrien Lst_Destroy(targets, NULL); 3247236769Sobrien Lst_Destroy(defIncPath, Dir_Destroy); 3248236769Sobrien Lst_Destroy(sysIncPath, Dir_Destroy); 3249236769Sobrien Lst_Destroy(parseIncPath, Dir_Destroy); 3250236769Sobrien Lst_Destroy(includes, NULL); /* Should be empty now */ 3251236769Sobrien#endif 3252236769Sobrien} 3253236769Sobrien 3254236769Sobrien 3255236769Sobrien/*- 3256236769Sobrien *----------------------------------------------------------------------- 3257236769Sobrien * Parse_MainName -- 3258236769Sobrien * Return a Lst of the main target to create for main()'s sake. If 3259236769Sobrien * no such target exists, we Punt with an obnoxious error message. 3260236769Sobrien * 3261236769Sobrien * Results: 3262236769Sobrien * A Lst of the single node to create. 3263236769Sobrien * 3264236769Sobrien * Side Effects: 3265236769Sobrien * None. 3266236769Sobrien * 3267236769Sobrien *----------------------------------------------------------------------- 3268236769Sobrien */ 3269236769SobrienLst 3270236769SobrienParse_MainName(void) 3271236769Sobrien{ 3272236769Sobrien Lst mainList; /* result list */ 3273236769Sobrien 3274236769Sobrien mainList = Lst_Init(FALSE); 3275236769Sobrien 3276236769Sobrien if (mainNode == NULL) { 3277236769Sobrien Punt("no target to make."); 3278236769Sobrien /*NOTREACHED*/ 3279236769Sobrien } else if (mainNode->type & OP_DOUBLEDEP) { 3280236769Sobrien (void)Lst_AtEnd(mainList, mainNode); 3281236769Sobrien Lst_Concat(mainList, mainNode->cohorts, LST_CONCNEW); 3282236769Sobrien } 3283236769Sobrien else 3284236769Sobrien (void)Lst_AtEnd(mainList, mainNode); 3285236769Sobrien Var_Append(".TARGETS", mainNode->name, VAR_GLOBAL); 3286236769Sobrien return (mainList); 3287236769Sobrien} 3288236769Sobrien 3289236769Sobrien/*- 3290236769Sobrien *----------------------------------------------------------------------- 3291236769Sobrien * ParseMark -- 3292236769Sobrien * Add the filename and lineno to the GNode so that we remember 3293236769Sobrien * where it was first defined. 3294236769Sobrien * 3295236769Sobrien * Side Effects: 3296236769Sobrien * None. 3297236769Sobrien * 3298236769Sobrien *----------------------------------------------------------------------- 3299236769Sobrien */ 3300236769Sobrienstatic void 3301236769SobrienParseMark(GNode *gn) 3302236769Sobrien{ 3303236769Sobrien gn->fname = curFile->fname; 3304236769Sobrien gn->lineno = curFile->lineno; 3305236769Sobrien} 3306