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