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*69086Schristos static char sccsid[] = "@(#)parse.c 8.5 (Berkeley) 04/28/95"; 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 * 40*69086Schristos * Parse_End Cleanup the module 41*69086Schristos * 4240393Sbostic * Parse_File Function used to parse a makefile. It must 4340393Sbostic * be given the name of the file, which should 4440393Sbostic * already have been opened, and a function 4540393Sbostic * to call to read a character from the file. 4640393Sbostic * 4740393Sbostic * Parse_IsVar Returns TRUE if the given line is a 4840393Sbostic * variable assignment. Used by MainParseArgs 4940393Sbostic * to determine if an argument is a target 5040393Sbostic * or a variable assignment. Used internally 5140393Sbostic * for pretty much the same thing... 5240393Sbostic * 5340393Sbostic * Parse_Error Function called when an error occurs in 5440393Sbostic * parsing. Used by the variable and 5540393Sbostic * conditional modules. 5640393Sbostic * Parse_MainName Returns a Lst of the main target to create. 5740393Sbostic */ 5840393Sbostic 5960285Sbostic #if __STDC__ 6060285Sbostic #include <stdarg.h> 6160285Sbostic #else 6240444Sbostic #include <varargs.h> 6360285Sbostic #endif 6440444Sbostic #include <stdio.h> 6540444Sbostic #include <ctype.h> 6660285Sbostic #include <errno.h> 6760285Sbostic #include <sys/wait.h> 6840444Sbostic #include "make.h" 6960285Sbostic #include "hash.h" 7060285Sbostic #include "dir.h" 7160285Sbostic #include "job.h" 7240444Sbostic #include "buf.h" 7340515Sbostic #include "pathnames.h" 7440393Sbostic 7540393Sbostic /* 7640393Sbostic * These values are returned by ParseEOF to tell Parse_File whether to 7740393Sbostic * CONTINUE parsing, i.e. it had only reached the end of an include file, 7840393Sbostic * or if it's DONE. 7940393Sbostic */ 8040393Sbostic #define CONTINUE 1 8140393Sbostic #define DONE 0 8240393Sbostic static Lst targets; /* targets we're working on */ 83*69086Schristos static Lst targCmds; /* command lines for targets */ 8440393Sbostic static Boolean inLine; /* true if currently in a dependency 8540393Sbostic * line or its commands */ 8660285Sbostic typedef struct { 8760285Sbostic char *str; 8860285Sbostic char *ptr; 8960285Sbostic } PTR; 9040393Sbostic 9140393Sbostic static char *fname; /* name of current file (for errors) */ 9240393Sbostic static int lineno; /* line number in current file */ 9360285Sbostic static FILE *curFILE = NULL; /* current makefile */ 9440393Sbostic 9560285Sbostic static PTR *curPTR = NULL; /* current makefile */ 9660285Sbostic 9740393Sbostic static int fatals = 0; 9840393Sbostic 9940393Sbostic static GNode *mainNode; /* The main target to create. This is the 10040393Sbostic * first target on the first dependency 10140393Sbostic * line in the first makefile */ 10240393Sbostic /* 10340393Sbostic * Definitions for handling #include specifications 10440393Sbostic */ 10540393Sbostic typedef struct IFile { 10640393Sbostic char *fname; /* name of previous file */ 10740393Sbostic int lineno; /* saved line number */ 10860285Sbostic FILE * F; /* the open stream */ 10960285Sbostic PTR * p; /* the char pointer */ 11060285Sbostic } IFile; 11140393Sbostic 11240393Sbostic static Lst includes; /* stack of IFiles generated by 11340393Sbostic * #includes */ 11440393Sbostic Lst parseIncPath; /* list of directories for "..." includes */ 11540393Sbostic Lst sysIncPath; /* list of directories for <...> includes */ 11640393Sbostic 11740393Sbostic /*- 11840393Sbostic * specType contains the SPECial TYPE of the current target. It is 11940393Sbostic * Not if the target is unspecial. If it *is* special, however, the children 12040393Sbostic * are linked as children of the parent but not vice versa. This variable is 12140393Sbostic * set in ParseDoDependency 12240393Sbostic */ 12340393Sbostic typedef enum { 12440393Sbostic Begin, /* .BEGIN */ 12540393Sbostic Default, /* .DEFAULT */ 12640393Sbostic End, /* .END */ 12740393Sbostic Ignore, /* .IGNORE */ 12840393Sbostic Includes, /* .INCLUDES */ 12940393Sbostic Interrupt, /* .INTERRUPT */ 13040393Sbostic Libs, /* .LIBS */ 13140393Sbostic MFlags, /* .MFLAGS or .MAKEFLAGS */ 13240393Sbostic Main, /* .MAIN and we don't have anything user-specified to 13340393Sbostic * make */ 13460285Sbostic NoExport, /* .NOEXPORT */ 13540393Sbostic Not, /* Not special */ 13640393Sbostic NotParallel, /* .NOTPARALELL */ 13740393Sbostic Null, /* .NULL */ 13840393Sbostic Order, /* .ORDER */ 13960285Sbostic ExPath, /* .PATH */ 14040393Sbostic Precious, /* .PRECIOUS */ 14160285Sbostic ExShell, /* .SHELL */ 14240393Sbostic Silent, /* .SILENT */ 14340393Sbostic SingleShell, /* .SINGLESHELL */ 14440393Sbostic Suffixes, /* .SUFFIXES */ 14560285Sbostic Attribute /* Generic attribute */ 14640393Sbostic } ParseSpecial; 14740393Sbostic 14860285Sbostic static ParseSpecial specType; 14940393Sbostic 15040393Sbostic /* 15140393Sbostic * Predecessor node for handling .ORDER. Initialized to NILGNODE when .ORDER 15240393Sbostic * seen, then set to each successive source on the line. 15340393Sbostic */ 15440393Sbostic static GNode *predecessor; 15540393Sbostic 15640393Sbostic /* 15740393Sbostic * The parseKeywords table is searched using binary search when deciding 15840393Sbostic * if a target or source is special. The 'spec' field is the ParseSpecial 15940393Sbostic * type of the keyword ("Not" if the keyword isn't special as a target) while 16040393Sbostic * the 'op' field is the operator to apply to the list of targets if the 16140393Sbostic * keyword is used as a source ("0" if the keyword isn't special as a source) 16240393Sbostic */ 16340393Sbostic static struct { 16440393Sbostic char *name; /* Name of keyword */ 16540393Sbostic ParseSpecial spec; /* Type when used as a target */ 16640393Sbostic int op; /* Operator when used as a source */ 16740393Sbostic } parseKeywords[] = { 16840393Sbostic { ".BEGIN", Begin, 0 }, 16940393Sbostic { ".DEFAULT", Default, 0 }, 17040546Sbostic { ".OPTIONAL", Attribute, OP_OPTIONAL }, 17140393Sbostic { ".END", End, 0 }, 17240393Sbostic { ".EXEC", Attribute, OP_EXEC }, 17340393Sbostic { ".IGNORE", Ignore, OP_IGNORE }, 17440393Sbostic { ".INCLUDES", Includes, 0 }, 17540393Sbostic { ".INTERRUPT", Interrupt, 0 }, 17640393Sbostic { ".INVISIBLE", Attribute, OP_INVISIBLE }, 17740393Sbostic { ".JOIN", Attribute, OP_JOIN }, 17840393Sbostic { ".LIBS", Libs, 0 }, 17940393Sbostic { ".MAIN", Main, 0 }, 18040393Sbostic { ".MAKE", Attribute, OP_MAKE }, 18140393Sbostic { ".MAKEFLAGS", MFlags, 0 }, 18240393Sbostic { ".MFLAGS", MFlags, 0 }, 18340393Sbostic { ".NOTMAIN", Attribute, OP_NOTMAIN }, 18440393Sbostic { ".NOTPARALLEL", NotParallel, 0 }, 18540393Sbostic { ".NULL", Null, 0 }, 18640393Sbostic { ".ORDER", Order, 0 }, 18760285Sbostic { ".PATH", ExPath, 0 }, 18840393Sbostic { ".PRECIOUS", Precious, OP_PRECIOUS }, 18940393Sbostic { ".RECURSIVE", Attribute, OP_MAKE }, 19060285Sbostic { ".SHELL", ExShell, 0 }, 19140393Sbostic { ".SILENT", Silent, OP_SILENT }, 19240393Sbostic { ".SINGLESHELL", SingleShell, 0 }, 19340393Sbostic { ".SUFFIXES", Suffixes, 0 }, 19440393Sbostic { ".USE", Attribute, OP_USE }, 19540393Sbostic }; 19640424Sbostic 19760285Sbostic static int ParseFindKeyword __P((char *)); 198*69086Schristos static int ParseLinkSrc __P((ClientData, ClientData)); 199*69086Schristos static int ParseDoOp __P((ClientData, ClientData)); 20060285Sbostic static void ParseDoSrc __P((int, char *)); 201*69086Schristos static int ParseFindMain __P((ClientData, ClientData)); 202*69086Schristos static int ParseAddDir __P((ClientData, ClientData)); 203*69086Schristos static int ParseClearPath __P((ClientData, ClientData)); 20460285Sbostic static void ParseDoDependency __P((char *)); 205*69086Schristos static int ParseAddCmd __P((ClientData, ClientData)); 20660285Sbostic static int ParseReadc __P((void)); 20760557Sbostic static void ParseUnreadc __P((int)); 208*69086Schristos static void ParseHasCommands __P((ClientData)); 20960285Sbostic static void ParseDoInclude __P((char *)); 21060285Sbostic #ifdef SYSVINCLUDE 21160285Sbostic static void ParseTraditionalInclude __P((char *)); 21260285Sbostic #endif 21360285Sbostic static int ParseEOF __P((int)); 21460285Sbostic static char *ParseReadLine __P((void)); 21560285Sbostic static char *ParseSkipLine __P((int)); 21660285Sbostic static void ParseFinishLine __P((void)); 21760285Sbostic 21840393Sbostic /*- 21940393Sbostic *---------------------------------------------------------------------- 22040393Sbostic * ParseFindKeyword -- 22140393Sbostic * Look in the table of keywords for one matching the given string. 22240393Sbostic * 22340393Sbostic * Results: 22440393Sbostic * The index of the keyword, or -1 if it isn't there. 22540393Sbostic * 22640393Sbostic * Side Effects: 22740393Sbostic * None 22840393Sbostic *---------------------------------------------------------------------- 22940393Sbostic */ 23040393Sbostic static int 23140393Sbostic ParseFindKeyword (str) 23240393Sbostic char *str; /* String to find */ 23340393Sbostic { 23440393Sbostic register int start, 23540393Sbostic end, 23640393Sbostic cur; 23740393Sbostic register int diff; 23840393Sbostic 23940393Sbostic start = 0; 24040393Sbostic end = (sizeof(parseKeywords)/sizeof(parseKeywords[0])) - 1; 24140393Sbostic 24240393Sbostic do { 24340393Sbostic cur = start + ((end - start) / 2); 24440393Sbostic diff = strcmp (str, parseKeywords[cur].name); 24540393Sbostic 24640393Sbostic if (diff == 0) { 24740393Sbostic return (cur); 24840393Sbostic } else if (diff < 0) { 24940393Sbostic end = cur - 1; 25040393Sbostic } else { 25140393Sbostic start = cur + 1; 25240393Sbostic } 25340393Sbostic } while (start <= end); 25440393Sbostic return (-1); 25540393Sbostic } 25640424Sbostic 25740393Sbostic /*- 25840393Sbostic * Parse_Error -- 25940393Sbostic * Error message abort function for parsing. Prints out the context 26040393Sbostic * of the error (line number and file) as well as the message with 26140393Sbostic * two optional arguments. 26240393Sbostic * 26340393Sbostic * Results: 26440393Sbostic * None 26540393Sbostic * 26640393Sbostic * Side Effects: 26740393Sbostic * "fatals" is incremented if the level is PARSE_FATAL. 26840393Sbostic */ 26940444Sbostic /* VARARGS */ 27040393Sbostic void 27160285Sbostic #if __STDC__ 272*69086Schristos Parse_Error(int type, char *fmt, ...) 27360285Sbostic #else 27466399Schristos Parse_Error(va_alist) 27540444Sbostic va_dcl 27660285Sbostic #endif 27740393Sbostic { 27840444Sbostic va_list ap; 27960285Sbostic #if __STDC__ 28060285Sbostic va_start(ap, fmt); 28160285Sbostic #else 28266399Schristos int type; /* Error type (PARSE_WARNING, PARSE_FATAL) */ 28366399Schristos char *fmt; 28466399Schristos 28560285Sbostic va_start(ap); 28666399Schristos type = va_arg(ap, int); 28766399Schristos fmt = va_arg(ap, char *); 28860285Sbostic #endif 28966399Schristos 29040444Sbostic (void)fprintf(stderr, "\"%s\", line %d: ", fname, lineno); 29140444Sbostic if (type == PARSE_WARNING) 29240540Sbostic (void)fprintf(stderr, "warning: "); 29340444Sbostic (void)vfprintf(stderr, fmt, ap); 29440444Sbostic va_end(ap); 29540444Sbostic (void)fprintf(stderr, "\n"); 29640444Sbostic (void)fflush(stderr); 29740444Sbostic if (type == PARSE_FATAL) 29840444Sbostic fatals += 1; 29940393Sbostic } 30040424Sbostic 30140393Sbostic /*- 30240393Sbostic *--------------------------------------------------------------------- 30340393Sbostic * ParseLinkSrc -- 30440393Sbostic * Link the parent node to its new child. Used in a Lst_ForEach by 30540393Sbostic * ParseDoDependency. If the specType isn't 'Not', the parent 30640393Sbostic * isn't linked as a parent of the child. 30740393Sbostic * 30840393Sbostic * Results: 30940393Sbostic * Always = 0 31040393Sbostic * 31140393Sbostic * Side Effects: 31240393Sbostic * New elements are added to the parents list of cgn and the 31340393Sbostic * children list of cgn. the unmade field of pgn is updated 31440393Sbostic * to reflect the additional child. 31540393Sbostic *--------------------------------------------------------------------- 31640393Sbostic */ 31740393Sbostic static int 318*69086Schristos ParseLinkSrc (pgnp, cgnp) 319*69086Schristos ClientData pgnp; /* The parent node */ 320*69086Schristos ClientData cgnp; /* The child node */ 32140393Sbostic { 322*69086Schristos GNode *pgn = (GNode *) pgnp; 323*69086Schristos GNode *cgn = (GNode *) cgnp; 32440393Sbostic if (Lst_Member (pgn->children, (ClientData)cgn) == NILLNODE) { 32540393Sbostic (void)Lst_AtEnd (pgn->children, (ClientData)cgn); 32640393Sbostic if (specType == Not) { 32740393Sbostic (void)Lst_AtEnd (cgn->parents, (ClientData)pgn); 32840393Sbostic } 32940393Sbostic pgn->unmade += 1; 33040393Sbostic } 33140393Sbostic return (0); 33240393Sbostic } 33340424Sbostic 33440393Sbostic /*- 33540393Sbostic *--------------------------------------------------------------------- 33640393Sbostic * ParseDoOp -- 33740393Sbostic * Apply the parsed operator to the given target node. Used in a 33840393Sbostic * Lst_ForEach call by ParseDoDependency once all targets have 33940393Sbostic * been found and their operator parsed. If the previous and new 34040393Sbostic * operators are incompatible, a major error is taken. 34140393Sbostic * 34240393Sbostic * Results: 34340393Sbostic * Always 0 34440393Sbostic * 34540393Sbostic * Side Effects: 34640393Sbostic * The type field of the node is altered to reflect any new bits in 34740393Sbostic * the op. 34840393Sbostic *--------------------------------------------------------------------- 34940393Sbostic */ 35040393Sbostic static int 351*69086Schristos ParseDoOp (gnp, opp) 352*69086Schristos ClientData gnp; /* The node to which the operator is to be 35340393Sbostic * applied */ 354*69086Schristos ClientData opp; /* The operator to apply */ 35540393Sbostic { 356*69086Schristos GNode *gn = (GNode *) gnp; 357*69086Schristos int op = *(int *) opp; 35840393Sbostic /* 35940393Sbostic * If the dependency mask of the operator and the node don't match and 36040393Sbostic * the node has actually had an operator applied to it before, and 36140393Sbostic * the operator actually has some dependency information in it, complain. 36240393Sbostic */ 36340393Sbostic if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) && 36440393Sbostic !OP_NOP(gn->type) && !OP_NOP(op)) 36540393Sbostic { 36640393Sbostic Parse_Error (PARSE_FATAL, "Inconsistent operator for %s", gn->name); 36740393Sbostic return (1); 36840393Sbostic } 36940393Sbostic 37040393Sbostic if ((op == OP_DOUBLEDEP) && ((gn->type & OP_OPMASK) == OP_DOUBLEDEP)) { 37140393Sbostic /* 37240393Sbostic * If the node was the object of a :: operator, we need to create a 37340393Sbostic * new instance of it for the children and commands on this dependency 37440393Sbostic * line. The new instance is placed on the 'cohorts' list of the 37540393Sbostic * initial one (note the initial one is not on its own cohorts list) 37640393Sbostic * and the new instance is linked to all parents of the initial 37740393Sbostic * instance. 37840393Sbostic */ 37940393Sbostic register GNode *cohort; 38040393Sbostic LstNode ln; 38140393Sbostic 38240393Sbostic cohort = Targ_NewGN(gn->name); 38340393Sbostic /* 38440393Sbostic * Duplicate links to parents so graph traversal is simple. Perhaps 38540393Sbostic * some type bits should be duplicated? 38640393Sbostic * 38740393Sbostic * Make the cohort invisible as well to avoid duplicating it into 38840393Sbostic * other variables. True, parents of this target won't tend to do 38940393Sbostic * anything with their local variables, but better safe than 39040393Sbostic * sorry. 39140393Sbostic */ 39240393Sbostic Lst_ForEach(gn->parents, ParseLinkSrc, (ClientData)cohort); 39340393Sbostic cohort->type = OP_DOUBLEDEP|OP_INVISIBLE; 39440393Sbostic (void)Lst_AtEnd(gn->cohorts, (ClientData)cohort); 39540393Sbostic 39640393Sbostic /* 39740393Sbostic * Replace the node in the targets list with the new copy 39840393Sbostic */ 39940393Sbostic ln = Lst_Member(targets, (ClientData)gn); 40040393Sbostic Lst_Replace(ln, (ClientData)cohort); 40140393Sbostic gn = cohort; 40240393Sbostic } 40340393Sbostic /* 40440393Sbostic * We don't want to nuke any previous flags (whatever they were) so we 40540393Sbostic * just OR the new operator into the old 40640393Sbostic */ 40740393Sbostic gn->type |= op; 40840393Sbostic 40940393Sbostic return (0); 41040393Sbostic } 41140424Sbostic 41240393Sbostic /*- 41340393Sbostic *--------------------------------------------------------------------- 41440393Sbostic * ParseDoSrc -- 41540393Sbostic * Given the name of a source, figure out if it is an attribute 41640393Sbostic * and apply it to the targets if it is. Else decide if there is 41740393Sbostic * some attribute which should be applied *to* the source because 41840393Sbostic * of some special target and apply it if so. Otherwise, make the 41940393Sbostic * source be a child of the targets in the list 'targets' 42040393Sbostic * 42140393Sbostic * Results: 42240393Sbostic * None 42340393Sbostic * 42440393Sbostic * Side Effects: 42540393Sbostic * Operator bits may be added to the list of targets or to the source. 42640393Sbostic * The targets may have a new source added to their lists of children. 42740393Sbostic *--------------------------------------------------------------------- 42840393Sbostic */ 42940393Sbostic static void 43040393Sbostic ParseDoSrc (tOp, src) 43140393Sbostic int tOp; /* operator (if any) from special targets */ 43240393Sbostic char *src; /* name of the source to handle */ 43340393Sbostic { 43440393Sbostic int op; /* operator (if any) from special source */ 43540393Sbostic GNode *gn; 43640393Sbostic 43740393Sbostic op = 0; 43840393Sbostic if (*src == '.' && isupper (src[1])) { 43940393Sbostic int keywd = ParseFindKeyword(src); 44040393Sbostic if (keywd != -1) { 44140393Sbostic op = parseKeywords[keywd].op; 44240393Sbostic } 44340393Sbostic } 44440393Sbostic if (op != 0) { 445*69086Schristos Lst_ForEach (targets, ParseDoOp, (ClientData)&op); 44640393Sbostic } else if (specType == Main) { 44740393Sbostic /* 44840393Sbostic * If we have noted the existence of a .MAIN, it means we need 44940393Sbostic * to add the sources of said target to the list of things 45040393Sbostic * to create. The string 'src' is likely to be free, so we 45140393Sbostic * must make a new copy of it. Note that this will only be 45240393Sbostic * invoked if the user didn't specify a target on the command 45340393Sbostic * line. This is to allow #ifmake's to succeed, or something... 45440393Sbostic */ 45540424Sbostic (void) Lst_AtEnd (create, (ClientData)strdup(src)); 45640393Sbostic /* 45740393Sbostic * Add the name to the .TARGETS variable as well, so the user cna 45840393Sbostic * employ that, if desired. 45940393Sbostic */ 46040393Sbostic Var_Append(".TARGETS", src, VAR_GLOBAL); 46140393Sbostic } else if (specType == Order) { 46240393Sbostic /* 46340393Sbostic * Create proper predecessor/successor links between the previous 46440393Sbostic * source and the current one. 46540393Sbostic */ 46640393Sbostic gn = Targ_FindNode(src, TARG_CREATE); 46740393Sbostic if (predecessor != NILGNODE) { 46840393Sbostic (void)Lst_AtEnd(predecessor->successors, (ClientData)gn); 46940393Sbostic (void)Lst_AtEnd(gn->preds, (ClientData)predecessor); 47040393Sbostic } 47140393Sbostic /* 47240393Sbostic * The current source now becomes the predecessor for the next one. 47340393Sbostic */ 47440393Sbostic predecessor = gn; 47540393Sbostic } else { 47640393Sbostic /* 47740393Sbostic * If the source is not an attribute, we need to find/create 47840393Sbostic * a node for it. After that we can apply any operator to it 47940393Sbostic * from a special target or link it to its parents, as 48040393Sbostic * appropriate. 48140393Sbostic * 48240393Sbostic * In the case of a source that was the object of a :: operator, 48340393Sbostic * the attribute is applied to all of its instances (as kept in 48440393Sbostic * the 'cohorts' list of the node) or all the cohorts are linked 48540393Sbostic * to all the targets. 48640393Sbostic */ 48740393Sbostic gn = Targ_FindNode (src, TARG_CREATE); 48840393Sbostic if (tOp) { 48940393Sbostic gn->type |= tOp; 49040393Sbostic } else { 49140393Sbostic Lst_ForEach (targets, ParseLinkSrc, (ClientData)gn); 49240393Sbostic } 49340393Sbostic if ((gn->type & OP_OPMASK) == OP_DOUBLEDEP) { 49440393Sbostic register GNode *cohort; 49540393Sbostic register LstNode ln; 49640393Sbostic 49740393Sbostic for (ln=Lst_First(gn->cohorts); ln != NILLNODE; ln = Lst_Succ(ln)){ 49840393Sbostic cohort = (GNode *)Lst_Datum(ln); 49940393Sbostic if (tOp) { 50040393Sbostic cohort->type |= tOp; 50140393Sbostic } else { 50240393Sbostic Lst_ForEach(targets, ParseLinkSrc, (ClientData)cohort); 50340393Sbostic } 50440393Sbostic } 50540393Sbostic } 50640393Sbostic } 50740393Sbostic } 50840424Sbostic 50940393Sbostic /*- 51040393Sbostic *----------------------------------------------------------------------- 51140393Sbostic * ParseFindMain -- 51240393Sbostic * Find a real target in the list and set it to be the main one. 51340393Sbostic * Called by ParseDoDependency when a main target hasn't been found 51440393Sbostic * yet. 51540393Sbostic * 51640393Sbostic * Results: 51740393Sbostic * 0 if main not found yet, 1 if it is. 51840393Sbostic * 51940393Sbostic * Side Effects: 52040393Sbostic * mainNode is changed and Targ_SetMain is called. 52140393Sbostic * 52240393Sbostic *----------------------------------------------------------------------- 52340393Sbostic */ 52440393Sbostic static int 525*69086Schristos ParseFindMain(gnp, dummy) 526*69086Schristos ClientData gnp; /* Node to examine */ 527*69086Schristos ClientData dummy; 52840393Sbostic { 529*69086Schristos GNode *gn = (GNode *) gnp; 53040393Sbostic if ((gn->type & (OP_NOTMAIN|OP_USE|OP_EXEC|OP_TRANSFORM)) == 0) { 53140393Sbostic mainNode = gn; 53240393Sbostic Targ_SetMain(gn); 533*69086Schristos return (dummy ? 1 : 1); 53440393Sbostic } else { 535*69086Schristos return (dummy ? 0 : 0); 53640393Sbostic } 53740393Sbostic } 53840424Sbostic 53940393Sbostic /*- 54040393Sbostic *----------------------------------------------------------------------- 54140393Sbostic * ParseAddDir -- 54240393Sbostic * Front-end for Dir_AddDir to make sure Lst_ForEach keeps going 54340393Sbostic * 54440393Sbostic * Results: 54540393Sbostic * === 0 54640393Sbostic * 54740393Sbostic * Side Effects: 54840393Sbostic * See Dir_AddDir. 54940393Sbostic * 55040393Sbostic *----------------------------------------------------------------------- 55140393Sbostic */ 55240393Sbostic static int 55340393Sbostic ParseAddDir(path, name) 554*69086Schristos ClientData path; 555*69086Schristos ClientData name; 55640393Sbostic { 557*69086Schristos Dir_AddDir((Lst) path, (char *) name); 55840393Sbostic return(0); 55940393Sbostic } 56040424Sbostic 56140393Sbostic /*- 56240393Sbostic *----------------------------------------------------------------------- 56340393Sbostic * ParseClearPath -- 56440393Sbostic * Front-end for Dir_ClearPath to make sure Lst_ForEach keeps going 56540393Sbostic * 56640393Sbostic * Results: 56740393Sbostic * === 0 56840393Sbostic * 56940393Sbostic * Side Effects: 57040393Sbostic * See Dir_ClearPath 57140393Sbostic * 57240393Sbostic *----------------------------------------------------------------------- 57340393Sbostic */ 57440393Sbostic static int 575*69086Schristos ParseClearPath(path, dummy) 576*69086Schristos ClientData path; 577*69086Schristos ClientData dummy; 57840393Sbostic { 579*69086Schristos Dir_ClearPath((Lst) path); 580*69086Schristos return(dummy ? 0 : 0); 58140393Sbostic } 58240424Sbostic 58340393Sbostic /*- 58440393Sbostic *--------------------------------------------------------------------- 58540393Sbostic * ParseDoDependency -- 58640393Sbostic * Parse the dependency line in line. 58740393Sbostic * 58840393Sbostic * Results: 58940393Sbostic * None 59040393Sbostic * 59140393Sbostic * Side Effects: 59240393Sbostic * The nodes of the sources are linked as children to the nodes of the 59340393Sbostic * targets. Some nodes may be created. 59440393Sbostic * 59540393Sbostic * We parse a dependency line by first extracting words from the line and 59640393Sbostic * finding nodes in the list of all targets with that name. This is done 59740393Sbostic * until a character is encountered which is an operator character. Currently 59840393Sbostic * these are only ! and :. At this point the operator is parsed and the 59940393Sbostic * pointer into the line advanced until the first source is encountered. 60040393Sbostic * The parsed operator is applied to each node in the 'targets' list, 60140393Sbostic * which is where the nodes found for the targets are kept, by means of 60240393Sbostic * the ParseDoOp function. 60340393Sbostic * The sources are read in much the same way as the targets were except 60440393Sbostic * that now they are expanded using the wildcarding scheme of the C-Shell 60540393Sbostic * and all instances of the resulting words in the list of all targets 60640393Sbostic * are found. Each of the resulting nodes is then linked to each of the 60740393Sbostic * targets as one of its children. 60840393Sbostic * Certain targets are handled specially. These are the ones detailed 60940393Sbostic * by the specType variable. 61040393Sbostic * The storing of transformation rules is also taken care of here. 61140393Sbostic * A target is recognized as a transformation rule by calling 61240393Sbostic * Suff_IsTransform. If it is a transformation rule, its node is gotten 61340393Sbostic * from the suffix module via Suff_AddTransform rather than the standard 61440393Sbostic * Targ_FindNode in the target module. 61540393Sbostic *--------------------------------------------------------------------- 61640393Sbostic */ 61740393Sbostic static void 61840393Sbostic ParseDoDependency (line) 61940393Sbostic char *line; /* the line to parse */ 62040393Sbostic { 621*69086Schristos char *cp; /* our current position */ 622*69086Schristos GNode *gn; /* a general purpose temporary node */ 623*69086Schristos int op; /* the operator on the line */ 62440393Sbostic char savec; /* a place to save a character */ 62540393Sbostic Lst paths; /* List of search paths to alter when parsing 62640393Sbostic * a list of .PATH targets */ 62740393Sbostic int tOp; /* operator from special target */ 62840393Sbostic Lst sources; /* list of source names after expansion */ 62940393Sbostic Lst curTargs; /* list of target names to be found and added 63040393Sbostic * to the targets list */ 63140393Sbostic 63240393Sbostic tOp = 0; 63340393Sbostic 63440393Sbostic specType = Not; 63540393Sbostic paths = (Lst)NULL; 63640393Sbostic 63740393Sbostic curTargs = Lst_Init(FALSE); 63840393Sbostic 63940393Sbostic do { 64040393Sbostic for (cp = line; 64140393Sbostic *cp && !isspace (*cp) && 64240393Sbostic (*cp != '!') && (*cp != ':') && (*cp != '('); 64340393Sbostic cp++) 64440393Sbostic { 64540393Sbostic if (*cp == '$') { 64640393Sbostic /* 64740393Sbostic * Must be a dynamic source (would have been expanded 64840393Sbostic * otherwise), so call the Var module to parse the puppy 64940393Sbostic * so we can safely advance beyond it...There should be 65040393Sbostic * no errors in this, as they would have been discovered 65140393Sbostic * in the initial Var_Subst and we wouldn't be here. 65240393Sbostic */ 65340393Sbostic int length; 65440393Sbostic Boolean freeIt; 65540393Sbostic char *result; 65640393Sbostic 65740393Sbostic result=Var_Parse(cp, VAR_CMD, TRUE, &length, &freeIt); 65840393Sbostic 65940393Sbostic if (freeIt) { 66040393Sbostic free(result); 66140393Sbostic } 66240393Sbostic cp += length-1; 66340393Sbostic } 66440393Sbostic continue; 66540393Sbostic } 66640393Sbostic if (*cp == '(') { 66740393Sbostic /* 66840393Sbostic * Archives must be handled specially to make sure the OP_ARCHV 66940393Sbostic * flag is set in their 'type' field, for one thing, and because 67040393Sbostic * things like "archive(file1.o file2.o file3.o)" are permissible. 67140393Sbostic * Arch_ParseArchive will set 'line' to be the first non-blank 67240393Sbostic * after the archive-spec. It creates/finds nodes for the members 67340393Sbostic * and places them on the given list, returning SUCCESS if all 67440393Sbostic * went well and FAILURE if there was an error in the 67540393Sbostic * specification. On error, line should remain untouched. 67640393Sbostic */ 67740393Sbostic if (Arch_ParseArchive (&line, targets, VAR_CMD) != SUCCESS) { 67840393Sbostic Parse_Error (PARSE_FATAL, 67940393Sbostic "Error in archive specification: \"%s\"", line); 68040393Sbostic return; 68140393Sbostic } else { 68240393Sbostic continue; 68340393Sbostic } 68440393Sbostic } 68540393Sbostic savec = *cp; 68640393Sbostic 68740393Sbostic if (!*cp) { 68840393Sbostic /* 68940393Sbostic * Ending a dependency line without an operator is a Bozo 69040393Sbostic * no-no 69140393Sbostic */ 69240393Sbostic Parse_Error (PARSE_FATAL, "Need an operator"); 69340393Sbostic return; 69440393Sbostic } 69540393Sbostic *cp = '\0'; 69640393Sbostic /* 69740393Sbostic * Have a word in line. See if it's a special target and set 69840393Sbostic * specType to match it. 69940393Sbostic */ 70040393Sbostic if (*line == '.' && isupper (line[1])) { 70140393Sbostic /* 70240393Sbostic * See if the target is a special target that must have it 70340393Sbostic * or its sources handled specially. 70440393Sbostic */ 70540393Sbostic int keywd = ParseFindKeyword(line); 70640393Sbostic if (keywd != -1) { 70760285Sbostic if (specType == ExPath && parseKeywords[keywd].spec != ExPath) { 70840393Sbostic Parse_Error(PARSE_FATAL, "Mismatched special targets"); 70940393Sbostic return; 71040393Sbostic } 71140393Sbostic 71240393Sbostic specType = parseKeywords[keywd].spec; 71340393Sbostic tOp = parseKeywords[keywd].op; 71440393Sbostic 71540393Sbostic /* 71640393Sbostic * Certain special targets have special semantics: 71740393Sbostic * .PATH Have to set the dirSearchPath 71840393Sbostic * variable too 71940393Sbostic * .MAIN Its sources are only used if 72040393Sbostic * nothing has been specified to 72140393Sbostic * create. 72240393Sbostic * .DEFAULT Need to create a node to hang 72340393Sbostic * commands on, but we don't want 72440393Sbostic * it in the graph, nor do we want 72540393Sbostic * it to be the Main Target, so we 72640393Sbostic * create it, set OP_NOTMAIN and 72740393Sbostic * add it to the list, setting 72840393Sbostic * DEFAULT to the new node for 72940393Sbostic * later use. We claim the node is 73040393Sbostic * A transformation rule to make 73140393Sbostic * life easier later, when we'll 73240393Sbostic * use Make_HandleUse to actually 73340393Sbostic * apply the .DEFAULT commands. 73440393Sbostic * .BEGIN 73540393Sbostic * .END 73640393Sbostic * .INTERRUPT Are not to be considered the 73740393Sbostic * main target. 73840393Sbostic * .NOTPARALLEL Make only one target at a time. 73940393Sbostic * .SINGLESHELL Create a shell for each command. 74040393Sbostic * .ORDER Must set initial predecessor to NIL 74140393Sbostic */ 74240393Sbostic switch (specType) { 74360285Sbostic case ExPath: 74440393Sbostic if (paths == NULL) { 74540393Sbostic paths = Lst_Init(FALSE); 74640393Sbostic } 74740393Sbostic (void)Lst_AtEnd(paths, (ClientData)dirSearchPath); 74840393Sbostic break; 74940393Sbostic case Main: 75040393Sbostic if (!Lst_IsEmpty(create)) { 75140393Sbostic specType = Not; 75240393Sbostic } 75340393Sbostic break; 75440393Sbostic case Begin: 75540393Sbostic case End: 75640393Sbostic case Interrupt: 75740393Sbostic gn = Targ_FindNode(line, TARG_CREATE); 75840393Sbostic gn->type |= OP_NOTMAIN; 75940393Sbostic (void)Lst_AtEnd(targets, (ClientData)gn); 76040393Sbostic break; 76140393Sbostic case Default: 76240393Sbostic gn = Targ_NewGN(".DEFAULT"); 76340393Sbostic gn->type |= (OP_NOTMAIN|OP_TRANSFORM); 76440393Sbostic (void)Lst_AtEnd(targets, (ClientData)gn); 76540393Sbostic DEFAULT = gn; 76640393Sbostic break; 76740393Sbostic case NotParallel: 76840393Sbostic { 76940393Sbostic extern int maxJobs; 77040393Sbostic 77140393Sbostic maxJobs = 1; 77240393Sbostic break; 77340393Sbostic } 77440393Sbostic case SingleShell: 77560285Sbostic compatMake = 1; 77640393Sbostic break; 77740393Sbostic case Order: 77840393Sbostic predecessor = NILGNODE; 77940393Sbostic break; 78060285Sbostic default: 78160285Sbostic break; 78240393Sbostic } 78340393Sbostic } else if (strncmp (line, ".PATH", 5) == 0) { 78440393Sbostic /* 78540393Sbostic * .PATH<suffix> has to be handled specially. 78640393Sbostic * Call on the suffix module to give us a path to 78740393Sbostic * modify. 78840393Sbostic */ 78940393Sbostic Lst path; 79040393Sbostic 79160285Sbostic specType = ExPath; 79240393Sbostic path = Suff_GetPath (&line[5]); 79340393Sbostic if (path == NILLST) { 79440393Sbostic Parse_Error (PARSE_FATAL, 79540393Sbostic "Suffix '%s' not defined (yet)", 79640393Sbostic &line[5]); 79740393Sbostic return; 79840393Sbostic } else { 79940393Sbostic if (paths == (Lst)NULL) { 80040393Sbostic paths = Lst_Init(FALSE); 80140393Sbostic } 80240393Sbostic (void)Lst_AtEnd(paths, (ClientData)path); 80340393Sbostic } 80440393Sbostic } 80540393Sbostic } 80640393Sbostic 80740393Sbostic /* 80840393Sbostic * Have word in line. Get or create its node and stick it at 80940393Sbostic * the end of the targets list 81040393Sbostic */ 81140393Sbostic if ((specType == Not) && (*line != '\0')) { 81240393Sbostic if (Dir_HasWildcards(line)) { 81340393Sbostic /* 81440393Sbostic * Targets are to be sought only in the current directory, 81540393Sbostic * so create an empty path for the thing. Note we need to 81640393Sbostic * use Dir_Destroy in the destruction of the path as the 81740393Sbostic * Dir module could have added a directory to the path... 81840393Sbostic */ 81940393Sbostic Lst emptyPath = Lst_Init(FALSE); 82040393Sbostic 82140393Sbostic Dir_Expand(line, emptyPath, curTargs); 82240393Sbostic 82340393Sbostic Lst_Destroy(emptyPath, Dir_Destroy); 82440393Sbostic } else { 82540393Sbostic /* 82640393Sbostic * No wildcards, but we want to avoid code duplication, 82740393Sbostic * so create a list with the word on it. 82840393Sbostic */ 82940393Sbostic (void)Lst_AtEnd(curTargs, (ClientData)line); 83040393Sbostic } 83140393Sbostic 83240393Sbostic while(!Lst_IsEmpty(curTargs)) { 83340393Sbostic char *targName = (char *)Lst_DeQueue(curTargs); 83440393Sbostic 83540393Sbostic if (!Suff_IsTransform (targName)) { 83640393Sbostic gn = Targ_FindNode (targName, TARG_CREATE); 83740393Sbostic } else { 83840393Sbostic gn = Suff_AddTransform (targName); 83940393Sbostic } 84040393Sbostic 84140393Sbostic (void)Lst_AtEnd (targets, (ClientData)gn); 84240393Sbostic } 84360285Sbostic } else if (specType == ExPath && *line != '.' && *line != '\0') { 84440393Sbostic Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line); 84540393Sbostic } 84640393Sbostic 84740393Sbostic *cp = savec; 84840393Sbostic /* 84940393Sbostic * If it is a special type and not .PATH, it's the only target we 85040393Sbostic * allow on this line... 85140393Sbostic */ 85260285Sbostic if (specType != Not && specType != ExPath) { 85340393Sbostic Boolean warn = FALSE; 85440393Sbostic 85540393Sbostic while ((*cp != '!') && (*cp != ':') && *cp) { 85640393Sbostic if (*cp != ' ' && *cp != '\t') { 85740393Sbostic warn = TRUE; 85840393Sbostic } 85940393Sbostic cp++; 86040393Sbostic } 86140393Sbostic if (warn) { 86240393Sbostic Parse_Error(PARSE_WARNING, "Extra target ignored"); 86340393Sbostic } 86440393Sbostic } else { 86540393Sbostic while (*cp && isspace (*cp)) { 86640393Sbostic cp++; 86740393Sbostic } 86840393Sbostic } 86940393Sbostic line = cp; 87040393Sbostic } while ((*line != '!') && (*line != ':') && *line); 87140393Sbostic 87240393Sbostic /* 87340393Sbostic * Don't need the list of target names anymore... 87440393Sbostic */ 87540393Sbostic Lst_Destroy(curTargs, NOFREE); 87640393Sbostic 87740393Sbostic if (!Lst_IsEmpty(targets)) { 87840393Sbostic switch(specType) { 87940393Sbostic default: 88040393Sbostic Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. Mundane ones ignored"); 88140393Sbostic break; 88240393Sbostic case Default: 88340393Sbostic case Begin: 88440393Sbostic case End: 88540393Sbostic case Interrupt: 88640393Sbostic /* 88740393Sbostic * These four create nodes on which to hang commands, so 88840393Sbostic * targets shouldn't be empty... 88940393Sbostic */ 89040393Sbostic case Not: 89140393Sbostic /* 89240393Sbostic * Nothing special here -- targets can be empty if it wants. 89340393Sbostic */ 89440393Sbostic break; 89540393Sbostic } 89640393Sbostic } 89740393Sbostic 89840393Sbostic /* 89940393Sbostic * Have now parsed all the target names. Must parse the operator next. The 90040393Sbostic * result is left in op . 90140393Sbostic */ 90240393Sbostic if (*cp == '!') { 90340393Sbostic op = OP_FORCE; 90440393Sbostic } else if (*cp == ':') { 90540393Sbostic if (cp[1] == ':') { 90640393Sbostic op = OP_DOUBLEDEP; 90740393Sbostic cp++; 90840393Sbostic } else { 90940393Sbostic op = OP_DEPENDS; 91040393Sbostic } 91140393Sbostic } else { 91240393Sbostic Parse_Error (PARSE_FATAL, "Missing dependency operator"); 91340393Sbostic return; 91440393Sbostic } 91540393Sbostic 91640393Sbostic cp++; /* Advance beyond operator */ 91740393Sbostic 918*69086Schristos Lst_ForEach (targets, ParseDoOp, (ClientData)&op); 91940393Sbostic 92040393Sbostic /* 92140393Sbostic * Get to the first source 92240393Sbostic */ 92340393Sbostic while (*cp && isspace (*cp)) { 92440393Sbostic cp++; 92540393Sbostic } 92640393Sbostic line = cp; 92740393Sbostic 92840393Sbostic /* 92940393Sbostic * Several special targets take different actions if present with no 93040393Sbostic * sources: 93140393Sbostic * a .SUFFIXES line with no sources clears out all old suffixes 93240393Sbostic * a .PRECIOUS line makes all targets precious 93340393Sbostic * a .IGNORE line ignores errors for all targets 93440393Sbostic * a .SILENT line creates silence when making all targets 93540393Sbostic * a .PATH removes all directories from the search path(s). 93640393Sbostic */ 93740393Sbostic if (!*line) { 93840393Sbostic switch (specType) { 93940393Sbostic case Suffixes: 94040393Sbostic Suff_ClearSuffixes (); 94140393Sbostic break; 94240393Sbostic case Precious: 94340393Sbostic allPrecious = TRUE; 94440393Sbostic break; 94540393Sbostic case Ignore: 94640393Sbostic ignoreErrors = TRUE; 94740393Sbostic break; 94840393Sbostic case Silent: 94940393Sbostic beSilent = TRUE; 95040393Sbostic break; 95160285Sbostic case ExPath: 95240393Sbostic Lst_ForEach(paths, ParseClearPath, (ClientData)NULL); 95340393Sbostic break; 95460285Sbostic default: 95560285Sbostic break; 95640393Sbostic } 95740393Sbostic } else if (specType == MFlags) { 95840393Sbostic /* 95940393Sbostic * Call on functions in main.c to deal with these arguments and 96040393Sbostic * set the initial character to a null-character so the loop to 96140393Sbostic * get sources won't get anything 96240393Sbostic */ 96340393Sbostic Main_ParseArgLine (line); 96440393Sbostic *line = '\0'; 96560285Sbostic } else if (specType == ExShell) { 96640393Sbostic if (Job_ParseShell (line) != SUCCESS) { 96740393Sbostic Parse_Error (PARSE_FATAL, "improper shell specification"); 96840393Sbostic return; 96940393Sbostic } 97040393Sbostic *line = '\0'; 97140393Sbostic } else if ((specType == NotParallel) || (specType == SingleShell)) { 97240393Sbostic *line = '\0'; 97340393Sbostic } 97440393Sbostic 97540393Sbostic /* 97640393Sbostic * NOW GO FOR THE SOURCES 97740393Sbostic */ 97860285Sbostic if ((specType == Suffixes) || (specType == ExPath) || 97940393Sbostic (specType == Includes) || (specType == Libs) || 98040439Sbostic (specType == Null)) 98140393Sbostic { 98240393Sbostic while (*line) { 98340393Sbostic /* 98440393Sbostic * If the target was one that doesn't take files as its sources 98540393Sbostic * but takes something like suffixes, we take each 98640393Sbostic * space-separated word on the line as a something and deal 98740393Sbostic * with it accordingly. 98840393Sbostic * 98940393Sbostic * If the target was .SUFFIXES, we take each source as a 99040393Sbostic * suffix and add it to the list of suffixes maintained by the 99140393Sbostic * Suff module. 99240393Sbostic * 99340393Sbostic * If the target was a .PATH, we add the source as a directory 99440393Sbostic * to search on the search path. 99540393Sbostic * 99640393Sbostic * If it was .INCLUDES, the source is taken to be the suffix of 99740393Sbostic * files which will be #included and whose search path should 99840393Sbostic * be present in the .INCLUDES variable. 99940393Sbostic * 100040393Sbostic * If it was .LIBS, the source is taken to be the suffix of 100140393Sbostic * files which are considered libraries and whose search path 100240393Sbostic * should be present in the .LIBS variable. 100340393Sbostic * 100440393Sbostic * If it was .NULL, the source is the suffix to use when a file 100540393Sbostic * has no valid suffix. 100640393Sbostic */ 100740393Sbostic char savec; 100840393Sbostic while (*cp && !isspace (*cp)) { 100940393Sbostic cp++; 101040393Sbostic } 101140393Sbostic savec = *cp; 101240393Sbostic *cp = '\0'; 101340393Sbostic switch (specType) { 101440393Sbostic case Suffixes: 101540393Sbostic Suff_AddSuffix (line); 101640393Sbostic break; 101760285Sbostic case ExPath: 101840393Sbostic Lst_ForEach(paths, ParseAddDir, (ClientData)line); 101940393Sbostic break; 102040393Sbostic case Includes: 102140393Sbostic Suff_AddInclude (line); 102240393Sbostic break; 102340393Sbostic case Libs: 102440393Sbostic Suff_AddLib (line); 102540393Sbostic break; 102640393Sbostic case Null: 102740393Sbostic Suff_SetNull (line); 102840393Sbostic break; 102960285Sbostic default: 103060285Sbostic break; 103140393Sbostic } 103240393Sbostic *cp = savec; 103340393Sbostic if (savec != '\0') { 103440393Sbostic cp++; 103540393Sbostic } 103640393Sbostic while (*cp && isspace (*cp)) { 103740393Sbostic cp++; 103840393Sbostic } 103940393Sbostic line = cp; 104040393Sbostic } 104140393Sbostic if (paths) { 104240393Sbostic Lst_Destroy(paths, NOFREE); 104340393Sbostic } 104440393Sbostic } else { 104540393Sbostic while (*line) { 104640393Sbostic /* 104740393Sbostic * The targets take real sources, so we must beware of archive 104840393Sbostic * specifications (i.e. things with left parentheses in them) 104940393Sbostic * and handle them accordingly. 105040393Sbostic */ 105140393Sbostic while (*cp && !isspace (*cp)) { 105240393Sbostic if ((*cp == '(') && (cp > line) && (cp[-1] != '$')) { 105340393Sbostic /* 105440393Sbostic * Only stop for a left parenthesis if it isn't at the 105540393Sbostic * start of a word (that'll be for variable changes 105640393Sbostic * later) and isn't preceded by a dollar sign (a dynamic 105740393Sbostic * source). 105840393Sbostic */ 105940393Sbostic break; 106040393Sbostic } else { 106140393Sbostic cp++; 106240393Sbostic } 106340393Sbostic } 106440393Sbostic 106540393Sbostic if (*cp == '(') { 106640393Sbostic GNode *gn; 106740393Sbostic 106840393Sbostic sources = Lst_Init (FALSE); 106940393Sbostic if (Arch_ParseArchive (&line, sources, VAR_CMD) != SUCCESS) { 107040393Sbostic Parse_Error (PARSE_FATAL, 107140393Sbostic "Error in source archive spec \"%s\"", line); 107240393Sbostic return; 107340393Sbostic } 107440393Sbostic 107540393Sbostic while (!Lst_IsEmpty (sources)) { 107640393Sbostic gn = (GNode *) Lst_DeQueue (sources); 107740393Sbostic ParseDoSrc (tOp, gn->name); 107840393Sbostic } 107940393Sbostic Lst_Destroy (sources, NOFREE); 108040393Sbostic cp = line; 108140393Sbostic } else { 108240393Sbostic if (*cp) { 108340393Sbostic *cp = '\0'; 108440393Sbostic cp += 1; 108540393Sbostic } 108640393Sbostic 108740393Sbostic ParseDoSrc (tOp, line); 108840393Sbostic } 108940393Sbostic while (*cp && isspace (*cp)) { 109040393Sbostic cp++; 109140393Sbostic } 109240393Sbostic line = cp; 109340393Sbostic } 109440393Sbostic } 109540393Sbostic 109640393Sbostic if (mainNode == NILGNODE) { 109740393Sbostic /* 109840393Sbostic * If we have yet to decide on a main target to make, in the 109940393Sbostic * absence of any user input, we want the first target on 110040393Sbostic * the first dependency line that is actually a real target 110140393Sbostic * (i.e. isn't a .USE or .EXEC rule) to be made. 110240393Sbostic */ 110340393Sbostic Lst_ForEach (targets, ParseFindMain, (ClientData)0); 110440393Sbostic } 110540393Sbostic 110640393Sbostic } 110740424Sbostic 110840393Sbostic /*- 110940393Sbostic *--------------------------------------------------------------------- 111040393Sbostic * Parse_IsVar -- 111140393Sbostic * Return TRUE if the passed line is a variable assignment. A variable 111240393Sbostic * assignment consists of a single word followed by optional whitespace 111340393Sbostic * followed by either a += or an = operator. 111440393Sbostic * This function is used both by the Parse_File function and main when 111540393Sbostic * parsing the command-line arguments. 111640393Sbostic * 111740393Sbostic * Results: 111840393Sbostic * TRUE if it is. FALSE if it ain't 111940393Sbostic * 112040393Sbostic * Side Effects: 112140393Sbostic * none 112240393Sbostic *--------------------------------------------------------------------- 112340393Sbostic */ 112440393Sbostic Boolean 112540393Sbostic Parse_IsVar (line) 112640393Sbostic register char *line; /* the line to check */ 112740393Sbostic { 112840393Sbostic register Boolean wasSpace = FALSE; /* set TRUE if found a space */ 112940393Sbostic register Boolean haveName = FALSE; /* Set TRUE if have a variable name */ 113040393Sbostic 113140393Sbostic /* 113240393Sbostic * Skip to variable name 113340393Sbostic */ 113440393Sbostic while ((*line == ' ') || (*line == '\t')) { 113540393Sbostic line++; 113640393Sbostic } 113740393Sbostic 113840393Sbostic while (*line != '=') { 113940393Sbostic if (*line == '\0') { 114040393Sbostic /* 114140393Sbostic * end-of-line -- can't be a variable assignment. 114240393Sbostic */ 114340393Sbostic return (FALSE); 114440393Sbostic } else if ((*line == ' ') || (*line == '\t')) { 114540393Sbostic /* 114640393Sbostic * there can be as much white space as desired so long as there is 114740393Sbostic * only one word before the operator 114840393Sbostic */ 114940393Sbostic wasSpace = TRUE; 115040393Sbostic } else if (wasSpace && haveName) { 115140393Sbostic /* 115240393Sbostic * Stop when an = operator is found. 115340393Sbostic */ 115440393Sbostic if ((*line == '+') || (*line == ':') || (*line == '?') || 115540393Sbostic (*line == '!')) { 115640393Sbostic break; 115740393Sbostic } 115840393Sbostic 115940393Sbostic /* 116040393Sbostic * This is the start of another word, so not assignment. 116140393Sbostic */ 116240393Sbostic return (FALSE); 116340393Sbostic } else { 116440393Sbostic haveName = TRUE; 116540393Sbostic wasSpace = FALSE; 116640393Sbostic } 116740393Sbostic line++; 116840393Sbostic } 116940393Sbostic 117040393Sbostic /* 117140393Sbostic * A final check: if we stopped on a +, ?, ! or :, the next character must 117240393Sbostic * be an = or it ain't a valid assignment 117340393Sbostic */ 117440393Sbostic if (((*line == '+') || 117540393Sbostic (*line == '?') || 117640393Sbostic (*line == ':') || 117740393Sbostic (*line == '!')) && 117840393Sbostic (line[1] != '=')) 117940393Sbostic { 118040393Sbostic return (FALSE); 118140393Sbostic } else { 118240393Sbostic return (haveName); 118340393Sbostic } 118440393Sbostic } 118540424Sbostic 118640393Sbostic /*- 118740393Sbostic *--------------------------------------------------------------------- 118840393Sbostic * Parse_DoVar -- 118940393Sbostic * Take the variable assignment in the passed line and do it in the 119040393Sbostic * global context. 119140393Sbostic * 119240393Sbostic * Note: There is a lexical ambiguity with assignment modifier characters 119340393Sbostic * in variable names. This routine interprets the character before the = 119440393Sbostic * as a modifier. Therefore, an assignment like 119540393Sbostic * C++=/usr/bin/CC 119640393Sbostic * is interpreted as "C+ +=" instead of "C++ =". 119740393Sbostic * 119840393Sbostic * Results: 119940393Sbostic * none 120040393Sbostic * 120140393Sbostic * Side Effects: 120240393Sbostic * the variable structure of the given variable name is altered in the 120340393Sbostic * global context. 120440393Sbostic *--------------------------------------------------------------------- 120540393Sbostic */ 120640393Sbostic void 120740393Sbostic Parse_DoVar (line, ctxt) 120840393Sbostic char *line; /* a line guaranteed to be a variable 120940393Sbostic * assignment. This reduces error checks */ 121040393Sbostic GNode *ctxt; /* Context in which to do the assignment */ 121140393Sbostic { 1212*69086Schristos char *cp; /* pointer into line */ 121340393Sbostic enum { 121440393Sbostic VAR_SUBST, VAR_APPEND, VAR_SHELL, VAR_NORMAL 121540393Sbostic } type; /* Type of assignment */ 121640393Sbostic char *opc; /* ptr to operator character to 121740393Sbostic * null-terminate the variable name */ 1218*69086Schristos /* 121966399Schristos * Avoid clobbered variable warnings by forcing the compiler 122066399Schristos * to ``unregister'' variables 1221*69086Schristos */ 122266399Schristos #if __GNUC__ 1223*69086Schristos (void) &cp; 1224*69086Schristos (void) &line; 1225*69086Schristos #endif 122640393Sbostic 122740393Sbostic /* 122840393Sbostic * Skip to variable name 122940393Sbostic */ 123040393Sbostic while ((*line == ' ') || (*line == '\t')) { 123140393Sbostic line++; 123240393Sbostic } 123340393Sbostic 123440393Sbostic /* 123540393Sbostic * Skip to operator character, nulling out whitespace as we go 123640393Sbostic */ 123740393Sbostic for (cp = line + 1; *cp != '='; cp++) { 123840393Sbostic if (isspace (*cp)) { 123940393Sbostic *cp = '\0'; 124040393Sbostic } 124140393Sbostic } 124240393Sbostic opc = cp-1; /* operator is the previous character */ 124340393Sbostic *cp++ = '\0'; /* nuke the = */ 124440393Sbostic 124540393Sbostic /* 124640393Sbostic * Check operator type 124740393Sbostic */ 124840393Sbostic switch (*opc) { 124940393Sbostic case '+': 125040393Sbostic type = VAR_APPEND; 125140393Sbostic *opc = '\0'; 125240393Sbostic break; 125340393Sbostic 125440393Sbostic case '?': 125540393Sbostic /* 125640393Sbostic * If the variable already has a value, we don't do anything. 125740393Sbostic */ 125840393Sbostic *opc = '\0'; 125940393Sbostic if (Var_Exists(line, ctxt)) { 126040393Sbostic return; 126140393Sbostic } else { 126240393Sbostic type = VAR_NORMAL; 126340393Sbostic } 126440393Sbostic break; 126540393Sbostic 126640393Sbostic case ':': 126740393Sbostic type = VAR_SUBST; 126840393Sbostic *opc = '\0'; 126940393Sbostic break; 127040393Sbostic 127140393Sbostic case '!': 127240393Sbostic type = VAR_SHELL; 127340393Sbostic *opc = '\0'; 127440393Sbostic break; 127540393Sbostic 127640393Sbostic default: 127740393Sbostic type = VAR_NORMAL; 127840393Sbostic break; 127940393Sbostic } 128040393Sbostic 128140393Sbostic while (isspace (*cp)) { 128240393Sbostic cp++; 128340393Sbostic } 128440393Sbostic 128540393Sbostic if (type == VAR_APPEND) { 128640393Sbostic Var_Append (line, cp, ctxt); 128740393Sbostic } else if (type == VAR_SUBST) { 128840393Sbostic /* 128940393Sbostic * Allow variables in the old value to be undefined, but leave their 129040393Sbostic * invocation alone -- this is done by forcing oldVars to be false. 129140393Sbostic * XXX: This can cause recursive variables, but that's not hard to do, 129240393Sbostic * and this allows someone to do something like 129340393Sbostic * 129440393Sbostic * CFLAGS = $(.INCLUDES) 129540393Sbostic * CFLAGS := -I.. $(CFLAGS) 129640393Sbostic * 129740393Sbostic * And not get an error. 129840393Sbostic */ 129940393Sbostic Boolean oldOldVars = oldVars; 130040393Sbostic 130140393Sbostic oldVars = FALSE; 130260285Sbostic cp = Var_Subst(NULL, cp, ctxt, FALSE); 130340393Sbostic oldVars = oldOldVars; 130440393Sbostic 130540393Sbostic Var_Set(line, cp, ctxt); 130640393Sbostic free(cp); 130740393Sbostic } else if (type == VAR_SHELL) { 130840393Sbostic char *args[4]; /* Args for invoking the shell */ 130940393Sbostic int fds[2]; /* Pipe streams */ 131040393Sbostic int cpid; /* Child PID */ 131140393Sbostic int pid; /* PID from wait() */ 131240393Sbostic Boolean freeCmd; /* TRUE if the command needs to be freed, i.e. 131340393Sbostic * if any variable expansion was performed */ 131440393Sbostic 1315*69086Schristos /* 131666399Schristos * Avoid clobbered variable warnings by forcing the compiler 131766399Schristos * to ``unregister'' variables 1318*69086Schristos */ 131966399Schristos #if __GNUC__ 132066399Schristos (void) &freeCmd; 1321*69086Schristos #endif 1322*69086Schristos 132340393Sbostic /* 132440393Sbostic * Set up arguments for shell 132540393Sbostic */ 132640393Sbostic args[0] = "sh"; 132740393Sbostic args[1] = "-c"; 132860285Sbostic if (strchr(cp, '$') != (char *)NULL) { 132940393Sbostic /* 133040393Sbostic * There's a dollar sign in the command, so perform variable 133140393Sbostic * expansion on the whole thing. The resulting string will need 133240393Sbostic * freeing when we're done, so set freeCmd to TRUE. 133340393Sbostic */ 133460285Sbostic args[2] = Var_Subst(NULL, cp, VAR_CMD, TRUE); 133540393Sbostic freeCmd = TRUE; 133640393Sbostic } else { 133740393Sbostic args[2] = cp; 133840393Sbostic freeCmd = FALSE; 133940393Sbostic } 134040393Sbostic args[3] = (char *)NULL; 134140393Sbostic 134240393Sbostic /* 134340393Sbostic * Open a pipe for fetching its output 134440393Sbostic */ 134540393Sbostic pipe(fds); 134640393Sbostic 134740393Sbostic /* 134840393Sbostic * Fork 134940393Sbostic */ 135040393Sbostic cpid = vfork(); 135140393Sbostic if (cpid == 0) { 135240393Sbostic /* 135340393Sbostic * Close input side of pipe 135440393Sbostic */ 135540393Sbostic close(fds[0]); 135640393Sbostic 135740393Sbostic /* 135840393Sbostic * Duplicate the output stream to the shell's output, then 135940393Sbostic * shut the extra thing down. Note we don't fetch the error 136040393Sbostic * stream...why not? Why? 136140393Sbostic */ 136240393Sbostic dup2(fds[1], 1); 136340393Sbostic close(fds[1]); 136440393Sbostic 136540393Sbostic execv("/bin/sh", args); 136640393Sbostic _exit(1); 136740393Sbostic } else if (cpid < 0) { 136840393Sbostic /* 136940393Sbostic * Couldn't fork -- tell the user and make the variable null 137040393Sbostic */ 137140393Sbostic Parse_Error(PARSE_WARNING, "Couldn't exec \"%s\"", cp); 137240393Sbostic Var_Set(line, "", ctxt); 137340393Sbostic } else { 137440393Sbostic int status; 137540393Sbostic int cc; 137660285Sbostic Buffer buf; 137760285Sbostic char *res; 137840393Sbostic 137940393Sbostic /* 138040393Sbostic * No need for the writing half 138140393Sbostic */ 138240393Sbostic close(fds[1]); 138340393Sbostic 138460285Sbostic buf = Buf_Init (MAKE_BSIZE); 138560285Sbostic 138660285Sbostic do { 138760285Sbostic char result[BUFSIZ]; 138860285Sbostic cc = read(fds[0], result, sizeof(result)); 138960285Sbostic if (cc > 0) 1390*69086Schristos Buf_AddBytes(buf, cc, (Byte *) result); 139160285Sbostic } 139260285Sbostic while (cc > 0 || (cc == -1 && errno == EINTR)); 139360285Sbostic 139440393Sbostic /* 139560285Sbostic * Close the input side of the pipe. 139640393Sbostic */ 139760285Sbostic close(fds[0]); 139840393Sbostic 139940393Sbostic /* 140060285Sbostic * Wait for the process to exit. 140140393Sbostic */ 140260285Sbostic while(((pid = wait(&status)) != cpid) && (pid >= 0)) 140360285Sbostic continue; 140440393Sbostic 140560285Sbostic res = (char *)Buf_GetAll (buf, &cc); 140660285Sbostic Buf_Destroy (buf, FALSE); 140760285Sbostic 140860285Sbostic if (cc == 0) { 140940393Sbostic /* 141040393Sbostic * Couldn't read the child's output -- tell the user and 141140393Sbostic * set the variable to null 141240393Sbostic */ 141340393Sbostic Parse_Error(PARSE_WARNING, "Couldn't read shell's output"); 141440393Sbostic } 141540393Sbostic 141640393Sbostic if (status) { 141740393Sbostic /* 141840393Sbostic * Child returned an error -- tell the user but still use 141940393Sbostic * the result. 142040393Sbostic */ 142140393Sbostic Parse_Error(PARSE_WARNING, "\"%s\" returned non-zero", cp); 142240393Sbostic } 142360285Sbostic 142440393Sbostic /* 142540393Sbostic * Null-terminate the result, convert newlines to spaces and 142640393Sbostic * install it in the variable. 142740393Sbostic */ 142860285Sbostic res[cc] = '\0'; 142960285Sbostic cp = &res[cc] - 1; 143040393Sbostic 143140393Sbostic if (*cp == '\n') { 143240393Sbostic /* 143340393Sbostic * A final newline is just stripped 143440393Sbostic */ 143540393Sbostic *cp-- = '\0'; 143640393Sbostic } 143760285Sbostic while (cp >= res) { 143840393Sbostic if (*cp == '\n') { 143940393Sbostic *cp = ' '; 144040393Sbostic } 144140393Sbostic cp--; 144240393Sbostic } 144360285Sbostic Var_Set(line, res, ctxt); 144460285Sbostic free(res); 144540393Sbostic 144640393Sbostic } 144740393Sbostic if (freeCmd) { 144840393Sbostic free(args[2]); 144940393Sbostic } 145040393Sbostic } else { 145140393Sbostic /* 145240393Sbostic * Normal assignment -- just do it. 145340393Sbostic */ 145440393Sbostic Var_Set (line, cp, ctxt); 145540393Sbostic } 145640393Sbostic } 145740424Sbostic 145840393Sbostic /*- 145940393Sbostic * ParseAddCmd -- 146040393Sbostic * Lst_ForEach function to add a command line to all targets 146140393Sbostic * 146240393Sbostic * Results: 146340393Sbostic * Always 0 146440393Sbostic * 146540393Sbostic * Side Effects: 146640393Sbostic * A new element is added to the commands list of the node. 146740393Sbostic */ 146860285Sbostic static int 1469*69086Schristos ParseAddCmd(gnp, cmd) 1470*69086Schristos ClientData gnp; /* the node to which the command is to be added */ 1471*69086Schristos ClientData cmd; /* the command to add */ 147240393Sbostic { 1473*69086Schristos GNode *gn = (GNode *) gnp; 1474*69086Schristos /* if target already supplied, ignore commands */ 1475*69086Schristos if (!(gn->type & OP_HAS_COMMANDS)) 1476*69086Schristos (void)Lst_AtEnd(gn->commands, cmd); 1477*69086Schristos return(0); 147840393Sbostic } 147940424Sbostic 148040393Sbostic /*- 148140393Sbostic *----------------------------------------------------------------------- 148240393Sbostic * ParseHasCommands -- 148340393Sbostic * Callback procedure for Parse_File when destroying the list of 148440393Sbostic * targets on the last dependency line. Marks a target as already 148540393Sbostic * having commands if it does, to keep from having shell commands 148640393Sbostic * on multiple dependency lines. 148740393Sbostic * 148840393Sbostic * Results: 1489*69086Schristos * None 149040393Sbostic * 149140393Sbostic * Side Effects: 149240393Sbostic * OP_HAS_COMMANDS may be set for the target. 149340393Sbostic * 149440393Sbostic *----------------------------------------------------------------------- 149540393Sbostic */ 1496*69086Schristos static void 1497*69086Schristos ParseHasCommands(gnp) 1498*69086Schristos ClientData gnp; /* Node to examine */ 149940393Sbostic { 1500*69086Schristos GNode *gn = (GNode *) gnp; 150140393Sbostic if (!Lst_IsEmpty(gn->commands)) { 150240393Sbostic gn->type |= OP_HAS_COMMANDS; 150340393Sbostic } 150440393Sbostic } 150540424Sbostic 150640393Sbostic /*- 150740393Sbostic *----------------------------------------------------------------------- 150840393Sbostic * Parse_AddIncludeDir -- 150940393Sbostic * Add a directory to the path searched for included makefiles 151040393Sbostic * bracketed by double-quotes. Used by functions in main.c 151140393Sbostic * 151240393Sbostic * Results: 151340393Sbostic * None. 151440393Sbostic * 151540393Sbostic * Side Effects: 151640393Sbostic * The directory is appended to the list. 151740393Sbostic * 151840393Sbostic *----------------------------------------------------------------------- 151940393Sbostic */ 152040393Sbostic void 152140393Sbostic Parse_AddIncludeDir (dir) 152240393Sbostic char *dir; /* The name of the directory to add */ 152340393Sbostic { 152440393Sbostic Dir_AddDir (parseIncPath, dir); 152540393Sbostic } 152640424Sbostic 152740393Sbostic /*- 152840393Sbostic *--------------------------------------------------------------------- 152940393Sbostic * ParseDoInclude -- 153040393Sbostic * Push to another file. 153140393Sbostic * 153240393Sbostic * The input is the line minus the #include. A file spec is a string 153340393Sbostic * enclosed in <> or "". The former is looked for only in sysIncPath. 153440393Sbostic * The latter in . and the directories specified by -I command line 153540393Sbostic * options 153640393Sbostic * 153740393Sbostic * Results: 153840393Sbostic * None 153940393Sbostic * 154040393Sbostic * Side Effects: 154140393Sbostic * A structure is added to the includes Lst and readProc, lineno, 154240393Sbostic * fname and curFILE are altered for the new file 154340393Sbostic *--------------------------------------------------------------------- 154440393Sbostic */ 154540393Sbostic static void 154640393Sbostic ParseDoInclude (file) 154740393Sbostic char *file; /* file specification */ 154840393Sbostic { 154940393Sbostic char *fullname; /* full pathname of file */ 155040393Sbostic IFile *oldFile; /* state associated with current file */ 155140393Sbostic char endc; /* the character which ends the file spec */ 155240393Sbostic char *cp; /* current position in file spec */ 155340393Sbostic Boolean isSystem; /* TRUE if makefile is a system makefile */ 155440393Sbostic 155540393Sbostic /* 155640393Sbostic * Skip to delimiter character so we know where to look 155740393Sbostic */ 155840393Sbostic while ((*file == ' ') || (*file == '\t')) { 155940393Sbostic file++; 156040393Sbostic } 156140393Sbostic 156240393Sbostic if ((*file != '"') && (*file != '<')) { 156342443Sbostic Parse_Error (PARSE_FATAL, 156442443Sbostic ".include filename must be delimited by '\"' or '<'"); 156540393Sbostic return; 156640393Sbostic } 156740393Sbostic 156840393Sbostic /* 156940393Sbostic * Set the search path on which to find the include file based on the 157040393Sbostic * characters which bracket its name. Angle-brackets imply it's 157140393Sbostic * a system Makefile while double-quotes imply it's a user makefile 157240393Sbostic */ 157340393Sbostic if (*file == '<') { 157440393Sbostic isSystem = TRUE; 157540393Sbostic endc = '>'; 157640393Sbostic } else { 157740393Sbostic isSystem = FALSE; 157840393Sbostic endc = '"'; 157940393Sbostic } 158040393Sbostic 158140393Sbostic /* 158240393Sbostic * Skip to matching delimiter 158340393Sbostic */ 158440393Sbostic for (cp = ++file; *cp && *cp != endc; cp++) { 158540393Sbostic continue; 158640393Sbostic } 158740393Sbostic 158840393Sbostic if (*cp != endc) { 158940393Sbostic Parse_Error (PARSE_FATAL, 159060285Sbostic "Unclosed %cinclude filename. '%c' expected", 159160285Sbostic '.', endc); 159240393Sbostic return; 159340393Sbostic } 159440393Sbostic *cp = '\0'; 159540393Sbostic 159640393Sbostic /* 159740393Sbostic * Substitute for any variables in the file name before trying to 159840393Sbostic * find the thing. 159940393Sbostic */ 160060285Sbostic file = Var_Subst (NULL, file, VAR_CMD, FALSE); 160140393Sbostic 160240393Sbostic /* 160340393Sbostic * Now we know the file's name and its search path, we attempt to 160440393Sbostic * find the durn thing. A return of NULL indicates the file don't 160540393Sbostic * exist. 160640393Sbostic */ 160740393Sbostic if (!isSystem) { 160840393Sbostic /* 160940393Sbostic * Include files contained in double-quotes are first searched for 161040393Sbostic * relative to the including file's location. We don't want to 161140393Sbostic * cd there, of course, so we just tack on the old file's 161240393Sbostic * leading path components and call Dir_FindFile to see if 161340393Sbostic * we can locate the beast. 161440393Sbostic */ 161540393Sbostic char *prefEnd; 161640393Sbostic 161760285Sbostic prefEnd = strrchr (fname, '/'); 161840393Sbostic if (prefEnd != (char *)NULL) { 161940393Sbostic char *newName; 162040393Sbostic 162140393Sbostic *prefEnd = '\0'; 1622*69086Schristos if (file[0] == '/') 1623*69086Schristos newName = strdup(file); 1624*69086Schristos else 1625*69086Schristos newName = str_concat (fname, file, STR_ADDSLASH); 162640393Sbostic fullname = Dir_FindFile (newName, parseIncPath); 162740393Sbostic if (fullname == (char *)NULL) { 162840393Sbostic fullname = Dir_FindFile(newName, dirSearchPath); 162940393Sbostic } 163040393Sbostic free (newName); 163140393Sbostic *prefEnd = '/'; 163240393Sbostic } else { 163340393Sbostic fullname = (char *)NULL; 163440393Sbostic } 163540393Sbostic } else { 163640393Sbostic fullname = (char *)NULL; 163740393Sbostic } 163840393Sbostic 163940393Sbostic if (fullname == (char *)NULL) { 164040393Sbostic /* 164140393Sbostic * System makefile or makefile wasn't found in same directory as 164240393Sbostic * included makefile. Search for it first on the -I search path, 164340393Sbostic * then on the .PATH search path, if not found in a -I directory. 164440393Sbostic * XXX: Suffix specific? 164540393Sbostic */ 164640393Sbostic fullname = Dir_FindFile (file, parseIncPath); 164740393Sbostic if (fullname == (char *)NULL) { 164840393Sbostic fullname = Dir_FindFile(file, dirSearchPath); 164940393Sbostic } 165040393Sbostic } 165140393Sbostic 165240393Sbostic if (fullname == (char *)NULL) { 165340393Sbostic /* 165440393Sbostic * Still haven't found the makefile. Look for it on the system 165540393Sbostic * path as a last resort. 165640393Sbostic */ 165740393Sbostic fullname = Dir_FindFile(file, sysIncPath); 165840393Sbostic } 165940393Sbostic 166040393Sbostic if (fullname == (char *) NULL) { 166140393Sbostic *cp = endc; 166240393Sbostic Parse_Error (PARSE_FATAL, "Could not find %s", file); 166340393Sbostic return; 166440393Sbostic } 166540393Sbostic 1666*69086Schristos free(file); 1667*69086Schristos 166840393Sbostic /* 166940393Sbostic * Once we find the absolute path to the file, we get to save all the 167040393Sbostic * state from the current file before we can start reading this 167140393Sbostic * include file. The state is stored in an IFile structure which 167240393Sbostic * is placed on a list with other IFile structures. The list makes 167340393Sbostic * a very nice stack to track how we got here... 167440393Sbostic */ 167540534Sbostic oldFile = (IFile *) emalloc (sizeof (IFile)); 167640393Sbostic oldFile->fname = fname; 167740393Sbostic 167840393Sbostic oldFile->F = curFILE; 167960285Sbostic oldFile->p = curPTR; 168040393Sbostic oldFile->lineno = lineno; 168140393Sbostic 168240393Sbostic (void) Lst_AtFront (includes, (ClientData)oldFile); 168340393Sbostic 168440393Sbostic /* 168540393Sbostic * Once the previous state has been saved, we can get down to reading 168640393Sbostic * the new file. We set up the name of the file to be the absolute 168740393Sbostic * name of the include file so error messages refer to the right 168840393Sbostic * place. Naturally enough, we start reading at line number 0. 168940393Sbostic */ 169040393Sbostic fname = fullname; 169140393Sbostic lineno = 0; 169240393Sbostic 169340393Sbostic curFILE = fopen (fullname, "r"); 169460285Sbostic curPTR = NULL; 169540393Sbostic if (curFILE == (FILE * ) NULL) { 169640393Sbostic Parse_Error (PARSE_FATAL, "Cannot open %s", fullname); 169740393Sbostic /* 169840393Sbostic * Pop to previous file 169940393Sbostic */ 170046462Sbostic (void) ParseEOF(0); 170140393Sbostic } 170240393Sbostic } 170340424Sbostic 170460285Sbostic 170540393Sbostic /*- 170640393Sbostic *--------------------------------------------------------------------- 170760285Sbostic * Parse_FromString -- 170860285Sbostic * Start Parsing from the given string 170960285Sbostic * 171060285Sbostic * Results: 171160285Sbostic * None 171260285Sbostic * 171360285Sbostic * Side Effects: 171460285Sbostic * A structure is added to the includes Lst and readProc, lineno, 171560285Sbostic * fname and curFILE are altered for the new file 171660285Sbostic *--------------------------------------------------------------------- 171760285Sbostic */ 171860285Sbostic void 171960285Sbostic Parse_FromString(str) 172060285Sbostic char *str; 172160285Sbostic { 172260285Sbostic IFile *oldFile; /* state associated with this file */ 172360285Sbostic 172460285Sbostic if (DEBUG(FOR)) 172560285Sbostic (void) fprintf(stderr, "%s\n----\n", str); 172660285Sbostic 172760285Sbostic oldFile = (IFile *) emalloc (sizeof (IFile)); 172860285Sbostic oldFile->lineno = lineno; 172960285Sbostic oldFile->fname = fname; 173060285Sbostic oldFile->F = curFILE; 173160285Sbostic oldFile->p = curPTR; 173260285Sbostic 173360285Sbostic (void) Lst_AtFront (includes, (ClientData)oldFile); 173460285Sbostic 173560285Sbostic curFILE = NULL; 173660285Sbostic curPTR = (PTR *) emalloc (sizeof (PTR)); 173760285Sbostic curPTR->str = curPTR->ptr = str; 173860285Sbostic lineno = 0; 173960285Sbostic fname = strdup(fname); 174060285Sbostic } 174160285Sbostic 174260285Sbostic 174360285Sbostic #ifdef SYSVINCLUDE 174460285Sbostic /*- 174560285Sbostic *--------------------------------------------------------------------- 174660285Sbostic * ParseTraditionalInclude -- 174760285Sbostic * Push to another file. 174860285Sbostic * 174960285Sbostic * The input is the line minus the "include". The file name is 175060285Sbostic * the string following the "include". 175160285Sbostic * 175260285Sbostic * Results: 175360285Sbostic * None 175460285Sbostic * 175560285Sbostic * Side Effects: 175660285Sbostic * A structure is added to the includes Lst and readProc, lineno, 175760285Sbostic * fname and curFILE are altered for the new file 175860285Sbostic *--------------------------------------------------------------------- 175960285Sbostic */ 176060285Sbostic static void 176160285Sbostic ParseTraditionalInclude (file) 176260285Sbostic char *file; /* file specification */ 176360285Sbostic { 176460285Sbostic char *fullname; /* full pathname of file */ 176560285Sbostic IFile *oldFile; /* state associated with current file */ 176660285Sbostic char *cp; /* current position in file spec */ 176760285Sbostic char *prefEnd; 176860285Sbostic 176960285Sbostic /* 177060285Sbostic * Skip over whitespace 177160285Sbostic */ 177260285Sbostic while ((*file == ' ') || (*file == '\t')) { 177360285Sbostic file++; 177460285Sbostic } 177560285Sbostic 177660285Sbostic if (*file == '\0') { 177760285Sbostic Parse_Error (PARSE_FATAL, 177860285Sbostic "Filename missing from \"include\""); 177960285Sbostic return; 178060285Sbostic } 178160285Sbostic 178260285Sbostic /* 178360285Sbostic * Skip to end of line or next whitespace 178460285Sbostic */ 178560285Sbostic for (cp = file; *cp && *cp != '\n' && *cp != '\t' && *cp != ' '; cp++) { 178660285Sbostic continue; 178760285Sbostic } 178860285Sbostic 178960285Sbostic *cp = '\0'; 179060285Sbostic 179160285Sbostic /* 179260285Sbostic * Substitute for any variables in the file name before trying to 179360285Sbostic * find the thing. 179460285Sbostic */ 179560285Sbostic file = Var_Subst (NULL, file, VAR_CMD, FALSE); 179660285Sbostic 179760285Sbostic /* 179860285Sbostic * Now we know the file's name, we attempt to find the durn thing. 179960285Sbostic * A return of NULL indicates the file don't exist. 180060285Sbostic * 180160285Sbostic * Include files are first searched for relative to the including 180260285Sbostic * file's location. We don't want to cd there, of course, so we 180360285Sbostic * just tack on the old file's leading path components and call 180460285Sbostic * Dir_FindFile to see if we can locate the beast. 180560285Sbostic * XXX - this *does* search in the current directory, right? 180660285Sbostic */ 180760285Sbostic 180860285Sbostic prefEnd = strrchr (fname, '/'); 180960285Sbostic if (prefEnd != (char *)NULL) { 181060285Sbostic char *newName; 181160285Sbostic 181260285Sbostic *prefEnd = '\0'; 181360285Sbostic newName = str_concat (fname, file, STR_ADDSLASH); 181460285Sbostic fullname = Dir_FindFile (newName, parseIncPath); 181560285Sbostic if (fullname == (char *)NULL) { 181660285Sbostic fullname = Dir_FindFile(newName, dirSearchPath); 181760285Sbostic } 181860285Sbostic free (newName); 181960285Sbostic *prefEnd = '/'; 182060285Sbostic } else { 182160285Sbostic fullname = (char *)NULL; 182260285Sbostic } 182360285Sbostic 182460285Sbostic if (fullname == (char *)NULL) { 182560285Sbostic /* 182660285Sbostic * System makefile or makefile wasn't found in same directory as 182760285Sbostic * included makefile. Search for it first on the -I search path, 182860285Sbostic * then on the .PATH search path, if not found in a -I directory. 182960285Sbostic * XXX: Suffix specific? 183060285Sbostic */ 183160285Sbostic fullname = Dir_FindFile (file, parseIncPath); 183260285Sbostic if (fullname == (char *)NULL) { 183360285Sbostic fullname = Dir_FindFile(file, dirSearchPath); 183460285Sbostic } 183560285Sbostic } 183660285Sbostic 183760285Sbostic if (fullname == (char *)NULL) { 183860285Sbostic /* 183960285Sbostic * Still haven't found the makefile. Look for it on the system 184060285Sbostic * path as a last resort. 184160285Sbostic */ 184260285Sbostic fullname = Dir_FindFile(file, sysIncPath); 184360285Sbostic } 184460285Sbostic 184560285Sbostic if (fullname == (char *) NULL) { 184660285Sbostic Parse_Error (PARSE_FATAL, "Could not find %s", file); 184760285Sbostic return; 184860285Sbostic } 184960285Sbostic 185060285Sbostic /* 185160285Sbostic * Once we find the absolute path to the file, we get to save all the 185260285Sbostic * state from the current file before we can start reading this 185360285Sbostic * include file. The state is stored in an IFile structure which 185460285Sbostic * is placed on a list with other IFile structures. The list makes 185560285Sbostic * a very nice stack to track how we got here... 185660285Sbostic */ 185760285Sbostic oldFile = (IFile *) emalloc (sizeof (IFile)); 185860285Sbostic oldFile->fname = fname; 185960285Sbostic 186060285Sbostic oldFile->F = curFILE; 186160285Sbostic oldFile->p = curPTR; 186260285Sbostic oldFile->lineno = lineno; 186360285Sbostic 186460285Sbostic (void) Lst_AtFront (includes, (ClientData)oldFile); 186560285Sbostic 186660285Sbostic /* 186760285Sbostic * Once the previous state has been saved, we can get down to reading 186860285Sbostic * the new file. We set up the name of the file to be the absolute 186960285Sbostic * name of the include file so error messages refer to the right 187060285Sbostic * place. Naturally enough, we start reading at line number 0. 187160285Sbostic */ 187260285Sbostic fname = fullname; 187360285Sbostic lineno = 0; 187460285Sbostic 187560285Sbostic curFILE = fopen (fullname, "r"); 187660285Sbostic curPTR = NULL; 187760285Sbostic if (curFILE == (FILE * ) NULL) { 187860285Sbostic Parse_Error (PARSE_FATAL, "Cannot open %s", fullname); 187960285Sbostic /* 188060285Sbostic * Pop to previous file 188160285Sbostic */ 188260285Sbostic (void) ParseEOF(1); 188360285Sbostic } 188460285Sbostic } 188560285Sbostic #endif 188660285Sbostic 188760285Sbostic /*- 188860285Sbostic *--------------------------------------------------------------------- 188940393Sbostic * ParseEOF -- 189040393Sbostic * Called when EOF is reached in the current file. If we were reading 189140393Sbostic * an include file, the includes stack is popped and things set up 189240393Sbostic * to go back to reading the previous file at the previous location. 189340393Sbostic * 189440393Sbostic * Results: 189540393Sbostic * CONTINUE if there's more to do. DONE if not. 189640393Sbostic * 189740393Sbostic * Side Effects: 189840393Sbostic * The old curFILE, is closed. The includes list is shortened. 189940393Sbostic * lineno, curFILE, and fname are changed if CONTINUE is returned. 190040393Sbostic *--------------------------------------------------------------------- 190140393Sbostic */ 190240393Sbostic static int 190346462Sbostic ParseEOF (opened) 190446462Sbostic int opened; 190540393Sbostic { 190640393Sbostic IFile *ifile; /* the state on the top of the includes stack */ 190740393Sbostic 190840393Sbostic if (Lst_IsEmpty (includes)) { 190940393Sbostic return (DONE); 191040393Sbostic } 191140393Sbostic 191240393Sbostic ifile = (IFile *) Lst_DeQueue (includes); 191360285Sbostic free ((Address) fname); 191440393Sbostic fname = ifile->fname; 191540393Sbostic lineno = ifile->lineno; 191660285Sbostic if (opened && curFILE) 191746462Sbostic (void) fclose (curFILE); 191860285Sbostic if (curPTR) { 191960285Sbostic free((Address) curPTR->str); 192060285Sbostic free((Address) curPTR); 192160285Sbostic } 192240393Sbostic curFILE = ifile->F; 192360285Sbostic curPTR = ifile->p; 192440393Sbostic free ((Address)ifile); 192540393Sbostic return (CONTINUE); 192640393Sbostic } 192740424Sbostic 192840393Sbostic /*- 192940393Sbostic *--------------------------------------------------------------------- 193040393Sbostic * ParseReadc -- 193160285Sbostic * Read a character from the current file 193240393Sbostic * 193340393Sbostic * Results: 193440393Sbostic * The character that was read 193540393Sbostic * 193640393Sbostic * Side Effects: 193740393Sbostic *--------------------------------------------------------------------- 193840393Sbostic */ 193960285Sbostic static int 194060285Sbostic ParseReadc() 194160285Sbostic { 194260285Sbostic if (curFILE) 194360285Sbostic return fgetc(curFILE); 194460285Sbostic 194560285Sbostic if (curPTR && *curPTR->ptr) 194660285Sbostic return *curPTR->ptr++; 194760285Sbostic return EOF; 194860285Sbostic } 194940393Sbostic 195060557Sbostic 195160557Sbostic /*- 195260557Sbostic *--------------------------------------------------------------------- 195360557Sbostic * ParseUnreadc -- 195460557Sbostic * Put back a character to the current file 195560557Sbostic * 195660557Sbostic * Results: 195760557Sbostic * None. 195860557Sbostic * 195960557Sbostic * Side Effects: 196060557Sbostic *--------------------------------------------------------------------- 196160557Sbostic */ 196260557Sbostic static void 196360557Sbostic ParseUnreadc(c) 196460557Sbostic int c; 196560557Sbostic { 196660557Sbostic if (curFILE) { 196760557Sbostic ungetc(c, curFILE); 196860557Sbostic return; 196960557Sbostic } 197060557Sbostic if (curPTR) { 197160557Sbostic *--(curPTR->ptr) = c; 197260557Sbostic return; 197360557Sbostic } 197460557Sbostic } 197560557Sbostic 197660557Sbostic 197760285Sbostic /* ParseSkipLine(): 197860285Sbostic * Grab the next line 197960285Sbostic */ 198060285Sbostic static char * 198160285Sbostic ParseSkipLine(skip) 198260285Sbostic int skip; /* Skip lines that don't start with . */ 198360285Sbostic { 198460285Sbostic char *line; 198560285Sbostic int c, lastc = '\0', lineLength; 198660285Sbostic Buffer buf; 198740393Sbostic 198860285Sbostic c = ParseReadc(); 198940424Sbostic 199060285Sbostic if (skip) { 199160285Sbostic /* 199260285Sbostic * Skip lines until get to one that begins with a 199360285Sbostic * special char. 199460285Sbostic */ 199560285Sbostic while ((c != '.') && (c != EOF)) { 199660285Sbostic while (((c != '\n') || (lastc == '\\')) && (c != EOF)) 199760285Sbostic { 199860285Sbostic /* 199960285Sbostic * Advance to next unescaped newline 200060285Sbostic */ 200160285Sbostic if ((lastc = c) == '\n') { 200260285Sbostic lineno++; 200360285Sbostic } 200460285Sbostic c = ParseReadc(); 200560285Sbostic } 200660285Sbostic lineno++; 200760285Sbostic 200860285Sbostic lastc = c; 200960285Sbostic c = ParseReadc (); 201060285Sbostic } 201160285Sbostic } 201260285Sbostic 201360285Sbostic if (c == EOF) { 201460285Sbostic Parse_Error (PARSE_FATAL, "Unclosed conditional/for loop"); 201560285Sbostic return ((char *)NULL); 201660285Sbostic } 201760285Sbostic 201860285Sbostic /* 201960285Sbostic * Read the entire line into buf 202060285Sbostic */ 202160285Sbostic buf = Buf_Init (MAKE_BSIZE); 202260285Sbostic if (c != '\n') { 202360285Sbostic do { 202460285Sbostic Buf_AddByte (buf, (Byte)c); 202560285Sbostic c = ParseReadc(); 202660285Sbostic } while ((c != '\n') && (c != EOF)); 202760285Sbostic } 202860285Sbostic lineno++; 202960285Sbostic 203060285Sbostic Buf_AddByte (buf, (Byte)'\0'); 203160285Sbostic line = (char *)Buf_GetAll (buf, &lineLength); 203260285Sbostic Buf_Destroy (buf, FALSE); 203360285Sbostic return line; 203460285Sbostic } 203560285Sbostic 203660285Sbostic 203740393Sbostic /*- 203840393Sbostic *--------------------------------------------------------------------- 203940393Sbostic * ParseReadLine -- 204040393Sbostic * Read an entire line from the input file. Called only by Parse_File. 204140393Sbostic * To facilitate escaped newlines and what have you, a character is 204240393Sbostic * buffered in 'lastc', which is '\0' when no characters have been 204340393Sbostic * read. When we break out of the loop, c holds the terminating 204440393Sbostic * character and lastc holds a character that should be added to 204540393Sbostic * the line (unless we don't read anything but a terminator). 204640393Sbostic * 204740393Sbostic * Results: 204840393Sbostic * A line w/o its newline 204940393Sbostic * 205040393Sbostic * Side Effects: 205140393Sbostic * Only those associated with reading a character 205240393Sbostic *--------------------------------------------------------------------- 205340393Sbostic */ 205440393Sbostic static char * 205540393Sbostic ParseReadLine () 205640393Sbostic { 205740393Sbostic Buffer buf; /* Buffer for current line */ 205840393Sbostic register int c; /* the current character */ 205940393Sbostic register int lastc; /* The most-recent character */ 206040393Sbostic Boolean semiNL; /* treat semi-colons as newlines */ 206140393Sbostic Boolean ignDepOp; /* TRUE if should ignore dependency operators 206240393Sbostic * for the purposes of setting semiNL */ 206340393Sbostic Boolean ignComment; /* TRUE if should ignore comments (in a 206440393Sbostic * shell command */ 2065*69086Schristos char *line; /* Result */ 2066*69086Schristos char *ep; /* to strip trailing blanks */ 206740393Sbostic int lineLength; /* Length of result */ 206840393Sbostic 206940393Sbostic semiNL = FALSE; 207040393Sbostic ignDepOp = FALSE; 207140393Sbostic ignComment = FALSE; 207240393Sbostic 207340393Sbostic /* 207440393Sbostic * Handle special-characters at the beginning of the line. Either a 207540393Sbostic * leading tab (shell command) or pound-sign (possible conditional) 207640393Sbostic * forces us to ignore comments and dependency operators and treat 207740393Sbostic * semi-colons as semi-colons (by leaving semiNL FALSE). This also 207840393Sbostic * discards completely blank lines. 207940393Sbostic */ 208060285Sbostic for (;;) { 208140393Sbostic c = ParseReadc(); 208240393Sbostic 208360557Sbostic if (c == '\t') { 208444599Sbostic ignComment = ignDepOp = TRUE; 208544599Sbostic break; 208640393Sbostic } else if (c == '\n') { 208740393Sbostic lineno++; 208861010Sbostic } else if (c == '#') { 208966399Schristos ParseUnreadc(c); 209066399Schristos break; 209140393Sbostic } else { 209240393Sbostic /* 209340393Sbostic * Anything else breaks out without doing anything 209440393Sbostic */ 209540393Sbostic break; 209640393Sbostic } 209740393Sbostic } 209840393Sbostic 209940393Sbostic if (c != EOF) { 210040393Sbostic lastc = c; 210160285Sbostic buf = Buf_Init(MAKE_BSIZE); 210240393Sbostic 210340393Sbostic while (((c = ParseReadc ()) != '\n' || (lastc == '\\')) && 210440393Sbostic (c != EOF)) 210540393Sbostic { 210640393Sbostic test_char: 210740393Sbostic switch(c) { 210840393Sbostic case '\n': 210940393Sbostic /* 211040393Sbostic * Escaped newline: read characters until a non-space or an 211140393Sbostic * unescaped newline and replace them all by a single space. 211240393Sbostic * This is done by storing the space over the backslash and 211340393Sbostic * dropping through with the next nonspace. If it is a 211440393Sbostic * semi-colon and semiNL is TRUE, it will be recognized as a 211540393Sbostic * newline in the code below this... 211640393Sbostic */ 211740393Sbostic lineno++; 211840393Sbostic lastc = ' '; 211940393Sbostic while ((c = ParseReadc ()) == ' ' || c == '\t') { 212040393Sbostic continue; 212140393Sbostic } 212240393Sbostic if (c == EOF || c == '\n') { 212340393Sbostic goto line_read; 212440393Sbostic } else { 212540393Sbostic /* 212640393Sbostic * Check for comments, semiNL's, etc. -- easier than 212760557Sbostic * ParseUnreadc(c); continue; 212840393Sbostic */ 212940393Sbostic goto test_char; 213040393Sbostic } 213160285Sbostic /*NOTREACHED*/ 213240393Sbostic break; 213360285Sbostic 213440393Sbostic case ';': 213540393Sbostic /* 213640393Sbostic * Semi-colon: Need to see if it should be interpreted as a 213740393Sbostic * newline 213840393Sbostic */ 213940393Sbostic if (semiNL) { 214040393Sbostic /* 214140393Sbostic * To make sure the command that may be following this 214240393Sbostic * semi-colon begins with a tab, we push one back into the 214340393Sbostic * input stream. This will overwrite the semi-colon in the 214440393Sbostic * buffer. If there is no command following, this does no 214540393Sbostic * harm, since the newline remains in the buffer and the 214640393Sbostic * whole line is ignored. 214740393Sbostic */ 214860557Sbostic ParseUnreadc('\t'); 214940393Sbostic goto line_read; 215040393Sbostic } 215140393Sbostic break; 215240393Sbostic case '=': 215340393Sbostic if (!semiNL) { 215440393Sbostic /* 215540393Sbostic * Haven't seen a dependency operator before this, so this 215640393Sbostic * must be a variable assignment -- don't pay attention to 215740393Sbostic * dependency operators after this. 215840393Sbostic */ 215940393Sbostic ignDepOp = TRUE; 216040393Sbostic } else if (lastc == ':' || lastc == '!') { 216140393Sbostic /* 216240393Sbostic * Well, we've seen a dependency operator already, but it 216340393Sbostic * was the previous character, so this is really just an 216440393Sbostic * expanded variable assignment. Revert semi-colons to 216540393Sbostic * being just semi-colons again and ignore any more 216640393Sbostic * dependency operators. 216740393Sbostic * 216840393Sbostic * XXX: Note that a line like "foo : a:=b" will blow up, 216940393Sbostic * but who'd write a line like that anyway? 217040393Sbostic */ 217140393Sbostic ignDepOp = TRUE; semiNL = FALSE; 217240393Sbostic } 217340393Sbostic break; 217440393Sbostic case '#': 217540393Sbostic if (!ignComment) { 217667227Schristos if (compatMake && (lastc != '\\')) { 217740393Sbostic /* 217840393Sbostic * If the character is a hash mark and it isn't escaped 217940393Sbostic * (or we're being compatible), the thing is a comment. 218040393Sbostic * Skip to the end of the line. 218140393Sbostic */ 218240393Sbostic do { 218340393Sbostic c = ParseReadc(); 218440393Sbostic } while ((c != '\n') && (c != EOF)); 218540393Sbostic goto line_read; 218660285Sbostic } else { 218760285Sbostic /* 218860285Sbostic * Don't add the backslash. Just let the # get copied 218960285Sbostic * over. 219060285Sbostic */ 219160285Sbostic lastc = c; 219260285Sbostic continue; 219360285Sbostic } 219440393Sbostic } 219540393Sbostic break; 219640393Sbostic case ':': 219740393Sbostic case '!': 219840393Sbostic if (!ignDepOp && (c == ':' || c == '!')) { 219940393Sbostic /* 220040393Sbostic * A semi-colon is recognized as a newline only on 220140393Sbostic * dependency lines. Dependency lines are lines with a 220240393Sbostic * colon or an exclamation point. Ergo... 220340393Sbostic */ 220440393Sbostic semiNL = TRUE; 220540393Sbostic } 220640393Sbostic break; 220740393Sbostic } 220840393Sbostic /* 220940393Sbostic * Copy in the previous character and save this one in lastc. 221040393Sbostic */ 221140393Sbostic Buf_AddByte (buf, (Byte)lastc); 221240393Sbostic lastc = c; 221340393Sbostic 221440393Sbostic } 221540393Sbostic line_read: 221640393Sbostic lineno++; 221740393Sbostic 221840393Sbostic if (lastc != '\0') { 221940393Sbostic Buf_AddByte (buf, (Byte)lastc); 222040393Sbostic } 222140393Sbostic Buf_AddByte (buf, (Byte)'\0'); 222240393Sbostic line = (char *)Buf_GetAll (buf, &lineLength); 222340393Sbostic Buf_Destroy (buf, FALSE); 2224*69086Schristos 2225*69086Schristos /* 2226*69086Schristos * Strip trailing blanks and tabs from the line. 2227*69086Schristos * Do not strip a blank or tab that is preceeded by 2228*69086Schristos * a '\' 2229*69086Schristos */ 2230*69086Schristos ep = line; 2231*69086Schristos while (*ep) 2232*69086Schristos ++ep; 2233*69086Schristos while (ep > line && (ep[-1] == ' ' || ep[-1] == '\t')) { 2234*69086Schristos if (ep > line + 1 && ep[-2] == '\\') 2235*69086Schristos break; 2236*69086Schristos --ep; 2237*69086Schristos } 2238*69086Schristos *ep = 0; 223940393Sbostic 224040435Sbostic if (line[0] == '.') { 224140393Sbostic /* 224240393Sbostic * The line might be a conditional. Ask the conditional module 224340393Sbostic * about it and act accordingly 224440393Sbostic */ 224540393Sbostic switch (Cond_Eval (line)) { 224640393Sbostic case COND_SKIP: 224760285Sbostic /* 224860285Sbostic * Skip to next conditional that evaluates to COND_PARSE. 224960285Sbostic */ 225040393Sbostic do { 225140393Sbostic free (line); 225260285Sbostic line = ParseSkipLine(1); 225360285Sbostic } while (line && Cond_Eval(line) != COND_PARSE); 225460285Sbostic if (line == NULL) 225560285Sbostic break; 225640393Sbostic /*FALLTHRU*/ 225740393Sbostic case COND_PARSE: 225860285Sbostic free ((Address) line); 225940393Sbostic line = ParseReadLine(); 226040393Sbostic break; 226160285Sbostic case COND_INVALID: 226260285Sbostic if (For_Eval(line)) { 226360285Sbostic int ok; 226460285Sbostic free(line); 226560285Sbostic do { 226660285Sbostic /* 226760285Sbostic * Skip after the matching end 226860285Sbostic */ 226960285Sbostic line = ParseSkipLine(0); 227060285Sbostic if (line == NULL) { 227160285Sbostic Parse_Error (PARSE_FATAL, 227260285Sbostic "Unexpected end of file in for loop.\n"); 227360285Sbostic break; 227460285Sbostic } 227560285Sbostic ok = For_Eval(line); 227660285Sbostic free(line); 227760285Sbostic } 227860285Sbostic while (ok); 227960285Sbostic if (line != NULL) 228060285Sbostic For_Run(); 228160285Sbostic line = ParseReadLine(); 228260285Sbostic } 228360285Sbostic break; 228440393Sbostic } 228540393Sbostic } 228640393Sbostic return (line); 228760285Sbostic 228840393Sbostic } else { 228940393Sbostic /* 229040393Sbostic * Hit end-of-file, so return a NULL line to indicate this. 229140393Sbostic */ 229240393Sbostic return((char *)NULL); 229340393Sbostic } 229440393Sbostic } 229540424Sbostic 229640393Sbostic /*- 229740393Sbostic *----------------------------------------------------------------------- 229840393Sbostic * ParseFinishLine -- 229940393Sbostic * Handle the end of a dependency group. 230040393Sbostic * 230140393Sbostic * Results: 230240393Sbostic * Nothing. 230340393Sbostic * 230440393Sbostic * Side Effects: 230540393Sbostic * inLine set FALSE. 'targets' list destroyed. 230640393Sbostic * 230740393Sbostic *----------------------------------------------------------------------- 230840393Sbostic */ 230940393Sbostic static void 231040393Sbostic ParseFinishLine() 231140393Sbostic { 231240393Sbostic if (inLine) { 231340393Sbostic Lst_ForEach(targets, Suff_EndTransform, (ClientData)NULL); 231440393Sbostic Lst_Destroy (targets, ParseHasCommands); 2315*69086Schristos targets = NULL; 231640393Sbostic inLine = FALSE; 231740393Sbostic } 231840393Sbostic } 231940393Sbostic 232040424Sbostic 232140393Sbostic /*- 232240393Sbostic *--------------------------------------------------------------------- 232340393Sbostic * Parse_File -- 232440393Sbostic * Parse a file into its component parts, incorporating it into the 232540393Sbostic * current dependency graph. This is the main function and controls 232640393Sbostic * almost every other function in this module 232740393Sbostic * 232840393Sbostic * Results: 232940393Sbostic * None 233040393Sbostic * 233140393Sbostic * Side Effects: 233240393Sbostic * Loads. Nodes are added to the list of all targets, nodes and links 233340393Sbostic * are added to the dependency graph. etc. etc. etc. 233440393Sbostic *--------------------------------------------------------------------- 233540393Sbostic */ 233640393Sbostic void 233740393Sbostic Parse_File(name, stream) 233840393Sbostic char *name; /* the name of the file being read */ 233940393Sbostic FILE * stream; /* Stream open to makefile to parse */ 234040393Sbostic { 234140393Sbostic register char *cp, /* pointer into the line */ 234240393Sbostic *line; /* the line we're working on */ 234340393Sbostic 234440393Sbostic inLine = FALSE; 234540393Sbostic fname = name; 234640393Sbostic curFILE = stream; 234740393Sbostic lineno = 0; 234840393Sbostic fatals = 0; 234940393Sbostic 235040393Sbostic do { 235160285Sbostic while ((line = ParseReadLine ()) != NULL) { 235240435Sbostic if (*line == '.') { 235340393Sbostic /* 235440393Sbostic * Lines that begin with the special character are either 235540393Sbostic * include or undef directives. 235640393Sbostic */ 235740393Sbostic for (cp = line + 1; isspace (*cp); cp++) { 235840393Sbostic continue; 235940393Sbostic } 236040393Sbostic if (strncmp (cp, "include", 7) == 0) { 236140393Sbostic ParseDoInclude (cp + 7); 236240393Sbostic goto nextLine; 236340393Sbostic } else if (strncmp(cp, "undef", 5) == 0) { 236440393Sbostic char *cp2; 2365*69086Schristos for (cp += 5; isspace((unsigned char) *cp); cp++) { 236640393Sbostic continue; 236740393Sbostic } 236840393Sbostic 2369*69086Schristos for (cp2 = cp; !isspace((unsigned char) *cp2) && 2370*69086Schristos (*cp2 != '\0'); cp2++) { 237140393Sbostic continue; 237240393Sbostic } 237340393Sbostic 237440393Sbostic *cp2 = '\0'; 237540393Sbostic 237640393Sbostic Var_Delete(cp, VAR_GLOBAL); 237740393Sbostic goto nextLine; 237840393Sbostic } 237940393Sbostic } 2380*69086Schristos if (*line == '#' || *line == '\0') { 2381*69086Schristos /* If we're this far, the line must be a comment. 2382*69086Schristos (Empty lines are ignored as well) */ 238340393Sbostic goto nextLine; 238440393Sbostic } 238540393Sbostic 2386*69086Schristos if (*line == '\t') { 238740393Sbostic /* 2388*69086Schristos * If a line starts with a tab, it can only hope to be 2389*69086Schristos * a creation command. 239040393Sbostic */ 2391*69086Schristos #ifndef POSIX 239240393Sbostic shellCommand: 2393*69086Schristos #endif 239440393Sbostic for (cp = line + 1; isspace (*cp); cp++) { 239540393Sbostic continue; 239640393Sbostic } 239740393Sbostic if (*cp) { 239840393Sbostic if (inLine) { 239940393Sbostic /* 240040393Sbostic * So long as it's not a blank line and we're actually 240140393Sbostic * in a dependency spec, add the command to the list of 240240393Sbostic * commands of all targets in the dependency spec 240340393Sbostic */ 2404*69086Schristos Lst_ForEach (targets, ParseAddCmd, cp); 2405*69086Schristos Lst_AtEnd(targCmds, (ClientData) line); 240640393Sbostic continue; 240740393Sbostic } else { 240840393Sbostic Parse_Error (PARSE_FATAL, 240940393Sbostic "Unassociated shell command \"%.20s\"", 241040393Sbostic cp); 241140393Sbostic } 241240393Sbostic } 241360285Sbostic #ifdef SYSVINCLUDE 241460285Sbostic } else if (strncmp (line, "include", 7) == 0 && 241560285Sbostic strchr(line, ':') == NULL) { 241660285Sbostic /* 241760285Sbostic * It's an S3/S5-style "include". 241860285Sbostic */ 241960285Sbostic ParseTraditionalInclude (line + 7); 242060285Sbostic goto nextLine; 242160285Sbostic #endif 242240393Sbostic } else if (Parse_IsVar (line)) { 242340393Sbostic ParseFinishLine(); 242440393Sbostic Parse_DoVar (line, VAR_GLOBAL); 242540393Sbostic } else { 242640393Sbostic /* 242740393Sbostic * We now know it's a dependency line so it needs to have all 242840393Sbostic * variables expanded before being parsed. Tell the variable 242940393Sbostic * module to complain if some variable is undefined... 243040393Sbostic * To make life easier on novices, if the line is indented we 243140393Sbostic * first make sure the line has a dependency operator in it. 243240393Sbostic * If it doesn't have an operator and we're in a dependency 243340393Sbostic * line's script, we assume it's actually a shell command 243440393Sbostic * and add it to the current list of targets. 243540393Sbostic */ 2436*69086Schristos #ifndef POSIX 243740393Sbostic Boolean nonSpace = FALSE; 2438*69086Schristos #endif 243940393Sbostic 244040393Sbostic cp = line; 2441*69086Schristos if (isspace((unsigned char) line[0])) { 2442*69086Schristos while ((*cp != '\0') && isspace((unsigned char) *cp)) { 2443*69086Schristos cp++; 2444*69086Schristos } 2445*69086Schristos if (*cp == '\0') { 2446*69086Schristos goto nextLine; 2447*69086Schristos } 244840393Sbostic #ifndef POSIX 244940393Sbostic while ((*cp != ':') && (*cp != '!') && (*cp != '\0')) { 2450*69086Schristos nonSpace = TRUE; 245140393Sbostic cp++; 245240393Sbostic } 2453*69086Schristos #endif 245440393Sbostic } 245540393Sbostic 2456*69086Schristos #ifndef POSIX 245740393Sbostic if (*cp == '\0') { 245840393Sbostic if (inLine) { 245940393Sbostic Parse_Error (PARSE_WARNING, 246040393Sbostic "Shell command needs a leading tab"); 246140393Sbostic goto shellCommand; 246240393Sbostic } else if (nonSpace) { 246340393Sbostic Parse_Error (PARSE_FATAL, "Missing operator"); 246440393Sbostic } 246540393Sbostic } else { 246640393Sbostic #endif 246740393Sbostic ParseFinishLine(); 246840393Sbostic 246960285Sbostic cp = Var_Subst (NULL, line, VAR_CMD, TRUE); 247040393Sbostic free (line); 247140393Sbostic line = cp; 247240393Sbostic 247340393Sbostic /* 247440393Sbostic * Need a non-circular list for the target nodes 247540393Sbostic */ 2476*69086Schristos if (targets) 2477*69086Schristos Lst_Destroy(targets, NOFREE); 2478*69086Schristos 247940393Sbostic targets = Lst_Init (FALSE); 248040393Sbostic inLine = TRUE; 248140393Sbostic 248240393Sbostic ParseDoDependency (line); 248340393Sbostic #ifndef POSIX 248440393Sbostic } 248540393Sbostic #endif 248640393Sbostic } 248740393Sbostic 248840393Sbostic nextLine: 248940393Sbostic 249040393Sbostic free (line); 249140393Sbostic } 249240393Sbostic /* 249340393Sbostic * Reached EOF, but it may be just EOF of an include file... 249440393Sbostic */ 249546462Sbostic } while (ParseEOF(1) == CONTINUE); 249640393Sbostic 249740393Sbostic /* 249840393Sbostic * Make sure conditionals are clean 249940393Sbostic */ 250040393Sbostic Cond_End(); 250140393Sbostic 250240393Sbostic if (fatals) { 250340393Sbostic fprintf (stderr, "Fatal errors encountered -- cannot continue\n"); 250440393Sbostic exit (1); 250540393Sbostic } 250640393Sbostic } 250740424Sbostic 250840393Sbostic /*- 250940393Sbostic *--------------------------------------------------------------------- 251040393Sbostic * Parse_Init -- 251140393Sbostic * initialize the parsing module 251240393Sbostic * 251340393Sbostic * Results: 251440393Sbostic * none 251540393Sbostic * 251640393Sbostic * Side Effects: 251740393Sbostic * the parseIncPath list is initialized... 251840393Sbostic *--------------------------------------------------------------------- 251940393Sbostic */ 252060285Sbostic void 252140393Sbostic Parse_Init () 252240393Sbostic { 252360285Sbostic char *cp = NULL, *start; 252440515Sbostic /* avoid faults on read-only strings */ 252540515Sbostic static char syspath[] = _PATH_DEFSYSPATH; 252640393Sbostic 252740393Sbostic mainNode = NILGNODE; 252840393Sbostic parseIncPath = Lst_Init (FALSE); 252940393Sbostic sysIncPath = Lst_Init (FALSE); 253040393Sbostic includes = Lst_Init (FALSE); 2531*69086Schristos targCmds = Lst_Init (FALSE); 253240393Sbostic 253340393Sbostic /* 253440393Sbostic * Add the directories from the DEFSYSPATH (more than one may be given 253540393Sbostic * as dir1:...:dirn) to the system include path. 253640393Sbostic */ 253740393Sbostic for (start = syspath; *start != '\0'; start = cp) { 253860285Sbostic for (cp = start; *cp != '\0' && *cp != ':'; cp++) 253960285Sbostic continue; 254040393Sbostic if (*cp == '\0') { 254140393Sbostic Dir_AddDir(sysIncPath, start); 254240393Sbostic } else { 254340393Sbostic *cp++ = '\0'; 254440393Sbostic Dir_AddDir(sysIncPath, start); 254540393Sbostic } 254640393Sbostic } 254740393Sbostic } 254840424Sbostic 2549*69086Schristos void 2550*69086Schristos Parse_End() 2551*69086Schristos { 2552*69086Schristos Lst_Destroy(targCmds, (void (*) __P((ClientData))) free); 2553*69086Schristos if (targets) 2554*69086Schristos Lst_Destroy(targets, NOFREE); 2555*69086Schristos Lst_Destroy(sysIncPath, Dir_Destroy); 2556*69086Schristos Lst_Destroy(parseIncPath, Dir_Destroy); 2557*69086Schristos Lst_Destroy(includes, NOFREE); /* Should be empty now */ 2558*69086Schristos } 2559*69086Schristos 2560*69086Schristos 256140393Sbostic /*- 256240393Sbostic *----------------------------------------------------------------------- 256340393Sbostic * Parse_MainName -- 256440393Sbostic * Return a Lst of the main target to create for main()'s sake. If 256540393Sbostic * no such target exists, we Punt with an obnoxious error message. 256640393Sbostic * 256740393Sbostic * Results: 256840393Sbostic * A Lst of the single node to create. 256940393Sbostic * 257040393Sbostic * Side Effects: 257140393Sbostic * None. 257240393Sbostic * 257340393Sbostic *----------------------------------------------------------------------- 257440393Sbostic */ 257540393Sbostic Lst 257640393Sbostic Parse_MainName() 257740393Sbostic { 257840393Sbostic Lst main; /* result list */ 257940393Sbostic 258040393Sbostic main = Lst_Init (FALSE); 258140393Sbostic 258240393Sbostic if (mainNode == NILGNODE) { 258345906Sbostic Punt ("make: no target to make.\n"); 258440393Sbostic /*NOTREACHED*/ 258540393Sbostic } else if (mainNode->type & OP_DOUBLEDEP) { 258666389Sbostic (void) Lst_AtEnd (main, (ClientData)mainNode); 258740393Sbostic Lst_Concat(main, mainNode->cohorts, LST_CONCNEW); 258840393Sbostic } 258966389Sbostic else 259066389Sbostic (void) Lst_AtEnd (main, (ClientData)mainNode); 259140393Sbostic return (main); 259240393Sbostic } 2593