parse.c revision 93056
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1988, 1989, 1990, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * Copyright (c) 1989 by Berkeley Softworks 51590Srgrimes * All rights reserved. 61590Srgrimes * 71590Srgrimes * This code is derived from software contributed to Berkeley by 81590Srgrimes * Adam de Boor. 91590Srgrimes * 101590Srgrimes * Redistribution and use in source and binary forms, with or without 111590Srgrimes * modification, are permitted provided that the following conditions 121590Srgrimes * are met: 131590Srgrimes * 1. Redistributions of source code must retain the above copyright 141590Srgrimes * notice, this list of conditions and the following disclaimer. 151590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 161590Srgrimes * notice, this list of conditions and the following disclaimer in the 171590Srgrimes * documentation and/or other materials provided with the distribution. 181590Srgrimes * 3. All advertising materials mentioning features or use of this software 191590Srgrimes * must display the following acknowledgement: 201590Srgrimes * This product includes software developed by the University of 211590Srgrimes * California, Berkeley and its contributors. 221590Srgrimes * 4. Neither the name of the University nor the names of its contributors 231590Srgrimes * may be used to endorse or promote products derived from this software 241590Srgrimes * without specific prior written permission. 251590Srgrimes * 261590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 271590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 281590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 291590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 301590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 311590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 321590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 331590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 341590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 351590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 361590Srgrimes * SUCH DAMAGE. 3762833Swsanchez * 3862833Swsanchez * @(#)parse.c 8.3 (Berkeley) 3/19/94 391590Srgrimes */ 401590Srgrimes 411590Srgrimes#ifndef lint 4262833Swsanchez#include <sys/cdefs.h> 4362833Swsanchez__RCSID("$FreeBSD: head/usr.bin/make/parse.c 93056 2002-03-23 23:30:30Z imp $"); 441590Srgrimes#endif /* not lint */ 451590Srgrimes 461590Srgrimes/*- 471590Srgrimes * parse.c -- 481590Srgrimes * Functions to parse a makefile. 491590Srgrimes * 501590Srgrimes * One function, Parse_Init, must be called before any functions 511590Srgrimes * in this module are used. After that, the function Parse_File is the 521590Srgrimes * main entry point and controls most of the other functions in this 531590Srgrimes * module. 541590Srgrimes * 551590Srgrimes * Most important structures are kept in Lsts. Directories for 561590Srgrimes * the #include "..." function are kept in the 'parseIncPath' Lst, while 571590Srgrimes * those for the #include <...> are kept in the 'sysIncPath' Lst. The 581590Srgrimes * targets currently being defined are kept in the 'targets' Lst. 591590Srgrimes * 601590Srgrimes * The variables 'fname' and 'lineno' are used to track the name 611590Srgrimes * of the current file and the line number in that file so that error 621590Srgrimes * messages can be more meaningful. 631590Srgrimes * 641590Srgrimes * Interface: 651590Srgrimes * Parse_Init Initialization function which must be 661590Srgrimes * called before anything else in this module 671590Srgrimes * is used. 681590Srgrimes * 695814Sjkh * Parse_End Cleanup the module 705814Sjkh * 711590Srgrimes * Parse_File Function used to parse a makefile. It must 721590Srgrimes * be given the name of the file, which should 731590Srgrimes * already have been opened, and a function 741590Srgrimes * to call to read a character from the file. 751590Srgrimes * 761590Srgrimes * Parse_IsVar Returns TRUE if the given line is a 771590Srgrimes * variable assignment. Used by MainParseArgs 781590Srgrimes * to determine if an argument is a target 791590Srgrimes * or a variable assignment. Used internally 801590Srgrimes * for pretty much the same thing... 811590Srgrimes * 821590Srgrimes * Parse_Error Function called when an error occurs in 831590Srgrimes * parsing. Used by the variable and 841590Srgrimes * conditional modules. 851590Srgrimes * Parse_MainName Returns a Lst of the main target to create. 861590Srgrimes */ 871590Srgrimes 881590Srgrimes#include <stdarg.h> 8927644Scharnier#include <ctype.h> 9027644Scharnier#include <err.h> 911590Srgrimes#include <stdio.h> 921590Srgrimes#include "make.h" 931590Srgrimes#include "hash.h" 941590Srgrimes#include "dir.h" 951590Srgrimes#include "job.h" 961590Srgrimes#include "buf.h" 971590Srgrimes#include "pathnames.h" 981590Srgrimes 991590Srgrimes/* 1001590Srgrimes * These values are returned by ParseEOF to tell Parse_File whether to 1011590Srgrimes * CONTINUE parsing, i.e. it had only reached the end of an include file, 1021590Srgrimes * or if it's DONE. 1031590Srgrimes */ 1041590Srgrimes#define CONTINUE 1 1051590Srgrimes#define DONE 0 1061590Srgrimesstatic Lst targets; /* targets we're working on */ 1075814Sjkhstatic Lst targCmds; /* command lines for targets */ 1081590Srgrimesstatic Boolean inLine; /* true if currently in a dependency 1091590Srgrimes * line or its commands */ 1101590Srgrimestypedef struct { 1111590Srgrimes char *str; 1121590Srgrimes char *ptr; 1131590Srgrimes} PTR; 1141590Srgrimes 1151590Srgrimesstatic char *fname; /* name of current file (for errors) */ 1161590Srgrimesstatic int lineno; /* line number in current file */ 1171590Srgrimesstatic FILE *curFILE = NULL; /* current makefile */ 1181590Srgrimes 1191590Srgrimesstatic PTR *curPTR = NULL; /* current makefile */ 1201590Srgrimes 1211590Srgrimesstatic int fatals = 0; 1221590Srgrimes 1231590Srgrimesstatic GNode *mainNode; /* The main target to create. This is the 1241590Srgrimes * first target on the first dependency 1251590Srgrimes * line in the first makefile */ 1261590Srgrimes/* 1271590Srgrimes * Definitions for handling #include specifications 1281590Srgrimes */ 1291590Srgrimestypedef struct IFile { 1301590Srgrimes char *fname; /* name of previous file */ 1311590Srgrimes int lineno; /* saved line number */ 1321590Srgrimes FILE * F; /* the open stream */ 1331590Srgrimes PTR * p; /* the char pointer */ 1341590Srgrimes} IFile; 1351590Srgrimes 1361590Srgrimesstatic Lst includes; /* stack of IFiles generated by 1371590Srgrimes * #includes */ 1381590SrgrimesLst parseIncPath; /* list of directories for "..." includes */ 1391590SrgrimesLst sysIncPath; /* list of directories for <...> includes */ 1401590Srgrimes 1411590Srgrimes/*- 1421590Srgrimes * specType contains the SPECial TYPE of the current target. It is 1431590Srgrimes * Not if the target is unspecial. If it *is* special, however, the children 1441590Srgrimes * are linked as children of the parent but not vice versa. This variable is 1451590Srgrimes * set in ParseDoDependency 1461590Srgrimes */ 1471590Srgrimestypedef enum { 1481590Srgrimes Begin, /* .BEGIN */ 1491590Srgrimes Default, /* .DEFAULT */ 1501590Srgrimes End, /* .END */ 1511590Srgrimes Ignore, /* .IGNORE */ 1521590Srgrimes Includes, /* .INCLUDES */ 1531590Srgrimes Interrupt, /* .INTERRUPT */ 1541590Srgrimes Libs, /* .LIBS */ 1551590Srgrimes MFlags, /* .MFLAGS or .MAKEFLAGS */ 1561590Srgrimes Main, /* .MAIN and we don't have anything user-specified to 1571590Srgrimes * make */ 1581590Srgrimes NoExport, /* .NOEXPORT */ 1591590Srgrimes Not, /* Not special */ 1601590Srgrimes NotParallel, /* .NOTPARALELL */ 1611590Srgrimes Null, /* .NULL */ 1621590Srgrimes Order, /* .ORDER */ 16318730Ssteve Parallel, /* .PARALLEL */ 1641590Srgrimes ExPath, /* .PATH */ 16518730Ssteve Phony, /* .PHONY */ 16619344Ssteve#ifdef POSIX 16719344Ssteve Posix, /* .POSIX */ 16819344Ssteve#endif 1691590Srgrimes Precious, /* .PRECIOUS */ 1701590Srgrimes ExShell, /* .SHELL */ 1711590Srgrimes Silent, /* .SILENT */ 1721590Srgrimes SingleShell, /* .SINGLESHELL */ 1731590Srgrimes Suffixes, /* .SUFFIXES */ 17418730Ssteve Wait, /* .WAIT */ 1751590Srgrimes Attribute /* Generic attribute */ 1761590Srgrimes} ParseSpecial; 1771590Srgrimes 1781590Srgrimesstatic ParseSpecial specType; 17918730Sstevestatic int waiting; 1801590Srgrimes 1811590Srgrimes/* 18269527Swill * Predecessor node for handling .ORDER. Initialized to NULL when .ORDER 1831590Srgrimes * seen, then set to each successive source on the line. 1841590Srgrimes */ 1851590Srgrimesstatic GNode *predecessor; 1861590Srgrimes 1871590Srgrimes/* 1881590Srgrimes * The parseKeywords table is searched using binary search when deciding 1891590Srgrimes * if a target or source is special. The 'spec' field is the ParseSpecial 1901590Srgrimes * type of the keyword ("Not" if the keyword isn't special as a target) while 1911590Srgrimes * the 'op' field is the operator to apply to the list of targets if the 1921590Srgrimes * keyword is used as a source ("0" if the keyword isn't special as a source) 1931590Srgrimes */ 1941590Srgrimesstatic struct { 1951590Srgrimes char *name; /* Name of keyword */ 1961590Srgrimes ParseSpecial spec; /* Type when used as a target */ 1971590Srgrimes int op; /* Operator when used as a source */ 1981590Srgrimes} parseKeywords[] = { 1991590Srgrimes{ ".BEGIN", Begin, 0 }, 2001590Srgrimes{ ".DEFAULT", Default, 0 }, 2011590Srgrimes{ ".END", End, 0 }, 2021590Srgrimes{ ".EXEC", Attribute, OP_EXEC }, 2031590Srgrimes{ ".IGNORE", Ignore, OP_IGNORE }, 2041590Srgrimes{ ".INCLUDES", Includes, 0 }, 2051590Srgrimes{ ".INTERRUPT", Interrupt, 0 }, 2061590Srgrimes{ ".INVISIBLE", Attribute, OP_INVISIBLE }, 2071590Srgrimes{ ".JOIN", Attribute, OP_JOIN }, 2081590Srgrimes{ ".LIBS", Libs, 0 }, 2091590Srgrimes{ ".MAIN", Main, 0 }, 2101590Srgrimes{ ".MAKE", Attribute, OP_MAKE }, 2111590Srgrimes{ ".MAKEFLAGS", MFlags, 0 }, 2121590Srgrimes{ ".MFLAGS", MFlags, 0 }, 2131590Srgrimes{ ".NOTMAIN", Attribute, OP_NOTMAIN }, 2141590Srgrimes{ ".NOTPARALLEL", NotParallel, 0 }, 21518730Ssteve{ ".NO_PARALLEL", NotParallel, 0 }, 2161590Srgrimes{ ".NULL", Null, 0 }, 2179254Sache{ ".OPTIONAL", Attribute, OP_OPTIONAL }, 2181590Srgrimes{ ".ORDER", Order, 0 }, 21918730Ssteve{ ".PARALLEL", Parallel, 0 }, 2201590Srgrimes{ ".PATH", ExPath, 0 }, 22118730Ssteve{ ".PHONY", Phony, OP_PHONY }, 22219344Ssteve#ifdef POSIX 22319344Ssteve{ ".POSIX", Posix, 0 }, 22419344Ssteve#endif 2251590Srgrimes{ ".PRECIOUS", Precious, OP_PRECIOUS }, 2261590Srgrimes{ ".RECURSIVE", Attribute, OP_MAKE }, 2271590Srgrimes{ ".SHELL", ExShell, 0 }, 2281590Srgrimes{ ".SILENT", Silent, OP_SILENT }, 2291590Srgrimes{ ".SINGLESHELL", SingleShell, 0 }, 2301590Srgrimes{ ".SUFFIXES", Suffixes, 0 }, 2311590Srgrimes{ ".USE", Attribute, OP_USE }, 23218730Ssteve{ ".WAIT", Wait, 0 }, 2331590Srgrimes}; 2341590Srgrimes 23592921Simpstatic int ParseFindKeyword(char *); 23692921Simpstatic int ParseLinkSrc(void *, void *); 23792921Simpstatic int ParseDoOp(void *, void *); 23892921Simpstatic int ParseAddDep(void *, void *); 23992921Simpstatic void ParseDoSrc(int, char *, Lst); 24092921Simpstatic int ParseFindMain(void *, void *); 24192921Simpstatic int ParseAddDir(void *, void *); 24292921Simpstatic int ParseClearPath(void *, void *); 24392921Simpstatic void ParseDoDependency(char *); 24492921Simpstatic int ParseAddCmd(void *, void *); 24592921Simpstatic int ParseReadc(void); 24692921Simpstatic void ParseUnreadc(int); 24792921Simpstatic void ParseHasCommands(void *); 24892921Simpstatic void ParseDoInclude(char *); 24992921Simpstatic void ParseDoError(char *); 2501590Srgrimes#ifdef SYSVINCLUDE 25192921Simpstatic void ParseTraditionalInclude(char *); 2521590Srgrimes#endif 25392921Simpstatic int ParseEOF(int); 25492921Simpstatic char *ParseReadLine(void); 25592921Simpstatic char *ParseSkipLine(int); 25692921Simpstatic void ParseFinishLine(void); 2571590Srgrimes 2581590Srgrimes/*- 2591590Srgrimes *---------------------------------------------------------------------- 2601590Srgrimes * ParseFindKeyword -- 2611590Srgrimes * Look in the table of keywords for one matching the given string. 2621590Srgrimes * 2631590Srgrimes * Results: 2641590Srgrimes * The index of the keyword, or -1 if it isn't there. 2651590Srgrimes * 2661590Srgrimes * Side Effects: 2671590Srgrimes * None 2681590Srgrimes *---------------------------------------------------------------------- 2691590Srgrimes */ 2701590Srgrimesstatic int 2711590SrgrimesParseFindKeyword (str) 2721590Srgrimes char *str; /* String to find */ 2731590Srgrimes{ 2741590Srgrimes register int start, 2751590Srgrimes end, 2761590Srgrimes cur; 2771590Srgrimes register int diff; 2788874Srgrimes 2791590Srgrimes start = 0; 2801590Srgrimes end = (sizeof(parseKeywords)/sizeof(parseKeywords[0])) - 1; 2811590Srgrimes 2821590Srgrimes do { 2831590Srgrimes cur = start + ((end - start) / 2); 2841590Srgrimes diff = strcmp (str, parseKeywords[cur].name); 2851590Srgrimes 2861590Srgrimes if (diff == 0) { 2871590Srgrimes return (cur); 2881590Srgrimes } else if (diff < 0) { 2891590Srgrimes end = cur - 1; 2901590Srgrimes } else { 2911590Srgrimes start = cur + 1; 2921590Srgrimes } 2931590Srgrimes } while (start <= end); 2941590Srgrimes return (-1); 2951590Srgrimes} 2961590Srgrimes 2971590Srgrimes/*- 2981590Srgrimes * Parse_Error -- 2991590Srgrimes * Error message abort function for parsing. Prints out the context 3001590Srgrimes * of the error (line number and file) as well as the message with 3011590Srgrimes * two optional arguments. 3021590Srgrimes * 3031590Srgrimes * Results: 3041590Srgrimes * None 3051590Srgrimes * 3061590Srgrimes * Side Effects: 3071590Srgrimes * "fatals" is incremented if the level is PARSE_FATAL. 3081590Srgrimes */ 3091590Srgrimes/* VARARGS */ 3101590Srgrimesvoid 3115814SjkhParse_Error(int type, char *fmt, ...) 3121590Srgrimes{ 3131590Srgrimes va_list ap; 31493056Simp 3151590Srgrimes va_start(ap, fmt); 3161590Srgrimes (void)fprintf(stderr, "\"%s\", line %d: ", fname, lineno); 3171590Srgrimes if (type == PARSE_WARNING) 3181590Srgrimes (void)fprintf(stderr, "warning: "); 3191590Srgrimes (void)vfprintf(stderr, fmt, ap); 3201590Srgrimes va_end(ap); 3211590Srgrimes (void)fprintf(stderr, "\n"); 3221590Srgrimes (void)fflush(stderr); 3231590Srgrimes if (type == PARSE_FATAL) 3241590Srgrimes fatals += 1; 3251590Srgrimes} 3261590Srgrimes 3271590Srgrimes/*- 3281590Srgrimes *--------------------------------------------------------------------- 3291590Srgrimes * ParseLinkSrc -- 3301590Srgrimes * Link the parent node to its new child. Used in a Lst_ForEach by 3311590Srgrimes * ParseDoDependency. If the specType isn't 'Not', the parent 3321590Srgrimes * isn't linked as a parent of the child. 3331590Srgrimes * 3341590Srgrimes * Results: 3351590Srgrimes * Always = 0 3361590Srgrimes * 3371590Srgrimes * Side Effects: 3381590Srgrimes * New elements are added to the parents list of cgn and the 3391590Srgrimes * children list of cgn. the unmade field of pgn is updated 3401590Srgrimes * to reflect the additional child. 3411590Srgrimes *--------------------------------------------------------------------- 3421590Srgrimes */ 3431590Srgrimesstatic int 3445814SjkhParseLinkSrc (pgnp, cgnp) 34569531Swill void * pgnp; /* The parent node */ 34669531Swill void * cgnp; /* The child node */ 3471590Srgrimes{ 3485814Sjkh GNode *pgn = (GNode *) pgnp; 3495814Sjkh GNode *cgn = (GNode *) cgnp; 35069531Swill if (Lst_Member (pgn->children, (void *)cgn) == NULL) { 35169531Swill (void)Lst_AtEnd (pgn->children, (void *)cgn); 3521590Srgrimes if (specType == Not) { 35369531Swill (void)Lst_AtEnd (cgn->parents, (void *)pgn); 3541590Srgrimes } 3551590Srgrimes pgn->unmade += 1; 3561590Srgrimes } 3571590Srgrimes return (0); 3581590Srgrimes} 3591590Srgrimes 3601590Srgrimes/*- 3611590Srgrimes *--------------------------------------------------------------------- 3621590Srgrimes * ParseDoOp -- 3631590Srgrimes * Apply the parsed operator to the given target node. Used in a 3641590Srgrimes * Lst_ForEach call by ParseDoDependency once all targets have 3651590Srgrimes * been found and their operator parsed. If the previous and new 3661590Srgrimes * operators are incompatible, a major error is taken. 3671590Srgrimes * 3681590Srgrimes * Results: 3691590Srgrimes * Always 0 3701590Srgrimes * 3711590Srgrimes * Side Effects: 3721590Srgrimes * The type field of the node is altered to reflect any new bits in 3731590Srgrimes * the op. 3741590Srgrimes *--------------------------------------------------------------------- 3751590Srgrimes */ 3761590Srgrimesstatic int 3775814SjkhParseDoOp (gnp, opp) 37869531Swill void * gnp; /* The node to which the operator is to be 3791590Srgrimes * applied */ 38069531Swill void * opp; /* The operator to apply */ 3811590Srgrimes{ 3825814Sjkh GNode *gn = (GNode *) gnp; 3835814Sjkh int op = *(int *) opp; 3841590Srgrimes /* 3851590Srgrimes * If the dependency mask of the operator and the node don't match and 3861590Srgrimes * the node has actually had an operator applied to it before, and 3878874Srgrimes * the operator actually has some dependency information in it, complain. 3881590Srgrimes */ 3891590Srgrimes if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) && 3901590Srgrimes !OP_NOP(gn->type) && !OP_NOP(op)) 3911590Srgrimes { 3921590Srgrimes Parse_Error (PARSE_FATAL, "Inconsistent operator for %s", gn->name); 3931590Srgrimes return (1); 3941590Srgrimes } 3951590Srgrimes 3961590Srgrimes if ((op == OP_DOUBLEDEP) && ((gn->type & OP_OPMASK) == OP_DOUBLEDEP)) { 3971590Srgrimes /* 3981590Srgrimes * If the node was the object of a :: operator, we need to create a 3991590Srgrimes * new instance of it for the children and commands on this dependency 4001590Srgrimes * line. The new instance is placed on the 'cohorts' list of the 4011590Srgrimes * initial one (note the initial one is not on its own cohorts list) 4021590Srgrimes * and the new instance is linked to all parents of the initial 4031590Srgrimes * instance. 4041590Srgrimes */ 4051590Srgrimes register GNode *cohort; 4061590Srgrimes LstNode ln; 4078874Srgrimes 4081590Srgrimes cohort = Targ_NewGN(gn->name); 4091590Srgrimes /* 4101590Srgrimes * Duplicate links to parents so graph traversal is simple. Perhaps 4111590Srgrimes * some type bits should be duplicated? 4121590Srgrimes * 4131590Srgrimes * Make the cohort invisible as well to avoid duplicating it into 4141590Srgrimes * other variables. True, parents of this target won't tend to do 4151590Srgrimes * anything with their local variables, but better safe than 4161590Srgrimes * sorry. 4171590Srgrimes */ 41869531Swill Lst_ForEach(gn->parents, ParseLinkSrc, (void *)cohort); 4191590Srgrimes cohort->type = OP_DOUBLEDEP|OP_INVISIBLE; 42069531Swill (void)Lst_AtEnd(gn->cohorts, (void *)cohort); 4211590Srgrimes 4221590Srgrimes /* 4231590Srgrimes * Replace the node in the targets list with the new copy 4241590Srgrimes */ 42569531Swill ln = Lst_Member(targets, (void *)gn); 42669531Swill Lst_Replace(ln, (void *)cohort); 4271590Srgrimes gn = cohort; 4281590Srgrimes } 4291590Srgrimes /* 4301590Srgrimes * We don't want to nuke any previous flags (whatever they were) so we 4318874Srgrimes * just OR the new operator into the old 4321590Srgrimes */ 4331590Srgrimes gn->type |= op; 4341590Srgrimes 4351590Srgrimes return (0); 4361590Srgrimes} 4371590Srgrimes 4381590Srgrimes/*- 4391590Srgrimes *--------------------------------------------------------------------- 44018730Ssteve * ParseAddDep -- 44118730Ssteve * Check if the pair of GNodes given needs to be synchronized. 44218730Ssteve * This has to be when two nodes are on different sides of a 44318730Ssteve * .WAIT directive. 44418730Ssteve * 44518730Ssteve * Results: 44618730Ssteve * Returns 1 if the two targets need to be ordered, 0 otherwise. 44718730Ssteve * If it returns 1, the search can stop 44818730Ssteve * 44918730Ssteve * Side Effects: 45018730Ssteve * A dependency can be added between the two nodes. 45118730Ssteve * 45218730Ssteve *--------------------------------------------------------------------- 45318730Ssteve */ 45449938Shoekstatic int 45518730SsteveParseAddDep(pp, sp) 45669531Swill void * pp; 45769531Swill void * sp; 45818730Ssteve{ 45918730Ssteve GNode *p = (GNode *) pp; 46018730Ssteve GNode *s = (GNode *) sp; 46118730Ssteve 46218730Ssteve if (p->order < s->order) { 46318730Ssteve /* 46418730Ssteve * XXX: This can cause loops, and loops can cause unmade targets, 46518730Ssteve * but checking is tedious, and the debugging output can show the 46618730Ssteve * problem 46718730Ssteve */ 46869531Swill (void)Lst_AtEnd(p->successors, (void *)s); 46969531Swill (void)Lst_AtEnd(s->preds, (void *)p); 47018730Ssteve return 0; 47118730Ssteve } 47218730Ssteve else 47318730Ssteve return 1; 47418730Ssteve} 47518730Ssteve 47618730Ssteve 47718730Ssteve/*- 47818730Ssteve *--------------------------------------------------------------------- 4791590Srgrimes * ParseDoSrc -- 4801590Srgrimes * Given the name of a source, figure out if it is an attribute 4811590Srgrimes * and apply it to the targets if it is. Else decide if there is 4821590Srgrimes * some attribute which should be applied *to* the source because 4831590Srgrimes * of some special target and apply it if so. Otherwise, make the 4841590Srgrimes * source be a child of the targets in the list 'targets' 4851590Srgrimes * 4861590Srgrimes * Results: 4871590Srgrimes * None 4881590Srgrimes * 4891590Srgrimes * Side Effects: 4901590Srgrimes * Operator bits may be added to the list of targets or to the source. 4911590Srgrimes * The targets may have a new source added to their lists of children. 4921590Srgrimes *--------------------------------------------------------------------- 4931590Srgrimes */ 4941590Srgrimesstatic void 49518730SsteveParseDoSrc (tOp, src, allsrc) 4961590Srgrimes int tOp; /* operator (if any) from special targets */ 4971590Srgrimes char *src; /* name of the source to handle */ 49818730Ssteve Lst allsrc; /* List of all sources to wait for */ 4991590Srgrimes{ 50018730Ssteve GNode *gn = NULL; 5011590Srgrimes 5021590Srgrimes if (*src == '.' && isupper (src[1])) { 5031590Srgrimes int keywd = ParseFindKeyword(src); 5041590Srgrimes if (keywd != -1) { 50518730Ssteve int op = parseKeywords[keywd].op; 50618730Ssteve if (op != 0) { 50769531Swill Lst_ForEach (targets, ParseDoOp, (void *)&op); 50818730Ssteve return; 50918730Ssteve } 51018730Ssteve if (parseKeywords[keywd].spec == Wait) { 51118730Ssteve waiting++; 51218730Ssteve return; 51318730Ssteve } 5141590Srgrimes } 5151590Srgrimes } 51618730Ssteve 51718730Ssteve switch (specType) { 51818730Ssteve case Main: 5191590Srgrimes /* 5201590Srgrimes * If we have noted the existence of a .MAIN, it means we need 5211590Srgrimes * to add the sources of said target to the list of things 5221590Srgrimes * to create. The string 'src' is likely to be free, so we 5231590Srgrimes * must make a new copy of it. Note that this will only be 5241590Srgrimes * invoked if the user didn't specify a target on the command 5251590Srgrimes * line. This is to allow #ifmake's to succeed, or something... 5261590Srgrimes */ 52769531Swill (void) Lst_AtEnd (create, (void *)estrdup(src)); 5281590Srgrimes /* 5291590Srgrimes * Add the name to the .TARGETS variable as well, so the user cna 5301590Srgrimes * employ that, if desired. 5311590Srgrimes */ 5321590Srgrimes Var_Append(".TARGETS", src, VAR_GLOBAL); 53318730Ssteve return; 53418730Ssteve 53518730Ssteve case Order: 5361590Srgrimes /* 5371590Srgrimes * Create proper predecessor/successor links between the previous 5381590Srgrimes * source and the current one. 5391590Srgrimes */ 5401590Srgrimes gn = Targ_FindNode(src, TARG_CREATE); 54169527Swill if (predecessor != NULL) { 54269531Swill (void)Lst_AtEnd(predecessor->successors, (void *)gn); 54369531Swill (void)Lst_AtEnd(gn->preds, (void *)predecessor); 5441590Srgrimes } 5451590Srgrimes /* 5461590Srgrimes * The current source now becomes the predecessor for the next one. 5471590Srgrimes */ 5481590Srgrimes predecessor = gn; 54918730Ssteve break; 55018730Ssteve 55118730Ssteve default: 5521590Srgrimes /* 5531590Srgrimes * If the source is not an attribute, we need to find/create 5541590Srgrimes * a node for it. After that we can apply any operator to it 5551590Srgrimes * from a special target or link it to its parents, as 5561590Srgrimes * appropriate. 5571590Srgrimes * 5581590Srgrimes * In the case of a source that was the object of a :: operator, 5591590Srgrimes * the attribute is applied to all of its instances (as kept in 5601590Srgrimes * the 'cohorts' list of the node) or all the cohorts are linked 5611590Srgrimes * to all the targets. 5621590Srgrimes */ 5631590Srgrimes gn = Targ_FindNode (src, TARG_CREATE); 5641590Srgrimes if (tOp) { 5651590Srgrimes gn->type |= tOp; 5661590Srgrimes } else { 56769531Swill Lst_ForEach (targets, ParseLinkSrc, (void *)gn); 5681590Srgrimes } 5691590Srgrimes if ((gn->type & OP_OPMASK) == OP_DOUBLEDEP) { 5701590Srgrimes register GNode *cohort; 5711590Srgrimes register LstNode ln; 5721590Srgrimes 57369527Swill for (ln=Lst_First(gn->cohorts); ln != NULL; ln = Lst_Succ(ln)){ 5741590Srgrimes cohort = (GNode *)Lst_Datum(ln); 5751590Srgrimes if (tOp) { 5761590Srgrimes cohort->type |= tOp; 5771590Srgrimes } else { 57869531Swill Lst_ForEach(targets, ParseLinkSrc, (void *)cohort); 5791590Srgrimes } 5801590Srgrimes } 5811590Srgrimes } 58218730Ssteve break; 5831590Srgrimes } 58418730Ssteve 58518730Ssteve gn->order = waiting; 58669531Swill (void)Lst_AtEnd(allsrc, (void *)gn); 58718730Ssteve if (waiting) { 58869531Swill Lst_ForEach(allsrc, ParseAddDep, (void *)gn); 58918730Ssteve } 5901590Srgrimes} 5911590Srgrimes 5921590Srgrimes/*- 5931590Srgrimes *----------------------------------------------------------------------- 5941590Srgrimes * ParseFindMain -- 5951590Srgrimes * Find a real target in the list and set it to be the main one. 5961590Srgrimes * Called by ParseDoDependency when a main target hasn't been found 5971590Srgrimes * yet. 5981590Srgrimes * 5991590Srgrimes * Results: 6001590Srgrimes * 0 if main not found yet, 1 if it is. 6011590Srgrimes * 6021590Srgrimes * Side Effects: 6031590Srgrimes * mainNode is changed and Targ_SetMain is called. 6041590Srgrimes * 6051590Srgrimes *----------------------------------------------------------------------- 6061590Srgrimes */ 6071590Srgrimesstatic int 6085814SjkhParseFindMain(gnp, dummy) 60969531Swill void * gnp; /* Node to examine */ 61069531Swill void * dummy; 6111590Srgrimes{ 6125814Sjkh GNode *gn = (GNode *) gnp; 6131590Srgrimes if ((gn->type & (OP_NOTMAIN|OP_USE|OP_EXEC|OP_TRANSFORM)) == 0) { 6141590Srgrimes mainNode = gn; 6151590Srgrimes Targ_SetMain(gn); 6165814Sjkh return (dummy ? 1 : 1); 6171590Srgrimes } else { 6185814Sjkh return (dummy ? 0 : 0); 6191590Srgrimes } 6201590Srgrimes} 6211590Srgrimes 6221590Srgrimes/*- 6231590Srgrimes *----------------------------------------------------------------------- 6241590Srgrimes * ParseAddDir -- 6251590Srgrimes * Front-end for Dir_AddDir to make sure Lst_ForEach keeps going 6261590Srgrimes * 6271590Srgrimes * Results: 6281590Srgrimes * === 0 6291590Srgrimes * 6301590Srgrimes * Side Effects: 6311590Srgrimes * See Dir_AddDir. 6321590Srgrimes * 6331590Srgrimes *----------------------------------------------------------------------- 6341590Srgrimes */ 6351590Srgrimesstatic int 6361590SrgrimesParseAddDir(path, name) 63769531Swill void * path; 63869531Swill void * name; 6391590Srgrimes{ 6405814Sjkh Dir_AddDir((Lst) path, (char *) name); 6411590Srgrimes return(0); 6421590Srgrimes} 6431590Srgrimes 6441590Srgrimes/*- 6451590Srgrimes *----------------------------------------------------------------------- 6461590Srgrimes * ParseClearPath -- 6471590Srgrimes * Front-end for Dir_ClearPath to make sure Lst_ForEach keeps going 6481590Srgrimes * 6491590Srgrimes * Results: 6501590Srgrimes * === 0 6511590Srgrimes * 6521590Srgrimes * Side Effects: 6531590Srgrimes * See Dir_ClearPath 6541590Srgrimes * 6551590Srgrimes *----------------------------------------------------------------------- 6561590Srgrimes */ 6571590Srgrimesstatic int 6585814SjkhParseClearPath(path, dummy) 65969531Swill void * path; 66069531Swill void * dummy; 6611590Srgrimes{ 6625814Sjkh Dir_ClearPath((Lst) path); 6635814Sjkh return(dummy ? 0 : 0); 6641590Srgrimes} 6651590Srgrimes 6661590Srgrimes/*- 6671590Srgrimes *--------------------------------------------------------------------- 6681590Srgrimes * ParseDoDependency -- 6691590Srgrimes * Parse the dependency line in line. 6701590Srgrimes * 6711590Srgrimes * Results: 6721590Srgrimes * None 6731590Srgrimes * 6741590Srgrimes * Side Effects: 6751590Srgrimes * The nodes of the sources are linked as children to the nodes of the 6761590Srgrimes * targets. Some nodes may be created. 6771590Srgrimes * 6781590Srgrimes * We parse a dependency line by first extracting words from the line and 6791590Srgrimes * finding nodes in the list of all targets with that name. This is done 6801590Srgrimes * until a character is encountered which is an operator character. Currently 6811590Srgrimes * these are only ! and :. At this point the operator is parsed and the 6821590Srgrimes * pointer into the line advanced until the first source is encountered. 6831590Srgrimes * The parsed operator is applied to each node in the 'targets' list, 6841590Srgrimes * which is where the nodes found for the targets are kept, by means of 6851590Srgrimes * the ParseDoOp function. 6861590Srgrimes * The sources are read in much the same way as the targets were except 6871590Srgrimes * that now they are expanded using the wildcarding scheme of the C-Shell 6881590Srgrimes * and all instances of the resulting words in the list of all targets 6891590Srgrimes * are found. Each of the resulting nodes is then linked to each of the 6901590Srgrimes * targets as one of its children. 6911590Srgrimes * Certain targets are handled specially. These are the ones detailed 6921590Srgrimes * by the specType variable. 6931590Srgrimes * The storing of transformation rules is also taken care of here. 6941590Srgrimes * A target is recognized as a transformation rule by calling 6951590Srgrimes * Suff_IsTransform. If it is a transformation rule, its node is gotten 6961590Srgrimes * from the suffix module via Suff_AddTransform rather than the standard 6971590Srgrimes * Targ_FindNode in the target module. 6981590Srgrimes *--------------------------------------------------------------------- 6991590Srgrimes */ 7001590Srgrimesstatic void 7011590SrgrimesParseDoDependency (line) 7021590Srgrimes char *line; /* the line to parse */ 7031590Srgrimes{ 7045814Sjkh char *cp; /* our current position */ 7055814Sjkh GNode *gn; /* a general purpose temporary node */ 7065814Sjkh int op; /* the operator on the line */ 7071590Srgrimes char savec; /* a place to save a character */ 7081590Srgrimes Lst paths; /* List of search paths to alter when parsing 7091590Srgrimes * a list of .PATH targets */ 7101590Srgrimes int tOp; /* operator from special target */ 71118730Ssteve Lst sources; /* list of archive source names after 71218730Ssteve * expansion */ 7131590Srgrimes Lst curTargs; /* list of target names to be found and added 7141590Srgrimes * to the targets list */ 71518730Ssteve Lst curSrcs; /* list of sources in order */ 7161590Srgrimes 7171590Srgrimes tOp = 0; 7181590Srgrimes 7191590Srgrimes specType = Not; 72018730Ssteve waiting = 0; 7211590Srgrimes paths = (Lst)NULL; 7221590Srgrimes 7231590Srgrimes curTargs = Lst_Init(FALSE); 72418730Ssteve curSrcs = Lst_Init(FALSE); 7258874Srgrimes 7261590Srgrimes do { 7271590Srgrimes for (cp = line; 7281590Srgrimes *cp && !isspace (*cp) && 7291590Srgrimes (*cp != '!') && (*cp != ':') && (*cp != '('); 7301590Srgrimes cp++) 7311590Srgrimes { 7321590Srgrimes if (*cp == '$') { 7331590Srgrimes /* 7341590Srgrimes * Must be a dynamic source (would have been expanded 7351590Srgrimes * otherwise), so call the Var module to parse the puppy 7361590Srgrimes * so we can safely advance beyond it...There should be 7371590Srgrimes * no errors in this, as they would have been discovered 7381590Srgrimes * in the initial Var_Subst and we wouldn't be here. 7391590Srgrimes */ 7401590Srgrimes int length; 7411590Srgrimes Boolean freeIt; 7421590Srgrimes char *result; 7431590Srgrimes 7441590Srgrimes result=Var_Parse(cp, VAR_CMD, TRUE, &length, &freeIt); 7451590Srgrimes 7461590Srgrimes if (freeIt) { 7471590Srgrimes free(result); 7481590Srgrimes } 7491590Srgrimes cp += length-1; 7501590Srgrimes } 7511590Srgrimes continue; 7521590Srgrimes } 7531590Srgrimes if (*cp == '(') { 7541590Srgrimes /* 7551590Srgrimes * Archives must be handled specially to make sure the OP_ARCHV 7561590Srgrimes * flag is set in their 'type' field, for one thing, and because 7571590Srgrimes * things like "archive(file1.o file2.o file3.o)" are permissible. 7581590Srgrimes * Arch_ParseArchive will set 'line' to be the first non-blank 7591590Srgrimes * after the archive-spec. It creates/finds nodes for the members 7601590Srgrimes * and places them on the given list, returning SUCCESS if all 7611590Srgrimes * went well and FAILURE if there was an error in the 7621590Srgrimes * specification. On error, line should remain untouched. 7631590Srgrimes */ 7641590Srgrimes if (Arch_ParseArchive (&line, targets, VAR_CMD) != SUCCESS) { 7651590Srgrimes Parse_Error (PARSE_FATAL, 7661590Srgrimes "Error in archive specification: \"%s\"", line); 7671590Srgrimes return; 7681590Srgrimes } else { 7691590Srgrimes continue; 7701590Srgrimes } 7711590Srgrimes } 7721590Srgrimes savec = *cp; 7738874Srgrimes 7741590Srgrimes if (!*cp) { 7751590Srgrimes /* 7761590Srgrimes * Ending a dependency line without an operator is a Bozo 7778874Srgrimes * no-no 7781590Srgrimes */ 7791590Srgrimes Parse_Error (PARSE_FATAL, "Need an operator"); 7801590Srgrimes return; 7811590Srgrimes } 7821590Srgrimes *cp = '\0'; 7831590Srgrimes /* 7841590Srgrimes * Have a word in line. See if it's a special target and set 7851590Srgrimes * specType to match it. 7861590Srgrimes */ 7871590Srgrimes if (*line == '.' && isupper (line[1])) { 7881590Srgrimes /* 7891590Srgrimes * See if the target is a special target that must have it 7908874Srgrimes * or its sources handled specially. 7911590Srgrimes */ 7921590Srgrimes int keywd = ParseFindKeyword(line); 7931590Srgrimes if (keywd != -1) { 7941590Srgrimes if (specType == ExPath && parseKeywords[keywd].spec != ExPath) { 7951590Srgrimes Parse_Error(PARSE_FATAL, "Mismatched special targets"); 7961590Srgrimes return; 7971590Srgrimes } 7988874Srgrimes 7991590Srgrimes specType = parseKeywords[keywd].spec; 8001590Srgrimes tOp = parseKeywords[keywd].op; 8011590Srgrimes 8021590Srgrimes /* 8031590Srgrimes * Certain special targets have special semantics: 8041590Srgrimes * .PATH Have to set the dirSearchPath 8051590Srgrimes * variable too 8061590Srgrimes * .MAIN Its sources are only used if 8071590Srgrimes * nothing has been specified to 8081590Srgrimes * create. 8091590Srgrimes * .DEFAULT Need to create a node to hang 8101590Srgrimes * commands on, but we don't want 8111590Srgrimes * it in the graph, nor do we want 8121590Srgrimes * it to be the Main Target, so we 8131590Srgrimes * create it, set OP_NOTMAIN and 8141590Srgrimes * add it to the list, setting 8151590Srgrimes * DEFAULT to the new node for 8161590Srgrimes * later use. We claim the node is 8171590Srgrimes * A transformation rule to make 8181590Srgrimes * life easier later, when we'll 8191590Srgrimes * use Make_HandleUse to actually 8201590Srgrimes * apply the .DEFAULT commands. 82118730Ssteve * .PHONY The list of targets 8221590Srgrimes * .BEGIN 8231590Srgrimes * .END 8241590Srgrimes * .INTERRUPT Are not to be considered the 8251590Srgrimes * main target. 8261590Srgrimes * .NOTPARALLEL Make only one target at a time. 8271590Srgrimes * .SINGLESHELL Create a shell for each command. 82869527Swill * .ORDER Must set initial predecessor to NULL 8291590Srgrimes */ 8301590Srgrimes switch (specType) { 8311590Srgrimes case ExPath: 8321590Srgrimes if (paths == NULL) { 8331590Srgrimes paths = Lst_Init(FALSE); 8341590Srgrimes } 83569531Swill (void)Lst_AtEnd(paths, (void *)dirSearchPath); 8361590Srgrimes break; 8371590Srgrimes case Main: 8381590Srgrimes if (!Lst_IsEmpty(create)) { 8391590Srgrimes specType = Not; 8401590Srgrimes } 8411590Srgrimes break; 8421590Srgrimes case Begin: 8431590Srgrimes case End: 8441590Srgrimes case Interrupt: 8451590Srgrimes gn = Targ_FindNode(line, TARG_CREATE); 8461590Srgrimes gn->type |= OP_NOTMAIN; 84769531Swill (void)Lst_AtEnd(targets, (void *)gn); 8481590Srgrimes break; 8491590Srgrimes case Default: 8501590Srgrimes gn = Targ_NewGN(".DEFAULT"); 8511590Srgrimes gn->type |= (OP_NOTMAIN|OP_TRANSFORM); 85269531Swill (void)Lst_AtEnd(targets, (void *)gn); 8531590Srgrimes DEFAULT = gn; 8541590Srgrimes break; 8551590Srgrimes case NotParallel: 8561590Srgrimes { 8571590Srgrimes extern int maxJobs; 8588874Srgrimes 8591590Srgrimes maxJobs = 1; 8601590Srgrimes break; 8611590Srgrimes } 8621590Srgrimes case SingleShell: 8631590Srgrimes compatMake = 1; 8641590Srgrimes break; 8651590Srgrimes case Order: 86669527Swill predecessor = NULL; 8671590Srgrimes break; 8681590Srgrimes default: 8691590Srgrimes break; 8701590Srgrimes } 8711590Srgrimes } else if (strncmp (line, ".PATH", 5) == 0) { 8721590Srgrimes /* 8731590Srgrimes * .PATH<suffix> has to be handled specially. 8741590Srgrimes * Call on the suffix module to give us a path to 8751590Srgrimes * modify. 8761590Srgrimes */ 8771590Srgrimes Lst path; 8788874Srgrimes 8791590Srgrimes specType = ExPath; 8801590Srgrimes path = Suff_GetPath (&line[5]); 88169527Swill if (path == NULL) { 8821590Srgrimes Parse_Error (PARSE_FATAL, 8831590Srgrimes "Suffix '%s' not defined (yet)", 8841590Srgrimes &line[5]); 8851590Srgrimes return; 8861590Srgrimes } else { 8871590Srgrimes if (paths == (Lst)NULL) { 8881590Srgrimes paths = Lst_Init(FALSE); 8891590Srgrimes } 89069531Swill (void)Lst_AtEnd(paths, (void *)path); 8911590Srgrimes } 8921590Srgrimes } 8931590Srgrimes } 8948874Srgrimes 8951590Srgrimes /* 8961590Srgrimes * Have word in line. Get or create its node and stick it at 8978874Srgrimes * the end of the targets list 8981590Srgrimes */ 8991590Srgrimes if ((specType == Not) && (*line != '\0')) { 9001590Srgrimes if (Dir_HasWildcards(line)) { 9011590Srgrimes /* 9021590Srgrimes * Targets are to be sought only in the current directory, 9031590Srgrimes * so create an empty path for the thing. Note we need to 9041590Srgrimes * use Dir_Destroy in the destruction of the path as the 9051590Srgrimes * Dir module could have added a directory to the path... 9061590Srgrimes */ 9071590Srgrimes Lst emptyPath = Lst_Init(FALSE); 9088874Srgrimes 9091590Srgrimes Dir_Expand(line, emptyPath, curTargs); 9108874Srgrimes 9111590Srgrimes Lst_Destroy(emptyPath, Dir_Destroy); 9121590Srgrimes } else { 9131590Srgrimes /* 9141590Srgrimes * No wildcards, but we want to avoid code duplication, 9151590Srgrimes * so create a list with the word on it. 9161590Srgrimes */ 91769531Swill (void)Lst_AtEnd(curTargs, (void *)line); 9181590Srgrimes } 9198874Srgrimes 9201590Srgrimes while(!Lst_IsEmpty(curTargs)) { 9211590Srgrimes char *targName = (char *)Lst_DeQueue(curTargs); 9228874Srgrimes 9231590Srgrimes if (!Suff_IsTransform (targName)) { 9241590Srgrimes gn = Targ_FindNode (targName, TARG_CREATE); 9251590Srgrimes } else { 9261590Srgrimes gn = Suff_AddTransform (targName); 9271590Srgrimes } 9288874Srgrimes 92969531Swill (void)Lst_AtEnd (targets, (void *)gn); 9301590Srgrimes } 9311590Srgrimes } else if (specType == ExPath && *line != '.' && *line != '\0') { 9321590Srgrimes Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line); 9331590Srgrimes } 9348874Srgrimes 9351590Srgrimes *cp = savec; 9361590Srgrimes /* 9371590Srgrimes * If it is a special type and not .PATH, it's the only target we 9381590Srgrimes * allow on this line... 9391590Srgrimes */ 9401590Srgrimes if (specType != Not && specType != ExPath) { 9411590Srgrimes Boolean warn = FALSE; 9428874Srgrimes 9431590Srgrimes while ((*cp != '!') && (*cp != ':') && *cp) { 9441590Srgrimes if (*cp != ' ' && *cp != '\t') { 9451590Srgrimes warn = TRUE; 9461590Srgrimes } 9471590Srgrimes cp++; 9481590Srgrimes } 9491590Srgrimes if (warn) { 9501590Srgrimes Parse_Error(PARSE_WARNING, "Extra target ignored"); 9511590Srgrimes } 9521590Srgrimes } else { 9531590Srgrimes while (*cp && isspace (*cp)) { 9541590Srgrimes cp++; 9551590Srgrimes } 9561590Srgrimes } 9571590Srgrimes line = cp; 9581590Srgrimes } while ((*line != '!') && (*line != ':') && *line); 9591590Srgrimes 9601590Srgrimes /* 9611590Srgrimes * Don't need the list of target names anymore... 9621590Srgrimes */ 9631590Srgrimes Lst_Destroy(curTargs, NOFREE); 9641590Srgrimes 9651590Srgrimes if (!Lst_IsEmpty(targets)) { 9661590Srgrimes switch(specType) { 9671590Srgrimes default: 9681590Srgrimes Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. Mundane ones ignored"); 9691590Srgrimes break; 9701590Srgrimes case Default: 9711590Srgrimes case Begin: 9721590Srgrimes case End: 9731590Srgrimes case Interrupt: 9741590Srgrimes /* 9751590Srgrimes * These four create nodes on which to hang commands, so 9761590Srgrimes * targets shouldn't be empty... 9771590Srgrimes */ 9781590Srgrimes case Not: 9791590Srgrimes /* 9801590Srgrimes * Nothing special here -- targets can be empty if it wants. 9811590Srgrimes */ 9821590Srgrimes break; 9831590Srgrimes } 9841590Srgrimes } 9851590Srgrimes 9861590Srgrimes /* 9871590Srgrimes * Have now parsed all the target names. Must parse the operator next. The 9881590Srgrimes * result is left in op . 9891590Srgrimes */ 9901590Srgrimes if (*cp == '!') { 9911590Srgrimes op = OP_FORCE; 9921590Srgrimes } else if (*cp == ':') { 9931590Srgrimes if (cp[1] == ':') { 9941590Srgrimes op = OP_DOUBLEDEP; 9951590Srgrimes cp++; 9961590Srgrimes } else { 9971590Srgrimes op = OP_DEPENDS; 9981590Srgrimes } 9991590Srgrimes } else { 10001590Srgrimes Parse_Error (PARSE_FATAL, "Missing dependency operator"); 10011590Srgrimes return; 10021590Srgrimes } 10031590Srgrimes 10041590Srgrimes cp++; /* Advance beyond operator */ 10051590Srgrimes 100669531Swill Lst_ForEach (targets, ParseDoOp, (void *)&op); 10071590Srgrimes 10081590Srgrimes /* 10098874Srgrimes * Get to the first source 10101590Srgrimes */ 10111590Srgrimes while (*cp && isspace (*cp)) { 10121590Srgrimes cp++; 10131590Srgrimes } 10141590Srgrimes line = cp; 10151590Srgrimes 10161590Srgrimes /* 10171590Srgrimes * Several special targets take different actions if present with no 10181590Srgrimes * sources: 10191590Srgrimes * a .SUFFIXES line with no sources clears out all old suffixes 10201590Srgrimes * a .PRECIOUS line makes all targets precious 10211590Srgrimes * a .IGNORE line ignores errors for all targets 10221590Srgrimes * a .SILENT line creates silence when making all targets 10231590Srgrimes * a .PATH removes all directories from the search path(s). 10241590Srgrimes */ 10251590Srgrimes if (!*line) { 10261590Srgrimes switch (specType) { 10271590Srgrimes case Suffixes: 10281590Srgrimes Suff_ClearSuffixes (); 10291590Srgrimes break; 10301590Srgrimes case Precious: 10311590Srgrimes allPrecious = TRUE; 10321590Srgrimes break; 10331590Srgrimes case Ignore: 10341590Srgrimes ignoreErrors = TRUE; 10351590Srgrimes break; 10361590Srgrimes case Silent: 10371590Srgrimes beSilent = TRUE; 10381590Srgrimes break; 10391590Srgrimes case ExPath: 104069531Swill Lst_ForEach(paths, ParseClearPath, (void *)NULL); 10411590Srgrimes break; 104219344Ssteve#ifdef POSIX 104319344Ssteve case Posix: 104419344Ssteve Var_Set("%POSIX", "1003.2", VAR_GLOBAL); 104519344Ssteve break; 104619344Ssteve#endif 10471590Srgrimes default: 10481590Srgrimes break; 10491590Srgrimes } 10501590Srgrimes } else if (specType == MFlags) { 10511590Srgrimes /* 10521590Srgrimes * Call on functions in main.c to deal with these arguments and 10531590Srgrimes * set the initial character to a null-character so the loop to 10541590Srgrimes * get sources won't get anything 10551590Srgrimes */ 10561590Srgrimes Main_ParseArgLine (line); 10571590Srgrimes *line = '\0'; 10581590Srgrimes } else if (specType == ExShell) { 10591590Srgrimes if (Job_ParseShell (line) != SUCCESS) { 10601590Srgrimes Parse_Error (PARSE_FATAL, "improper shell specification"); 10611590Srgrimes return; 10621590Srgrimes } 10631590Srgrimes *line = '\0'; 10641590Srgrimes } else if ((specType == NotParallel) || (specType == SingleShell)) { 10651590Srgrimes *line = '\0'; 10661590Srgrimes } 10678874Srgrimes 10681590Srgrimes /* 10698874Srgrimes * NOW GO FOR THE SOURCES 10701590Srgrimes */ 10711590Srgrimes if ((specType == Suffixes) || (specType == ExPath) || 10721590Srgrimes (specType == Includes) || (specType == Libs) || 10731590Srgrimes (specType == Null)) 10741590Srgrimes { 10751590Srgrimes while (*line) { 10761590Srgrimes /* 10771590Srgrimes * If the target was one that doesn't take files as its sources 10781590Srgrimes * but takes something like suffixes, we take each 10791590Srgrimes * space-separated word on the line as a something and deal 10801590Srgrimes * with it accordingly. 10811590Srgrimes * 10821590Srgrimes * If the target was .SUFFIXES, we take each source as a 10831590Srgrimes * suffix and add it to the list of suffixes maintained by the 10841590Srgrimes * Suff module. 10851590Srgrimes * 10861590Srgrimes * If the target was a .PATH, we add the source as a directory 10871590Srgrimes * to search on the search path. 10881590Srgrimes * 10891590Srgrimes * If it was .INCLUDES, the source is taken to be the suffix of 10901590Srgrimes * files which will be #included and whose search path should 10911590Srgrimes * be present in the .INCLUDES variable. 10921590Srgrimes * 10931590Srgrimes * If it was .LIBS, the source is taken to be the suffix of 10941590Srgrimes * files which are considered libraries and whose search path 10951590Srgrimes * should be present in the .LIBS variable. 10961590Srgrimes * 10971590Srgrimes * If it was .NULL, the source is the suffix to use when a file 10981590Srgrimes * has no valid suffix. 10991590Srgrimes */ 11001590Srgrimes char savec; 11011590Srgrimes while (*cp && !isspace (*cp)) { 11021590Srgrimes cp++; 11031590Srgrimes } 11041590Srgrimes savec = *cp; 11051590Srgrimes *cp = '\0'; 11061590Srgrimes switch (specType) { 11071590Srgrimes case Suffixes: 11081590Srgrimes Suff_AddSuffix (line); 11091590Srgrimes break; 11101590Srgrimes case ExPath: 111169531Swill Lst_ForEach(paths, ParseAddDir, (void *)line); 11121590Srgrimes break; 11131590Srgrimes case Includes: 11141590Srgrimes Suff_AddInclude (line); 11151590Srgrimes break; 11161590Srgrimes case Libs: 11171590Srgrimes Suff_AddLib (line); 11181590Srgrimes break; 11191590Srgrimes case Null: 11201590Srgrimes Suff_SetNull (line); 11211590Srgrimes break; 11221590Srgrimes default: 11231590Srgrimes break; 11241590Srgrimes } 11251590Srgrimes *cp = savec; 11261590Srgrimes if (savec != '\0') { 11271590Srgrimes cp++; 11281590Srgrimes } 11291590Srgrimes while (*cp && isspace (*cp)) { 11301590Srgrimes cp++; 11311590Srgrimes } 11321590Srgrimes line = cp; 11331590Srgrimes } 11341590Srgrimes if (paths) { 11351590Srgrimes Lst_Destroy(paths, NOFREE); 11361590Srgrimes } 11371590Srgrimes } else { 11381590Srgrimes while (*line) { 11391590Srgrimes /* 11401590Srgrimes * The targets take real sources, so we must beware of archive 11411590Srgrimes * specifications (i.e. things with left parentheses in them) 11421590Srgrimes * and handle them accordingly. 11431590Srgrimes */ 11441590Srgrimes while (*cp && !isspace (*cp)) { 11451590Srgrimes if ((*cp == '(') && (cp > line) && (cp[-1] != '$')) { 11461590Srgrimes /* 11471590Srgrimes * Only stop for a left parenthesis if it isn't at the 11481590Srgrimes * start of a word (that'll be for variable changes 11491590Srgrimes * later) and isn't preceded by a dollar sign (a dynamic 11501590Srgrimes * source). 11511590Srgrimes */ 11521590Srgrimes break; 11531590Srgrimes } else { 11541590Srgrimes cp++; 11551590Srgrimes } 11561590Srgrimes } 11571590Srgrimes 11581590Srgrimes if (*cp == '(') { 11591590Srgrimes GNode *gn; 11601590Srgrimes 11611590Srgrimes sources = Lst_Init (FALSE); 11621590Srgrimes if (Arch_ParseArchive (&line, sources, VAR_CMD) != SUCCESS) { 11631590Srgrimes Parse_Error (PARSE_FATAL, 11641590Srgrimes "Error in source archive spec \"%s\"", line); 11651590Srgrimes return; 11661590Srgrimes } 11671590Srgrimes 11681590Srgrimes while (!Lst_IsEmpty (sources)) { 11691590Srgrimes gn = (GNode *) Lst_DeQueue (sources); 117018730Ssteve ParseDoSrc (tOp, gn->name, curSrcs); 11711590Srgrimes } 11721590Srgrimes Lst_Destroy (sources, NOFREE); 11731590Srgrimes cp = line; 11741590Srgrimes } else { 11751590Srgrimes if (*cp) { 11761590Srgrimes *cp = '\0'; 11771590Srgrimes cp += 1; 11781590Srgrimes } 11791590Srgrimes 118018730Ssteve ParseDoSrc (tOp, line, curSrcs); 11811590Srgrimes } 11821590Srgrimes while (*cp && isspace (*cp)) { 11831590Srgrimes cp++; 11841590Srgrimes } 11851590Srgrimes line = cp; 11861590Srgrimes } 11871590Srgrimes } 11888874Srgrimes 118969527Swill if (mainNode == NULL) { 11901590Srgrimes /* 11911590Srgrimes * If we have yet to decide on a main target to make, in the 11921590Srgrimes * absence of any user input, we want the first target on 11931590Srgrimes * the first dependency line that is actually a real target 11941590Srgrimes * (i.e. isn't a .USE or .EXEC rule) to be made. 11951590Srgrimes */ 119669531Swill Lst_ForEach (targets, ParseFindMain, (void *)0); 11971590Srgrimes } 11981590Srgrimes 119918730Ssteve /* 120018730Ssteve * Finally, destroy the list of sources 120118730Ssteve */ 120218730Ssteve Lst_Destroy(curSrcs, NOFREE); 12031590Srgrimes} 12041590Srgrimes 12051590Srgrimes/*- 12061590Srgrimes *--------------------------------------------------------------------- 12071590Srgrimes * Parse_IsVar -- 12081590Srgrimes * Return TRUE if the passed line is a variable assignment. A variable 12091590Srgrimes * assignment consists of a single word followed by optional whitespace 12101590Srgrimes * followed by either a += or an = operator. 12111590Srgrimes * This function is used both by the Parse_File function and main when 12121590Srgrimes * parsing the command-line arguments. 12131590Srgrimes * 12141590Srgrimes * Results: 12151590Srgrimes * TRUE if it is. FALSE if it ain't 12161590Srgrimes * 12171590Srgrimes * Side Effects: 12181590Srgrimes * none 12191590Srgrimes *--------------------------------------------------------------------- 12201590Srgrimes */ 12211590SrgrimesBoolean 12221590SrgrimesParse_IsVar (line) 12231590Srgrimes register char *line; /* the line to check */ 12241590Srgrimes{ 12251590Srgrimes register Boolean wasSpace = FALSE; /* set TRUE if found a space */ 12261590Srgrimes register Boolean haveName = FALSE; /* Set TRUE if have a variable name */ 122718730Ssteve int level = 0; 122818730Ssteve#define ISEQOPERATOR(c) \ 122918730Ssteve (((c) == '+') || ((c) == ':') || ((c) == '?') || ((c) == '!')) 12301590Srgrimes 12311590Srgrimes /* 12321590Srgrimes * Skip to variable name 12331590Srgrimes */ 123418730Ssteve for (;(*line == ' ') || (*line == '\t'); line++) 123518730Ssteve continue; 12361590Srgrimes 123718730Ssteve for (; *line != '=' || level != 0; line++) 123818730Ssteve switch (*line) { 123918730Ssteve case '\0': 12401590Srgrimes /* 12411590Srgrimes * end-of-line -- can't be a variable assignment. 12421590Srgrimes */ 124318730Ssteve return FALSE; 124418730Ssteve 124518730Ssteve case ' ': 124618730Ssteve case '\t': 12471590Srgrimes /* 12481590Srgrimes * there can be as much white space as desired so long as there is 12498874Srgrimes * only one word before the operator 12501590Srgrimes */ 12511590Srgrimes wasSpace = TRUE; 125218730Ssteve break; 125318730Ssteve 125418730Ssteve case '(': 125518730Ssteve case '{': 125618730Ssteve level++; 125718730Ssteve break; 125818730Ssteve 125918730Ssteve case '}': 126018730Ssteve case ')': 126118730Ssteve level--; 126218730Ssteve break; 126318730Ssteve 126418730Ssteve default: 126518730Ssteve if (wasSpace && haveName) { 126618730Ssteve if (ISEQOPERATOR(*line)) { 126718730Ssteve /* 126818730Ssteve * We must have a finished word 126918730Ssteve */ 127018730Ssteve if (level != 0) 127118730Ssteve return FALSE; 127218730Ssteve 127318730Ssteve /* 127418730Ssteve * When an = operator [+?!:] is found, the next 127518730Ssteve * character must be an = or it ain't a valid 127618730Ssteve * assignment. 127718730Ssteve */ 127818730Ssteve if (line[1] == '=') 127918730Ssteve return haveName; 128018730Ssteve#ifdef SUNSHCMD 128118730Ssteve /* 128218730Ssteve * This is a shell command 128318730Ssteve */ 128418730Ssteve if (strncmp(line, ":sh", 3) == 0) 128518730Ssteve return haveName; 128618730Ssteve#endif 128718730Ssteve } 128818730Ssteve /* 128918730Ssteve * This is the start of another word, so not assignment. 129018730Ssteve */ 129118730Ssteve return FALSE; 12921590Srgrimes } 129318730Ssteve else { 129418730Ssteve haveName = TRUE; 129518730Ssteve wasSpace = FALSE; 129618730Ssteve } 129718730Ssteve break; 12981590Srgrimes } 12991590Srgrimes 130018730Ssteve return haveName; 13011590Srgrimes} 13021590Srgrimes 13031590Srgrimes/*- 13041590Srgrimes *--------------------------------------------------------------------- 13051590Srgrimes * Parse_DoVar -- 13061590Srgrimes * Take the variable assignment in the passed line and do it in the 13071590Srgrimes * global context. 13081590Srgrimes * 13091590Srgrimes * Note: There is a lexical ambiguity with assignment modifier characters 13101590Srgrimes * in variable names. This routine interprets the character before the = 13111590Srgrimes * as a modifier. Therefore, an assignment like 13121590Srgrimes * C++=/usr/bin/CC 13131590Srgrimes * is interpreted as "C+ +=" instead of "C++ =". 13141590Srgrimes * 13151590Srgrimes * Results: 13161590Srgrimes * none 13171590Srgrimes * 13181590Srgrimes * Side Effects: 13191590Srgrimes * the variable structure of the given variable name is altered in the 13201590Srgrimes * global context. 13211590Srgrimes *--------------------------------------------------------------------- 13221590Srgrimes */ 13231590Srgrimesvoid 13241590SrgrimesParse_DoVar (line, ctxt) 13251590Srgrimes char *line; /* a line guaranteed to be a variable 13261590Srgrimes * assignment. This reduces error checks */ 13271590Srgrimes GNode *ctxt; /* Context in which to do the assignment */ 13281590Srgrimes{ 13295814Sjkh char *cp; /* pointer into line */ 13301590Srgrimes enum { 13311590Srgrimes VAR_SUBST, VAR_APPEND, VAR_SHELL, VAR_NORMAL 13321590Srgrimes } type; /* Type of assignment */ 13338874Srgrimes char *opc; /* ptr to operator character to 13341590Srgrimes * null-terminate the variable name */ 13358874Srgrimes /* 13361590Srgrimes * Avoid clobbered variable warnings by forcing the compiler 13371590Srgrimes * to ``unregister'' variables 13385814Sjkh */ 13391590Srgrimes#if __GNUC__ 13405814Sjkh (void) &cp; 13415814Sjkh (void) &line; 13425814Sjkh#endif 13431590Srgrimes 13441590Srgrimes /* 13451590Srgrimes * Skip to variable name 13461590Srgrimes */ 13471590Srgrimes while ((*line == ' ') || (*line == '\t')) { 13481590Srgrimes line++; 13491590Srgrimes } 13501590Srgrimes 13511590Srgrimes /* 13521590Srgrimes * Skip to operator character, nulling out whitespace as we go 13531590Srgrimes */ 13541590Srgrimes for (cp = line + 1; *cp != '='; cp++) { 13551590Srgrimes if (isspace (*cp)) { 13561590Srgrimes *cp = '\0'; 13571590Srgrimes } 13581590Srgrimes } 13591590Srgrimes opc = cp-1; /* operator is the previous character */ 13601590Srgrimes *cp++ = '\0'; /* nuke the = */ 13611590Srgrimes 13621590Srgrimes /* 13631590Srgrimes * Check operator type 13641590Srgrimes */ 13651590Srgrimes switch (*opc) { 13661590Srgrimes case '+': 13671590Srgrimes type = VAR_APPEND; 13681590Srgrimes *opc = '\0'; 13691590Srgrimes break; 13701590Srgrimes 13711590Srgrimes case '?': 13721590Srgrimes /* 13731590Srgrimes * If the variable already has a value, we don't do anything. 13741590Srgrimes */ 13751590Srgrimes *opc = '\0'; 13761590Srgrimes if (Var_Exists(line, ctxt)) { 13771590Srgrimes return; 13781590Srgrimes } else { 13791590Srgrimes type = VAR_NORMAL; 13801590Srgrimes } 13811590Srgrimes break; 13821590Srgrimes 13831590Srgrimes case ':': 13841590Srgrimes type = VAR_SUBST; 13851590Srgrimes *opc = '\0'; 13861590Srgrimes break; 13871590Srgrimes 13881590Srgrimes case '!': 13891590Srgrimes type = VAR_SHELL; 13901590Srgrimes *opc = '\0'; 13911590Srgrimes break; 13921590Srgrimes 13931590Srgrimes default: 139418730Ssteve#ifdef SUNSHCMD 139518730Ssteve while (*opc != ':') 139642409Sjkh if (opc == line) 139718730Ssteve break; 139842409Sjkh else 139942409Sjkh --opc; 140018730Ssteve 140118730Ssteve if (strncmp(opc, ":sh", 3) == 0) { 140218730Ssteve type = VAR_SHELL; 140318730Ssteve *opc = '\0'; 140418730Ssteve break; 140518730Ssteve } 140618730Ssteve#endif 14071590Srgrimes type = VAR_NORMAL; 14081590Srgrimes break; 14091590Srgrimes } 14101590Srgrimes 14111590Srgrimes while (isspace (*cp)) { 14121590Srgrimes cp++; 14131590Srgrimes } 14141590Srgrimes 14151590Srgrimes if (type == VAR_APPEND) { 14161590Srgrimes Var_Append (line, cp, ctxt); 14171590Srgrimes } else if (type == VAR_SUBST) { 14181590Srgrimes /* 14191590Srgrimes * Allow variables in the old value to be undefined, but leave their 14201590Srgrimes * invocation alone -- this is done by forcing oldVars to be false. 14211590Srgrimes * XXX: This can cause recursive variables, but that's not hard to do, 14221590Srgrimes * and this allows someone to do something like 14231590Srgrimes * 14241590Srgrimes * CFLAGS = $(.INCLUDES) 14251590Srgrimes * CFLAGS := -I.. $(CFLAGS) 14261590Srgrimes * 14271590Srgrimes * And not get an error. 14281590Srgrimes */ 14291590Srgrimes Boolean oldOldVars = oldVars; 14301590Srgrimes 14311590Srgrimes oldVars = FALSE; 14321590Srgrimes cp = Var_Subst(NULL, cp, ctxt, FALSE); 14331590Srgrimes oldVars = oldOldVars; 14341590Srgrimes 14351590Srgrimes Var_Set(line, cp, ctxt); 14361590Srgrimes free(cp); 14371590Srgrimes } else if (type == VAR_SHELL) { 143818730Ssteve Boolean freeCmd = FALSE; /* TRUE if the command needs to be freed, i.e. 143918730Ssteve * if any variable expansion was performed */ 144018730Ssteve char *res, *err; 14411590Srgrimes 144218730Ssteve if (strchr(cp, '$') != NULL) { 14431590Srgrimes /* 14441590Srgrimes * There's a dollar sign in the command, so perform variable 14451590Srgrimes * expansion on the whole thing. The resulting string will need 14461590Srgrimes * freeing when we're done, so set freeCmd to TRUE. 14471590Srgrimes */ 144818730Ssteve cp = Var_Subst(NULL, cp, VAR_CMD, TRUE); 14491590Srgrimes freeCmd = TRUE; 14501590Srgrimes } 14511590Srgrimes 145218730Ssteve res = Cmd_Exec(cp, &err); 145318730Ssteve Var_Set(line, res, ctxt); 145418730Ssteve free(res); 14551590Srgrimes 145618730Ssteve if (err) 145718730Ssteve Parse_Error(PARSE_WARNING, err, cp); 14581590Srgrimes 145918730Ssteve if (freeCmd) 146018730Ssteve free(cp); 14611590Srgrimes } else { 14621590Srgrimes /* 14631590Srgrimes * Normal assignment -- just do it. 14641590Srgrimes */ 146518730Ssteve Var_Set(line, cp, ctxt); 14661590Srgrimes } 14671590Srgrimes} 14681590Srgrimes 146918730Ssteve 14701590Srgrimes/*- 14711590Srgrimes * ParseAddCmd -- 14721590Srgrimes * Lst_ForEach function to add a command line to all targets 14731590Srgrimes * 14741590Srgrimes * Results: 14751590Srgrimes * Always 0 14761590Srgrimes * 14771590Srgrimes * Side Effects: 14781590Srgrimes * A new element is added to the commands list of the node. 14791590Srgrimes */ 14801590Srgrimesstatic int 14815814SjkhParseAddCmd(gnp, cmd) 148269531Swill void * gnp; /* the node to which the command is to be added */ 148369531Swill void * cmd; /* the command to add */ 14841590Srgrimes{ 14855814Sjkh GNode *gn = (GNode *) gnp; 14865814Sjkh /* if target already supplied, ignore commands */ 14875814Sjkh if (!(gn->type & OP_HAS_COMMANDS)) 14885814Sjkh (void)Lst_AtEnd(gn->commands, cmd); 14895814Sjkh return(0); 14901590Srgrimes} 14911590Srgrimes 14921590Srgrimes/*- 14931590Srgrimes *----------------------------------------------------------------------- 14941590Srgrimes * ParseHasCommands -- 14951590Srgrimes * Callback procedure for Parse_File when destroying the list of 14961590Srgrimes * targets on the last dependency line. Marks a target as already 14971590Srgrimes * having commands if it does, to keep from having shell commands 14981590Srgrimes * on multiple dependency lines. 14991590Srgrimes * 15001590Srgrimes * Results: 15015814Sjkh * None 15021590Srgrimes * 15031590Srgrimes * Side Effects: 15041590Srgrimes * OP_HAS_COMMANDS may be set for the target. 15051590Srgrimes * 15061590Srgrimes *----------------------------------------------------------------------- 15071590Srgrimes */ 15085814Sjkhstatic void 15095814SjkhParseHasCommands(gnp) 151069531Swill void * gnp; /* Node to examine */ 15111590Srgrimes{ 15125814Sjkh GNode *gn = (GNode *) gnp; 15131590Srgrimes if (!Lst_IsEmpty(gn->commands)) { 15141590Srgrimes gn->type |= OP_HAS_COMMANDS; 15151590Srgrimes } 15161590Srgrimes} 15171590Srgrimes 15181590Srgrimes/*- 15191590Srgrimes *----------------------------------------------------------------------- 15201590Srgrimes * Parse_AddIncludeDir -- 15211590Srgrimes * Add a directory to the path searched for included makefiles 15221590Srgrimes * bracketed by double-quotes. Used by functions in main.c 15231590Srgrimes * 15241590Srgrimes * Results: 15251590Srgrimes * None. 15261590Srgrimes * 15271590Srgrimes * Side Effects: 15281590Srgrimes * The directory is appended to the list. 15291590Srgrimes * 15301590Srgrimes *----------------------------------------------------------------------- 15311590Srgrimes */ 15321590Srgrimesvoid 15331590SrgrimesParse_AddIncludeDir (dir) 15341590Srgrimes char *dir; /* The name of the directory to add */ 15351590Srgrimes{ 15361590Srgrimes Dir_AddDir (parseIncPath, dir); 15371590Srgrimes} 15381590Srgrimes 153936347Ssteve/*--------------------------------------------------------------------- 154036347Ssteve * ParseDoError -- 154136347Ssteve * Handle error directive 154236347Ssteve * 154336347Ssteve * The input is the line minus the ".error". We substitute variables, 154436347Ssteve * print the message and exit(1) or just print a warning if the ".error" 154536347Ssteve * directive is malformed. 154636347Ssteve * 154736347Ssteve *--------------------------------------------------------------------- 154836347Ssteve */ 154936347Sstevestatic void 155036347SsteveParseDoError(errmsg) 155136347Ssteve char *errmsg; /* error message */ 155236347Ssteve{ 155336347Ssteve if (!isspace(*errmsg)) { 155436347Ssteve Parse_Error(PARSE_WARNING, "invalid syntax: .error%s", errmsg); 155536347Ssteve return; 155636347Ssteve } 155736347Ssteve 155836347Ssteve while (isspace(*errmsg)) 155936347Ssteve errmsg++; 156036347Ssteve 156136347Ssteve errmsg = Var_Subst(NULL, errmsg, VAR_GLOBAL, FALSE); 156236347Ssteve 156336347Ssteve /* use fprintf/exit instead of Parse_Error to terminate immediately */ 156436347Ssteve fprintf(stderr, "\"%s\", line %d: %s\n", fname, lineno, errmsg); 156536347Ssteve exit(1); 156636347Ssteve} 156736347Ssteve 15681590Srgrimes/*- 15691590Srgrimes *--------------------------------------------------------------------- 15701590Srgrimes * ParseDoInclude -- 15711590Srgrimes * Push to another file. 15728874Srgrimes * 15731590Srgrimes * The input is the line minus the #include. A file spec is a string 15741590Srgrimes * enclosed in <> or "". The former is looked for only in sysIncPath. 15751590Srgrimes * The latter in . and the directories specified by -I command line 15761590Srgrimes * options 15771590Srgrimes * 15781590Srgrimes * Results: 15791590Srgrimes * None 15801590Srgrimes * 15811590Srgrimes * Side Effects: 15821590Srgrimes * A structure is added to the includes Lst and readProc, lineno, 15831590Srgrimes * fname and curFILE are altered for the new file 15841590Srgrimes *--------------------------------------------------------------------- 15851590Srgrimes */ 15861590Srgrimesstatic void 15871590SrgrimesParseDoInclude (file) 15881590Srgrimes char *file; /* file specification */ 15891590Srgrimes{ 15901590Srgrimes char *fullname; /* full pathname of file */ 15911590Srgrimes IFile *oldFile; /* state associated with current file */ 15921590Srgrimes char endc; /* the character which ends the file spec */ 15931590Srgrimes char *cp; /* current position in file spec */ 15941590Srgrimes Boolean isSystem; /* TRUE if makefile is a system makefile */ 15951590Srgrimes 15961590Srgrimes /* 15971590Srgrimes * Skip to delimiter character so we know where to look 15981590Srgrimes */ 15991590Srgrimes while ((*file == ' ') || (*file == '\t')) { 16001590Srgrimes file++; 16011590Srgrimes } 16021590Srgrimes 16031590Srgrimes if ((*file != '"') && (*file != '<')) { 16041590Srgrimes Parse_Error (PARSE_FATAL, 16051590Srgrimes ".include filename must be delimited by '\"' or '<'"); 16061590Srgrimes return; 16071590Srgrimes } 16081590Srgrimes 16091590Srgrimes /* 16101590Srgrimes * Set the search path on which to find the include file based on the 16111590Srgrimes * characters which bracket its name. Angle-brackets imply it's 16121590Srgrimes * a system Makefile while double-quotes imply it's a user makefile 16131590Srgrimes */ 16141590Srgrimes if (*file == '<') { 16151590Srgrimes isSystem = TRUE; 16161590Srgrimes endc = '>'; 16171590Srgrimes } else { 16181590Srgrimes isSystem = FALSE; 16191590Srgrimes endc = '"'; 16201590Srgrimes } 16211590Srgrimes 16221590Srgrimes /* 16231590Srgrimes * Skip to matching delimiter 16241590Srgrimes */ 16251590Srgrimes for (cp = ++file; *cp && *cp != endc; cp++) { 16261590Srgrimes continue; 16271590Srgrimes } 16281590Srgrimes 16291590Srgrimes if (*cp != endc) { 16301590Srgrimes Parse_Error (PARSE_FATAL, 16311590Srgrimes "Unclosed %cinclude filename. '%c' expected", 16321590Srgrimes '.', endc); 16331590Srgrimes return; 16341590Srgrimes } 16351590Srgrimes *cp = '\0'; 16361590Srgrimes 16371590Srgrimes /* 16381590Srgrimes * Substitute for any variables in the file name before trying to 16391590Srgrimes * find the thing. 16401590Srgrimes */ 16411590Srgrimes file = Var_Subst (NULL, file, VAR_CMD, FALSE); 16421590Srgrimes 16431590Srgrimes /* 16441590Srgrimes * Now we know the file's name and its search path, we attempt to 16451590Srgrimes * find the durn thing. A return of NULL indicates the file don't 16461590Srgrimes * exist. 16471590Srgrimes */ 16481590Srgrimes if (!isSystem) { 16491590Srgrimes /* 16501590Srgrimes * Include files contained in double-quotes are first searched for 16511590Srgrimes * relative to the including file's location. We don't want to 16521590Srgrimes * cd there, of course, so we just tack on the old file's 16531590Srgrimes * leading path components and call Dir_FindFile to see if 16541590Srgrimes * we can locate the beast. 16551590Srgrimes */ 165618730Ssteve char *prefEnd, *Fname; 16571590Srgrimes 165818730Ssteve /* Make a temporary copy of this, to be safe. */ 165918730Ssteve Fname = estrdup(fname); 166018730Ssteve 166118730Ssteve prefEnd = strrchr (Fname, '/'); 16621590Srgrimes if (prefEnd != (char *)NULL) { 16631590Srgrimes char *newName; 16648874Srgrimes 16651590Srgrimes *prefEnd = '\0'; 16665814Sjkh if (file[0] == '/') 166718730Ssteve newName = estrdup(file); 16685814Sjkh else 166918730Ssteve newName = str_concat (Fname, file, STR_ADDSLASH); 16701590Srgrimes fullname = Dir_FindFile (newName, parseIncPath); 16711590Srgrimes if (fullname == (char *)NULL) { 16721590Srgrimes fullname = Dir_FindFile(newName, dirSearchPath); 16731590Srgrimes } 16741590Srgrimes free (newName); 16751590Srgrimes *prefEnd = '/'; 16761590Srgrimes } else { 16771590Srgrimes fullname = (char *)NULL; 16781590Srgrimes } 167918730Ssteve free (Fname); 16801590Srgrimes } else { 16811590Srgrimes fullname = (char *)NULL; 16821590Srgrimes } 16831590Srgrimes 16841590Srgrimes if (fullname == (char *)NULL) { 16851590Srgrimes /* 16861590Srgrimes * System makefile or makefile wasn't found in same directory as 16871590Srgrimes * included makefile. Search for it first on the -I search path, 16881590Srgrimes * then on the .PATH search path, if not found in a -I directory. 16891590Srgrimes * XXX: Suffix specific? 16901590Srgrimes */ 16911590Srgrimes fullname = Dir_FindFile (file, parseIncPath); 16921590Srgrimes if (fullname == (char *)NULL) { 16931590Srgrimes fullname = Dir_FindFile(file, dirSearchPath); 16941590Srgrimes } 16951590Srgrimes } 16961590Srgrimes 16971590Srgrimes if (fullname == (char *)NULL) { 16981590Srgrimes /* 16991590Srgrimes * Still haven't found the makefile. Look for it on the system 17001590Srgrimes * path as a last resort. 17011590Srgrimes */ 17021590Srgrimes fullname = Dir_FindFile(file, sysIncPath); 17031590Srgrimes } 17041590Srgrimes 17051590Srgrimes if (fullname == (char *) NULL) { 17061590Srgrimes *cp = endc; 17071590Srgrimes Parse_Error (PARSE_FATAL, "Could not find %s", file); 17081590Srgrimes return; 17091590Srgrimes } 17101590Srgrimes 17115814Sjkh free(file); 17125814Sjkh 17131590Srgrimes /* 17141590Srgrimes * Once we find the absolute path to the file, we get to save all the 17151590Srgrimes * state from the current file before we can start reading this 17161590Srgrimes * include file. The state is stored in an IFile structure which 17171590Srgrimes * is placed on a list with other IFile structures. The list makes 17181590Srgrimes * a very nice stack to track how we got here... 17191590Srgrimes */ 17201590Srgrimes oldFile = (IFile *) emalloc (sizeof (IFile)); 17211590Srgrimes oldFile->fname = fname; 17221590Srgrimes 17231590Srgrimes oldFile->F = curFILE; 17241590Srgrimes oldFile->p = curPTR; 17251590Srgrimes oldFile->lineno = lineno; 17261590Srgrimes 172769531Swill (void) Lst_AtFront (includes, (void *)oldFile); 17281590Srgrimes 17291590Srgrimes /* 17301590Srgrimes * Once the previous state has been saved, we can get down to reading 17311590Srgrimes * the new file. We set up the name of the file to be the absolute 17321590Srgrimes * name of the include file so error messages refer to the right 17331590Srgrimes * place. Naturally enough, we start reading at line number 0. 17341590Srgrimes */ 17351590Srgrimes fname = fullname; 17361590Srgrimes lineno = 0; 17371590Srgrimes 17381590Srgrimes curFILE = fopen (fullname, "r"); 17391590Srgrimes curPTR = NULL; 17401590Srgrimes if (curFILE == (FILE * ) NULL) { 17411590Srgrimes Parse_Error (PARSE_FATAL, "Cannot open %s", fullname); 17421590Srgrimes /* 17431590Srgrimes * Pop to previous file 17441590Srgrimes */ 17451590Srgrimes (void) ParseEOF(0); 17461590Srgrimes } 17471590Srgrimes} 17481590Srgrimes 17491590Srgrimes 175036347Ssteve 17511590Srgrimes/*- 17521590Srgrimes *--------------------------------------------------------------------- 17531590Srgrimes * Parse_FromString -- 17541590Srgrimes * Start Parsing from the given string 17558874Srgrimes * 17561590Srgrimes * Results: 17571590Srgrimes * None 17581590Srgrimes * 17591590Srgrimes * Side Effects: 17601590Srgrimes * A structure is added to the includes Lst and readProc, lineno, 17611590Srgrimes * fname and curFILE are altered for the new file 17621590Srgrimes *--------------------------------------------------------------------- 17631590Srgrimes */ 17641590Srgrimesvoid 17651590SrgrimesParse_FromString(str) 17661590Srgrimes char *str; 17671590Srgrimes{ 17681590Srgrimes IFile *oldFile; /* state associated with this file */ 17691590Srgrimes 17701590Srgrimes if (DEBUG(FOR)) 17711590Srgrimes (void) fprintf(stderr, "%s\n----\n", str); 17721590Srgrimes 17731590Srgrimes oldFile = (IFile *) emalloc (sizeof (IFile)); 17741590Srgrimes oldFile->lineno = lineno; 17751590Srgrimes oldFile->fname = fname; 17761590Srgrimes oldFile->F = curFILE; 17771590Srgrimes oldFile->p = curPTR; 17788874Srgrimes 177969531Swill (void) Lst_AtFront (includes, (void *)oldFile); 17801590Srgrimes 17811590Srgrimes curFILE = NULL; 17821590Srgrimes curPTR = (PTR *) emalloc (sizeof (PTR)); 17831590Srgrimes curPTR->str = curPTR->ptr = str; 17841590Srgrimes lineno = 0; 178518730Ssteve fname = estrdup(fname); 17861590Srgrimes} 17871590Srgrimes 17881590Srgrimes 17891590Srgrimes#ifdef SYSVINCLUDE 17901590Srgrimes/*- 17911590Srgrimes *--------------------------------------------------------------------- 17921590Srgrimes * ParseTraditionalInclude -- 17931590Srgrimes * Push to another file. 17948874Srgrimes * 17951590Srgrimes * The input is the line minus the "include". The file name is 17961590Srgrimes * the string following the "include". 17971590Srgrimes * 17981590Srgrimes * Results: 17991590Srgrimes * None 18001590Srgrimes * 18011590Srgrimes * Side Effects: 18021590Srgrimes * A structure is added to the includes Lst and readProc, lineno, 18031590Srgrimes * fname and curFILE are altered for the new file 18041590Srgrimes *--------------------------------------------------------------------- 18051590Srgrimes */ 18061590Srgrimesstatic void 18071590SrgrimesParseTraditionalInclude (file) 18081590Srgrimes char *file; /* file specification */ 18091590Srgrimes{ 18101590Srgrimes char *fullname; /* full pathname of file */ 18111590Srgrimes IFile *oldFile; /* state associated with current file */ 18121590Srgrimes char *cp; /* current position in file spec */ 18131590Srgrimes char *prefEnd; 18141590Srgrimes 18151590Srgrimes /* 18161590Srgrimes * Skip over whitespace 18171590Srgrimes */ 18181590Srgrimes while ((*file == ' ') || (*file == '\t')) { 18191590Srgrimes file++; 18201590Srgrimes } 18211590Srgrimes 18221590Srgrimes if (*file == '\0') { 18231590Srgrimes Parse_Error (PARSE_FATAL, 18241590Srgrimes "Filename missing from \"include\""); 18251590Srgrimes return; 18261590Srgrimes } 18271590Srgrimes 18281590Srgrimes /* 18291590Srgrimes * Skip to end of line or next whitespace 18301590Srgrimes */ 18311590Srgrimes for (cp = file; *cp && *cp != '\n' && *cp != '\t' && *cp != ' '; cp++) { 18321590Srgrimes continue; 18331590Srgrimes } 18341590Srgrimes 18351590Srgrimes *cp = '\0'; 18361590Srgrimes 18371590Srgrimes /* 18381590Srgrimes * Substitute for any variables in the file name before trying to 18391590Srgrimes * find the thing. 18401590Srgrimes */ 18411590Srgrimes file = Var_Subst (NULL, file, VAR_CMD, FALSE); 18421590Srgrimes 18431590Srgrimes /* 18441590Srgrimes * Now we know the file's name, we attempt to find the durn thing. 18451590Srgrimes * A return of NULL indicates the file don't exist. 18461590Srgrimes * 18471590Srgrimes * Include files are first searched for relative to the including 18481590Srgrimes * file's location. We don't want to cd there, of course, so we 18491590Srgrimes * just tack on the old file's leading path components and call 18501590Srgrimes * Dir_FindFile to see if we can locate the beast. 18511590Srgrimes * XXX - this *does* search in the current directory, right? 18521590Srgrimes */ 18531590Srgrimes 18541590Srgrimes prefEnd = strrchr (fname, '/'); 18551590Srgrimes if (prefEnd != (char *)NULL) { 18561590Srgrimes char *newName; 18578874Srgrimes 18581590Srgrimes *prefEnd = '\0'; 18591590Srgrimes newName = str_concat (fname, file, STR_ADDSLASH); 18601590Srgrimes fullname = Dir_FindFile (newName, parseIncPath); 18611590Srgrimes if (fullname == (char *)NULL) { 18621590Srgrimes fullname = Dir_FindFile(newName, dirSearchPath); 18631590Srgrimes } 18641590Srgrimes free (newName); 18651590Srgrimes *prefEnd = '/'; 18661590Srgrimes } else { 18671590Srgrimes fullname = (char *)NULL; 18681590Srgrimes } 18691590Srgrimes 18701590Srgrimes if (fullname == (char *)NULL) { 18711590Srgrimes /* 18721590Srgrimes * System makefile or makefile wasn't found in same directory as 18731590Srgrimes * included makefile. Search for it first on the -I search path, 18741590Srgrimes * then on the .PATH search path, if not found in a -I directory. 18751590Srgrimes * XXX: Suffix specific? 18761590Srgrimes */ 18771590Srgrimes fullname = Dir_FindFile (file, parseIncPath); 18781590Srgrimes if (fullname == (char *)NULL) { 18791590Srgrimes fullname = Dir_FindFile(file, dirSearchPath); 18801590Srgrimes } 18811590Srgrimes } 18821590Srgrimes 18831590Srgrimes if (fullname == (char *)NULL) { 18841590Srgrimes /* 18851590Srgrimes * Still haven't found the makefile. Look for it on the system 18861590Srgrimes * path as a last resort. 18871590Srgrimes */ 18881590Srgrimes fullname = Dir_FindFile(file, sysIncPath); 18891590Srgrimes } 18901590Srgrimes 18911590Srgrimes if (fullname == (char *) NULL) { 18921590Srgrimes Parse_Error (PARSE_FATAL, "Could not find %s", file); 18931590Srgrimes return; 18941590Srgrimes } 18951590Srgrimes 18961590Srgrimes /* 18971590Srgrimes * Once we find the absolute path to the file, we get to save all the 18981590Srgrimes * state from the current file before we can start reading this 18991590Srgrimes * include file. The state is stored in an IFile structure which 19001590Srgrimes * is placed on a list with other IFile structures. The list makes 19011590Srgrimes * a very nice stack to track how we got here... 19021590Srgrimes */ 19031590Srgrimes oldFile = (IFile *) emalloc (sizeof (IFile)); 19041590Srgrimes oldFile->fname = fname; 19051590Srgrimes 19061590Srgrimes oldFile->F = curFILE; 19071590Srgrimes oldFile->p = curPTR; 19081590Srgrimes oldFile->lineno = lineno; 19091590Srgrimes 191069531Swill (void) Lst_AtFront (includes, (void *)oldFile); 19111590Srgrimes 19121590Srgrimes /* 19131590Srgrimes * Once the previous state has been saved, we can get down to reading 19141590Srgrimes * the new file. We set up the name of the file to be the absolute 19151590Srgrimes * name of the include file so error messages refer to the right 19161590Srgrimes * place. Naturally enough, we start reading at line number 0. 19171590Srgrimes */ 19181590Srgrimes fname = fullname; 19191590Srgrimes lineno = 0; 19201590Srgrimes 19211590Srgrimes curFILE = fopen (fullname, "r"); 19221590Srgrimes curPTR = NULL; 19231590Srgrimes if (curFILE == (FILE * ) NULL) { 19241590Srgrimes Parse_Error (PARSE_FATAL, "Cannot open %s", fullname); 19251590Srgrimes /* 19261590Srgrimes * Pop to previous file 19271590Srgrimes */ 19281590Srgrimes (void) ParseEOF(1); 19291590Srgrimes } 19301590Srgrimes} 19311590Srgrimes#endif 19321590Srgrimes 19331590Srgrimes/*- 19341590Srgrimes *--------------------------------------------------------------------- 19351590Srgrimes * ParseEOF -- 19361590Srgrimes * Called when EOF is reached in the current file. If we were reading 19371590Srgrimes * an include file, the includes stack is popped and things set up 19381590Srgrimes * to go back to reading the previous file at the previous location. 19391590Srgrimes * 19401590Srgrimes * Results: 19411590Srgrimes * CONTINUE if there's more to do. DONE if not. 19421590Srgrimes * 19431590Srgrimes * Side Effects: 19441590Srgrimes * The old curFILE, is closed. The includes list is shortened. 19451590Srgrimes * lineno, curFILE, and fname are changed if CONTINUE is returned. 19461590Srgrimes *--------------------------------------------------------------------- 19471590Srgrimes */ 19481590Srgrimesstatic int 19491590SrgrimesParseEOF (opened) 19501590Srgrimes int opened; 19511590Srgrimes{ 19521590Srgrimes IFile *ifile; /* the state on the top of the includes stack */ 19531590Srgrimes 19541590Srgrimes if (Lst_IsEmpty (includes)) { 19551590Srgrimes return (DONE); 19561590Srgrimes } 19571590Srgrimes 19581590Srgrimes ifile = (IFile *) Lst_DeQueue (includes); 195969531Swill free (fname); 19601590Srgrimes fname = ifile->fname; 19611590Srgrimes lineno = ifile->lineno; 19621590Srgrimes if (opened && curFILE) 19631590Srgrimes (void) fclose (curFILE); 19641590Srgrimes if (curPTR) { 196569531Swill free(curPTR->str); 196669531Swill free(curPTR); 19671590Srgrimes } 19681590Srgrimes curFILE = ifile->F; 19691590Srgrimes curPTR = ifile->p; 197069531Swill free (ifile); 19711590Srgrimes return (CONTINUE); 19721590Srgrimes} 19731590Srgrimes 19741590Srgrimes/*- 19751590Srgrimes *--------------------------------------------------------------------- 19761590Srgrimes * ParseReadc -- 19778874Srgrimes * Read a character from the current file 19781590Srgrimes * 19791590Srgrimes * Results: 19801590Srgrimes * The character that was read 19811590Srgrimes * 19821590Srgrimes * Side Effects: 19831590Srgrimes *--------------------------------------------------------------------- 19841590Srgrimes */ 19851590Srgrimesstatic int 19861590SrgrimesParseReadc() 19871590Srgrimes{ 19881590Srgrimes if (curFILE) 19891590Srgrimes return fgetc(curFILE); 19908874Srgrimes 19911590Srgrimes if (curPTR && *curPTR->ptr) 19921590Srgrimes return *curPTR->ptr++; 19931590Srgrimes return EOF; 19941590Srgrimes} 19951590Srgrimes 19961590Srgrimes 19971590Srgrimes/*- 19981590Srgrimes *--------------------------------------------------------------------- 19991590Srgrimes * ParseUnreadc -- 20008874Srgrimes * Put back a character to the current file 20011590Srgrimes * 20021590Srgrimes * Results: 20031590Srgrimes * None. 20041590Srgrimes * 20051590Srgrimes * Side Effects: 20061590Srgrimes *--------------------------------------------------------------------- 20071590Srgrimes */ 20081590Srgrimesstatic void 20091590SrgrimesParseUnreadc(c) 20101590Srgrimes int c; 20111590Srgrimes{ 20121590Srgrimes if (curFILE) { 20131590Srgrimes ungetc(c, curFILE); 20141590Srgrimes return; 20151590Srgrimes } 20161590Srgrimes if (curPTR) { 20171590Srgrimes *--(curPTR->ptr) = c; 20181590Srgrimes return; 20191590Srgrimes } 20201590Srgrimes} 20211590Srgrimes 20221590Srgrimes 20231590Srgrimes/* ParseSkipLine(): 20241590Srgrimes * Grab the next line 20251590Srgrimes */ 20261590Srgrimesstatic char * 20271590SrgrimesParseSkipLine(skip) 20281590Srgrimes int skip; /* Skip lines that don't start with . */ 20291590Srgrimes{ 20301590Srgrimes char *line; 203118456Ssteve int c, lastc, lineLength = 0; 20321590Srgrimes Buffer buf; 20331590Srgrimes 203418456Ssteve buf = Buf_Init(MAKE_BSIZE); 20351590Srgrimes 203618456Ssteve do { 203718456Ssteve Buf_Discard(buf, lineLength); 203818456Ssteve lastc = '\0'; 20398874Srgrimes 204018456Ssteve while (((c = ParseReadc()) != '\n' || lastc == '\\') 204118456Ssteve && c != EOF) { 204274293Swill if (c == '\n') { 204374293Swill Buf_ReplaceLastByte(buf, (Byte)' '); 204474293Swill lineno++; 20458874Srgrimes 204674293Swill while ((c = ParseReadc()) == ' ' || c == '\t'); 20478874Srgrimes 204874293Swill if (c == EOF) 204974293Swill break; 205074293Swill } 205174272Swill 205274293Swill Buf_AddByte(buf, (Byte)c); 205374293Swill lastc = c; 205418456Ssteve } 205518456Ssteve 205618456Ssteve if (c == EOF) { 205718456Ssteve Parse_Error(PARSE_FATAL, "Unclosed conditional/for loop"); 205818456Ssteve Buf_Destroy(buf, TRUE); 205918456Ssteve return((char *)NULL); 206018456Ssteve } 206118456Ssteve 206218456Ssteve lineno++; 206318456Ssteve Buf_AddByte(buf, (Byte)'\0'); 206418456Ssteve line = (char *)Buf_GetAll(buf, &lineLength); 206518456Ssteve } while (skip == 1 && line[0] != '.'); 206618456Ssteve 206718456Ssteve Buf_Destroy(buf, FALSE); 20681590Srgrimes return line; 20691590Srgrimes} 20701590Srgrimes 20711590Srgrimes 20721590Srgrimes/*- 20731590Srgrimes *--------------------------------------------------------------------- 20741590Srgrimes * ParseReadLine -- 20751590Srgrimes * Read an entire line from the input file. Called only by Parse_File. 20761590Srgrimes * To facilitate escaped newlines and what have you, a character is 20771590Srgrimes * buffered in 'lastc', which is '\0' when no characters have been 20781590Srgrimes * read. When we break out of the loop, c holds the terminating 20791590Srgrimes * character and lastc holds a character that should be added to 20801590Srgrimes * the line (unless we don't read anything but a terminator). 20811590Srgrimes * 20821590Srgrimes * Results: 20831590Srgrimes * A line w/o its newline 20841590Srgrimes * 20851590Srgrimes * Side Effects: 20861590Srgrimes * Only those associated with reading a character 20871590Srgrimes *--------------------------------------------------------------------- 20881590Srgrimes */ 20891590Srgrimesstatic char * 20901590SrgrimesParseReadLine () 20911590Srgrimes{ 20921590Srgrimes Buffer buf; /* Buffer for current line */ 20931590Srgrimes register int c; /* the current character */ 20941590Srgrimes register int lastc; /* The most-recent character */ 20951590Srgrimes Boolean semiNL; /* treat semi-colons as newlines */ 20961590Srgrimes Boolean ignDepOp; /* TRUE if should ignore dependency operators 20971590Srgrimes * for the purposes of setting semiNL */ 20981590Srgrimes Boolean ignComment; /* TRUE if should ignore comments (in a 20991590Srgrimes * shell command */ 21005814Sjkh char *line; /* Result */ 21015814Sjkh char *ep; /* to strip trailing blanks */ 21021590Srgrimes int lineLength; /* Length of result */ 21031590Srgrimes 21041590Srgrimes semiNL = FALSE; 21051590Srgrimes ignDepOp = FALSE; 21061590Srgrimes ignComment = FALSE; 21071590Srgrimes 21081590Srgrimes /* 21091590Srgrimes * Handle special-characters at the beginning of the line. Either a 21101590Srgrimes * leading tab (shell command) or pound-sign (possible conditional) 21111590Srgrimes * forces us to ignore comments and dependency operators and treat 21121590Srgrimes * semi-colons as semi-colons (by leaving semiNL FALSE). This also 21131590Srgrimes * discards completely blank lines. 21141590Srgrimes */ 21151590Srgrimes for (;;) { 21161590Srgrimes c = ParseReadc(); 21171590Srgrimes 21181590Srgrimes if (c == '\t') { 21191590Srgrimes ignComment = ignDepOp = TRUE; 21201590Srgrimes break; 21211590Srgrimes } else if (c == '\n') { 21221590Srgrimes lineno++; 21231590Srgrimes } else if (c == '#') { 21241590Srgrimes ParseUnreadc(c); 21251590Srgrimes break; 21261590Srgrimes } else { 21271590Srgrimes /* 21281590Srgrimes * Anything else breaks out without doing anything 21291590Srgrimes */ 21301590Srgrimes break; 21311590Srgrimes } 21321590Srgrimes } 21338874Srgrimes 21341590Srgrimes if (c != EOF) { 21351590Srgrimes lastc = c; 21361590Srgrimes buf = Buf_Init(MAKE_BSIZE); 21378874Srgrimes 21381590Srgrimes while (((c = ParseReadc ()) != '\n' || (lastc == '\\')) && 21391590Srgrimes (c != EOF)) 21401590Srgrimes { 21411590Srgrimestest_char: 21421590Srgrimes switch(c) { 21431590Srgrimes case '\n': 21441590Srgrimes /* 21451590Srgrimes * Escaped newline: read characters until a non-space or an 21461590Srgrimes * unescaped newline and replace them all by a single space. 21471590Srgrimes * This is done by storing the space over the backslash and 21481590Srgrimes * dropping through with the next nonspace. If it is a 21491590Srgrimes * semi-colon and semiNL is TRUE, it will be recognized as a 21501590Srgrimes * newline in the code below this... 21511590Srgrimes */ 21521590Srgrimes lineno++; 21531590Srgrimes lastc = ' '; 21541590Srgrimes while ((c = ParseReadc ()) == ' ' || c == '\t') { 21551590Srgrimes continue; 21561590Srgrimes } 21571590Srgrimes if (c == EOF || c == '\n') { 21581590Srgrimes goto line_read; 21591590Srgrimes } else { 21601590Srgrimes /* 21611590Srgrimes * Check for comments, semiNL's, etc. -- easier than 21621590Srgrimes * ParseUnreadc(c); continue; 21631590Srgrimes */ 21641590Srgrimes goto test_char; 21651590Srgrimes } 21661590Srgrimes /*NOTREACHED*/ 21671590Srgrimes break; 21681590Srgrimes 21691590Srgrimes case ';': 21701590Srgrimes /* 21711590Srgrimes * Semi-colon: Need to see if it should be interpreted as a 21721590Srgrimes * newline 21731590Srgrimes */ 21741590Srgrimes if (semiNL) { 21751590Srgrimes /* 21761590Srgrimes * To make sure the command that may be following this 21771590Srgrimes * semi-colon begins with a tab, we push one back into the 21781590Srgrimes * input stream. This will overwrite the semi-colon in the 21791590Srgrimes * buffer. If there is no command following, this does no 21801590Srgrimes * harm, since the newline remains in the buffer and the 21811590Srgrimes * whole line is ignored. 21821590Srgrimes */ 21831590Srgrimes ParseUnreadc('\t'); 21841590Srgrimes goto line_read; 21858874Srgrimes } 21861590Srgrimes break; 21871590Srgrimes case '=': 21881590Srgrimes if (!semiNL) { 21891590Srgrimes /* 21901590Srgrimes * Haven't seen a dependency operator before this, so this 21911590Srgrimes * must be a variable assignment -- don't pay attention to 21921590Srgrimes * dependency operators after this. 21931590Srgrimes */ 21941590Srgrimes ignDepOp = TRUE; 21951590Srgrimes } else if (lastc == ':' || lastc == '!') { 21961590Srgrimes /* 21971590Srgrimes * Well, we've seen a dependency operator already, but it 21981590Srgrimes * was the previous character, so this is really just an 21991590Srgrimes * expanded variable assignment. Revert semi-colons to 22001590Srgrimes * being just semi-colons again and ignore any more 22011590Srgrimes * dependency operators. 22021590Srgrimes * 22031590Srgrimes * XXX: Note that a line like "foo : a:=b" will blow up, 22041590Srgrimes * but who'd write a line like that anyway? 22051590Srgrimes */ 22061590Srgrimes ignDepOp = TRUE; semiNL = FALSE; 22071590Srgrimes } 22081590Srgrimes break; 22091590Srgrimes case '#': 22101590Srgrimes if (!ignComment) { 221118730Ssteve if ( 221218730Ssteve#if 0 221318730Ssteve compatMake && 221418730Ssteve#endif 221518730Ssteve (lastc != '\\')) { 22161590Srgrimes /* 22171590Srgrimes * If the character is a hash mark and it isn't escaped 22181590Srgrimes * (or we're being compatible), the thing is a comment. 22191590Srgrimes * Skip to the end of the line. 22201590Srgrimes */ 22211590Srgrimes do { 22221590Srgrimes c = ParseReadc(); 22231590Srgrimes } while ((c != '\n') && (c != EOF)); 22241590Srgrimes goto line_read; 22251590Srgrimes } else { 22261590Srgrimes /* 22271590Srgrimes * Don't add the backslash. Just let the # get copied 22281590Srgrimes * over. 22291590Srgrimes */ 22301590Srgrimes lastc = c; 22311590Srgrimes continue; 22321590Srgrimes } 22331590Srgrimes } 22341590Srgrimes break; 22351590Srgrimes case ':': 22361590Srgrimes case '!': 22371590Srgrimes if (!ignDepOp && (c == ':' || c == '!')) { 22381590Srgrimes /* 22391590Srgrimes * A semi-colon is recognized as a newline only on 22401590Srgrimes * dependency lines. Dependency lines are lines with a 22411590Srgrimes * colon or an exclamation point. Ergo... 22421590Srgrimes */ 22431590Srgrimes semiNL = TRUE; 22441590Srgrimes } 22451590Srgrimes break; 22461590Srgrimes } 22471590Srgrimes /* 22481590Srgrimes * Copy in the previous character and save this one in lastc. 22491590Srgrimes */ 22501590Srgrimes Buf_AddByte (buf, (Byte)lastc); 22511590Srgrimes lastc = c; 22528874Srgrimes 22531590Srgrimes } 22541590Srgrimes line_read: 22551590Srgrimes lineno++; 22568874Srgrimes 22571590Srgrimes if (lastc != '\0') { 22581590Srgrimes Buf_AddByte (buf, (Byte)lastc); 22591590Srgrimes } 22601590Srgrimes Buf_AddByte (buf, (Byte)'\0'); 22611590Srgrimes line = (char *)Buf_GetAll (buf, &lineLength); 22621590Srgrimes Buf_Destroy (buf, FALSE); 22635814Sjkh 22645814Sjkh /* 22655814Sjkh * Strip trailing blanks and tabs from the line. 226672645Sasmodai * Do not strip a blank or tab that is preceded by 22675814Sjkh * a '\' 22685814Sjkh */ 22695814Sjkh ep = line; 22705814Sjkh while (*ep) 22715814Sjkh ++ep; 22729298Sache while (ep > line + 1 && (ep[-1] == ' ' || ep[-1] == '\t')) { 227318730Ssteve if (ep > line + 1 && ep[-2] == '\\') 22745814Sjkh break; 22755814Sjkh --ep; 22765814Sjkh } 22775814Sjkh *ep = 0; 22788874Srgrimes 22791590Srgrimes if (line[0] == '.') { 22801590Srgrimes /* 22811590Srgrimes * The line might be a conditional. Ask the conditional module 22821590Srgrimes * about it and act accordingly 22831590Srgrimes */ 22841590Srgrimes switch (Cond_Eval (line)) { 22851590Srgrimes case COND_SKIP: 22861590Srgrimes /* 22871590Srgrimes * Skip to next conditional that evaluates to COND_PARSE. 22881590Srgrimes */ 22891590Srgrimes do { 22901590Srgrimes free (line); 22911590Srgrimes line = ParseSkipLine(1); 22921590Srgrimes } while (line && Cond_Eval(line) != COND_PARSE); 22931590Srgrimes if (line == NULL) 22941590Srgrimes break; 22951590Srgrimes /*FALLTHRU*/ 22961590Srgrimes case COND_PARSE: 229769531Swill free (line); 22981590Srgrimes line = ParseReadLine(); 22991590Srgrimes break; 23001590Srgrimes case COND_INVALID: 23011590Srgrimes if (For_Eval(line)) { 23021590Srgrimes int ok; 23031590Srgrimes free(line); 23041590Srgrimes do { 23051590Srgrimes /* 23061590Srgrimes * Skip after the matching end 23071590Srgrimes */ 23081590Srgrimes line = ParseSkipLine(0); 23091590Srgrimes if (line == NULL) { 23108874Srgrimes Parse_Error (PARSE_FATAL, 23111590Srgrimes "Unexpected end of file in for loop.\n"); 23121590Srgrimes break; 23131590Srgrimes } 23141590Srgrimes ok = For_Eval(line); 23151590Srgrimes free(line); 23161590Srgrimes } 23171590Srgrimes while (ok); 23181590Srgrimes if (line != NULL) 23191590Srgrimes For_Run(); 23201590Srgrimes line = ParseReadLine(); 23211590Srgrimes } 23221590Srgrimes break; 23231590Srgrimes } 23241590Srgrimes } 23251590Srgrimes return (line); 23261590Srgrimes 23271590Srgrimes } else { 23281590Srgrimes /* 23291590Srgrimes * Hit end-of-file, so return a NULL line to indicate this. 23301590Srgrimes */ 23311590Srgrimes return((char *)NULL); 23321590Srgrimes } 23331590Srgrimes} 23341590Srgrimes 23351590Srgrimes/*- 23361590Srgrimes *----------------------------------------------------------------------- 23371590Srgrimes * ParseFinishLine -- 23381590Srgrimes * Handle the end of a dependency group. 23391590Srgrimes * 23401590Srgrimes * Results: 23411590Srgrimes * Nothing. 23421590Srgrimes * 23431590Srgrimes * Side Effects: 23441590Srgrimes * inLine set FALSE. 'targets' list destroyed. 23451590Srgrimes * 23461590Srgrimes *----------------------------------------------------------------------- 23471590Srgrimes */ 23481590Srgrimesstatic void 23491590SrgrimesParseFinishLine() 23501590Srgrimes{ 23511590Srgrimes if (inLine) { 235269531Swill Lst_ForEach(targets, Suff_EndTransform, (void *)NULL); 23531590Srgrimes Lst_Destroy (targets, ParseHasCommands); 23545814Sjkh targets = NULL; 23551590Srgrimes inLine = FALSE; 23561590Srgrimes } 23571590Srgrimes} 23581590Srgrimes 23598874Srgrimes 23601590Srgrimes/*- 23611590Srgrimes *--------------------------------------------------------------------- 23621590Srgrimes * Parse_File -- 23631590Srgrimes * Parse a file into its component parts, incorporating it into the 23641590Srgrimes * current dependency graph. This is the main function and controls 23651590Srgrimes * almost every other function in this module 23661590Srgrimes * 23671590Srgrimes * Results: 23681590Srgrimes * None 23691590Srgrimes * 23701590Srgrimes * Side Effects: 23711590Srgrimes * Loads. Nodes are added to the list of all targets, nodes and links 23721590Srgrimes * are added to the dependency graph. etc. etc. etc. 23731590Srgrimes *--------------------------------------------------------------------- 23741590Srgrimes */ 23751590Srgrimesvoid 23761590SrgrimesParse_File(name, stream) 23771590Srgrimes char *name; /* the name of the file being read */ 23781590Srgrimes FILE * stream; /* Stream open to makefile to parse */ 23791590Srgrimes{ 23801590Srgrimes register char *cp, /* pointer into the line */ 23811590Srgrimes *line; /* the line we're working on */ 23821590Srgrimes 23831590Srgrimes inLine = FALSE; 23841590Srgrimes fname = name; 23851590Srgrimes curFILE = stream; 23861590Srgrimes lineno = 0; 23871590Srgrimes fatals = 0; 23881590Srgrimes 23891590Srgrimes do { 23901590Srgrimes while ((line = ParseReadLine ()) != NULL) { 23911590Srgrimes if (*line == '.') { 23921590Srgrimes /* 23931590Srgrimes * Lines that begin with the special character are either 23941590Srgrimes * include or undef directives. 23951590Srgrimes */ 23961590Srgrimes for (cp = line + 1; isspace (*cp); cp++) { 23971590Srgrimes continue; 23981590Srgrimes } 23991590Srgrimes if (strncmp (cp, "include", 7) == 0) { 24001590Srgrimes ParseDoInclude (cp + 7); 24011590Srgrimes goto nextLine; 240236347Ssteve } else if (strncmp (cp, "error", 5) == 0) { 240336347Ssteve ParseDoError(cp + 5); 240436347Ssteve goto nextLine; 24051590Srgrimes } else if (strncmp(cp, "undef", 5) == 0) { 24061590Srgrimes char *cp2; 24075814Sjkh for (cp += 5; isspace((unsigned char) *cp); cp++) { 24081590Srgrimes continue; 24091590Srgrimes } 24101590Srgrimes 24115814Sjkh for (cp2 = cp; !isspace((unsigned char) *cp2) && 24125814Sjkh (*cp2 != '\0'); cp2++) { 24131590Srgrimes continue; 24141590Srgrimes } 24151590Srgrimes 24161590Srgrimes *cp2 = '\0'; 24171590Srgrimes 24181590Srgrimes Var_Delete(cp, VAR_GLOBAL); 24191590Srgrimes goto nextLine; 24201590Srgrimes } 24211590Srgrimes } 24229298Sache if (*line == '#') { 24231590Srgrimes /* If we're this far, the line must be a comment. */ 24241590Srgrimes goto nextLine; 24251590Srgrimes } 24268874Srgrimes 24275814Sjkh if (*line == '\t') { 24281590Srgrimes /* 24295814Sjkh * If a line starts with a tab, it can only hope to be 24305814Sjkh * a creation command. 24311590Srgrimes */ 24325814Sjkh#ifndef POSIX 24331590Srgrimes shellCommand: 24345814Sjkh#endif 24351590Srgrimes for (cp = line + 1; isspace (*cp); cp++) { 24361590Srgrimes continue; 24371590Srgrimes } 24381590Srgrimes if (*cp) { 24391590Srgrimes if (inLine) { 24401590Srgrimes /* 24411590Srgrimes * So long as it's not a blank line and we're actually 24421590Srgrimes * in a dependency spec, add the command to the list of 24438874Srgrimes * commands of all targets in the dependency spec 24441590Srgrimes */ 24455814Sjkh Lst_ForEach (targets, ParseAddCmd, cp); 244669531Swill Lst_AtEnd(targCmds, (void *) line); 24471590Srgrimes continue; 24481590Srgrimes } else { 24491590Srgrimes Parse_Error (PARSE_FATAL, 245018730Ssteve "Unassociated shell command \"%s\"", 24511590Srgrimes cp); 24521590Srgrimes } 24531590Srgrimes } 24541590Srgrimes#ifdef SYSVINCLUDE 24558874Srgrimes } else if (strncmp (line, "include", 7) == 0 && 245618730Ssteve isspace((unsigned char) line[7]) && 24571590Srgrimes strchr(line, ':') == NULL) { 24581590Srgrimes /* 24591590Srgrimes * It's an S3/S5-style "include". 24601590Srgrimes */ 24611590Srgrimes ParseTraditionalInclude (line + 7); 24621590Srgrimes goto nextLine; 24631590Srgrimes#endif 24641590Srgrimes } else if (Parse_IsVar (line)) { 24651590Srgrimes ParseFinishLine(); 24661590Srgrimes Parse_DoVar (line, VAR_GLOBAL); 24671590Srgrimes } else { 24681590Srgrimes /* 24691590Srgrimes * We now know it's a dependency line so it needs to have all 24701590Srgrimes * variables expanded before being parsed. Tell the variable 24711590Srgrimes * module to complain if some variable is undefined... 24721590Srgrimes * To make life easier on novices, if the line is indented we 24731590Srgrimes * first make sure the line has a dependency operator in it. 24741590Srgrimes * If it doesn't have an operator and we're in a dependency 24751590Srgrimes * line's script, we assume it's actually a shell command 24761590Srgrimes * and add it to the current list of targets. 24771590Srgrimes */ 24785814Sjkh#ifndef POSIX 24791590Srgrimes Boolean nonSpace = FALSE; 24805814Sjkh#endif 24818874Srgrimes 24821590Srgrimes cp = line; 24835814Sjkh if (isspace((unsigned char) line[0])) { 24845814Sjkh while ((*cp != '\0') && isspace((unsigned char) *cp)) { 24855814Sjkh cp++; 24865814Sjkh } 24875814Sjkh if (*cp == '\0') { 24885814Sjkh goto nextLine; 24895814Sjkh } 24901590Srgrimes#ifndef POSIX 24911590Srgrimes while ((*cp != ':') && (*cp != '!') && (*cp != '\0')) { 24925814Sjkh nonSpace = TRUE; 24931590Srgrimes cp++; 24941590Srgrimes } 24955814Sjkh#endif 24961590Srgrimes } 24978874Srgrimes 24985814Sjkh#ifndef POSIX 24991590Srgrimes if (*cp == '\0') { 25001590Srgrimes if (inLine) { 25011590Srgrimes Parse_Error (PARSE_WARNING, 25021590Srgrimes "Shell command needs a leading tab"); 25031590Srgrimes goto shellCommand; 25041590Srgrimes } else if (nonSpace) { 25051590Srgrimes Parse_Error (PARSE_FATAL, "Missing operator"); 25061590Srgrimes } 25071590Srgrimes } else { 25081590Srgrimes#endif 25091590Srgrimes ParseFinishLine(); 25101590Srgrimes 25111590Srgrimes cp = Var_Subst (NULL, line, VAR_CMD, TRUE); 25121590Srgrimes free (line); 25131590Srgrimes line = cp; 25148874Srgrimes 25151590Srgrimes /* 25168874Srgrimes * Need a non-circular list for the target nodes 25171590Srgrimes */ 25185814Sjkh if (targets) 25195814Sjkh Lst_Destroy(targets, NOFREE); 25205814Sjkh 25211590Srgrimes targets = Lst_Init (FALSE); 25221590Srgrimes inLine = TRUE; 25238874Srgrimes 25241590Srgrimes ParseDoDependency (line); 25251590Srgrimes#ifndef POSIX 25261590Srgrimes } 25271590Srgrimes#endif 25281590Srgrimes } 25291590Srgrimes 25301590Srgrimes nextLine: 25311590Srgrimes 25321590Srgrimes free (line); 25331590Srgrimes } 25341590Srgrimes /* 25358874Srgrimes * Reached EOF, but it may be just EOF of an include file... 25361590Srgrimes */ 25371590Srgrimes } while (ParseEOF(1) == CONTINUE); 25381590Srgrimes 25391590Srgrimes /* 25401590Srgrimes * Make sure conditionals are clean 25411590Srgrimes */ 25421590Srgrimes Cond_End(); 25431590Srgrimes 254427644Scharnier if (fatals) 254527644Scharnier errx(1, "fatal errors encountered -- cannot continue"); 25461590Srgrimes} 25471590Srgrimes 25481590Srgrimes/*- 25491590Srgrimes *--------------------------------------------------------------------- 25501590Srgrimes * Parse_Init -- 25511590Srgrimes * initialize the parsing module 25521590Srgrimes * 25531590Srgrimes * Results: 25541590Srgrimes * none 25551590Srgrimes * 25561590Srgrimes * Side Effects: 25571590Srgrimes * the parseIncPath list is initialized... 25581590Srgrimes *--------------------------------------------------------------------- 25591590Srgrimes */ 25601590Srgrimesvoid 25611590SrgrimesParse_Init () 25621590Srgrimes{ 256369527Swill mainNode = NULL; 25641590Srgrimes parseIncPath = Lst_Init (FALSE); 25651590Srgrimes sysIncPath = Lst_Init (FALSE); 25661590Srgrimes includes = Lst_Init (FALSE); 25675814Sjkh targCmds = Lst_Init (FALSE); 25681590Srgrimes} 25691590Srgrimes 25705814Sjkhvoid 25715814SjkhParse_End() 25725814Sjkh{ 257392921Simp Lst_Destroy(targCmds, (void (*)(void *)) free); 25745814Sjkh if (targets) 25755814Sjkh Lst_Destroy(targets, NOFREE); 25765814Sjkh Lst_Destroy(sysIncPath, Dir_Destroy); 25775814Sjkh Lst_Destroy(parseIncPath, Dir_Destroy); 25785814Sjkh Lst_Destroy(includes, NOFREE); /* Should be empty now */ 25795814Sjkh} 25805814Sjkh 25818874Srgrimes 25821590Srgrimes/*- 25831590Srgrimes *----------------------------------------------------------------------- 25841590Srgrimes * Parse_MainName -- 25851590Srgrimes * Return a Lst of the main target to create for main()'s sake. If 25861590Srgrimes * no such target exists, we Punt with an obnoxious error message. 25871590Srgrimes * 25881590Srgrimes * Results: 25891590Srgrimes * A Lst of the single node to create. 25901590Srgrimes * 25911590Srgrimes * Side Effects: 25921590Srgrimes * None. 25931590Srgrimes * 25941590Srgrimes *----------------------------------------------------------------------- 25951590Srgrimes */ 25961590SrgrimesLst 25971590SrgrimesParse_MainName() 25981590Srgrimes{ 259949938Shoek Lst listmain; /* result list */ 26001590Srgrimes 260149938Shoek listmain = Lst_Init (FALSE); 26021590Srgrimes 260369527Swill if (mainNode == NULL) { 260417259Snate Punt ("no target to make."); 26051590Srgrimes /*NOTREACHED*/ 26061590Srgrimes } else if (mainNode->type & OP_DOUBLEDEP) { 260769531Swill (void) Lst_AtEnd (listmain, (void *)mainNode); 260849938Shoek Lst_Concat(listmain, mainNode->cohorts, LST_CONCNEW); 26091590Srgrimes } 26101590Srgrimes else 261169531Swill (void) Lst_AtEnd (listmain, (void *)mainNode); 261249938Shoek return (listmain); 26131590Srgrimes} 2614