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