140395Sbostic /* 262092Sbostic * Copyright (c) 1988, 1989, 1990, 1993 362092Sbostic * The Regents of the University of California. All rights reserved. 440395Sbostic * Copyright (c) 1989 by Berkeley Softworks 540395Sbostic * All rights reserved. 640395Sbostic * 740395Sbostic * This code is derived from software contributed to Berkeley by 840395Sbostic * Adam de Boor. 940395Sbostic * 1042752Sbostic * %sccs.include.redist.c% 1140395Sbostic */ 1240395Sbostic 1340395Sbostic #ifndef lint 14*66399Schristos static char sccsid[] = "@(#)parse.c 8.3 (Berkeley) 03/19/94"; 1540395Sbostic #endif /* not lint */ 1640395Sbostic 1740393Sbostic /*- 1840393Sbostic * parse.c -- 1940393Sbostic * Functions to parse a makefile. 2040393Sbostic * 2140393Sbostic * One function, Parse_Init, must be called before any functions 2240393Sbostic * in this module are used. After that, the function Parse_File is the 2340393Sbostic * main entry point and controls most of the other functions in this 2440393Sbostic * module. 2540393Sbostic * 2640393Sbostic * Most important structures are kept in Lsts. Directories for 2740393Sbostic * the #include "..." function are kept in the 'parseIncPath' Lst, while 2840393Sbostic * those for the #include <...> are kept in the 'sysIncPath' Lst. The 2940393Sbostic * targets currently being defined are kept in the 'targets' Lst. 3040393Sbostic * 3140393Sbostic * The variables 'fname' and 'lineno' are used to track the name 3240393Sbostic * of the current file and the line number in that file so that error 3340393Sbostic * messages can be more meaningful. 3440393Sbostic * 3540393Sbostic * Interface: 3640393Sbostic * Parse_Init Initialization function which must be 3740393Sbostic * called before anything else in this module 3840393Sbostic * is used. 3940393Sbostic * 4040393Sbostic * Parse_File Function used to parse a makefile. It must 4140393Sbostic * be given the name of the file, which should 4240393Sbostic * already have been opened, and a function 4340393Sbostic * to call to read a character from the file. 4440393Sbostic * 4540393Sbostic * Parse_IsVar Returns TRUE if the given line is a 4640393Sbostic * variable assignment. Used by MainParseArgs 4740393Sbostic * to determine if an argument is a target 4840393Sbostic * or a variable assignment. Used internally 4940393Sbostic * for pretty much the same thing... 5040393Sbostic * 5140393Sbostic * Parse_Error Function called when an error occurs in 5240393Sbostic * parsing. Used by the variable and 5340393Sbostic * conditional modules. 5440393Sbostic * Parse_MainName Returns a Lst of the main target to create. 5540393Sbostic */ 5640393Sbostic 5760285Sbostic #if __STDC__ 5860285Sbostic #include <stdarg.h> 5960285Sbostic #else 6040444Sbostic #include <varargs.h> 6160285Sbostic #endif 6240444Sbostic #include <stdio.h> 6340444Sbostic #include <ctype.h> 6460285Sbostic #include <errno.h> 6560285Sbostic #include <sys/wait.h> 6640444Sbostic #include "make.h" 6760285Sbostic #include "hash.h" 6860285Sbostic #include "dir.h" 6960285Sbostic #include "job.h" 7040444Sbostic #include "buf.h" 7140515Sbostic #include "pathnames.h" 7240393Sbostic 7340393Sbostic /* 7440393Sbostic * These values are returned by ParseEOF to tell Parse_File whether to 7540393Sbostic * CONTINUE parsing, i.e. it had only reached the end of an include file, 7640393Sbostic * or if it's DONE. 7740393Sbostic */ 7840393Sbostic #define CONTINUE 1 7940393Sbostic #define DONE 0 8040393Sbostic static Lst targets; /* targets we're working on */ 8140393Sbostic static Boolean inLine; /* true if currently in a dependency 8240393Sbostic * line or its commands */ 8360285Sbostic typedef struct { 8460285Sbostic char *str; 8560285Sbostic char *ptr; 8660285Sbostic } PTR; 8740393Sbostic 8840393Sbostic static char *fname; /* name of current file (for errors) */ 8940393Sbostic static int lineno; /* line number in current file */ 9060285Sbostic static FILE *curFILE = NULL; /* current makefile */ 9140393Sbostic 9260285Sbostic static PTR *curPTR = NULL; /* current makefile */ 9360285Sbostic 9440393Sbostic static int fatals = 0; 9540393Sbostic 9640393Sbostic static GNode *mainNode; /* The main target to create. This is the 9740393Sbostic * first target on the first dependency 9840393Sbostic * line in the first makefile */ 9940393Sbostic /* 10040393Sbostic * Definitions for handling #include specifications 10140393Sbostic */ 10240393Sbostic typedef struct IFile { 10340393Sbostic char *fname; /* name of previous file */ 10440393Sbostic int lineno; /* saved line number */ 10560285Sbostic FILE * F; /* the open stream */ 10660285Sbostic PTR * p; /* the char pointer */ 10760285Sbostic } IFile; 10840393Sbostic 10940393Sbostic static Lst includes; /* stack of IFiles generated by 11040393Sbostic * #includes */ 11140393Sbostic Lst parseIncPath; /* list of directories for "..." includes */ 11240393Sbostic Lst sysIncPath; /* list of directories for <...> includes */ 11340393Sbostic 11440393Sbostic /*- 11540393Sbostic * specType contains the SPECial TYPE of the current target. It is 11640393Sbostic * Not if the target is unspecial. If it *is* special, however, the children 11740393Sbostic * are linked as children of the parent but not vice versa. This variable is 11840393Sbostic * set in ParseDoDependency 11940393Sbostic */ 12040393Sbostic typedef enum { 12140393Sbostic Begin, /* .BEGIN */ 12240393Sbostic Default, /* .DEFAULT */ 12340393Sbostic End, /* .END */ 12440393Sbostic Ignore, /* .IGNORE */ 12540393Sbostic Includes, /* .INCLUDES */ 12640393Sbostic Interrupt, /* .INTERRUPT */ 12740393Sbostic Libs, /* .LIBS */ 12840393Sbostic MFlags, /* .MFLAGS or .MAKEFLAGS */ 12940393Sbostic Main, /* .MAIN and we don't have anything user-specified to 13040393Sbostic * make */ 13160285Sbostic NoExport, /* .NOEXPORT */ 13240393Sbostic Not, /* Not special */ 13340393Sbostic NotParallel, /* .NOTPARALELL */ 13440393Sbostic Null, /* .NULL */ 13540393Sbostic Order, /* .ORDER */ 13660285Sbostic ExPath, /* .PATH */ 13740393Sbostic Precious, /* .PRECIOUS */ 13860285Sbostic ExShell, /* .SHELL */ 13940393Sbostic Silent, /* .SILENT */ 14040393Sbostic SingleShell, /* .SINGLESHELL */ 14140393Sbostic Suffixes, /* .SUFFIXES */ 14260285Sbostic Attribute /* Generic attribute */ 14340393Sbostic } ParseSpecial; 14440393Sbostic 14560285Sbostic static ParseSpecial specType; 14640393Sbostic 14740393Sbostic /* 14840393Sbostic * Predecessor node for handling .ORDER. Initialized to NILGNODE when .ORDER 14940393Sbostic * seen, then set to each successive source on the line. 15040393Sbostic */ 15140393Sbostic static GNode *predecessor; 15240393Sbostic 15340393Sbostic /* 15440393Sbostic * The parseKeywords table is searched using binary search when deciding 15540393Sbostic * if a target or source is special. The 'spec' field is the ParseSpecial 15640393Sbostic * type of the keyword ("Not" if the keyword isn't special as a target) while 15740393Sbostic * the 'op' field is the operator to apply to the list of targets if the 15840393Sbostic * keyword is used as a source ("0" if the keyword isn't special as a source) 15940393Sbostic */ 16040393Sbostic static struct { 16140393Sbostic char *name; /* Name of keyword */ 16240393Sbostic ParseSpecial spec; /* Type when used as a target */ 16340393Sbostic int op; /* Operator when used as a source */ 16440393Sbostic } parseKeywords[] = { 16540393Sbostic { ".BEGIN", Begin, 0 }, 16640393Sbostic { ".DEFAULT", Default, 0 }, 16740546Sbostic { ".OPTIONAL", Attribute, OP_OPTIONAL }, 16840393Sbostic { ".END", End, 0 }, 16940393Sbostic { ".EXEC", Attribute, OP_EXEC }, 17040393Sbostic { ".IGNORE", Ignore, OP_IGNORE }, 17140393Sbostic { ".INCLUDES", Includes, 0 }, 17240393Sbostic { ".INTERRUPT", Interrupt, 0 }, 17340393Sbostic { ".INVISIBLE", Attribute, OP_INVISIBLE }, 17440393Sbostic { ".JOIN", Attribute, OP_JOIN }, 17540393Sbostic { ".LIBS", Libs, 0 }, 17640393Sbostic { ".MAIN", Main, 0 }, 17740393Sbostic { ".MAKE", Attribute, OP_MAKE }, 17840393Sbostic { ".MAKEFLAGS", MFlags, 0 }, 17940393Sbostic { ".MFLAGS", MFlags, 0 }, 18040393Sbostic { ".NOTMAIN", Attribute, OP_NOTMAIN }, 18140393Sbostic { ".NOTPARALLEL", NotParallel, 0 }, 18240393Sbostic { ".NULL", Null, 0 }, 18340393Sbostic { ".ORDER", Order, 0 }, 18460285Sbostic { ".PATH", ExPath, 0 }, 18540393Sbostic { ".PRECIOUS", Precious, OP_PRECIOUS }, 18640393Sbostic { ".RECURSIVE", Attribute, OP_MAKE }, 18760285Sbostic { ".SHELL", ExShell, 0 }, 18840393Sbostic { ".SILENT", Silent, OP_SILENT }, 18940393Sbostic { ".SINGLESHELL", SingleShell, 0 }, 19040393Sbostic { ".SUFFIXES", Suffixes, 0 }, 19140393Sbostic { ".USE", Attribute, OP_USE }, 19240393Sbostic }; 19340424Sbostic 19460285Sbostic static int ParseFindKeyword __P((char *)); 19560285Sbostic static int ParseLinkSrc __P((GNode *, GNode *)); 19660285Sbostic static int ParseDoOp __P((GNode *, int)); 19760285Sbostic static void ParseDoSrc __P((int, char *)); 19860285Sbostic static int ParseFindMain __P((GNode *)); 19960285Sbostic static int ParseAddDir __P((Lst, char *)); 20060285Sbostic static int ParseClearPath __P((Lst)); 20160285Sbostic static void ParseDoDependency __P((char *)); 20260285Sbostic static int ParseAddCmd __P((GNode *, char *)); 20360285Sbostic static int ParseReadc __P((void)); 20460557Sbostic static void ParseUnreadc __P((int)); 20560285Sbostic static int ParseHasCommands __P((GNode *)); 20660285Sbostic static void ParseDoInclude __P((char *)); 20760285Sbostic #ifdef SYSVINCLUDE 20860285Sbostic static void ParseTraditionalInclude __P((char *)); 20960285Sbostic #endif 21060285Sbostic static int ParseEOF __P((int)); 21160285Sbostic static char *ParseReadLine __P((void)); 21260285Sbostic static char *ParseSkipLine __P((int)); 21360285Sbostic static void ParseFinishLine __P((void)); 21460285Sbostic 21540393Sbostic /*- 21640393Sbostic *---------------------------------------------------------------------- 21740393Sbostic * ParseFindKeyword -- 21840393Sbostic * Look in the table of keywords for one matching the given string. 21940393Sbostic * 22040393Sbostic * Results: 22140393Sbostic * The index of the keyword, or -1 if it isn't there. 22240393Sbostic * 22340393Sbostic * Side Effects: 22440393Sbostic * None 22540393Sbostic *---------------------------------------------------------------------- 22640393Sbostic */ 22740393Sbostic static int 22840393Sbostic ParseFindKeyword (str) 22940393Sbostic char *str; /* String to find */ 23040393Sbostic { 23140393Sbostic register int start, 23240393Sbostic end, 23340393Sbostic cur; 23440393Sbostic register int diff; 23540393Sbostic 23640393Sbostic start = 0; 23740393Sbostic end = (sizeof(parseKeywords)/sizeof(parseKeywords[0])) - 1; 23840393Sbostic 23940393Sbostic do { 24040393Sbostic cur = start + ((end - start) / 2); 24140393Sbostic diff = strcmp (str, parseKeywords[cur].name); 24240393Sbostic 24340393Sbostic if (diff == 0) { 24440393Sbostic return (cur); 24540393Sbostic } else if (diff < 0) { 24640393Sbostic end = cur - 1; 24740393Sbostic } else { 24840393Sbostic start = cur + 1; 24940393Sbostic } 25040393Sbostic } while (start <= end); 25140393Sbostic return (-1); 25240393Sbostic } 25340424Sbostic 25440393Sbostic /*- 25540393Sbostic * Parse_Error -- 25640393Sbostic * Error message abort function for parsing. Prints out the context 25740393Sbostic * of the error (line number and file) as well as the message with 25840393Sbostic * two optional arguments. 25940393Sbostic * 26040393Sbostic * Results: 26140393Sbostic * None 26240393Sbostic * 26340393Sbostic * Side Effects: 26440393Sbostic * "fatals" is incremented if the level is PARSE_FATAL. 26540393Sbostic */ 26640444Sbostic /* VARARGS */ 26740393Sbostic void 26860285Sbostic #if __STDC__ 26960285Sbostic Parse_Error(int type, const char *fmt, ...) 27060285Sbostic #else 271*66399Schristos Parse_Error(va_alist) 27240444Sbostic va_dcl 27360285Sbostic #endif 27440393Sbostic { 27540444Sbostic va_list ap; 27660285Sbostic #if __STDC__ 27760285Sbostic va_start(ap, fmt); 27860285Sbostic #else 279*66399Schristos int type; /* Error type (PARSE_WARNING, PARSE_FATAL) */ 280*66399Schristos char *fmt; 281*66399Schristos 28260285Sbostic va_start(ap); 283*66399Schristos type = va_arg(ap, int); 284*66399Schristos fmt = va_arg(ap, char *); 28560285Sbostic #endif 286*66399Schristos 28740444Sbostic (void)fprintf(stderr, "\"%s\", line %d: ", fname, lineno); 28840444Sbostic if (type == PARSE_WARNING) 28940540Sbostic (void)fprintf(stderr, "warning: "); 29040444Sbostic (void)vfprintf(stderr, fmt, ap); 29140444Sbostic va_end(ap); 29240444Sbostic (void)fprintf(stderr, "\n"); 29340444Sbostic (void)fflush(stderr); 29440444Sbostic if (type == PARSE_FATAL) 29540444Sbostic fatals += 1; 29640393Sbostic } 29740424Sbostic 29840393Sbostic /*- 29940393Sbostic *--------------------------------------------------------------------- 30040393Sbostic * ParseLinkSrc -- 30140393Sbostic * Link the parent node to its new child. Used in a Lst_ForEach by 30240393Sbostic * ParseDoDependency. If the specType isn't 'Not', the parent 30340393Sbostic * isn't linked as a parent of the child. 30440393Sbostic * 30540393Sbostic * Results: 30640393Sbostic * Always = 0 30740393Sbostic * 30840393Sbostic * Side Effects: 30940393Sbostic * New elements are added to the parents list of cgn and the 31040393Sbostic * children list of cgn. the unmade field of pgn is updated 31140393Sbostic * to reflect the additional child. 31240393Sbostic *--------------------------------------------------------------------- 31340393Sbostic */ 31440393Sbostic static int 31540393Sbostic ParseLinkSrc (pgn, cgn) 31640393Sbostic GNode *pgn; /* The parent node */ 31740393Sbostic GNode *cgn; /* The child node */ 31840393Sbostic { 31940393Sbostic if (Lst_Member (pgn->children, (ClientData)cgn) == NILLNODE) { 32040393Sbostic (void)Lst_AtEnd (pgn->children, (ClientData)cgn); 32140393Sbostic if (specType == Not) { 32240393Sbostic (void)Lst_AtEnd (cgn->parents, (ClientData)pgn); 32340393Sbostic } 32440393Sbostic pgn->unmade += 1; 32540393Sbostic } 32640393Sbostic return (0); 32740393Sbostic } 32840424Sbostic 32940393Sbostic /*- 33040393Sbostic *--------------------------------------------------------------------- 33140393Sbostic * ParseDoOp -- 33240393Sbostic * Apply the parsed operator to the given target node. Used in a 33340393Sbostic * Lst_ForEach call by ParseDoDependency once all targets have 33440393Sbostic * been found and their operator parsed. If the previous and new 33540393Sbostic * operators are incompatible, a major error is taken. 33640393Sbostic * 33740393Sbostic * Results: 33840393Sbostic * Always 0 33940393Sbostic * 34040393Sbostic * Side Effects: 34140393Sbostic * The type field of the node is altered to reflect any new bits in 34240393Sbostic * the op. 34340393Sbostic *--------------------------------------------------------------------- 34440393Sbostic */ 34540393Sbostic static int 34640393Sbostic ParseDoOp (gn, op) 34740393Sbostic GNode *gn; /* The node to which the operator is to be 34840393Sbostic * applied */ 34940393Sbostic int op; /* The operator to apply */ 35040393Sbostic { 35140393Sbostic /* 35240393Sbostic * If the dependency mask of the operator and the node don't match and 35340393Sbostic * the node has actually had an operator applied to it before, and 35440393Sbostic * the operator actually has some dependency information in it, complain. 35540393Sbostic */ 35640393Sbostic if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) && 35740393Sbostic !OP_NOP(gn->type) && !OP_NOP(op)) 35840393Sbostic { 35940393Sbostic Parse_Error (PARSE_FATAL, "Inconsistent operator for %s", gn->name); 36040393Sbostic return (1); 36140393Sbostic } 36240393Sbostic 36340393Sbostic if ((op == OP_DOUBLEDEP) && ((gn->type & OP_OPMASK) == OP_DOUBLEDEP)) { 36440393Sbostic /* 36540393Sbostic * If the node was the object of a :: operator, we need to create a 36640393Sbostic * new instance of it for the children and commands on this dependency 36740393Sbostic * line. The new instance is placed on the 'cohorts' list of the 36840393Sbostic * initial one (note the initial one is not on its own cohorts list) 36940393Sbostic * and the new instance is linked to all parents of the initial 37040393Sbostic * instance. 37140393Sbostic */ 37240393Sbostic register GNode *cohort; 37340393Sbostic LstNode ln; 37440393Sbostic 37540393Sbostic cohort = Targ_NewGN(gn->name); 37640393Sbostic /* 37740393Sbostic * Duplicate links to parents so graph traversal is simple. Perhaps 37840393Sbostic * some type bits should be duplicated? 37940393Sbostic * 38040393Sbostic * Make the cohort invisible as well to avoid duplicating it into 38140393Sbostic * other variables. True, parents of this target won't tend to do 38240393Sbostic * anything with their local variables, but better safe than 38340393Sbostic * sorry. 38440393Sbostic */ 38540393Sbostic Lst_ForEach(gn->parents, ParseLinkSrc, (ClientData)cohort); 38640393Sbostic cohort->type = OP_DOUBLEDEP|OP_INVISIBLE; 38740393Sbostic (void)Lst_AtEnd(gn->cohorts, (ClientData)cohort); 38840393Sbostic 38940393Sbostic /* 39040393Sbostic * Replace the node in the targets list with the new copy 39140393Sbostic */ 39240393Sbostic ln = Lst_Member(targets, (ClientData)gn); 39340393Sbostic Lst_Replace(ln, (ClientData)cohort); 39440393Sbostic gn = cohort; 39540393Sbostic } 39640393Sbostic /* 39740393Sbostic * We don't want to nuke any previous flags (whatever they were) so we 39840393Sbostic * just OR the new operator into the old 39940393Sbostic */ 40040393Sbostic gn->type |= op; 40140393Sbostic 40240393Sbostic return (0); 40340393Sbostic } 40440424Sbostic 40540393Sbostic /*- 40640393Sbostic *--------------------------------------------------------------------- 40740393Sbostic * ParseDoSrc -- 40840393Sbostic * Given the name of a source, figure out if it is an attribute 40940393Sbostic * and apply it to the targets if it is. Else decide if there is 41040393Sbostic * some attribute which should be applied *to* the source because 41140393Sbostic * of some special target and apply it if so. Otherwise, make the 41240393Sbostic * source be a child of the targets in the list 'targets' 41340393Sbostic * 41440393Sbostic * Results: 41540393Sbostic * None 41640393Sbostic * 41740393Sbostic * Side Effects: 41840393Sbostic * Operator bits may be added to the list of targets or to the source. 41940393Sbostic * The targets may have a new source added to their lists of children. 42040393Sbostic *--------------------------------------------------------------------- 42140393Sbostic */ 42240393Sbostic static void 42340393Sbostic ParseDoSrc (tOp, src) 42440393Sbostic int tOp; /* operator (if any) from special targets */ 42540393Sbostic char *src; /* name of the source to handle */ 42640393Sbostic { 42740393Sbostic int op; /* operator (if any) from special source */ 42840393Sbostic GNode *gn; 42940393Sbostic 43040393Sbostic op = 0; 43140393Sbostic if (*src == '.' && isupper (src[1])) { 43240393Sbostic int keywd = ParseFindKeyword(src); 43340393Sbostic if (keywd != -1) { 43440393Sbostic op = parseKeywords[keywd].op; 43540393Sbostic } 43640393Sbostic } 43740393Sbostic if (op != 0) { 43840393Sbostic Lst_ForEach (targets, ParseDoOp, (ClientData)op); 43940393Sbostic } else if (specType == Main) { 44040393Sbostic /* 44140393Sbostic * If we have noted the existence of a .MAIN, it means we need 44240393Sbostic * to add the sources of said target to the list of things 44340393Sbostic * to create. The string 'src' is likely to be free, so we 44440393Sbostic * must make a new copy of it. Note that this will only be 44540393Sbostic * invoked if the user didn't specify a target on the command 44640393Sbostic * line. This is to allow #ifmake's to succeed, or something... 44740393Sbostic */ 44840424Sbostic (void) Lst_AtEnd (create, (ClientData)strdup(src)); 44940393Sbostic /* 45040393Sbostic * Add the name to the .TARGETS variable as well, so the user cna 45140393Sbostic * employ that, if desired. 45240393Sbostic */ 45340393Sbostic Var_Append(".TARGETS", src, VAR_GLOBAL); 45440393Sbostic } else if (specType == Order) { 45540393Sbostic /* 45640393Sbostic * Create proper predecessor/successor links between the previous 45740393Sbostic * source and the current one. 45840393Sbostic */ 45940393Sbostic gn = Targ_FindNode(src, TARG_CREATE); 46040393Sbostic if (predecessor != NILGNODE) { 46140393Sbostic (void)Lst_AtEnd(predecessor->successors, (ClientData)gn); 46240393Sbostic (void)Lst_AtEnd(gn->preds, (ClientData)predecessor); 46340393Sbostic } 46440393Sbostic /* 46540393Sbostic * The current source now becomes the predecessor for the next one. 46640393Sbostic */ 46740393Sbostic predecessor = gn; 46840393Sbostic } else { 46940393Sbostic /* 47040393Sbostic * If the source is not an attribute, we need to find/create 47140393Sbostic * a node for it. After that we can apply any operator to it 47240393Sbostic * from a special target or link it to its parents, as 47340393Sbostic * appropriate. 47440393Sbostic * 47540393Sbostic * In the case of a source that was the object of a :: operator, 47640393Sbostic * the attribute is applied to all of its instances (as kept in 47740393Sbostic * the 'cohorts' list of the node) or all the cohorts are linked 47840393Sbostic * to all the targets. 47940393Sbostic */ 48040393Sbostic gn = Targ_FindNode (src, TARG_CREATE); 48140393Sbostic if (tOp) { 48240393Sbostic gn->type |= tOp; 48340393Sbostic } else { 48440393Sbostic Lst_ForEach (targets, ParseLinkSrc, (ClientData)gn); 48540393Sbostic } 48640393Sbostic if ((gn->type & OP_OPMASK) == OP_DOUBLEDEP) { 48740393Sbostic register GNode *cohort; 48840393Sbostic register LstNode ln; 48940393Sbostic 49040393Sbostic for (ln=Lst_First(gn->cohorts); ln != NILLNODE; ln = Lst_Succ(ln)){ 49140393Sbostic cohort = (GNode *)Lst_Datum(ln); 49240393Sbostic if (tOp) { 49340393Sbostic cohort->type |= tOp; 49440393Sbostic } else { 49540393Sbostic Lst_ForEach(targets, ParseLinkSrc, (ClientData)cohort); 49640393Sbostic } 49740393Sbostic } 49840393Sbostic } 49940393Sbostic } 50040393Sbostic } 50140424Sbostic 50240393Sbostic /*- 50340393Sbostic *----------------------------------------------------------------------- 50440393Sbostic * ParseFindMain -- 50540393Sbostic * Find a real target in the list and set it to be the main one. 50640393Sbostic * Called by ParseDoDependency when a main target hasn't been found 50740393Sbostic * yet. 50840393Sbostic * 50940393Sbostic * Results: 51040393Sbostic * 0 if main not found yet, 1 if it is. 51140393Sbostic * 51240393Sbostic * Side Effects: 51340393Sbostic * mainNode is changed and Targ_SetMain is called. 51440393Sbostic * 51540393Sbostic *----------------------------------------------------------------------- 51640393Sbostic */ 51740393Sbostic static int 51840393Sbostic ParseFindMain(gn) 51940393Sbostic GNode *gn; /* Node to examine */ 52040393Sbostic { 52140393Sbostic if ((gn->type & (OP_NOTMAIN|OP_USE|OP_EXEC|OP_TRANSFORM)) == 0) { 52240393Sbostic mainNode = gn; 52340393Sbostic Targ_SetMain(gn); 52440393Sbostic return (1); 52540393Sbostic } else { 52640393Sbostic return (0); 52740393Sbostic } 52840393Sbostic } 52940424Sbostic 53040393Sbostic /*- 53140393Sbostic *----------------------------------------------------------------------- 53240393Sbostic * ParseAddDir -- 53340393Sbostic * Front-end for Dir_AddDir to make sure Lst_ForEach keeps going 53440393Sbostic * 53540393Sbostic * Results: 53640393Sbostic * === 0 53740393Sbostic * 53840393Sbostic * Side Effects: 53940393Sbostic * See Dir_AddDir. 54040393Sbostic * 54140393Sbostic *----------------------------------------------------------------------- 54240393Sbostic */ 54340393Sbostic static int 54440393Sbostic ParseAddDir(path, name) 54540393Sbostic Lst path; 54640393Sbostic char *name; 54740393Sbostic { 54840393Sbostic Dir_AddDir(path, name); 54940393Sbostic return(0); 55040393Sbostic } 55140424Sbostic 55240393Sbostic /*- 55340393Sbostic *----------------------------------------------------------------------- 55440393Sbostic * ParseClearPath -- 55540393Sbostic * Front-end for Dir_ClearPath to make sure Lst_ForEach keeps going 55640393Sbostic * 55740393Sbostic * Results: 55840393Sbostic * === 0 55940393Sbostic * 56040393Sbostic * Side Effects: 56140393Sbostic * See Dir_ClearPath 56240393Sbostic * 56340393Sbostic *----------------------------------------------------------------------- 56440393Sbostic */ 56540393Sbostic static int 56640393Sbostic ParseClearPath(path) 56740393Sbostic Lst path; 56840393Sbostic { 56940393Sbostic Dir_ClearPath(path); 57040393Sbostic return(0); 57140393Sbostic } 57240424Sbostic 57340393Sbostic /*- 57440393Sbostic *--------------------------------------------------------------------- 57540393Sbostic * ParseDoDependency -- 57640393Sbostic * Parse the dependency line in line. 57740393Sbostic * 57840393Sbostic * Results: 57940393Sbostic * None 58040393Sbostic * 58140393Sbostic * Side Effects: 58240393Sbostic * The nodes of the sources are linked as children to the nodes of the 58340393Sbostic * targets. Some nodes may be created. 58440393Sbostic * 58540393Sbostic * We parse a dependency line by first extracting words from the line and 58640393Sbostic * finding nodes in the list of all targets with that name. This is done 58740393Sbostic * until a character is encountered which is an operator character. Currently 58840393Sbostic * these are only ! and :. At this point the operator is parsed and the 58940393Sbostic * pointer into the line advanced until the first source is encountered. 59040393Sbostic * The parsed operator is applied to each node in the 'targets' list, 59140393Sbostic * which is where the nodes found for the targets are kept, by means of 59240393Sbostic * the ParseDoOp function. 59340393Sbostic * The sources are read in much the same way as the targets were except 59440393Sbostic * that now they are expanded using the wildcarding scheme of the C-Shell 59540393Sbostic * and all instances of the resulting words in the list of all targets 59640393Sbostic * are found. Each of the resulting nodes is then linked to each of the 59740393Sbostic * targets as one of its children. 59840393Sbostic * Certain targets are handled specially. These are the ones detailed 59940393Sbostic * by the specType variable. 60040393Sbostic * The storing of transformation rules is also taken care of here. 60140393Sbostic * A target is recognized as a transformation rule by calling 60240393Sbostic * Suff_IsTransform. If it is a transformation rule, its node is gotten 60340393Sbostic * from the suffix module via Suff_AddTransform rather than the standard 60440393Sbostic * Targ_FindNode in the target module. 60540393Sbostic *--------------------------------------------------------------------- 60640393Sbostic */ 60740393Sbostic static void 60840393Sbostic ParseDoDependency (line) 60940393Sbostic char *line; /* the line to parse */ 61040393Sbostic { 61140393Sbostic register char *cp; /* our current position */ 61240393Sbostic register GNode *gn; /* a general purpose temporary node */ 61340393Sbostic register int op; /* the operator on the line */ 61440393Sbostic char savec; /* a place to save a character */ 61540393Sbostic Lst paths; /* List of search paths to alter when parsing 61640393Sbostic * a list of .PATH targets */ 61740393Sbostic int tOp; /* operator from special target */ 61840393Sbostic Lst sources; /* list of source names after expansion */ 61940393Sbostic Lst curTargs; /* list of target names to be found and added 62040393Sbostic * to the targets list */ 62140393Sbostic 62240393Sbostic tOp = 0; 62340393Sbostic 62440393Sbostic specType = Not; 62540393Sbostic paths = (Lst)NULL; 62640393Sbostic 62740393Sbostic curTargs = Lst_Init(FALSE); 62840393Sbostic 62940393Sbostic do { 63040393Sbostic for (cp = line; 63140393Sbostic *cp && !isspace (*cp) && 63240393Sbostic (*cp != '!') && (*cp != ':') && (*cp != '('); 63340393Sbostic cp++) 63440393Sbostic { 63540393Sbostic if (*cp == '$') { 63640393Sbostic /* 63740393Sbostic * Must be a dynamic source (would have been expanded 63840393Sbostic * otherwise), so call the Var module to parse the puppy 63940393Sbostic * so we can safely advance beyond it...There should be 64040393Sbostic * no errors in this, as they would have been discovered 64140393Sbostic * in the initial Var_Subst and we wouldn't be here. 64240393Sbostic */ 64340393Sbostic int length; 64440393Sbostic Boolean freeIt; 64540393Sbostic char *result; 64640393Sbostic 64740393Sbostic result=Var_Parse(cp, VAR_CMD, TRUE, &length, &freeIt); 64840393Sbostic 64940393Sbostic if (freeIt) { 65040393Sbostic free(result); 65140393Sbostic } 65240393Sbostic cp += length-1; 65340393Sbostic } 65440393Sbostic continue; 65540393Sbostic } 65640393Sbostic if (*cp == '(') { 65740393Sbostic /* 65840393Sbostic * Archives must be handled specially to make sure the OP_ARCHV 65940393Sbostic * flag is set in their 'type' field, for one thing, and because 66040393Sbostic * things like "archive(file1.o file2.o file3.o)" are permissible. 66140393Sbostic * Arch_ParseArchive will set 'line' to be the first non-blank 66240393Sbostic * after the archive-spec. It creates/finds nodes for the members 66340393Sbostic * and places them on the given list, returning SUCCESS if all 66440393Sbostic * went well and FAILURE if there was an error in the 66540393Sbostic * specification. On error, line should remain untouched. 66640393Sbostic */ 66740393Sbostic if (Arch_ParseArchive (&line, targets, VAR_CMD) != SUCCESS) { 66840393Sbostic Parse_Error (PARSE_FATAL, 66940393Sbostic "Error in archive specification: \"%s\"", line); 67040393Sbostic return; 67140393Sbostic } else { 67240393Sbostic continue; 67340393Sbostic } 67440393Sbostic } 67540393Sbostic savec = *cp; 67640393Sbostic 67740393Sbostic if (!*cp) { 67840393Sbostic /* 67940393Sbostic * Ending a dependency line without an operator is a Bozo 68040393Sbostic * no-no 68140393Sbostic */ 68240393Sbostic Parse_Error (PARSE_FATAL, "Need an operator"); 68340393Sbostic return; 68440393Sbostic } 68540393Sbostic *cp = '\0'; 68640393Sbostic /* 68740393Sbostic * Have a word in line. See if it's a special target and set 68840393Sbostic * specType to match it. 68940393Sbostic */ 69040393Sbostic if (*line == '.' && isupper (line[1])) { 69140393Sbostic /* 69240393Sbostic * See if the target is a special target that must have it 69340393Sbostic * or its sources handled specially. 69440393Sbostic */ 69540393Sbostic int keywd = ParseFindKeyword(line); 69640393Sbostic if (keywd != -1) { 69760285Sbostic if (specType == ExPath && parseKeywords[keywd].spec != ExPath) { 69840393Sbostic Parse_Error(PARSE_FATAL, "Mismatched special targets"); 69940393Sbostic return; 70040393Sbostic } 70140393Sbostic 70240393Sbostic specType = parseKeywords[keywd].spec; 70340393Sbostic tOp = parseKeywords[keywd].op; 70440393Sbostic 70540393Sbostic /* 70640393Sbostic * Certain special targets have special semantics: 70740393Sbostic * .PATH Have to set the dirSearchPath 70840393Sbostic * variable too 70940393Sbostic * .MAIN Its sources are only used if 71040393Sbostic * nothing has been specified to 71140393Sbostic * create. 71240393Sbostic * .DEFAULT Need to create a node to hang 71340393Sbostic * commands on, but we don't want 71440393Sbostic * it in the graph, nor do we want 71540393Sbostic * it to be the Main Target, so we 71640393Sbostic * create it, set OP_NOTMAIN and 71740393Sbostic * add it to the list, setting 71840393Sbostic * DEFAULT to the new node for 71940393Sbostic * later use. We claim the node is 72040393Sbostic * A transformation rule to make 72140393Sbostic * life easier later, when we'll 72240393Sbostic * use Make_HandleUse to actually 72340393Sbostic * apply the .DEFAULT commands. 72440393Sbostic * .BEGIN 72540393Sbostic * .END 72640393Sbostic * .INTERRUPT Are not to be considered the 72740393Sbostic * main target. 72840393Sbostic * .NOTPARALLEL Make only one target at a time. 72940393Sbostic * .SINGLESHELL Create a shell for each command. 73040393Sbostic * .ORDER Must set initial predecessor to NIL 73140393Sbostic */ 73240393Sbostic switch (specType) { 73360285Sbostic case ExPath: 73440393Sbostic if (paths == NULL) { 73540393Sbostic paths = Lst_Init(FALSE); 73640393Sbostic } 73740393Sbostic (void)Lst_AtEnd(paths, (ClientData)dirSearchPath); 73840393Sbostic break; 73940393Sbostic case Main: 74040393Sbostic if (!Lst_IsEmpty(create)) { 74140393Sbostic specType = Not; 74240393Sbostic } 74340393Sbostic break; 74440393Sbostic case Begin: 74540393Sbostic case End: 74640393Sbostic case Interrupt: 74740393Sbostic gn = Targ_FindNode(line, TARG_CREATE); 74840393Sbostic gn->type |= OP_NOTMAIN; 74940393Sbostic (void)Lst_AtEnd(targets, (ClientData)gn); 75040393Sbostic break; 75140393Sbostic case Default: 75240393Sbostic gn = Targ_NewGN(".DEFAULT"); 75340393Sbostic gn->type |= (OP_NOTMAIN|OP_TRANSFORM); 75440393Sbostic (void)Lst_AtEnd(targets, (ClientData)gn); 75540393Sbostic DEFAULT = gn; 75640393Sbostic break; 75740393Sbostic case NotParallel: 75840393Sbostic { 75940393Sbostic extern int maxJobs; 76040393Sbostic 76140393Sbostic maxJobs = 1; 76240393Sbostic break; 76340393Sbostic } 76440393Sbostic case SingleShell: 76560285Sbostic compatMake = 1; 76640393Sbostic break; 76740393Sbostic case Order: 76840393Sbostic predecessor = NILGNODE; 76940393Sbostic break; 77060285Sbostic default: 77160285Sbostic break; 77240393Sbostic } 77340393Sbostic } else if (strncmp (line, ".PATH", 5) == 0) { 77440393Sbostic /* 77540393Sbostic * .PATH<suffix> has to be handled specially. 77640393Sbostic * Call on the suffix module to give us a path to 77740393Sbostic * modify. 77840393Sbostic */ 77940393Sbostic Lst path; 78040393Sbostic 78160285Sbostic specType = ExPath; 78240393Sbostic path = Suff_GetPath (&line[5]); 78340393Sbostic if (path == NILLST) { 78440393Sbostic Parse_Error (PARSE_FATAL, 78540393Sbostic "Suffix '%s' not defined (yet)", 78640393Sbostic &line[5]); 78740393Sbostic return; 78840393Sbostic } else { 78940393Sbostic if (paths == (Lst)NULL) { 79040393Sbostic paths = Lst_Init(FALSE); 79140393Sbostic } 79240393Sbostic (void)Lst_AtEnd(paths, (ClientData)path); 79340393Sbostic } 79440393Sbostic } 79540393Sbostic } 79640393Sbostic 79740393Sbostic /* 79840393Sbostic * Have word in line. Get or create its node and stick it at 79940393Sbostic * the end of the targets list 80040393Sbostic */ 80140393Sbostic if ((specType == Not) && (*line != '\0')) { 80240393Sbostic if (Dir_HasWildcards(line)) { 80340393Sbostic /* 80440393Sbostic * Targets are to be sought only in the current directory, 80540393Sbostic * so create an empty path for the thing. Note we need to 80640393Sbostic * use Dir_Destroy in the destruction of the path as the 80740393Sbostic * Dir module could have added a directory to the path... 80840393Sbostic */ 80940393Sbostic Lst emptyPath = Lst_Init(FALSE); 81040393Sbostic 81140393Sbostic Dir_Expand(line, emptyPath, curTargs); 81240393Sbostic 81340393Sbostic Lst_Destroy(emptyPath, Dir_Destroy); 81440393Sbostic } else { 81540393Sbostic /* 81640393Sbostic * No wildcards, but we want to avoid code duplication, 81740393Sbostic * so create a list with the word on it. 81840393Sbostic */ 81940393Sbostic (void)Lst_AtEnd(curTargs, (ClientData)line); 82040393Sbostic } 82140393Sbostic 82240393Sbostic while(!Lst_IsEmpty(curTargs)) { 82340393Sbostic char *targName = (char *)Lst_DeQueue(curTargs); 82440393Sbostic 82540393Sbostic if (!Suff_IsTransform (targName)) { 82640393Sbostic gn = Targ_FindNode (targName, TARG_CREATE); 82740393Sbostic } else { 82840393Sbostic gn = Suff_AddTransform (targName); 82940393Sbostic } 83040393Sbostic 83140393Sbostic (void)Lst_AtEnd (targets, (ClientData)gn); 83240393Sbostic } 83360285Sbostic } else if (specType == ExPath && *line != '.' && *line != '\0') { 83440393Sbostic Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line); 83540393Sbostic } 83640393Sbostic 83740393Sbostic *cp = savec; 83840393Sbostic /* 83940393Sbostic * If it is a special type and not .PATH, it's the only target we 84040393Sbostic * allow on this line... 84140393Sbostic */ 84260285Sbostic if (specType != Not && specType != ExPath) { 84340393Sbostic Boolean warn = FALSE; 84440393Sbostic 84540393Sbostic while ((*cp != '!') && (*cp != ':') && *cp) { 84640393Sbostic if (*cp != ' ' && *cp != '\t') { 84740393Sbostic warn = TRUE; 84840393Sbostic } 84940393Sbostic cp++; 85040393Sbostic } 85140393Sbostic if (warn) { 85240393Sbostic Parse_Error(PARSE_WARNING, "Extra target ignored"); 85340393Sbostic } 85440393Sbostic } else { 85540393Sbostic while (*cp && isspace (*cp)) { 85640393Sbostic cp++; 85740393Sbostic } 85840393Sbostic } 85940393Sbostic line = cp; 86040393Sbostic } while ((*line != '!') && (*line != ':') && *line); 86140393Sbostic 86240393Sbostic /* 86340393Sbostic * Don't need the list of target names anymore... 86440393Sbostic */ 86540393Sbostic Lst_Destroy(curTargs, NOFREE); 86640393Sbostic 86740393Sbostic if (!Lst_IsEmpty(targets)) { 86840393Sbostic switch(specType) { 86940393Sbostic default: 87040393Sbostic Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. Mundane ones ignored"); 87140393Sbostic break; 87240393Sbostic case Default: 87340393Sbostic case Begin: 87440393Sbostic case End: 87540393Sbostic case Interrupt: 87640393Sbostic /* 87740393Sbostic * These four create nodes on which to hang commands, so 87840393Sbostic * targets shouldn't be empty... 87940393Sbostic */ 88040393Sbostic case Not: 88140393Sbostic /* 88240393Sbostic * Nothing special here -- targets can be empty if it wants. 88340393Sbostic */ 88440393Sbostic break; 88540393Sbostic } 88640393Sbostic } 88740393Sbostic 88840393Sbostic /* 88940393Sbostic * Have now parsed all the target names. Must parse the operator next. The 89040393Sbostic * result is left in op . 89140393Sbostic */ 89240393Sbostic if (*cp == '!') { 89340393Sbostic op = OP_FORCE; 89440393Sbostic } else if (*cp == ':') { 89540393Sbostic if (cp[1] == ':') { 89640393Sbostic op = OP_DOUBLEDEP; 89740393Sbostic cp++; 89840393Sbostic } else { 89940393Sbostic op = OP_DEPENDS; 90040393Sbostic } 90140393Sbostic } else { 90240393Sbostic Parse_Error (PARSE_FATAL, "Missing dependency operator"); 90340393Sbostic return; 90440393Sbostic } 90540393Sbostic 90640393Sbostic cp++; /* Advance beyond operator */ 90740393Sbostic 90840393Sbostic Lst_ForEach (targets, ParseDoOp, (ClientData)op); 90940393Sbostic 91040393Sbostic /* 91140393Sbostic * Get to the first source 91240393Sbostic */ 91340393Sbostic while (*cp && isspace (*cp)) { 91440393Sbostic cp++; 91540393Sbostic } 91640393Sbostic line = cp; 91740393Sbostic 91840393Sbostic /* 91940393Sbostic * Several special targets take different actions if present with no 92040393Sbostic * sources: 92140393Sbostic * a .SUFFIXES line with no sources clears out all old suffixes 92240393Sbostic * a .PRECIOUS line makes all targets precious 92340393Sbostic * a .IGNORE line ignores errors for all targets 92440393Sbostic * a .SILENT line creates silence when making all targets 92540393Sbostic * a .PATH removes all directories from the search path(s). 92640393Sbostic */ 92740393Sbostic if (!*line) { 92840393Sbostic switch (specType) { 92940393Sbostic case Suffixes: 93040393Sbostic Suff_ClearSuffixes (); 93140393Sbostic break; 93240393Sbostic case Precious: 93340393Sbostic allPrecious = TRUE; 93440393Sbostic break; 93540393Sbostic case Ignore: 93640393Sbostic ignoreErrors = TRUE; 93740393Sbostic break; 93840393Sbostic case Silent: 93940393Sbostic beSilent = TRUE; 94040393Sbostic break; 94160285Sbostic case ExPath: 94240393Sbostic Lst_ForEach(paths, ParseClearPath, (ClientData)NULL); 94340393Sbostic break; 94460285Sbostic default: 94560285Sbostic break; 94640393Sbostic } 94740393Sbostic } else if (specType == MFlags) { 94840393Sbostic /* 94940393Sbostic * Call on functions in main.c to deal with these arguments and 95040393Sbostic * set the initial character to a null-character so the loop to 95140393Sbostic * get sources won't get anything 95240393Sbostic */ 95340393Sbostic Main_ParseArgLine (line); 95440393Sbostic *line = '\0'; 95560285Sbostic } else if (specType == ExShell) { 95640393Sbostic if (Job_ParseShell (line) != SUCCESS) { 95740393Sbostic Parse_Error (PARSE_FATAL, "improper shell specification"); 95840393Sbostic return; 95940393Sbostic } 96040393Sbostic *line = '\0'; 96140393Sbostic } else if ((specType == NotParallel) || (specType == SingleShell)) { 96240393Sbostic *line = '\0'; 96340393Sbostic } 96440393Sbostic 96540393Sbostic /* 96640393Sbostic * NOW GO FOR THE SOURCES 96740393Sbostic */ 96860285Sbostic if ((specType == Suffixes) || (specType == ExPath) || 96940393Sbostic (specType == Includes) || (specType == Libs) || 97040439Sbostic (specType == Null)) 97140393Sbostic { 97240393Sbostic while (*line) { 97340393Sbostic /* 97440393Sbostic * If the target was one that doesn't take files as its sources 97540393Sbostic * but takes something like suffixes, we take each 97640393Sbostic * space-separated word on the line as a something and deal 97740393Sbostic * with it accordingly. 97840393Sbostic * 97940393Sbostic * If the target was .SUFFIXES, we take each source as a 98040393Sbostic * suffix and add it to the list of suffixes maintained by the 98140393Sbostic * Suff module. 98240393Sbostic * 98340393Sbostic * If the target was a .PATH, we add the source as a directory 98440393Sbostic * to search on the search path. 98540393Sbostic * 98640393Sbostic * If it was .INCLUDES, the source is taken to be the suffix of 98740393Sbostic * files which will be #included and whose search path should 98840393Sbostic * be present in the .INCLUDES variable. 98940393Sbostic * 99040393Sbostic * If it was .LIBS, the source is taken to be the suffix of 99140393Sbostic * files which are considered libraries and whose search path 99240393Sbostic * should be present in the .LIBS variable. 99340393Sbostic * 99440393Sbostic * If it was .NULL, the source is the suffix to use when a file 99540393Sbostic * has no valid suffix. 99640393Sbostic */ 99740393Sbostic char savec; 99840393Sbostic while (*cp && !isspace (*cp)) { 99940393Sbostic cp++; 100040393Sbostic } 100140393Sbostic savec = *cp; 100240393Sbostic *cp = '\0'; 100340393Sbostic switch (specType) { 100440393Sbostic case Suffixes: 100540393Sbostic Suff_AddSuffix (line); 100640393Sbostic break; 100760285Sbostic case ExPath: 100840393Sbostic Lst_ForEach(paths, ParseAddDir, (ClientData)line); 100940393Sbostic break; 101040393Sbostic case Includes: 101140393Sbostic Suff_AddInclude (line); 101240393Sbostic break; 101340393Sbostic case Libs: 101440393Sbostic Suff_AddLib (line); 101540393Sbostic break; 101640393Sbostic case Null: 101740393Sbostic Suff_SetNull (line); 101840393Sbostic break; 101960285Sbostic default: 102060285Sbostic break; 102140393Sbostic } 102240393Sbostic *cp = savec; 102340393Sbostic if (savec != '\0') { 102440393Sbostic cp++; 102540393Sbostic } 102640393Sbostic while (*cp && isspace (*cp)) { 102740393Sbostic cp++; 102840393Sbostic } 102940393Sbostic line = cp; 103040393Sbostic } 103140393Sbostic if (paths) { 103240393Sbostic Lst_Destroy(paths, NOFREE); 103340393Sbostic } 103440393Sbostic } else { 103540393Sbostic while (*line) { 103640393Sbostic /* 103740393Sbostic * The targets take real sources, so we must beware of archive 103840393Sbostic * specifications (i.e. things with left parentheses in them) 103940393Sbostic * and handle them accordingly. 104040393Sbostic */ 104140393Sbostic while (*cp && !isspace (*cp)) { 104240393Sbostic if ((*cp == '(') && (cp > line) && (cp[-1] != '$')) { 104340393Sbostic /* 104440393Sbostic * Only stop for a left parenthesis if it isn't at the 104540393Sbostic * start of a word (that'll be for variable changes 104640393Sbostic * later) and isn't preceded by a dollar sign (a dynamic 104740393Sbostic * source). 104840393Sbostic */ 104940393Sbostic break; 105040393Sbostic } else { 105140393Sbostic cp++; 105240393Sbostic } 105340393Sbostic } 105440393Sbostic 105540393Sbostic if (*cp == '(') { 105640393Sbostic GNode *gn; 105740393Sbostic 105840393Sbostic sources = Lst_Init (FALSE); 105940393Sbostic if (Arch_ParseArchive (&line, sources, VAR_CMD) != SUCCESS) { 106040393Sbostic Parse_Error (PARSE_FATAL, 106140393Sbostic "Error in source archive spec \"%s\"", line); 106240393Sbostic return; 106340393Sbostic } 106440393Sbostic 106540393Sbostic while (!Lst_IsEmpty (sources)) { 106640393Sbostic gn = (GNode *) Lst_DeQueue (sources); 106740393Sbostic ParseDoSrc (tOp, gn->name); 106840393Sbostic } 106940393Sbostic Lst_Destroy (sources, NOFREE); 107040393Sbostic cp = line; 107140393Sbostic } else { 107240393Sbostic if (*cp) { 107340393Sbostic *cp = '\0'; 107440393Sbostic cp += 1; 107540393Sbostic } 107640393Sbostic 107740393Sbostic ParseDoSrc (tOp, line); 107840393Sbostic } 107940393Sbostic while (*cp && isspace (*cp)) { 108040393Sbostic cp++; 108140393Sbostic } 108240393Sbostic line = cp; 108340393Sbostic } 108440393Sbostic } 108540393Sbostic 108640393Sbostic if (mainNode == NILGNODE) { 108740393Sbostic /* 108840393Sbostic * If we have yet to decide on a main target to make, in the 108940393Sbostic * absence of any user input, we want the first target on 109040393Sbostic * the first dependency line that is actually a real target 109140393Sbostic * (i.e. isn't a .USE or .EXEC rule) to be made. 109240393Sbostic */ 109340393Sbostic Lst_ForEach (targets, ParseFindMain, (ClientData)0); 109440393Sbostic } 109540393Sbostic 109640393Sbostic } 109740424Sbostic 109840393Sbostic /*- 109940393Sbostic *--------------------------------------------------------------------- 110040393Sbostic * Parse_IsVar -- 110140393Sbostic * Return TRUE if the passed line is a variable assignment. A variable 110240393Sbostic * assignment consists of a single word followed by optional whitespace 110340393Sbostic * followed by either a += or an = operator. 110440393Sbostic * This function is used both by the Parse_File function and main when 110540393Sbostic * parsing the command-line arguments. 110640393Sbostic * 110740393Sbostic * Results: 110840393Sbostic * TRUE if it is. FALSE if it ain't 110940393Sbostic * 111040393Sbostic * Side Effects: 111140393Sbostic * none 111240393Sbostic *--------------------------------------------------------------------- 111340393Sbostic */ 111440393Sbostic Boolean 111540393Sbostic Parse_IsVar (line) 111640393Sbostic register char *line; /* the line to check */ 111740393Sbostic { 111840393Sbostic register Boolean wasSpace = FALSE; /* set TRUE if found a space */ 111940393Sbostic register Boolean haveName = FALSE; /* Set TRUE if have a variable name */ 112040393Sbostic 112140393Sbostic /* 112240393Sbostic * Skip to variable name 112340393Sbostic */ 112440393Sbostic while ((*line == ' ') || (*line == '\t')) { 112540393Sbostic line++; 112640393Sbostic } 112740393Sbostic 112840393Sbostic while (*line != '=') { 112940393Sbostic if (*line == '\0') { 113040393Sbostic /* 113140393Sbostic * end-of-line -- can't be a variable assignment. 113240393Sbostic */ 113340393Sbostic return (FALSE); 113440393Sbostic } else if ((*line == ' ') || (*line == '\t')) { 113540393Sbostic /* 113640393Sbostic * there can be as much white space as desired so long as there is 113740393Sbostic * only one word before the operator 113840393Sbostic */ 113940393Sbostic wasSpace = TRUE; 114040393Sbostic } else if (wasSpace && haveName) { 114140393Sbostic /* 114240393Sbostic * Stop when an = operator is found. 114340393Sbostic */ 114440393Sbostic if ((*line == '+') || (*line == ':') || (*line == '?') || 114540393Sbostic (*line == '!')) { 114640393Sbostic break; 114740393Sbostic } 114840393Sbostic 114940393Sbostic /* 115040393Sbostic * This is the start of another word, so not assignment. 115140393Sbostic */ 115240393Sbostic return (FALSE); 115340393Sbostic } else { 115440393Sbostic haveName = TRUE; 115540393Sbostic wasSpace = FALSE; 115640393Sbostic } 115740393Sbostic line++; 115840393Sbostic } 115940393Sbostic 116040393Sbostic /* 116140393Sbostic * A final check: if we stopped on a +, ?, ! or :, the next character must 116240393Sbostic * be an = or it ain't a valid assignment 116340393Sbostic */ 116440393Sbostic if (((*line == '+') || 116540393Sbostic (*line == '?') || 116640393Sbostic (*line == ':') || 116740393Sbostic (*line == '!')) && 116840393Sbostic (line[1] != '=')) 116940393Sbostic { 117040393Sbostic return (FALSE); 117140393Sbostic } else { 117240393Sbostic return (haveName); 117340393Sbostic } 117440393Sbostic } 117540424Sbostic 117640393Sbostic /*- 117740393Sbostic *--------------------------------------------------------------------- 117840393Sbostic * Parse_DoVar -- 117940393Sbostic * Take the variable assignment in the passed line and do it in the 118040393Sbostic * global context. 118140393Sbostic * 118240393Sbostic * Note: There is a lexical ambiguity with assignment modifier characters 118340393Sbostic * in variable names. This routine interprets the character before the = 118440393Sbostic * as a modifier. Therefore, an assignment like 118540393Sbostic * C++=/usr/bin/CC 118640393Sbostic * is interpreted as "C+ +=" instead of "C++ =". 118740393Sbostic * 118840393Sbostic * Results: 118940393Sbostic * none 119040393Sbostic * 119140393Sbostic * Side Effects: 119240393Sbostic * the variable structure of the given variable name is altered in the 119340393Sbostic * global context. 119440393Sbostic *--------------------------------------------------------------------- 119540393Sbostic */ 119640393Sbostic void 119740393Sbostic Parse_DoVar (line, ctxt) 119840393Sbostic char *line; /* a line guaranteed to be a variable 119940393Sbostic * assignment. This reduces error checks */ 120040393Sbostic GNode *ctxt; /* Context in which to do the assignment */ 120140393Sbostic { 1202*66399Schristos char *cp; /* pointer into line */ 120340393Sbostic enum { 120440393Sbostic VAR_SUBST, VAR_APPEND, VAR_SHELL, VAR_NORMAL 120540393Sbostic } type; /* Type of assignment */ 120640393Sbostic char *opc; /* ptr to operator character to 120740393Sbostic * null-terminate the variable name */ 1208*66399Schristos /* 1209*66399Schristos * Avoid clobbered variable warnings by forcing the compiler 1210*66399Schristos * to ``unregister'' variables 1211*66399Schristos */ 1212*66399Schristos #if __GNUC__ 1213*66399Schristos (void) &cp; 1214*66399Schristos (void) &line; 1215*66399Schristos #endif 121640393Sbostic 121740393Sbostic /* 121840393Sbostic * Skip to variable name 121940393Sbostic */ 122040393Sbostic while ((*line == ' ') || (*line == '\t')) { 122140393Sbostic line++; 122240393Sbostic } 122340393Sbostic 122440393Sbostic /* 122540393Sbostic * Skip to operator character, nulling out whitespace as we go 122640393Sbostic */ 122740393Sbostic for (cp = line + 1; *cp != '='; cp++) { 122840393Sbostic if (isspace (*cp)) { 122940393Sbostic *cp = '\0'; 123040393Sbostic } 123140393Sbostic } 123240393Sbostic opc = cp-1; /* operator is the previous character */ 123340393Sbostic *cp++ = '\0'; /* nuke the = */ 123440393Sbostic 123540393Sbostic /* 123640393Sbostic * Check operator type 123740393Sbostic */ 123840393Sbostic switch (*opc) { 123940393Sbostic case '+': 124040393Sbostic type = VAR_APPEND; 124140393Sbostic *opc = '\0'; 124240393Sbostic break; 124340393Sbostic 124440393Sbostic case '?': 124540393Sbostic /* 124640393Sbostic * If the variable already has a value, we don't do anything. 124740393Sbostic */ 124840393Sbostic *opc = '\0'; 124940393Sbostic if (Var_Exists(line, ctxt)) { 125040393Sbostic return; 125140393Sbostic } else { 125240393Sbostic type = VAR_NORMAL; 125340393Sbostic } 125440393Sbostic break; 125540393Sbostic 125640393Sbostic case ':': 125740393Sbostic type = VAR_SUBST; 125840393Sbostic *opc = '\0'; 125940393Sbostic break; 126040393Sbostic 126140393Sbostic case '!': 126240393Sbostic type = VAR_SHELL; 126340393Sbostic *opc = '\0'; 126440393Sbostic break; 126540393Sbostic 126640393Sbostic default: 126740393Sbostic type = VAR_NORMAL; 126840393Sbostic break; 126940393Sbostic } 127040393Sbostic 127140393Sbostic while (isspace (*cp)) { 127240393Sbostic cp++; 127340393Sbostic } 127440393Sbostic 127540393Sbostic if (type == VAR_APPEND) { 127640393Sbostic Var_Append (line, cp, ctxt); 127740393Sbostic } else if (type == VAR_SUBST) { 127840393Sbostic /* 127940393Sbostic * Allow variables in the old value to be undefined, but leave their 128040393Sbostic * invocation alone -- this is done by forcing oldVars to be false. 128140393Sbostic * XXX: This can cause recursive variables, but that's not hard to do, 128240393Sbostic * and this allows someone to do something like 128340393Sbostic * 128440393Sbostic * CFLAGS = $(.INCLUDES) 128540393Sbostic * CFLAGS := -I.. $(CFLAGS) 128640393Sbostic * 128740393Sbostic * And not get an error. 128840393Sbostic */ 128940393Sbostic Boolean oldOldVars = oldVars; 129040393Sbostic 129140393Sbostic oldVars = FALSE; 129260285Sbostic cp = Var_Subst(NULL, cp, ctxt, FALSE); 129340393Sbostic oldVars = oldOldVars; 129440393Sbostic 129540393Sbostic Var_Set(line, cp, ctxt); 129640393Sbostic free(cp); 129740393Sbostic } else if (type == VAR_SHELL) { 129840393Sbostic char *args[4]; /* Args for invoking the shell */ 129940393Sbostic int fds[2]; /* Pipe streams */ 130040393Sbostic int cpid; /* Child PID */ 130140393Sbostic int pid; /* PID from wait() */ 130240393Sbostic Boolean freeCmd; /* TRUE if the command needs to be freed, i.e. 130340393Sbostic * if any variable expansion was performed */ 130440393Sbostic 1305*66399Schristos /* 1306*66399Schristos * Avoid clobbered variable warnings by forcing the compiler 1307*66399Schristos * to ``unregister'' variables 1308*66399Schristos */ 1309*66399Schristos #if __GNUC__ 1310*66399Schristos (void) &freeCmd; 1311*66399Schristos #endif 131240393Sbostic /* 131340393Sbostic * Set up arguments for shell 131440393Sbostic */ 131540393Sbostic args[0] = "sh"; 131640393Sbostic args[1] = "-c"; 131760285Sbostic if (strchr(cp, '$') != (char *)NULL) { 131840393Sbostic /* 131940393Sbostic * There's a dollar sign in the command, so perform variable 132040393Sbostic * expansion on the whole thing. The resulting string will need 132140393Sbostic * freeing when we're done, so set freeCmd to TRUE. 132240393Sbostic */ 132360285Sbostic args[2] = Var_Subst(NULL, cp, VAR_CMD, TRUE); 132440393Sbostic freeCmd = TRUE; 132540393Sbostic } else { 132640393Sbostic args[2] = cp; 132740393Sbostic freeCmd = FALSE; 132840393Sbostic } 132940393Sbostic args[3] = (char *)NULL; 133040393Sbostic 133140393Sbostic /* 133240393Sbostic * Open a pipe for fetching its output 133340393Sbostic */ 133440393Sbostic pipe(fds); 133540393Sbostic 133640393Sbostic /* 133740393Sbostic * Fork 133840393Sbostic */ 133940393Sbostic cpid = vfork(); 134040393Sbostic if (cpid == 0) { 134140393Sbostic /* 134240393Sbostic * Close input side of pipe 134340393Sbostic */ 134440393Sbostic close(fds[0]); 134540393Sbostic 134640393Sbostic /* 134740393Sbostic * Duplicate the output stream to the shell's output, then 134840393Sbostic * shut the extra thing down. Note we don't fetch the error 134940393Sbostic * stream...why not? Why? 135040393Sbostic */ 135140393Sbostic dup2(fds[1], 1); 135240393Sbostic close(fds[1]); 135340393Sbostic 135440393Sbostic execv("/bin/sh", args); 135540393Sbostic _exit(1); 135640393Sbostic } else if (cpid < 0) { 135740393Sbostic /* 135840393Sbostic * Couldn't fork -- tell the user and make the variable null 135940393Sbostic */ 136040393Sbostic Parse_Error(PARSE_WARNING, "Couldn't exec \"%s\"", cp); 136140393Sbostic Var_Set(line, "", ctxt); 136240393Sbostic } else { 136340393Sbostic int status; 136440393Sbostic int cc; 136560285Sbostic Buffer buf; 136660285Sbostic char *res; 136740393Sbostic 136840393Sbostic /* 136940393Sbostic * No need for the writing half 137040393Sbostic */ 137140393Sbostic close(fds[1]); 137240393Sbostic 137360285Sbostic buf = Buf_Init (MAKE_BSIZE); 137460285Sbostic 137560285Sbostic do { 137660285Sbostic char result[BUFSIZ]; 137760285Sbostic cc = read(fds[0], result, sizeof(result)); 137860285Sbostic if (cc > 0) 137960285Sbostic Buf_AddBytes(buf, cc, (unsigned char *) result); 138060285Sbostic } 138160285Sbostic while (cc > 0 || (cc == -1 && errno == EINTR)); 138260285Sbostic 138340393Sbostic /* 138460285Sbostic * Close the input side of the pipe. 138540393Sbostic */ 138660285Sbostic close(fds[0]); 138740393Sbostic 138840393Sbostic /* 138960285Sbostic * Wait for the process to exit. 139040393Sbostic */ 139160285Sbostic while(((pid = wait(&status)) != cpid) && (pid >= 0)) 139260285Sbostic continue; 139340393Sbostic 139460285Sbostic res = (char *)Buf_GetAll (buf, &cc); 139560285Sbostic Buf_Destroy (buf, FALSE); 139660285Sbostic 139760285Sbostic if (cc == 0) { 139840393Sbostic /* 139940393Sbostic * Couldn't read the child's output -- tell the user and 140040393Sbostic * set the variable to null 140140393Sbostic */ 140240393Sbostic Parse_Error(PARSE_WARNING, "Couldn't read shell's output"); 140340393Sbostic } 140440393Sbostic 140540393Sbostic if (status) { 140640393Sbostic /* 140740393Sbostic * Child returned an error -- tell the user but still use 140840393Sbostic * the result. 140940393Sbostic */ 141040393Sbostic Parse_Error(PARSE_WARNING, "\"%s\" returned non-zero", cp); 141140393Sbostic } 141260285Sbostic 141340393Sbostic /* 141440393Sbostic * Null-terminate the result, convert newlines to spaces and 141540393Sbostic * install it in the variable. 141640393Sbostic */ 141760285Sbostic res[cc] = '\0'; 141860285Sbostic cp = &res[cc] - 1; 141940393Sbostic 142040393Sbostic if (*cp == '\n') { 142140393Sbostic /* 142240393Sbostic * A final newline is just stripped 142340393Sbostic */ 142440393Sbostic *cp-- = '\0'; 142540393Sbostic } 142660285Sbostic while (cp >= res) { 142740393Sbostic if (*cp == '\n') { 142840393Sbostic *cp = ' '; 142940393Sbostic } 143040393Sbostic cp--; 143140393Sbostic } 143260285Sbostic Var_Set(line, res, ctxt); 143360285Sbostic free(res); 143440393Sbostic 143540393Sbostic } 143640393Sbostic if (freeCmd) { 143740393Sbostic free(args[2]); 143840393Sbostic } 143940393Sbostic } else { 144040393Sbostic /* 144140393Sbostic * Normal assignment -- just do it. 144240393Sbostic */ 144340393Sbostic Var_Set (line, cp, ctxt); 144440393Sbostic } 144540393Sbostic } 144640424Sbostic 144740393Sbostic /*- 144840393Sbostic * ParseAddCmd -- 144940393Sbostic * Lst_ForEach function to add a command line to all targets 145040393Sbostic * 145140393Sbostic * Results: 145240393Sbostic * Always 0 145340393Sbostic * 145440393Sbostic * Side Effects: 145540393Sbostic * A new element is added to the commands list of the node. 145640393Sbostic */ 145760285Sbostic static int 145840476Sbostic ParseAddCmd(gn, cmd) 145940476Sbostic GNode *gn; /* the node to which the command is to be added */ 146040476Sbostic char *cmd; /* the command to add */ 146140393Sbostic { 146240476Sbostic /* if target already supplied, ignore commands */ 146340476Sbostic if (!(gn->type & OP_HAS_COMMANDS)) 146440476Sbostic (void)Lst_AtEnd(gn->commands, (ClientData)cmd); 146540476Sbostic return(0); 146640393Sbostic } 146740424Sbostic 146840393Sbostic /*- 146940393Sbostic *----------------------------------------------------------------------- 147040393Sbostic * ParseHasCommands -- 147140393Sbostic * Callback procedure for Parse_File when destroying the list of 147240393Sbostic * targets on the last dependency line. Marks a target as already 147340393Sbostic * having commands if it does, to keep from having shell commands 147440393Sbostic * on multiple dependency lines. 147540393Sbostic * 147640393Sbostic * Results: 147740393Sbostic * Always 0. 147840393Sbostic * 147940393Sbostic * Side Effects: 148040393Sbostic * OP_HAS_COMMANDS may be set for the target. 148140393Sbostic * 148240393Sbostic *----------------------------------------------------------------------- 148340393Sbostic */ 148440393Sbostic static int 148540393Sbostic ParseHasCommands(gn) 148640393Sbostic GNode *gn; /* Node to examine */ 148740393Sbostic { 148840393Sbostic if (!Lst_IsEmpty(gn->commands)) { 148940393Sbostic gn->type |= OP_HAS_COMMANDS; 149040393Sbostic } 149140393Sbostic return(0); 149240393Sbostic } 149340424Sbostic 149440393Sbostic /*- 149540393Sbostic *----------------------------------------------------------------------- 149640393Sbostic * Parse_AddIncludeDir -- 149740393Sbostic * Add a directory to the path searched for included makefiles 149840393Sbostic * bracketed by double-quotes. Used by functions in main.c 149940393Sbostic * 150040393Sbostic * Results: 150140393Sbostic * None. 150240393Sbostic * 150340393Sbostic * Side Effects: 150440393Sbostic * The directory is appended to the list. 150540393Sbostic * 150640393Sbostic *----------------------------------------------------------------------- 150740393Sbostic */ 150840393Sbostic void 150940393Sbostic Parse_AddIncludeDir (dir) 151040393Sbostic char *dir; /* The name of the directory to add */ 151140393Sbostic { 151240393Sbostic Dir_AddDir (parseIncPath, dir); 151340393Sbostic } 151440424Sbostic 151540393Sbostic /*- 151640393Sbostic *--------------------------------------------------------------------- 151740393Sbostic * ParseDoInclude -- 151840393Sbostic * Push to another file. 151940393Sbostic * 152040393Sbostic * The input is the line minus the #include. A file spec is a string 152140393Sbostic * enclosed in <> or "". The former is looked for only in sysIncPath. 152240393Sbostic * The latter in . and the directories specified by -I command line 152340393Sbostic * options 152440393Sbostic * 152540393Sbostic * Results: 152640393Sbostic * None 152740393Sbostic * 152840393Sbostic * Side Effects: 152940393Sbostic * A structure is added to the includes Lst and readProc, lineno, 153040393Sbostic * fname and curFILE are altered for the new file 153140393Sbostic *--------------------------------------------------------------------- 153240393Sbostic */ 153340393Sbostic static void 153440393Sbostic ParseDoInclude (file) 153540393Sbostic char *file; /* file specification */ 153640393Sbostic { 153740393Sbostic char *fullname; /* full pathname of file */ 153840393Sbostic IFile *oldFile; /* state associated with current file */ 153940393Sbostic char endc; /* the character which ends the file spec */ 154040393Sbostic char *cp; /* current position in file spec */ 154140393Sbostic Boolean isSystem; /* TRUE if makefile is a system makefile */ 154240393Sbostic 154340393Sbostic /* 154440393Sbostic * Skip to delimiter character so we know where to look 154540393Sbostic */ 154640393Sbostic while ((*file == ' ') || (*file == '\t')) { 154740393Sbostic file++; 154840393Sbostic } 154940393Sbostic 155040393Sbostic if ((*file != '"') && (*file != '<')) { 155142443Sbostic Parse_Error (PARSE_FATAL, 155242443Sbostic ".include filename must be delimited by '\"' or '<'"); 155340393Sbostic return; 155440393Sbostic } 155540393Sbostic 155640393Sbostic /* 155740393Sbostic * Set the search path on which to find the include file based on the 155840393Sbostic * characters which bracket its name. Angle-brackets imply it's 155940393Sbostic * a system Makefile while double-quotes imply it's a user makefile 156040393Sbostic */ 156140393Sbostic if (*file == '<') { 156240393Sbostic isSystem = TRUE; 156340393Sbostic endc = '>'; 156440393Sbostic } else { 156540393Sbostic isSystem = FALSE; 156640393Sbostic endc = '"'; 156740393Sbostic } 156840393Sbostic 156940393Sbostic /* 157040393Sbostic * Skip to matching delimiter 157140393Sbostic */ 157240393Sbostic for (cp = ++file; *cp && *cp != endc; cp++) { 157340393Sbostic continue; 157440393Sbostic } 157540393Sbostic 157640393Sbostic if (*cp != endc) { 157740393Sbostic Parse_Error (PARSE_FATAL, 157860285Sbostic "Unclosed %cinclude filename. '%c' expected", 157960285Sbostic '.', endc); 158040393Sbostic return; 158140393Sbostic } 158240393Sbostic *cp = '\0'; 158340393Sbostic 158440393Sbostic /* 158540393Sbostic * Substitute for any variables in the file name before trying to 158640393Sbostic * find the thing. 158740393Sbostic */ 158860285Sbostic file = Var_Subst (NULL, file, VAR_CMD, FALSE); 158940393Sbostic 159040393Sbostic /* 159140393Sbostic * Now we know the file's name and its search path, we attempt to 159240393Sbostic * find the durn thing. A return of NULL indicates the file don't 159340393Sbostic * exist. 159440393Sbostic */ 159540393Sbostic if (!isSystem) { 159640393Sbostic /* 159740393Sbostic * Include files contained in double-quotes are first searched for 159840393Sbostic * relative to the including file's location. We don't want to 159940393Sbostic * cd there, of course, so we just tack on the old file's 160040393Sbostic * leading path components and call Dir_FindFile to see if 160140393Sbostic * we can locate the beast. 160240393Sbostic */ 160340393Sbostic char *prefEnd; 160440393Sbostic 160560285Sbostic prefEnd = strrchr (fname, '/'); 160640393Sbostic if (prefEnd != (char *)NULL) { 160740393Sbostic char *newName; 160840393Sbostic 160940393Sbostic *prefEnd = '\0'; 161040534Sbostic newName = str_concat (fname, file, STR_ADDSLASH); 161140393Sbostic fullname = Dir_FindFile (newName, parseIncPath); 161240393Sbostic if (fullname == (char *)NULL) { 161340393Sbostic fullname = Dir_FindFile(newName, dirSearchPath); 161440393Sbostic } 161540393Sbostic free (newName); 161640393Sbostic *prefEnd = '/'; 161740393Sbostic } else { 161840393Sbostic fullname = (char *)NULL; 161940393Sbostic } 162040393Sbostic } else { 162140393Sbostic fullname = (char *)NULL; 162240393Sbostic } 162340393Sbostic 162440393Sbostic if (fullname == (char *)NULL) { 162540393Sbostic /* 162640393Sbostic * System makefile or makefile wasn't found in same directory as 162740393Sbostic * included makefile. Search for it first on the -I search path, 162840393Sbostic * then on the .PATH search path, if not found in a -I directory. 162940393Sbostic * XXX: Suffix specific? 163040393Sbostic */ 163140393Sbostic fullname = Dir_FindFile (file, parseIncPath); 163240393Sbostic if (fullname == (char *)NULL) { 163340393Sbostic fullname = Dir_FindFile(file, dirSearchPath); 163440393Sbostic } 163540393Sbostic } 163640393Sbostic 163740393Sbostic if (fullname == (char *)NULL) { 163840393Sbostic /* 163940393Sbostic * Still haven't found the makefile. Look for it on the system 164040393Sbostic * path as a last resort. 164140393Sbostic */ 164240393Sbostic fullname = Dir_FindFile(file, sysIncPath); 164340393Sbostic } 164440393Sbostic 164540393Sbostic if (fullname == (char *) NULL) { 164640393Sbostic *cp = endc; 164740393Sbostic Parse_Error (PARSE_FATAL, "Could not find %s", file); 164840393Sbostic return; 164940393Sbostic } 165040393Sbostic 165140393Sbostic /* 165240393Sbostic * Once we find the absolute path to the file, we get to save all the 165340393Sbostic * state from the current file before we can start reading this 165440393Sbostic * include file. The state is stored in an IFile structure which 165540393Sbostic * is placed on a list with other IFile structures. The list makes 165640393Sbostic * a very nice stack to track how we got here... 165740393Sbostic */ 165840534Sbostic oldFile = (IFile *) emalloc (sizeof (IFile)); 165940393Sbostic oldFile->fname = fname; 166040393Sbostic 166140393Sbostic oldFile->F = curFILE; 166260285Sbostic oldFile->p = curPTR; 166340393Sbostic oldFile->lineno = lineno; 166440393Sbostic 166540393Sbostic (void) Lst_AtFront (includes, (ClientData)oldFile); 166640393Sbostic 166740393Sbostic /* 166840393Sbostic * Once the previous state has been saved, we can get down to reading 166940393Sbostic * the new file. We set up the name of the file to be the absolute 167040393Sbostic * name of the include file so error messages refer to the right 167140393Sbostic * place. Naturally enough, we start reading at line number 0. 167240393Sbostic */ 167340393Sbostic fname = fullname; 167440393Sbostic lineno = 0; 167540393Sbostic 167640393Sbostic curFILE = fopen (fullname, "r"); 167760285Sbostic curPTR = NULL; 167840393Sbostic if (curFILE == (FILE * ) NULL) { 167940393Sbostic Parse_Error (PARSE_FATAL, "Cannot open %s", fullname); 168040393Sbostic /* 168140393Sbostic * Pop to previous file 168240393Sbostic */ 168346462Sbostic (void) ParseEOF(0); 168440393Sbostic } 168540393Sbostic } 168640424Sbostic 168760285Sbostic 168840393Sbostic /*- 168940393Sbostic *--------------------------------------------------------------------- 169060285Sbostic * Parse_FromString -- 169160285Sbostic * Start Parsing from the given string 169260285Sbostic * 169360285Sbostic * Results: 169460285Sbostic * None 169560285Sbostic * 169660285Sbostic * Side Effects: 169760285Sbostic * A structure is added to the includes Lst and readProc, lineno, 169860285Sbostic * fname and curFILE are altered for the new file 169960285Sbostic *--------------------------------------------------------------------- 170060285Sbostic */ 170160285Sbostic void 170260285Sbostic Parse_FromString(str) 170360285Sbostic char *str; 170460285Sbostic { 170560285Sbostic IFile *oldFile; /* state associated with this file */ 170660285Sbostic 170760285Sbostic if (DEBUG(FOR)) 170860285Sbostic (void) fprintf(stderr, "%s\n----\n", str); 170960285Sbostic 171060285Sbostic oldFile = (IFile *) emalloc (sizeof (IFile)); 171160285Sbostic oldFile->lineno = lineno; 171260285Sbostic oldFile->fname = fname; 171360285Sbostic oldFile->F = curFILE; 171460285Sbostic oldFile->p = curPTR; 171560285Sbostic 171660285Sbostic (void) Lst_AtFront (includes, (ClientData)oldFile); 171760285Sbostic 171860285Sbostic curFILE = NULL; 171960285Sbostic curPTR = (PTR *) emalloc (sizeof (PTR)); 172060285Sbostic curPTR->str = curPTR->ptr = str; 172160285Sbostic lineno = 0; 172260285Sbostic fname = strdup(fname); 172360285Sbostic } 172460285Sbostic 172560285Sbostic 172660285Sbostic #ifdef SYSVINCLUDE 172760285Sbostic /*- 172860285Sbostic *--------------------------------------------------------------------- 172960285Sbostic * ParseTraditionalInclude -- 173060285Sbostic * Push to another file. 173160285Sbostic * 173260285Sbostic * The input is the line minus the "include". The file name is 173360285Sbostic * the string following the "include". 173460285Sbostic * 173560285Sbostic * Results: 173660285Sbostic * None 173760285Sbostic * 173860285Sbostic * Side Effects: 173960285Sbostic * A structure is added to the includes Lst and readProc, lineno, 174060285Sbostic * fname and curFILE are altered for the new file 174160285Sbostic *--------------------------------------------------------------------- 174260285Sbostic */ 174360285Sbostic static void 174460285Sbostic ParseTraditionalInclude (file) 174560285Sbostic char *file; /* file specification */ 174660285Sbostic { 174760285Sbostic char *fullname; /* full pathname of file */ 174860285Sbostic IFile *oldFile; /* state associated with current file */ 174960285Sbostic char *cp; /* current position in file spec */ 175060285Sbostic char *prefEnd; 175160285Sbostic 175260285Sbostic /* 175360285Sbostic * Skip over whitespace 175460285Sbostic */ 175560285Sbostic while ((*file == ' ') || (*file == '\t')) { 175660285Sbostic file++; 175760285Sbostic } 175860285Sbostic 175960285Sbostic if (*file == '\0') { 176060285Sbostic Parse_Error (PARSE_FATAL, 176160285Sbostic "Filename missing from \"include\""); 176260285Sbostic return; 176360285Sbostic } 176460285Sbostic 176560285Sbostic /* 176660285Sbostic * Skip to end of line or next whitespace 176760285Sbostic */ 176860285Sbostic for (cp = file; *cp && *cp != '\n' && *cp != '\t' && *cp != ' '; cp++) { 176960285Sbostic continue; 177060285Sbostic } 177160285Sbostic 177260285Sbostic *cp = '\0'; 177360285Sbostic 177460285Sbostic /* 177560285Sbostic * Substitute for any variables in the file name before trying to 177660285Sbostic * find the thing. 177760285Sbostic */ 177860285Sbostic file = Var_Subst (NULL, file, VAR_CMD, FALSE); 177960285Sbostic 178060285Sbostic /* 178160285Sbostic * Now we know the file's name, we attempt to find the durn thing. 178260285Sbostic * A return of NULL indicates the file don't exist. 178360285Sbostic * 178460285Sbostic * Include files are first searched for relative to the including 178560285Sbostic * file's location. We don't want to cd there, of course, so we 178660285Sbostic * just tack on the old file's leading path components and call 178760285Sbostic * Dir_FindFile to see if we can locate the beast. 178860285Sbostic * XXX - this *does* search in the current directory, right? 178960285Sbostic */ 179060285Sbostic 179160285Sbostic prefEnd = strrchr (fname, '/'); 179260285Sbostic if (prefEnd != (char *)NULL) { 179360285Sbostic char *newName; 179460285Sbostic 179560285Sbostic *prefEnd = '\0'; 179660285Sbostic newName = str_concat (fname, file, STR_ADDSLASH); 179760285Sbostic fullname = Dir_FindFile (newName, parseIncPath); 179860285Sbostic if (fullname == (char *)NULL) { 179960285Sbostic fullname = Dir_FindFile(newName, dirSearchPath); 180060285Sbostic } 180160285Sbostic free (newName); 180260285Sbostic *prefEnd = '/'; 180360285Sbostic } else { 180460285Sbostic fullname = (char *)NULL; 180560285Sbostic } 180660285Sbostic 180760285Sbostic if (fullname == (char *)NULL) { 180860285Sbostic /* 180960285Sbostic * System makefile or makefile wasn't found in same directory as 181060285Sbostic * included makefile. Search for it first on the -I search path, 181160285Sbostic * then on the .PATH search path, if not found in a -I directory. 181260285Sbostic * XXX: Suffix specific? 181360285Sbostic */ 181460285Sbostic fullname = Dir_FindFile (file, parseIncPath); 181560285Sbostic if (fullname == (char *)NULL) { 181660285Sbostic fullname = Dir_FindFile(file, dirSearchPath); 181760285Sbostic } 181860285Sbostic } 181960285Sbostic 182060285Sbostic if (fullname == (char *)NULL) { 182160285Sbostic /* 182260285Sbostic * Still haven't found the makefile. Look for it on the system 182360285Sbostic * path as a last resort. 182460285Sbostic */ 182560285Sbostic fullname = Dir_FindFile(file, sysIncPath); 182660285Sbostic } 182760285Sbostic 182860285Sbostic if (fullname == (char *) NULL) { 182960285Sbostic Parse_Error (PARSE_FATAL, "Could not find %s", file); 183060285Sbostic return; 183160285Sbostic } 183260285Sbostic 183360285Sbostic /* 183460285Sbostic * Once we find the absolute path to the file, we get to save all the 183560285Sbostic * state from the current file before we can start reading this 183660285Sbostic * include file. The state is stored in an IFile structure which 183760285Sbostic * is placed on a list with other IFile structures. The list makes 183860285Sbostic * a very nice stack to track how we got here... 183960285Sbostic */ 184060285Sbostic oldFile = (IFile *) emalloc (sizeof (IFile)); 184160285Sbostic oldFile->fname = fname; 184260285Sbostic 184360285Sbostic oldFile->F = curFILE; 184460285Sbostic oldFile->p = curPTR; 184560285Sbostic oldFile->lineno = lineno; 184660285Sbostic 184760285Sbostic (void) Lst_AtFront (includes, (ClientData)oldFile); 184860285Sbostic 184960285Sbostic /* 185060285Sbostic * Once the previous state has been saved, we can get down to reading 185160285Sbostic * the new file. We set up the name of the file to be the absolute 185260285Sbostic * name of the include file so error messages refer to the right 185360285Sbostic * place. Naturally enough, we start reading at line number 0. 185460285Sbostic */ 185560285Sbostic fname = fullname; 185660285Sbostic lineno = 0; 185760285Sbostic 185860285Sbostic curFILE = fopen (fullname, "r"); 185960285Sbostic curPTR = NULL; 186060285Sbostic if (curFILE == (FILE * ) NULL) { 186160285Sbostic Parse_Error (PARSE_FATAL, "Cannot open %s", fullname); 186260285Sbostic /* 186360285Sbostic * Pop to previous file 186460285Sbostic */ 186560285Sbostic (void) ParseEOF(1); 186660285Sbostic } 186760285Sbostic } 186860285Sbostic #endif 186960285Sbostic 187060285Sbostic /*- 187160285Sbostic *--------------------------------------------------------------------- 187240393Sbostic * ParseEOF -- 187340393Sbostic * Called when EOF is reached in the current file. If we were reading 187440393Sbostic * an include file, the includes stack is popped and things set up 187540393Sbostic * to go back to reading the previous file at the previous location. 187640393Sbostic * 187740393Sbostic * Results: 187840393Sbostic * CONTINUE if there's more to do. DONE if not. 187940393Sbostic * 188040393Sbostic * Side Effects: 188140393Sbostic * The old curFILE, is closed. The includes list is shortened. 188240393Sbostic * lineno, curFILE, and fname are changed if CONTINUE is returned. 188340393Sbostic *--------------------------------------------------------------------- 188440393Sbostic */ 188540393Sbostic static int 188646462Sbostic ParseEOF (opened) 188746462Sbostic int opened; 188840393Sbostic { 188940393Sbostic IFile *ifile; /* the state on the top of the includes stack */ 189040393Sbostic 189140393Sbostic if (Lst_IsEmpty (includes)) { 189240393Sbostic return (DONE); 189340393Sbostic } 189440393Sbostic 189540393Sbostic ifile = (IFile *) Lst_DeQueue (includes); 189660285Sbostic free ((Address) fname); 189740393Sbostic fname = ifile->fname; 189840393Sbostic lineno = ifile->lineno; 189960285Sbostic if (opened && curFILE) 190046462Sbostic (void) fclose (curFILE); 190160285Sbostic if (curPTR) { 190260285Sbostic free((Address) curPTR->str); 190360285Sbostic free((Address) curPTR); 190460285Sbostic } 190540393Sbostic curFILE = ifile->F; 190660285Sbostic curPTR = ifile->p; 190740393Sbostic free ((Address)ifile); 190840393Sbostic return (CONTINUE); 190940393Sbostic } 191040424Sbostic 191140393Sbostic /*- 191240393Sbostic *--------------------------------------------------------------------- 191340393Sbostic * ParseReadc -- 191460285Sbostic * Read a character from the current file 191540393Sbostic * 191640393Sbostic * Results: 191740393Sbostic * The character that was read 191840393Sbostic * 191940393Sbostic * Side Effects: 192040393Sbostic *--------------------------------------------------------------------- 192140393Sbostic */ 192260285Sbostic static int 192360285Sbostic ParseReadc() 192460285Sbostic { 192560285Sbostic if (curFILE) 192660285Sbostic return fgetc(curFILE); 192760285Sbostic 192860285Sbostic if (curPTR && *curPTR->ptr) 192960285Sbostic return *curPTR->ptr++; 193060285Sbostic return EOF; 193160285Sbostic } 193240393Sbostic 193360557Sbostic 193460557Sbostic /*- 193560557Sbostic *--------------------------------------------------------------------- 193660557Sbostic * ParseUnreadc -- 193760557Sbostic * Put back a character to the current file 193860557Sbostic * 193960557Sbostic * Results: 194060557Sbostic * None. 194160557Sbostic * 194260557Sbostic * Side Effects: 194360557Sbostic *--------------------------------------------------------------------- 194460557Sbostic */ 194560557Sbostic static void 194660557Sbostic ParseUnreadc(c) 194760557Sbostic int c; 194860557Sbostic { 194960557Sbostic if (curFILE) { 195060557Sbostic ungetc(c, curFILE); 195160557Sbostic return; 195260557Sbostic } 195360557Sbostic if (curPTR) { 195460557Sbostic *--(curPTR->ptr) = c; 195560557Sbostic return; 195660557Sbostic } 195760557Sbostic } 195860557Sbostic 195960557Sbostic 196060285Sbostic /* ParseSkipLine(): 196160285Sbostic * Grab the next line 196260285Sbostic */ 196360285Sbostic static char * 196460285Sbostic ParseSkipLine(skip) 196560285Sbostic int skip; /* Skip lines that don't start with . */ 196660285Sbostic { 196760285Sbostic char *line; 196860285Sbostic int c, lastc = '\0', lineLength; 196960285Sbostic Buffer buf; 197040393Sbostic 197160285Sbostic c = ParseReadc(); 197240424Sbostic 197360285Sbostic if (skip) { 197460285Sbostic /* 197560285Sbostic * Skip lines until get to one that begins with a 197660285Sbostic * special char. 197760285Sbostic */ 197860285Sbostic while ((c != '.') && (c != EOF)) { 197960285Sbostic while (((c != '\n') || (lastc == '\\')) && (c != EOF)) 198060285Sbostic { 198160285Sbostic /* 198260285Sbostic * Advance to next unescaped newline 198360285Sbostic */ 198460285Sbostic if ((lastc = c) == '\n') { 198560285Sbostic lineno++; 198660285Sbostic } 198760285Sbostic c = ParseReadc(); 198860285Sbostic } 198960285Sbostic lineno++; 199060285Sbostic 199160285Sbostic lastc = c; 199260285Sbostic c = ParseReadc (); 199360285Sbostic } 199460285Sbostic } 199560285Sbostic 199660285Sbostic if (c == EOF) { 199760285Sbostic Parse_Error (PARSE_FATAL, "Unclosed conditional/for loop"); 199860285Sbostic return ((char *)NULL); 199960285Sbostic } 200060285Sbostic 200160285Sbostic /* 200260285Sbostic * Read the entire line into buf 200360285Sbostic */ 200460285Sbostic buf = Buf_Init (MAKE_BSIZE); 200560285Sbostic if (c != '\n') { 200660285Sbostic do { 200760285Sbostic Buf_AddByte (buf, (Byte)c); 200860285Sbostic c = ParseReadc(); 200960285Sbostic } while ((c != '\n') && (c != EOF)); 201060285Sbostic } 201160285Sbostic lineno++; 201260285Sbostic 201360285Sbostic Buf_AddByte (buf, (Byte)'\0'); 201460285Sbostic line = (char *)Buf_GetAll (buf, &lineLength); 201560285Sbostic Buf_Destroy (buf, FALSE); 201660285Sbostic return line; 201760285Sbostic } 201860285Sbostic 201960285Sbostic 202040393Sbostic /*- 202140393Sbostic *--------------------------------------------------------------------- 202240393Sbostic * ParseReadLine -- 202340393Sbostic * Read an entire line from the input file. Called only by Parse_File. 202440393Sbostic * To facilitate escaped newlines and what have you, a character is 202540393Sbostic * buffered in 'lastc', which is '\0' when no characters have been 202640393Sbostic * read. When we break out of the loop, c holds the terminating 202740393Sbostic * character and lastc holds a character that should be added to 202840393Sbostic * the line (unless we don't read anything but a terminator). 202940393Sbostic * 203040393Sbostic * Results: 203140393Sbostic * A line w/o its newline 203240393Sbostic * 203340393Sbostic * Side Effects: 203440393Sbostic * Only those associated with reading a character 203540393Sbostic *--------------------------------------------------------------------- 203640393Sbostic */ 203740393Sbostic static char * 203840393Sbostic ParseReadLine () 203940393Sbostic { 204040393Sbostic Buffer buf; /* Buffer for current line */ 204140393Sbostic register int c; /* the current character */ 204240393Sbostic register int lastc; /* The most-recent character */ 204340393Sbostic Boolean semiNL; /* treat semi-colons as newlines */ 204440393Sbostic Boolean ignDepOp; /* TRUE if should ignore dependency operators 204540393Sbostic * for the purposes of setting semiNL */ 204640393Sbostic Boolean ignComment; /* TRUE if should ignore comments (in a 204740393Sbostic * shell command */ 204840393Sbostic char *line; /* Result */ 204940393Sbostic int lineLength; /* Length of result */ 205040393Sbostic 205140393Sbostic semiNL = FALSE; 205240393Sbostic ignDepOp = FALSE; 205340393Sbostic ignComment = FALSE; 205440393Sbostic 205540393Sbostic /* 205640393Sbostic * Handle special-characters at the beginning of the line. Either a 205740393Sbostic * leading tab (shell command) or pound-sign (possible conditional) 205840393Sbostic * forces us to ignore comments and dependency operators and treat 205940393Sbostic * semi-colons as semi-colons (by leaving semiNL FALSE). This also 206040393Sbostic * discards completely blank lines. 206140393Sbostic */ 206260285Sbostic for (;;) { 206340393Sbostic c = ParseReadc(); 206440393Sbostic 206560557Sbostic if (c == '\t') { 206644599Sbostic ignComment = ignDepOp = TRUE; 206744599Sbostic break; 206840393Sbostic } else if (c == '\n') { 206940393Sbostic lineno++; 207061010Sbostic } else if (c == '#') { 2071*66399Schristos ParseUnreadc(c); 2072*66399Schristos break; 207340393Sbostic } else { 207440393Sbostic /* 207540393Sbostic * Anything else breaks out without doing anything 207640393Sbostic */ 207740393Sbostic break; 207840393Sbostic } 207940393Sbostic } 208040393Sbostic 208140393Sbostic if (c != EOF) { 208240393Sbostic lastc = c; 208360285Sbostic buf = Buf_Init(MAKE_BSIZE); 208440393Sbostic 208540393Sbostic while (((c = ParseReadc ()) != '\n' || (lastc == '\\')) && 208640393Sbostic (c != EOF)) 208740393Sbostic { 208840393Sbostic test_char: 208940393Sbostic switch(c) { 209040393Sbostic case '\n': 209140393Sbostic /* 209240393Sbostic * Escaped newline: read characters until a non-space or an 209340393Sbostic * unescaped newline and replace them all by a single space. 209440393Sbostic * This is done by storing the space over the backslash and 209540393Sbostic * dropping through with the next nonspace. If it is a 209640393Sbostic * semi-colon and semiNL is TRUE, it will be recognized as a 209740393Sbostic * newline in the code below this... 209840393Sbostic */ 209940393Sbostic lineno++; 210040393Sbostic lastc = ' '; 210140393Sbostic while ((c = ParseReadc ()) == ' ' || c == '\t') { 210240393Sbostic continue; 210340393Sbostic } 210440393Sbostic if (c == EOF || c == '\n') { 210540393Sbostic goto line_read; 210640393Sbostic } else { 210740393Sbostic /* 210840393Sbostic * Check for comments, semiNL's, etc. -- easier than 210960557Sbostic * ParseUnreadc(c); continue; 211040393Sbostic */ 211140393Sbostic goto test_char; 211240393Sbostic } 211360285Sbostic /*NOTREACHED*/ 211440393Sbostic break; 211560285Sbostic 211640393Sbostic case ';': 211740393Sbostic /* 211840393Sbostic * Semi-colon: Need to see if it should be interpreted as a 211940393Sbostic * newline 212040393Sbostic */ 212140393Sbostic if (semiNL) { 212240393Sbostic /* 212340393Sbostic * To make sure the command that may be following this 212440393Sbostic * semi-colon begins with a tab, we push one back into the 212540393Sbostic * input stream. This will overwrite the semi-colon in the 212640393Sbostic * buffer. If there is no command following, this does no 212740393Sbostic * harm, since the newline remains in the buffer and the 212840393Sbostic * whole line is ignored. 212940393Sbostic */ 213060557Sbostic ParseUnreadc('\t'); 213140393Sbostic goto line_read; 213240393Sbostic } 213340393Sbostic break; 213440393Sbostic case '=': 213540393Sbostic if (!semiNL) { 213640393Sbostic /* 213740393Sbostic * Haven't seen a dependency operator before this, so this 213840393Sbostic * must be a variable assignment -- don't pay attention to 213940393Sbostic * dependency operators after this. 214040393Sbostic */ 214140393Sbostic ignDepOp = TRUE; 214240393Sbostic } else if (lastc == ':' || lastc == '!') { 214340393Sbostic /* 214440393Sbostic * Well, we've seen a dependency operator already, but it 214540393Sbostic * was the previous character, so this is really just an 214640393Sbostic * expanded variable assignment. Revert semi-colons to 214740393Sbostic * being just semi-colons again and ignore any more 214840393Sbostic * dependency operators. 214940393Sbostic * 215040393Sbostic * XXX: Note that a line like "foo : a:=b" will blow up, 215140393Sbostic * but who'd write a line like that anyway? 215240393Sbostic */ 215340393Sbostic ignDepOp = TRUE; semiNL = FALSE; 215440393Sbostic } 215540393Sbostic break; 215640393Sbostic case '#': 215740393Sbostic if (!ignComment) { 215860285Sbostic if (compatMake || (lastc != '\\')) { 215940393Sbostic /* 216040393Sbostic * If the character is a hash mark and it isn't escaped 216140393Sbostic * (or we're being compatible), the thing is a comment. 216240393Sbostic * Skip to the end of the line. 216340393Sbostic */ 216440393Sbostic do { 216540393Sbostic c = ParseReadc(); 216640393Sbostic } while ((c != '\n') && (c != EOF)); 216740393Sbostic goto line_read; 216860285Sbostic } else { 216960285Sbostic /* 217060285Sbostic * Don't add the backslash. Just let the # get copied 217160285Sbostic * over. 217260285Sbostic */ 217360285Sbostic lastc = c; 217460285Sbostic continue; 217560285Sbostic } 217640393Sbostic } 217740393Sbostic break; 217840393Sbostic case ':': 217940393Sbostic case '!': 218040393Sbostic if (!ignDepOp && (c == ':' || c == '!')) { 218140393Sbostic /* 218240393Sbostic * A semi-colon is recognized as a newline only on 218340393Sbostic * dependency lines. Dependency lines are lines with a 218440393Sbostic * colon or an exclamation point. Ergo... 218540393Sbostic */ 218640393Sbostic semiNL = TRUE; 218740393Sbostic } 218840393Sbostic break; 218940393Sbostic } 219040393Sbostic /* 219140393Sbostic * Copy in the previous character and save this one in lastc. 219240393Sbostic */ 219340393Sbostic Buf_AddByte (buf, (Byte)lastc); 219440393Sbostic lastc = c; 219540393Sbostic 219640393Sbostic } 219740393Sbostic line_read: 219840393Sbostic lineno++; 219940393Sbostic 220040393Sbostic if (lastc != '\0') { 220140393Sbostic Buf_AddByte (buf, (Byte)lastc); 220240393Sbostic } 220340393Sbostic Buf_AddByte (buf, (Byte)'\0'); 220440393Sbostic line = (char *)Buf_GetAll (buf, &lineLength); 220540393Sbostic Buf_Destroy (buf, FALSE); 220640393Sbostic 220740435Sbostic if (line[0] == '.') { 220840393Sbostic /* 220940393Sbostic * The line might be a conditional. Ask the conditional module 221040393Sbostic * about it and act accordingly 221140393Sbostic */ 221240393Sbostic switch (Cond_Eval (line)) { 221340393Sbostic case COND_SKIP: 221460285Sbostic /* 221560285Sbostic * Skip to next conditional that evaluates to COND_PARSE. 221660285Sbostic */ 221740393Sbostic do { 221840393Sbostic free (line); 221960285Sbostic line = ParseSkipLine(1); 222060285Sbostic } while (line && Cond_Eval(line) != COND_PARSE); 222160285Sbostic if (line == NULL) 222260285Sbostic break; 222340393Sbostic /*FALLTHRU*/ 222440393Sbostic case COND_PARSE: 222560285Sbostic free ((Address) line); 222640393Sbostic line = ParseReadLine(); 222740393Sbostic break; 222860285Sbostic case COND_INVALID: 222960285Sbostic if (For_Eval(line)) { 223060285Sbostic int ok; 223160285Sbostic free(line); 223260285Sbostic do { 223360285Sbostic /* 223460285Sbostic * Skip after the matching end 223560285Sbostic */ 223660285Sbostic line = ParseSkipLine(0); 223760285Sbostic if (line == NULL) { 223860285Sbostic Parse_Error (PARSE_FATAL, 223960285Sbostic "Unexpected end of file in for loop.\n"); 224060285Sbostic break; 224160285Sbostic } 224260285Sbostic ok = For_Eval(line); 224360285Sbostic free(line); 224460285Sbostic } 224560285Sbostic while (ok); 224660285Sbostic if (line != NULL) 224760285Sbostic For_Run(); 224860285Sbostic line = ParseReadLine(); 224960285Sbostic } 225060285Sbostic break; 225140393Sbostic } 225240393Sbostic } 225340393Sbostic return (line); 225460285Sbostic 225540393Sbostic } else { 225640393Sbostic /* 225740393Sbostic * Hit end-of-file, so return a NULL line to indicate this. 225840393Sbostic */ 225940393Sbostic return((char *)NULL); 226040393Sbostic } 226140393Sbostic } 226240424Sbostic 226340393Sbostic /*- 226440393Sbostic *----------------------------------------------------------------------- 226540393Sbostic * ParseFinishLine -- 226640393Sbostic * Handle the end of a dependency group. 226740393Sbostic * 226840393Sbostic * Results: 226940393Sbostic * Nothing. 227040393Sbostic * 227140393Sbostic * Side Effects: 227240393Sbostic * inLine set FALSE. 'targets' list destroyed. 227340393Sbostic * 227440393Sbostic *----------------------------------------------------------------------- 227540393Sbostic */ 227640393Sbostic static void 227740393Sbostic ParseFinishLine() 227840393Sbostic { 227940393Sbostic extern int Suff_EndTransform(); 228040393Sbostic 228140393Sbostic if (inLine) { 228240393Sbostic Lst_ForEach(targets, Suff_EndTransform, (ClientData)NULL); 228340393Sbostic Lst_Destroy (targets, ParseHasCommands); 228440393Sbostic inLine = FALSE; 228540393Sbostic } 228640393Sbostic } 228740393Sbostic 228840424Sbostic 228940393Sbostic /*- 229040393Sbostic *--------------------------------------------------------------------- 229140393Sbostic * Parse_File -- 229240393Sbostic * Parse a file into its component parts, incorporating it into the 229340393Sbostic * current dependency graph. This is the main function and controls 229440393Sbostic * almost every other function in this module 229540393Sbostic * 229640393Sbostic * Results: 229740393Sbostic * None 229840393Sbostic * 229940393Sbostic * Side Effects: 230040393Sbostic * Loads. Nodes are added to the list of all targets, nodes and links 230140393Sbostic * are added to the dependency graph. etc. etc. etc. 230240393Sbostic *--------------------------------------------------------------------- 230340393Sbostic */ 230440393Sbostic void 230540393Sbostic Parse_File(name, stream) 230640393Sbostic char *name; /* the name of the file being read */ 230740393Sbostic FILE * stream; /* Stream open to makefile to parse */ 230840393Sbostic { 230940393Sbostic register char *cp, /* pointer into the line */ 231040393Sbostic *line; /* the line we're working on */ 231140393Sbostic 231240393Sbostic inLine = FALSE; 231340393Sbostic fname = name; 231440393Sbostic curFILE = stream; 231540393Sbostic lineno = 0; 231640393Sbostic fatals = 0; 231740393Sbostic 231840393Sbostic do { 231960285Sbostic while ((line = ParseReadLine ()) != NULL) { 232040435Sbostic if (*line == '.') { 232140393Sbostic /* 232240393Sbostic * Lines that begin with the special character are either 232340393Sbostic * include or undef directives. 232440393Sbostic */ 232540393Sbostic for (cp = line + 1; isspace (*cp); cp++) { 232640393Sbostic continue; 232740393Sbostic } 232840393Sbostic if (strncmp (cp, "include", 7) == 0) { 232940393Sbostic ParseDoInclude (cp + 7); 233040393Sbostic goto nextLine; 233140393Sbostic } else if (strncmp(cp, "undef", 5) == 0) { 233240393Sbostic char *cp2; 233340393Sbostic for (cp += 5; isspace(*cp); cp++) { 233440393Sbostic continue; 233540393Sbostic } 233640393Sbostic 233740393Sbostic for (cp2 = cp; !isspace(*cp2) && (*cp2 != '\0'); cp2++) { 233840393Sbostic continue; 233940393Sbostic } 234040393Sbostic 234140393Sbostic *cp2 = '\0'; 234240393Sbostic 234340393Sbostic Var_Delete(cp, VAR_GLOBAL); 234440393Sbostic goto nextLine; 234540393Sbostic } 234640393Sbostic } 234740393Sbostic if (*line == '#') { 234840435Sbostic /* If we're this far, the line must be a comment. */ 234940393Sbostic goto nextLine; 235040393Sbostic } 235140393Sbostic 235240393Sbostic if (*line == '\t' 235340393Sbostic #ifdef POSIX 235440393Sbostic || *line == ' ' 235540393Sbostic #endif 235640393Sbostic ) 235740393Sbostic { 235840393Sbostic /* 235940393Sbostic * If a line starts with a tab (or space in POSIX-land), it 236040393Sbostic * can only hope to be a creation command. 236140393Sbostic */ 236240393Sbostic shellCommand: 236340393Sbostic for (cp = line + 1; isspace (*cp); cp++) { 236440393Sbostic continue; 236540393Sbostic } 236640393Sbostic if (*cp) { 236740393Sbostic if (inLine) { 236840393Sbostic /* 236940393Sbostic * So long as it's not a blank line and we're actually 237040393Sbostic * in a dependency spec, add the command to the list of 237140393Sbostic * commands of all targets in the dependency spec 237240393Sbostic */ 237340393Sbostic Lst_ForEach (targets, ParseAddCmd, (ClientData)cp); 237440393Sbostic continue; 237540393Sbostic } else { 237640393Sbostic Parse_Error (PARSE_FATAL, 237740393Sbostic "Unassociated shell command \"%.20s\"", 237840393Sbostic cp); 237940393Sbostic } 238040393Sbostic } 238160285Sbostic #ifdef SYSVINCLUDE 238260285Sbostic } else if (strncmp (line, "include", 7) == 0 && 238360285Sbostic strchr(line, ':') == NULL) { 238460285Sbostic /* 238560285Sbostic * It's an S3/S5-style "include". 238660285Sbostic */ 238760285Sbostic ParseTraditionalInclude (line + 7); 238860285Sbostic goto nextLine; 238960285Sbostic #endif 239040393Sbostic } else if (Parse_IsVar (line)) { 239140393Sbostic ParseFinishLine(); 239240393Sbostic Parse_DoVar (line, VAR_GLOBAL); 239340393Sbostic } else { 239440393Sbostic /* 239540393Sbostic * We now know it's a dependency line so it needs to have all 239640393Sbostic * variables expanded before being parsed. Tell the variable 239740393Sbostic * module to complain if some variable is undefined... 239840393Sbostic * To make life easier on novices, if the line is indented we 239940393Sbostic * first make sure the line has a dependency operator in it. 240040393Sbostic * If it doesn't have an operator and we're in a dependency 240140393Sbostic * line's script, we assume it's actually a shell command 240240393Sbostic * and add it to the current list of targets. 240340393Sbostic * 240440393Sbostic * Note that POSIX declares all lines that start with 240540393Sbostic * whitespace are shell commands, so there's no need to check 240640393Sbostic * here... 240740393Sbostic */ 240840393Sbostic Boolean nonSpace = FALSE; 240940393Sbostic 241040393Sbostic cp = line; 241140393Sbostic #ifndef POSIX 241240393Sbostic if (line[0] == ' ') { 241340393Sbostic while ((*cp != ':') && (*cp != '!') && (*cp != '\0')) { 241440393Sbostic if (!isspace(*cp)) { 241540393Sbostic nonSpace = TRUE; 241640393Sbostic } 241740393Sbostic cp++; 241840393Sbostic } 241940393Sbostic } 242040393Sbostic 242140393Sbostic if (*cp == '\0') { 242240393Sbostic if (inLine) { 242340393Sbostic Parse_Error (PARSE_WARNING, 242440393Sbostic "Shell command needs a leading tab"); 242540393Sbostic goto shellCommand; 242640393Sbostic } else if (nonSpace) { 242740393Sbostic Parse_Error (PARSE_FATAL, "Missing operator"); 242840393Sbostic } 242940393Sbostic } else { 243040393Sbostic #endif 243140393Sbostic ParseFinishLine(); 243240393Sbostic 243360285Sbostic cp = Var_Subst (NULL, line, VAR_CMD, TRUE); 243440393Sbostic free (line); 243540393Sbostic line = cp; 243640393Sbostic 243740393Sbostic /* 243840393Sbostic * Need a non-circular list for the target nodes 243940393Sbostic */ 244040393Sbostic targets = Lst_Init (FALSE); 244140393Sbostic inLine = TRUE; 244240393Sbostic 244340393Sbostic ParseDoDependency (line); 244440393Sbostic #ifndef POSIX 244540393Sbostic } 244640393Sbostic #endif 244740393Sbostic } 244840393Sbostic 244940393Sbostic nextLine: 245040393Sbostic 245140393Sbostic free (line); 245240393Sbostic } 245340393Sbostic /* 245440393Sbostic * Reached EOF, but it may be just EOF of an include file... 245540393Sbostic */ 245646462Sbostic } while (ParseEOF(1) == CONTINUE); 245740393Sbostic 245840393Sbostic /* 245940393Sbostic * Make sure conditionals are clean 246040393Sbostic */ 246140393Sbostic Cond_End(); 246240393Sbostic 246340393Sbostic if (fatals) { 246440393Sbostic fprintf (stderr, "Fatal errors encountered -- cannot continue\n"); 246540393Sbostic exit (1); 246640393Sbostic } 246740393Sbostic } 246840424Sbostic 246940393Sbostic /*- 247040393Sbostic *--------------------------------------------------------------------- 247140393Sbostic * Parse_Init -- 247240393Sbostic * initialize the parsing module 247340393Sbostic * 247440393Sbostic * Results: 247540393Sbostic * none 247640393Sbostic * 247740393Sbostic * Side Effects: 247840393Sbostic * the parseIncPath list is initialized... 247940393Sbostic *--------------------------------------------------------------------- 248040393Sbostic */ 248160285Sbostic void 248240393Sbostic Parse_Init () 248340393Sbostic { 248460285Sbostic char *cp = NULL, *start; 248540515Sbostic /* avoid faults on read-only strings */ 248640515Sbostic static char syspath[] = _PATH_DEFSYSPATH; 248740393Sbostic 248840393Sbostic mainNode = NILGNODE; 248940393Sbostic parseIncPath = Lst_Init (FALSE); 249040393Sbostic sysIncPath = Lst_Init (FALSE); 249140393Sbostic includes = Lst_Init (FALSE); 249240393Sbostic 249340393Sbostic /* 249440393Sbostic * Add the directories from the DEFSYSPATH (more than one may be given 249540393Sbostic * as dir1:...:dirn) to the system include path. 249640393Sbostic */ 249740393Sbostic for (start = syspath; *start != '\0'; start = cp) { 249860285Sbostic for (cp = start; *cp != '\0' && *cp != ':'; cp++) 249960285Sbostic continue; 250040393Sbostic if (*cp == '\0') { 250140393Sbostic Dir_AddDir(sysIncPath, start); 250240393Sbostic } else { 250340393Sbostic *cp++ = '\0'; 250440393Sbostic Dir_AddDir(sysIncPath, start); 250540393Sbostic } 250640393Sbostic } 250740393Sbostic } 250840424Sbostic 250940393Sbostic /*- 251040393Sbostic *----------------------------------------------------------------------- 251140393Sbostic * Parse_MainName -- 251240393Sbostic * Return a Lst of the main target to create for main()'s sake. If 251340393Sbostic * no such target exists, we Punt with an obnoxious error message. 251440393Sbostic * 251540393Sbostic * Results: 251640393Sbostic * A Lst of the single node to create. 251740393Sbostic * 251840393Sbostic * Side Effects: 251940393Sbostic * None. 252040393Sbostic * 252140393Sbostic *----------------------------------------------------------------------- 252240393Sbostic */ 252340393Sbostic Lst 252440393Sbostic Parse_MainName() 252540393Sbostic { 252640393Sbostic Lst main; /* result list */ 252740393Sbostic 252840393Sbostic main = Lst_Init (FALSE); 252940393Sbostic 253040393Sbostic if (mainNode == NILGNODE) { 253145906Sbostic Punt ("make: no target to make.\n"); 253240393Sbostic /*NOTREACHED*/ 253340393Sbostic } else if (mainNode->type & OP_DOUBLEDEP) { 253466389Sbostic (void) Lst_AtEnd (main, (ClientData)mainNode); 253540393Sbostic Lst_Concat(main, mainNode->cohorts, LST_CONCNEW); 253640393Sbostic } 253766389Sbostic else 253866389Sbostic (void) Lst_AtEnd (main, (ClientData)mainNode); 253940393Sbostic return (main); 254040393Sbostic } 2541