140395Sbostic /* 240395Sbostic * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. 340395Sbostic * Copyright (c) 1988, 1989 by Adam de Boor 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 * 1040395Sbostic * Redistribution and use in source and binary forms are permitted 1140395Sbostic * provided that the above copyright notice and this paragraph are 1240395Sbostic * duplicated in all such forms and that any documentation, 1340395Sbostic * advertising materials, and other materials related to such 1440395Sbostic * distribution and use acknowledge that the software was developed 1540395Sbostic * by the University of California, Berkeley. The name of the 1640395Sbostic * University may not be used to endorse or promote products derived 1740395Sbostic * from this software without specific prior written permission. 1840395Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1940395Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 2040395Sbostic * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2140395Sbostic */ 2240395Sbostic 2340395Sbostic #ifndef lint 24*40424Sbostic static char sccsid[] = "@(#)parse.c 5.3 (Berkeley) 03/12/90"; 2540395Sbostic #endif /* not lint */ 2640395Sbostic 2740393Sbostic /*- 2840393Sbostic * parse.c -- 2940393Sbostic * Functions to parse a makefile. 3040393Sbostic * 3140393Sbostic * One function, Parse_Init, must be called before any functions 3240393Sbostic * in this module are used. After that, the function Parse_File is the 3340393Sbostic * main entry point and controls most of the other functions in this 3440393Sbostic * module. 3540393Sbostic * 3640393Sbostic * Most important structures are kept in Lsts. Directories for 3740393Sbostic * the #include "..." function are kept in the 'parseIncPath' Lst, while 3840393Sbostic * those for the #include <...> are kept in the 'sysIncPath' Lst. The 3940393Sbostic * targets currently being defined are kept in the 'targets' Lst. 4040393Sbostic * 4140393Sbostic * The variables 'fname' and 'lineno' are used to track the name 4240393Sbostic * of the current file and the line number in that file so that error 4340393Sbostic * messages can be more meaningful. 4440393Sbostic * 4540393Sbostic * Interface: 4640393Sbostic * Parse_Init Initialization function which must be 4740393Sbostic * called before anything else in this module 4840393Sbostic * is used. 4940393Sbostic * 5040393Sbostic * Parse_File Function used to parse a makefile. It must 5140393Sbostic * be given the name of the file, which should 5240393Sbostic * already have been opened, and a function 5340393Sbostic * to call to read a character from the file. 5440393Sbostic * 5540393Sbostic * Parse_IsVar Returns TRUE if the given line is a 5640393Sbostic * variable assignment. Used by MainParseArgs 5740393Sbostic * to determine if an argument is a target 5840393Sbostic * or a variable assignment. Used internally 5940393Sbostic * for pretty much the same thing... 6040393Sbostic * 6140393Sbostic * Parse_Error Function called when an error occurs in 6240393Sbostic * parsing. Used by the variable and 6340393Sbostic * conditional modules. 6440393Sbostic * Parse_MainName Returns a Lst of the main target to create. 6540393Sbostic */ 6640393Sbostic 6740393Sbostic #include <stdio.h> 6840393Sbostic #include <ctype.h> 6940393Sbostic #include "make.h" 7040393Sbostic #include "buf.h" 7140393Sbostic 7240393Sbostic /* 7340393Sbostic * These values are returned by ParseEOF to tell Parse_File whether to 7440393Sbostic * CONTINUE parsing, i.e. it had only reached the end of an include file, 7540393Sbostic * or if it's DONE. 7640393Sbostic */ 7740393Sbostic #define CONTINUE 1 7840393Sbostic #define DONE 0 7940393Sbostic static int ParseEOF(); 8040393Sbostic 8140393Sbostic static Lst targets; /* targets we're working on */ 8240393Sbostic static Boolean inLine; /* true if currently in a dependency 8340393Sbostic * line or its commands */ 8440393Sbostic 8540393Sbostic static char *fname; /* name of current file (for errors) */ 8640393Sbostic static int lineno; /* line number in current file */ 8740393Sbostic static FILE *curFILE; /* current makefile */ 8840393Sbostic 8940393Sbostic static int fatals = 0; 9040393Sbostic 9140393Sbostic static GNode *mainNode; /* The main target to create. This is the 9240393Sbostic * first target on the first dependency 9340393Sbostic * line in the first makefile */ 9440393Sbostic /* 9540393Sbostic * Definitions for handling #include specifications 9640393Sbostic */ 9740393Sbostic typedef struct IFile { 9840393Sbostic char *fname; /* name of previous file */ 9940393Sbostic int lineno; /* saved line number */ 10040393Sbostic FILE * F; /* the open stream */ 10140393Sbostic } IFile; 10240393Sbostic 10340393Sbostic static Lst includes; /* stack of IFiles generated by 10440393Sbostic * #includes */ 10540393Sbostic Lst parseIncPath; /* list of directories for "..." includes */ 10640393Sbostic Lst sysIncPath; /* list of directories for <...> includes */ 10740393Sbostic 10840393Sbostic /*- 10940393Sbostic * anyExport is used to trace if any target will need exportation. If none 11040393Sbostic * does, then any .EXPORT target can be ignored and the process needn't 11140393Sbostic * be slowed down by trying to connect to some load-balancing system. 11240393Sbostic */ 11340393Sbostic static Boolean anyExport = FALSE; 11440393Sbostic 11540393Sbostic /*- 11640393Sbostic * specType contains the SPECial TYPE of the current target. It is 11740393Sbostic * Not if the target is unspecial. If it *is* special, however, the children 11840393Sbostic * are linked as children of the parent but not vice versa. This variable is 11940393Sbostic * set in ParseDoDependency 12040393Sbostic */ 12140393Sbostic typedef enum { 12240393Sbostic Begin, /* .BEGIN */ 12340393Sbostic Default, /* .DEFAULT */ 12440393Sbostic End, /* .END */ 12540393Sbostic Export, /* .EXPORT */ 12640393Sbostic Ignore, /* .IGNORE */ 12740393Sbostic Includes, /* .INCLUDES */ 12840393Sbostic Interrupt, /* .INTERRUPT */ 12940393Sbostic Libs, /* .LIBS */ 13040393Sbostic MFlags, /* .MFLAGS or .MAKEFLAGS */ 13140393Sbostic Main, /* .MAIN and we don't have anything user-specified to 13240393Sbostic * make */ 13340393Sbostic NoExport, /* .NOEXPORT */ 13440393Sbostic Not, /* Not special */ 13540393Sbostic NotParallel, /* .NOTPARALELL */ 13640393Sbostic Null, /* .NULL */ 13740393Sbostic Order, /* .ORDER */ 13840393Sbostic Path, /* .PATH */ 13940393Sbostic Precious, /* .PRECIOUS */ 14040393Sbostic Shell, /* .SHELL */ 14140393Sbostic Silent, /* .SILENT */ 14240393Sbostic SingleShell, /* .SINGLESHELL */ 14340393Sbostic Suffixes, /* .SUFFIXES */ 14440393Sbostic Attribute, /* Generic attribute */ 14540393Sbostic } ParseSpecial; 14640393Sbostic 14740393Sbostic ParseSpecial specType; 14840393Sbostic 14940393Sbostic /* 15040393Sbostic * Predecessor node for handling .ORDER. Initialized to NILGNODE when .ORDER 15140393Sbostic * seen, then set to each successive source on the line. 15240393Sbostic */ 15340393Sbostic static GNode *predecessor; 15440393Sbostic 15540393Sbostic /* 15640393Sbostic * The parseKeywords table is searched using binary search when deciding 15740393Sbostic * if a target or source is special. The 'spec' field is the ParseSpecial 15840393Sbostic * type of the keyword ("Not" if the keyword isn't special as a target) while 15940393Sbostic * the 'op' field is the operator to apply to the list of targets if the 16040393Sbostic * keyword is used as a source ("0" if the keyword isn't special as a source) 16140393Sbostic */ 16240393Sbostic static struct { 16340393Sbostic char *name; /* Name of keyword */ 16440393Sbostic ParseSpecial spec; /* Type when used as a target */ 16540393Sbostic int op; /* Operator when used as a source */ 16640393Sbostic } parseKeywords[] = { 16740393Sbostic { ".BEGIN", Begin, 0 }, 16840393Sbostic { ".DEFAULT", Default, 0 }, 16940393Sbostic { ".DONTCARE", Attribute, OP_DONTCARE }, 17040393Sbostic { ".END", End, 0 }, 17140393Sbostic { ".EXEC", Attribute, OP_EXEC }, 17240393Sbostic { ".EXPORT", Export, OP_EXPORT }, 17340393Sbostic { ".EXPORTSAME", Attribute, OP_EXPORTSAME }, 17440393Sbostic { ".IGNORE", Ignore, OP_IGNORE }, 17540393Sbostic { ".INCLUDES", Includes, 0 }, 17640393Sbostic { ".INTERRUPT", Interrupt, 0 }, 17740393Sbostic { ".INVISIBLE", Attribute, OP_INVISIBLE }, 17840393Sbostic { ".JOIN", Attribute, OP_JOIN }, 17940393Sbostic { ".LIBS", Libs, 0 }, 18040393Sbostic { ".M68020", Attribute, OP_M68020 }, 18140393Sbostic { ".MAIN", Main, 0 }, 18240393Sbostic { ".MAKE", Attribute, OP_MAKE }, 18340393Sbostic { ".MAKEFLAGS", MFlags, 0 }, 18440393Sbostic { ".MFLAGS", MFlags, 0 }, 18540393Sbostic { ".NOEXPORT", NoExport, OP_NOEXPORT }, 18640393Sbostic { ".NOTMAIN", Attribute, OP_NOTMAIN }, 18740393Sbostic { ".NOTPARALLEL", NotParallel, 0 }, 18840393Sbostic { ".NULL", Null, 0 }, 18940393Sbostic { ".ORDER", Order, 0 }, 19040393Sbostic { ".PATH", Path, 0 }, 19140393Sbostic { ".PRECIOUS", Precious, OP_PRECIOUS }, 19240393Sbostic { ".RECURSIVE", Attribute, OP_MAKE }, 19340393Sbostic { ".SHELL", Shell, 0 }, 19440393Sbostic { ".SILENT", Silent, OP_SILENT }, 19540393Sbostic { ".SINGLESHELL", SingleShell, 0 }, 19640393Sbostic { ".SUFFIXES", Suffixes, 0 }, 19740393Sbostic { ".USE", Attribute, OP_USE }, 19840393Sbostic }; 199*40424Sbostic 20040393Sbostic /*- 20140393Sbostic *---------------------------------------------------------------------- 20240393Sbostic * ParseFindKeyword -- 20340393Sbostic * Look in the table of keywords for one matching the given string. 20440393Sbostic * 20540393Sbostic * Results: 20640393Sbostic * The index of the keyword, or -1 if it isn't there. 20740393Sbostic * 20840393Sbostic * Side Effects: 20940393Sbostic * None 21040393Sbostic *---------------------------------------------------------------------- 21140393Sbostic */ 21240393Sbostic static int 21340393Sbostic ParseFindKeyword (str) 21440393Sbostic char *str; /* String to find */ 21540393Sbostic { 21640393Sbostic register int start, 21740393Sbostic end, 21840393Sbostic cur; 21940393Sbostic register int diff; 22040393Sbostic 22140393Sbostic start = 0; 22240393Sbostic end = (sizeof(parseKeywords)/sizeof(parseKeywords[0])) - 1; 22340393Sbostic 22440393Sbostic do { 22540393Sbostic cur = start + ((end - start) / 2); 22640393Sbostic diff = strcmp (str, parseKeywords[cur].name); 22740393Sbostic 22840393Sbostic if (diff == 0) { 22940393Sbostic return (cur); 23040393Sbostic } else if (diff < 0) { 23140393Sbostic end = cur - 1; 23240393Sbostic } else { 23340393Sbostic start = cur + 1; 23440393Sbostic } 23540393Sbostic } while (start <= end); 23640393Sbostic return (-1); 23740393Sbostic } 238*40424Sbostic 23940393Sbostic /*- 24040393Sbostic *--------------------------------------------------------------------- 24140393Sbostic * Parse_Error -- 24240393Sbostic * Error message abort function for parsing. Prints out the context 24340393Sbostic * of the error (line number and file) as well as the message with 24440393Sbostic * two optional arguments. 24540393Sbostic * 24640393Sbostic * Results: 24740393Sbostic * None 24840393Sbostic * 24940393Sbostic * Side Effects: 25040393Sbostic * "fatals" is incremented if the level is PARSE_FATAL. 25140393Sbostic *--------------------------------------------------------------------- 25240393Sbostic */ 25340393Sbostic /* VARARGS1 */ 25440393Sbostic void 25540393Sbostic Parse_Error (type, fmt, arg1, arg2) 25640393Sbostic int type; /* Error type: PARSE_WARNING if just a warning, 25740393Sbostic * PARSE_FATAL if can't continue (after parsing) */ 25840393Sbostic char *fmt; /* printf format string */ 25940393Sbostic int arg1; /* First optional argument for the fmt string */ 26040393Sbostic int arg2; /* Second optional argument for the fmt string */ 26140393Sbostic { 26240393Sbostic if ((type != PARSE_WARNING) || !noWarnings) { 26340393Sbostic fprintf (stderr, "\"%s\", line %d: ", fname, lineno); 26440393Sbostic if (type == PARSE_WARNING) { 26540393Sbostic fprintf (stderr, "Warning: "); 26640393Sbostic } 26740393Sbostic fprintf (stderr, fmt, arg1, arg2); 26840393Sbostic putc ('\n', stderr); 26940393Sbostic 27040393Sbostic if (type == PARSE_FATAL) { 27140393Sbostic fatals += 1; 27240393Sbostic } 27340393Sbostic } 27440393Sbostic } 275*40424Sbostic 27640393Sbostic /*- 27740393Sbostic *----------------------------------------------------------------------- 27840393Sbostic * Parse_AnyExport -- 27940393Sbostic * Return TRUE if any target was labeled for exportation. 28040393Sbostic * 28140393Sbostic * Results: 28240393Sbostic * TRUE or FALSE... 28340393Sbostic * 28440393Sbostic * Side Effects: 28540393Sbostic * None. 28640393Sbostic * 28740393Sbostic *----------------------------------------------------------------------- 28840393Sbostic */ 28940393Sbostic Boolean 29040393Sbostic Parse_AnyExport() 29140393Sbostic { 29240393Sbostic return (anyExport); 29340393Sbostic } 294*40424Sbostic 29540393Sbostic /*- 29640393Sbostic *--------------------------------------------------------------------- 29740393Sbostic * ParseLinkSrc -- 29840393Sbostic * Link the parent node to its new child. Used in a Lst_ForEach by 29940393Sbostic * ParseDoDependency. If the specType isn't 'Not', the parent 30040393Sbostic * isn't linked as a parent of the child. 30140393Sbostic * 30240393Sbostic * Results: 30340393Sbostic * Always = 0 30440393Sbostic * 30540393Sbostic * Side Effects: 30640393Sbostic * New elements are added to the parents list of cgn and the 30740393Sbostic * children list of cgn. the unmade field of pgn is updated 30840393Sbostic * to reflect the additional child. 30940393Sbostic *--------------------------------------------------------------------- 31040393Sbostic */ 31140393Sbostic static int 31240393Sbostic ParseLinkSrc (pgn, cgn) 31340393Sbostic GNode *pgn; /* The parent node */ 31440393Sbostic GNode *cgn; /* The child node */ 31540393Sbostic { 31640393Sbostic if (Lst_Member (pgn->children, (ClientData)cgn) == NILLNODE) { 31740393Sbostic (void)Lst_AtEnd (pgn->children, (ClientData)cgn); 31840393Sbostic if (specType == Not) { 31940393Sbostic (void)Lst_AtEnd (cgn->parents, (ClientData)pgn); 32040393Sbostic } 32140393Sbostic pgn->unmade += 1; 32240393Sbostic } 32340393Sbostic return (0); 32440393Sbostic } 325*40424Sbostic 32640393Sbostic /*- 32740393Sbostic *--------------------------------------------------------------------- 32840393Sbostic * ParseDoOp -- 32940393Sbostic * Apply the parsed operator to the given target node. Used in a 33040393Sbostic * Lst_ForEach call by ParseDoDependency once all targets have 33140393Sbostic * been found and their operator parsed. If the previous and new 33240393Sbostic * operators are incompatible, a major error is taken. 33340393Sbostic * 33440393Sbostic * Results: 33540393Sbostic * Always 0 33640393Sbostic * 33740393Sbostic * Side Effects: 33840393Sbostic * The type field of the node is altered to reflect any new bits in 33940393Sbostic * the op. 34040393Sbostic *--------------------------------------------------------------------- 34140393Sbostic */ 34240393Sbostic static int 34340393Sbostic ParseDoOp (gn, op) 34440393Sbostic GNode *gn; /* The node to which the operator is to be 34540393Sbostic * applied */ 34640393Sbostic int op; /* The operator to apply */ 34740393Sbostic { 34840393Sbostic /* 34940393Sbostic * If the dependency mask of the operator and the node don't match and 35040393Sbostic * the node has actually had an operator applied to it before, and 35140393Sbostic * the operator actually has some dependency information in it, complain. 35240393Sbostic */ 35340393Sbostic if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) && 35440393Sbostic !OP_NOP(gn->type) && !OP_NOP(op)) 35540393Sbostic { 35640393Sbostic Parse_Error (PARSE_FATAL, "Inconsistent operator for %s", gn->name); 35740393Sbostic return (1); 35840393Sbostic } 35940393Sbostic 36040393Sbostic if ((op == OP_DOUBLEDEP) && ((gn->type & OP_OPMASK) == OP_DOUBLEDEP)) { 36140393Sbostic /* 36240393Sbostic * If the node was the object of a :: operator, we need to create a 36340393Sbostic * new instance of it for the children and commands on this dependency 36440393Sbostic * line. The new instance is placed on the 'cohorts' list of the 36540393Sbostic * initial one (note the initial one is not on its own cohorts list) 36640393Sbostic * and the new instance is linked to all parents of the initial 36740393Sbostic * instance. 36840393Sbostic */ 36940393Sbostic register GNode *cohort; 37040393Sbostic LstNode ln; 37140393Sbostic 37240393Sbostic cohort = Targ_NewGN(gn->name); 37340393Sbostic /* 37440393Sbostic * Duplicate links to parents so graph traversal is simple. Perhaps 37540393Sbostic * some type bits should be duplicated? 37640393Sbostic * 37740393Sbostic * Make the cohort invisible as well to avoid duplicating it into 37840393Sbostic * other variables. True, parents of this target won't tend to do 37940393Sbostic * anything with their local variables, but better safe than 38040393Sbostic * sorry. 38140393Sbostic */ 38240393Sbostic Lst_ForEach(gn->parents, ParseLinkSrc, (ClientData)cohort); 38340393Sbostic cohort->type = OP_DOUBLEDEP|OP_INVISIBLE; 38440393Sbostic (void)Lst_AtEnd(gn->cohorts, (ClientData)cohort); 38540393Sbostic 38640393Sbostic /* 38740393Sbostic * Replace the node in the targets list with the new copy 38840393Sbostic */ 38940393Sbostic ln = Lst_Member(targets, (ClientData)gn); 39040393Sbostic Lst_Replace(ln, (ClientData)cohort); 39140393Sbostic gn = cohort; 39240393Sbostic } 39340393Sbostic /* 39440393Sbostic * We don't want to nuke any previous flags (whatever they were) so we 39540393Sbostic * just OR the new operator into the old 39640393Sbostic */ 39740393Sbostic gn->type |= op; 39840393Sbostic 39940393Sbostic return (0); 40040393Sbostic } 401*40424Sbostic 40240393Sbostic /*- 40340393Sbostic *--------------------------------------------------------------------- 40440393Sbostic * ParseDoSrc -- 40540393Sbostic * Given the name of a source, figure out if it is an attribute 40640393Sbostic * and apply it to the targets if it is. Else decide if there is 40740393Sbostic * some attribute which should be applied *to* the source because 40840393Sbostic * of some special target and apply it if so. Otherwise, make the 40940393Sbostic * source be a child of the targets in the list 'targets' 41040393Sbostic * 41140393Sbostic * Results: 41240393Sbostic * None 41340393Sbostic * 41440393Sbostic * Side Effects: 41540393Sbostic * Operator bits may be added to the list of targets or to the source. 41640393Sbostic * The targets may have a new source added to their lists of children. 41740393Sbostic *--------------------------------------------------------------------- 41840393Sbostic */ 41940393Sbostic static void 42040393Sbostic ParseDoSrc (tOp, src) 42140393Sbostic int tOp; /* operator (if any) from special targets */ 42240393Sbostic char *src; /* name of the source to handle */ 42340393Sbostic { 42440393Sbostic int op; /* operator (if any) from special source */ 42540393Sbostic GNode *gn; 42640393Sbostic 42740393Sbostic op = 0; 42840393Sbostic if (*src == '.' && isupper (src[1])) { 42940393Sbostic int keywd = ParseFindKeyword(src); 43040393Sbostic if (keywd != -1) { 43140393Sbostic op = parseKeywords[keywd].op; 43240393Sbostic } 43340393Sbostic } 43440393Sbostic if (op != 0) { 43540393Sbostic Lst_ForEach (targets, ParseDoOp, (ClientData)op); 43640393Sbostic if (op == OP_EXPORT) { 43740393Sbostic anyExport = TRUE; 43840393Sbostic } 43940393Sbostic } else if (specType == Main) { 44040393Sbostic /* 44140393Sbostic * If we have noted the existence of a .MAIN, it means we need 44240393Sbostic * to add the sources of said target to the list of things 44340393Sbostic * to create. The string 'src' is likely to be free, so we 44440393Sbostic * must make a new copy of it. Note that this will only be 44540393Sbostic * invoked if the user didn't specify a target on the command 44640393Sbostic * line. This is to allow #ifmake's to succeed, or something... 44740393Sbostic */ 448*40424Sbostic (void) Lst_AtEnd (create, (ClientData)strdup(src)); 44940393Sbostic /* 45040393Sbostic * Add the name to the .TARGETS variable as well, so the user cna 45140393Sbostic * employ that, if desired. 45240393Sbostic */ 45340393Sbostic Var_Append(".TARGETS", src, VAR_GLOBAL); 45440393Sbostic } else if (specType == Order) { 45540393Sbostic /* 45640393Sbostic * Create proper predecessor/successor links between the previous 45740393Sbostic * source and the current one. 45840393Sbostic */ 45940393Sbostic gn = Targ_FindNode(src, TARG_CREATE); 46040393Sbostic if (predecessor != NILGNODE) { 46140393Sbostic (void)Lst_AtEnd(predecessor->successors, (ClientData)gn); 46240393Sbostic (void)Lst_AtEnd(gn->preds, (ClientData)predecessor); 46340393Sbostic } 46440393Sbostic /* 46540393Sbostic * The current source now becomes the predecessor for the next one. 46640393Sbostic */ 46740393Sbostic predecessor = gn; 46840393Sbostic } else { 46940393Sbostic /* 47040393Sbostic * If the source is not an attribute, we need to find/create 47140393Sbostic * a node for it. After that we can apply any operator to it 47240393Sbostic * from a special target or link it to its parents, as 47340393Sbostic * appropriate. 47440393Sbostic * 47540393Sbostic * In the case of a source that was the object of a :: operator, 47640393Sbostic * the attribute is applied to all of its instances (as kept in 47740393Sbostic * the 'cohorts' list of the node) or all the cohorts are linked 47840393Sbostic * to all the targets. 47940393Sbostic */ 48040393Sbostic gn = Targ_FindNode (src, TARG_CREATE); 48140393Sbostic if (tOp) { 48240393Sbostic gn->type |= tOp; 48340393Sbostic } else { 48440393Sbostic Lst_ForEach (targets, ParseLinkSrc, (ClientData)gn); 48540393Sbostic } 48640393Sbostic if ((gn->type & OP_OPMASK) == OP_DOUBLEDEP) { 48740393Sbostic register GNode *cohort; 48840393Sbostic register LstNode ln; 48940393Sbostic 49040393Sbostic for (ln=Lst_First(gn->cohorts); ln != NILLNODE; ln = Lst_Succ(ln)){ 49140393Sbostic cohort = (GNode *)Lst_Datum(ln); 49240393Sbostic if (tOp) { 49340393Sbostic cohort->type |= tOp; 49440393Sbostic } else { 49540393Sbostic Lst_ForEach(targets, ParseLinkSrc, (ClientData)cohort); 49640393Sbostic } 49740393Sbostic } 49840393Sbostic } 49940393Sbostic } 50040393Sbostic } 501*40424Sbostic 50240393Sbostic /*- 50340393Sbostic *----------------------------------------------------------------------- 50440393Sbostic * ParseFindMain -- 50540393Sbostic * Find a real target in the list and set it to be the main one. 50640393Sbostic * Called by ParseDoDependency when a main target hasn't been found 50740393Sbostic * yet. 50840393Sbostic * 50940393Sbostic * Results: 51040393Sbostic * 0 if main not found yet, 1 if it is. 51140393Sbostic * 51240393Sbostic * Side Effects: 51340393Sbostic * mainNode is changed and Targ_SetMain is called. 51440393Sbostic * 51540393Sbostic *----------------------------------------------------------------------- 51640393Sbostic */ 51740393Sbostic static int 51840393Sbostic ParseFindMain(gn) 51940393Sbostic GNode *gn; /* Node to examine */ 52040393Sbostic { 52140393Sbostic if ((gn->type & (OP_NOTMAIN|OP_USE|OP_EXEC|OP_TRANSFORM)) == 0) { 52240393Sbostic mainNode = gn; 52340393Sbostic Targ_SetMain(gn); 52440393Sbostic return (1); 52540393Sbostic } else { 52640393Sbostic return (0); 52740393Sbostic } 52840393Sbostic } 529*40424Sbostic 53040393Sbostic /*- 53140393Sbostic *----------------------------------------------------------------------- 53240393Sbostic * ParseAddDir -- 53340393Sbostic * Front-end for Dir_AddDir to make sure Lst_ForEach keeps going 53440393Sbostic * 53540393Sbostic * Results: 53640393Sbostic * === 0 53740393Sbostic * 53840393Sbostic * Side Effects: 53940393Sbostic * See Dir_AddDir. 54040393Sbostic * 54140393Sbostic *----------------------------------------------------------------------- 54240393Sbostic */ 54340393Sbostic static int 54440393Sbostic ParseAddDir(path, name) 54540393Sbostic Lst path; 54640393Sbostic char *name; 54740393Sbostic { 54840393Sbostic Dir_AddDir(path, name); 54940393Sbostic return(0); 55040393Sbostic } 551*40424Sbostic 55240393Sbostic /*- 55340393Sbostic *----------------------------------------------------------------------- 55440393Sbostic * ParseClearPath -- 55540393Sbostic * Front-end for Dir_ClearPath to make sure Lst_ForEach keeps going 55640393Sbostic * 55740393Sbostic * Results: 55840393Sbostic * === 0 55940393Sbostic * 56040393Sbostic * Side Effects: 56140393Sbostic * See Dir_ClearPath 56240393Sbostic * 56340393Sbostic *----------------------------------------------------------------------- 56440393Sbostic */ 56540393Sbostic static int 56640393Sbostic ParseClearPath(path) 56740393Sbostic Lst path; 56840393Sbostic { 56940393Sbostic Dir_ClearPath(path); 57040393Sbostic return(0); 57140393Sbostic } 572*40424Sbostic 57340393Sbostic /*- 57440393Sbostic *--------------------------------------------------------------------- 57540393Sbostic * ParseDoDependency -- 57640393Sbostic * Parse the dependency line in line. 57740393Sbostic * 57840393Sbostic * Results: 57940393Sbostic * None 58040393Sbostic * 58140393Sbostic * Side Effects: 58240393Sbostic * The nodes of the sources are linked as children to the nodes of the 58340393Sbostic * targets. Some nodes may be created. 58440393Sbostic * 58540393Sbostic * We parse a dependency line by first extracting words from the line and 58640393Sbostic * finding nodes in the list of all targets with that name. This is done 58740393Sbostic * until a character is encountered which is an operator character. Currently 58840393Sbostic * these are only ! and :. At this point the operator is parsed and the 58940393Sbostic * pointer into the line advanced until the first source is encountered. 59040393Sbostic * The parsed operator is applied to each node in the 'targets' list, 59140393Sbostic * which is where the nodes found for the targets are kept, by means of 59240393Sbostic * the ParseDoOp function. 59340393Sbostic * The sources are read in much the same way as the targets were except 59440393Sbostic * that now they are expanded using the wildcarding scheme of the C-Shell 59540393Sbostic * and all instances of the resulting words in the list of all targets 59640393Sbostic * are found. Each of the resulting nodes is then linked to each of the 59740393Sbostic * targets as one of its children. 59840393Sbostic * Certain targets are handled specially. These are the ones detailed 59940393Sbostic * by the specType variable. 60040393Sbostic * The storing of transformation rules is also taken care of here. 60140393Sbostic * A target is recognized as a transformation rule by calling 60240393Sbostic * Suff_IsTransform. If it is a transformation rule, its node is gotten 60340393Sbostic * from the suffix module via Suff_AddTransform rather than the standard 60440393Sbostic * Targ_FindNode in the target module. 60540393Sbostic *--------------------------------------------------------------------- 60640393Sbostic */ 60740393Sbostic static void 60840393Sbostic ParseDoDependency (line) 60940393Sbostic char *line; /* the line to parse */ 61040393Sbostic { 61140393Sbostic register char *cp; /* our current position */ 61240393Sbostic register GNode *gn; /* a general purpose temporary node */ 61340393Sbostic register int op; /* the operator on the line */ 61440393Sbostic char savec; /* a place to save a character */ 61540393Sbostic Lst paths; /* List of search paths to alter when parsing 61640393Sbostic * a list of .PATH targets */ 61740393Sbostic int tOp; /* operator from special target */ 61840393Sbostic Lst sources; /* list of source names after expansion */ 61940393Sbostic Lst curTargs; /* list of target names to be found and added 62040393Sbostic * to the targets list */ 62140393Sbostic 62240393Sbostic tOp = 0; 62340393Sbostic 62440393Sbostic specType = Not; 62540393Sbostic paths = (Lst)NULL; 62640393Sbostic 62740393Sbostic curTargs = Lst_Init(FALSE); 62840393Sbostic 62940393Sbostic do { 63040393Sbostic for (cp = line; 63140393Sbostic *cp && !isspace (*cp) && 63240393Sbostic (*cp != '!') && (*cp != ':') && (*cp != '('); 63340393Sbostic cp++) 63440393Sbostic { 63540393Sbostic if (*cp == '$') { 63640393Sbostic /* 63740393Sbostic * Must be a dynamic source (would have been expanded 63840393Sbostic * otherwise), so call the Var module to parse the puppy 63940393Sbostic * so we can safely advance beyond it...There should be 64040393Sbostic * no errors in this, as they would have been discovered 64140393Sbostic * in the initial Var_Subst and we wouldn't be here. 64240393Sbostic */ 64340393Sbostic int length; 64440393Sbostic Boolean freeIt; 64540393Sbostic char *result; 64640393Sbostic 64740393Sbostic result=Var_Parse(cp, VAR_CMD, TRUE, &length, &freeIt); 64840393Sbostic 64940393Sbostic if (freeIt) { 65040393Sbostic free(result); 65140393Sbostic } 65240393Sbostic cp += length-1; 65340393Sbostic } 65440393Sbostic continue; 65540393Sbostic } 65640393Sbostic if (*cp == '(') { 65740393Sbostic /* 65840393Sbostic * Archives must be handled specially to make sure the OP_ARCHV 65940393Sbostic * flag is set in their 'type' field, for one thing, and because 66040393Sbostic * things like "archive(file1.o file2.o file3.o)" are permissible. 66140393Sbostic * Arch_ParseArchive will set 'line' to be the first non-blank 66240393Sbostic * after the archive-spec. It creates/finds nodes for the members 66340393Sbostic * and places them on the given list, returning SUCCESS if all 66440393Sbostic * went well and FAILURE if there was an error in the 66540393Sbostic * specification. On error, line should remain untouched. 66640393Sbostic */ 66740393Sbostic if (Arch_ParseArchive (&line, targets, VAR_CMD) != SUCCESS) { 66840393Sbostic Parse_Error (PARSE_FATAL, 66940393Sbostic "Error in archive specification: \"%s\"", line); 67040393Sbostic return; 67140393Sbostic } else { 67240393Sbostic continue; 67340393Sbostic } 67440393Sbostic } 67540393Sbostic savec = *cp; 67640393Sbostic 67740393Sbostic if (!*cp) { 67840393Sbostic /* 67940393Sbostic * Ending a dependency line without an operator is a Bozo 68040393Sbostic * no-no 68140393Sbostic */ 68240393Sbostic Parse_Error (PARSE_FATAL, "Need an operator"); 68340393Sbostic return; 68440393Sbostic } 68540393Sbostic *cp = '\0'; 68640393Sbostic /* 68740393Sbostic * Have a word in line. See if it's a special target and set 68840393Sbostic * specType to match it. 68940393Sbostic */ 69040393Sbostic if (*line == '.' && isupper (line[1])) { 69140393Sbostic /* 69240393Sbostic * See if the target is a special target that must have it 69340393Sbostic * or its sources handled specially. 69440393Sbostic */ 69540393Sbostic int keywd = ParseFindKeyword(line); 69640393Sbostic if (keywd != -1) { 69740393Sbostic if (specType == Path && parseKeywords[keywd].spec != Path) { 69840393Sbostic Parse_Error(PARSE_FATAL, "Mismatched special targets"); 69940393Sbostic return; 70040393Sbostic } 70140393Sbostic 70240393Sbostic specType = parseKeywords[keywd].spec; 70340393Sbostic tOp = parseKeywords[keywd].op; 70440393Sbostic 70540393Sbostic /* 70640393Sbostic * Certain special targets have special semantics: 70740393Sbostic * .PATH Have to set the dirSearchPath 70840393Sbostic * variable too 70940393Sbostic * .EXPORT Doesn't really apply the 71040393Sbostic * .EXPORT operator to its 71140393Sbostic * sources, so we reset tOp. 71240393Sbostic * .MAIN Its sources are only used if 71340393Sbostic * nothing has been specified to 71440393Sbostic * create. 71540393Sbostic * .DEFAULT Need to create a node to hang 71640393Sbostic * commands on, but we don't want 71740393Sbostic * it in the graph, nor do we want 71840393Sbostic * it to be the Main Target, so we 71940393Sbostic * create it, set OP_NOTMAIN and 72040393Sbostic * add it to the list, setting 72140393Sbostic * DEFAULT to the new node for 72240393Sbostic * later use. We claim the node is 72340393Sbostic * A transformation rule to make 72440393Sbostic * life easier later, when we'll 72540393Sbostic * use Make_HandleUse to actually 72640393Sbostic * apply the .DEFAULT commands. 72740393Sbostic * .BEGIN 72840393Sbostic * .END 72940393Sbostic * .INTERRUPT Are not to be considered the 73040393Sbostic * main target. 73140393Sbostic * .NOTPARALLEL Make only one target at a time. 73240393Sbostic * .SINGLESHELL Create a shell for each command. 73340393Sbostic * .ORDER Must set initial predecessor to NIL 73440393Sbostic */ 73540393Sbostic switch (specType) { 73640393Sbostic case Path: 73740393Sbostic if (paths == NULL) { 73840393Sbostic paths = Lst_Init(FALSE); 73940393Sbostic } 74040393Sbostic (void)Lst_AtEnd(paths, (ClientData)dirSearchPath); 74140393Sbostic break; 74240393Sbostic case Export: 74340393Sbostic tOp = 0; 74440393Sbostic break; 74540393Sbostic case Main: 74640393Sbostic if (!Lst_IsEmpty(create)) { 74740393Sbostic specType = Not; 74840393Sbostic } 74940393Sbostic break; 75040393Sbostic case Begin: 75140393Sbostic case End: 75240393Sbostic case Interrupt: 75340393Sbostic gn = Targ_FindNode(line, TARG_CREATE); 75440393Sbostic gn->type |= OP_NOTMAIN; 75540393Sbostic (void)Lst_AtEnd(targets, (ClientData)gn); 75640393Sbostic break; 75740393Sbostic case Default: 75840393Sbostic gn = Targ_NewGN(".DEFAULT"); 75940393Sbostic gn->type |= (OP_NOTMAIN|OP_TRANSFORM); 76040393Sbostic (void)Lst_AtEnd(targets, (ClientData)gn); 76140393Sbostic DEFAULT = gn; 76240393Sbostic break; 76340393Sbostic case NotParallel: 76440393Sbostic { 76540393Sbostic extern int maxJobs; 76640393Sbostic 76740393Sbostic maxJobs = 1; 76840393Sbostic break; 76940393Sbostic } 77040393Sbostic case SingleShell: 77140393Sbostic backwards = 1; 77240393Sbostic break; 77340393Sbostic case Order: 77440393Sbostic predecessor = NILGNODE; 77540393Sbostic break; 77640393Sbostic } 77740393Sbostic } else if (strncmp (line, ".PATH", 5) == 0) { 77840393Sbostic /* 77940393Sbostic * .PATH<suffix> has to be handled specially. 78040393Sbostic * Call on the suffix module to give us a path to 78140393Sbostic * modify. 78240393Sbostic */ 78340393Sbostic Lst path; 78440393Sbostic 78540393Sbostic specType = Path; 78640393Sbostic path = Suff_GetPath (&line[5]); 78740393Sbostic if (path == NILLST) { 78840393Sbostic Parse_Error (PARSE_FATAL, 78940393Sbostic "Suffix '%s' not defined (yet)", 79040393Sbostic &line[5]); 79140393Sbostic return; 79240393Sbostic } else { 79340393Sbostic if (paths == (Lst)NULL) { 79440393Sbostic paths = Lst_Init(FALSE); 79540393Sbostic } 79640393Sbostic (void)Lst_AtEnd(paths, (ClientData)path); 79740393Sbostic } 79840393Sbostic } 79940393Sbostic } 80040393Sbostic 80140393Sbostic /* 80240393Sbostic * Have word in line. Get or create its node and stick it at 80340393Sbostic * the end of the targets list 80440393Sbostic */ 80540393Sbostic if ((specType == Not) && (*line != '\0')) { 80640393Sbostic if (Dir_HasWildcards(line)) { 80740393Sbostic /* 80840393Sbostic * Targets are to be sought only in the current directory, 80940393Sbostic * so create an empty path for the thing. Note we need to 81040393Sbostic * use Dir_Destroy in the destruction of the path as the 81140393Sbostic * Dir module could have added a directory to the path... 81240393Sbostic */ 81340393Sbostic Lst emptyPath = Lst_Init(FALSE); 81440393Sbostic 81540393Sbostic Dir_Expand(line, emptyPath, curTargs); 81640393Sbostic 81740393Sbostic Lst_Destroy(emptyPath, Dir_Destroy); 81840393Sbostic } else { 81940393Sbostic /* 82040393Sbostic * No wildcards, but we want to avoid code duplication, 82140393Sbostic * so create a list with the word on it. 82240393Sbostic */ 82340393Sbostic (void)Lst_AtEnd(curTargs, (ClientData)line); 82440393Sbostic } 82540393Sbostic 82640393Sbostic while(!Lst_IsEmpty(curTargs)) { 82740393Sbostic char *targName = (char *)Lst_DeQueue(curTargs); 82840393Sbostic 82940393Sbostic if (!Suff_IsTransform (targName)) { 83040393Sbostic gn = Targ_FindNode (targName, TARG_CREATE); 83140393Sbostic } else { 83240393Sbostic gn = Suff_AddTransform (targName); 83340393Sbostic } 83440393Sbostic 83540393Sbostic (void)Lst_AtEnd (targets, (ClientData)gn); 83640393Sbostic } 83740393Sbostic } else if (specType == Path && *line != '.' && *line != '\0') { 83840393Sbostic Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line); 83940393Sbostic } 84040393Sbostic 84140393Sbostic *cp = savec; 84240393Sbostic /* 84340393Sbostic * If it is a special type and not .PATH, it's the only target we 84440393Sbostic * allow on this line... 84540393Sbostic */ 84640393Sbostic if (specType != Not && specType != Path) { 84740393Sbostic Boolean warn = FALSE; 84840393Sbostic 84940393Sbostic while ((*cp != '!') && (*cp != ':') && *cp) { 85040393Sbostic if (*cp != ' ' && *cp != '\t') { 85140393Sbostic warn = TRUE; 85240393Sbostic } 85340393Sbostic cp++; 85440393Sbostic } 85540393Sbostic if (warn) { 85640393Sbostic Parse_Error(PARSE_WARNING, "Extra target ignored"); 85740393Sbostic } 85840393Sbostic } else { 85940393Sbostic while (*cp && isspace (*cp)) { 86040393Sbostic cp++; 86140393Sbostic } 86240393Sbostic } 86340393Sbostic line = cp; 86440393Sbostic } while ((*line != '!') && (*line != ':') && *line); 86540393Sbostic 86640393Sbostic /* 86740393Sbostic * Don't need the list of target names anymore... 86840393Sbostic */ 86940393Sbostic Lst_Destroy(curTargs, NOFREE); 87040393Sbostic 87140393Sbostic if (!Lst_IsEmpty(targets)) { 87240393Sbostic switch(specType) { 87340393Sbostic default: 87440393Sbostic Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. Mundane ones ignored"); 87540393Sbostic break; 87640393Sbostic case Default: 87740393Sbostic case Begin: 87840393Sbostic case End: 87940393Sbostic case Interrupt: 88040393Sbostic /* 88140393Sbostic * These four create nodes on which to hang commands, so 88240393Sbostic * targets shouldn't be empty... 88340393Sbostic */ 88440393Sbostic case Not: 88540393Sbostic /* 88640393Sbostic * Nothing special here -- targets can be empty if it wants. 88740393Sbostic */ 88840393Sbostic break; 88940393Sbostic } 89040393Sbostic } 89140393Sbostic 89240393Sbostic /* 89340393Sbostic * Have now parsed all the target names. Must parse the operator next. The 89440393Sbostic * result is left in op . 89540393Sbostic */ 89640393Sbostic if (*cp == '!') { 89740393Sbostic op = OP_FORCE; 89840393Sbostic } else if (*cp == ':') { 89940393Sbostic if (cp[1] == ':') { 90040393Sbostic op = OP_DOUBLEDEP; 90140393Sbostic cp++; 90240393Sbostic } else { 90340393Sbostic op = OP_DEPENDS; 90440393Sbostic } 90540393Sbostic } else { 90640393Sbostic Parse_Error (PARSE_FATAL, "Missing dependency operator"); 90740393Sbostic return; 90840393Sbostic } 90940393Sbostic 91040393Sbostic cp++; /* Advance beyond operator */ 91140393Sbostic 91240393Sbostic Lst_ForEach (targets, ParseDoOp, (ClientData)op); 91340393Sbostic 91440393Sbostic /* 91540393Sbostic * Get to the first source 91640393Sbostic */ 91740393Sbostic while (*cp && isspace (*cp)) { 91840393Sbostic cp++; 91940393Sbostic } 92040393Sbostic line = cp; 92140393Sbostic 92240393Sbostic /* 92340393Sbostic * Several special targets take different actions if present with no 92440393Sbostic * sources: 92540393Sbostic * a .SUFFIXES line with no sources clears out all old suffixes 92640393Sbostic * a .PRECIOUS line makes all targets precious 92740393Sbostic * a .IGNORE line ignores errors for all targets 92840393Sbostic * a .SILENT line creates silence when making all targets 92940393Sbostic * a .PATH removes all directories from the search path(s). 93040393Sbostic * a .NOEXPORT turns off exportation for all jobs. 93140393Sbostic */ 93240393Sbostic if (!*line) { 93340393Sbostic switch (specType) { 93440393Sbostic case Suffixes: 93540393Sbostic Suff_ClearSuffixes (); 93640393Sbostic break; 93740393Sbostic case Precious: 93840393Sbostic allPrecious = TRUE; 93940393Sbostic break; 94040393Sbostic case Ignore: 94140393Sbostic ignoreErrors = TRUE; 94240393Sbostic break; 94340393Sbostic case Silent: 94440393Sbostic beSilent = TRUE; 94540393Sbostic break; 94640393Sbostic case Path: 94740393Sbostic Lst_ForEach(paths, ParseClearPath, (ClientData)NULL); 94840393Sbostic break; 94940393Sbostic case NoExport: 95040393Sbostic noExport = TRUE; 95140393Sbostic break; 95240393Sbostic } 95340393Sbostic } else if (specType == MFlags) { 95440393Sbostic /* 95540393Sbostic * Call on functions in main.c to deal with these arguments and 95640393Sbostic * set the initial character to a null-character so the loop to 95740393Sbostic * get sources won't get anything 95840393Sbostic */ 95940393Sbostic Main_ParseArgLine (line); 96040393Sbostic *line = '\0'; 96140393Sbostic } else if (specType == Shell) { 96240393Sbostic if (Job_ParseShell (line) != SUCCESS) { 96340393Sbostic Parse_Error (PARSE_FATAL, "improper shell specification"); 96440393Sbostic return; 96540393Sbostic } 96640393Sbostic *line = '\0'; 96740393Sbostic } else if ((specType == NotParallel) || (specType == SingleShell)) { 96840393Sbostic *line = '\0'; 96940393Sbostic } 97040393Sbostic 97140393Sbostic /* 97240393Sbostic * NOW GO FOR THE SOURCES 97340393Sbostic */ 97440393Sbostic if ((specType == Suffixes) || (specType == Path) || 97540393Sbostic (specType == Includes) || (specType == Libs) || 97640393Sbostic (specType == Export) || (specType == Null)) 97740393Sbostic { 97840393Sbostic while (*line) { 97940393Sbostic /* 98040393Sbostic * If the target was one that doesn't take files as its sources 98140393Sbostic * but takes something like suffixes, we take each 98240393Sbostic * space-separated word on the line as a something and deal 98340393Sbostic * with it accordingly. 98440393Sbostic * 98540393Sbostic * If the target was .SUFFIXES, we take each source as a 98640393Sbostic * suffix and add it to the list of suffixes maintained by the 98740393Sbostic * Suff module. 98840393Sbostic * 98940393Sbostic * If the target was a .PATH, we add the source as a directory 99040393Sbostic * to search on the search path. 99140393Sbostic * 99240393Sbostic * If it was .INCLUDES, the source is taken to be the suffix of 99340393Sbostic * files which will be #included and whose search path should 99440393Sbostic * be present in the .INCLUDES variable. 99540393Sbostic * 99640393Sbostic * If it was .LIBS, the source is taken to be the suffix of 99740393Sbostic * files which are considered libraries and whose search path 99840393Sbostic * should be present in the .LIBS variable. 99940393Sbostic * 100040393Sbostic * If it was .EXPORT, the source is the location of the export 100140393Sbostic * server and is passed to the Rmt module as such. 100240393Sbostic * 100340393Sbostic * If it was .NULL, the source is the suffix to use when a file 100440393Sbostic * has no valid suffix. 100540393Sbostic */ 100640393Sbostic char savec; 100740393Sbostic while (*cp && !isspace (*cp)) { 100840393Sbostic cp++; 100940393Sbostic } 101040393Sbostic savec = *cp; 101140393Sbostic *cp = '\0'; 101240393Sbostic switch (specType) { 101340393Sbostic case Suffixes: 101440393Sbostic Suff_AddSuffix (line); 101540393Sbostic break; 101640393Sbostic case Path: 101740393Sbostic Lst_ForEach(paths, ParseAddDir, (ClientData)line); 101840393Sbostic break; 101940393Sbostic case Includes: 102040393Sbostic Suff_AddInclude (line); 102140393Sbostic break; 102240393Sbostic case Libs: 102340393Sbostic Suff_AddLib (line); 102440393Sbostic break; 102540393Sbostic case Export: 102640393Sbostic Rmt_AddServer (line); 102740393Sbostic break; 102840393Sbostic case Null: 102940393Sbostic Suff_SetNull (line); 103040393Sbostic 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 } 1107*40424Sbostic 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 } 1185*40424Sbostic 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 { 121240393Sbostic register 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 */ 121840393Sbostic 121940393Sbostic /* 122040393Sbostic * Skip to variable name 122140393Sbostic */ 122240393Sbostic while ((*line == ' ') || (*line == '\t')) { 122340393Sbostic line++; 122440393Sbostic } 122540393Sbostic 122640393Sbostic /* 122740393Sbostic * Skip to operator character, nulling out whitespace as we go 122840393Sbostic */ 122940393Sbostic for (cp = line + 1; *cp != '='; cp++) { 123040393Sbostic if (isspace (*cp)) { 123140393Sbostic *cp = '\0'; 123240393Sbostic } 123340393Sbostic } 123440393Sbostic opc = cp-1; /* operator is the previous character */ 123540393Sbostic *cp++ = '\0'; /* nuke the = */ 123640393Sbostic 123740393Sbostic /* 123840393Sbostic * Check operator type 123940393Sbostic */ 124040393Sbostic switch (*opc) { 124140393Sbostic case '+': 124240393Sbostic type = VAR_APPEND; 124340393Sbostic *opc = '\0'; 124440393Sbostic break; 124540393Sbostic 124640393Sbostic case '?': 124740393Sbostic /* 124840393Sbostic * If the variable already has a value, we don't do anything. 124940393Sbostic */ 125040393Sbostic *opc = '\0'; 125140393Sbostic if (Var_Exists(line, ctxt)) { 125240393Sbostic return; 125340393Sbostic } else { 125440393Sbostic type = VAR_NORMAL; 125540393Sbostic } 125640393Sbostic break; 125740393Sbostic 125840393Sbostic case ':': 125940393Sbostic type = VAR_SUBST; 126040393Sbostic *opc = '\0'; 126140393Sbostic break; 126240393Sbostic 126340393Sbostic case '!': 126440393Sbostic type = VAR_SHELL; 126540393Sbostic *opc = '\0'; 126640393Sbostic break; 126740393Sbostic 126840393Sbostic default: 126940393Sbostic type = VAR_NORMAL; 127040393Sbostic break; 127140393Sbostic } 127240393Sbostic 127340393Sbostic while (isspace (*cp)) { 127440393Sbostic cp++; 127540393Sbostic } 127640393Sbostic 127740393Sbostic if (type == VAR_APPEND) { 127840393Sbostic Var_Append (line, cp, ctxt); 127940393Sbostic } else if (type == VAR_SUBST) { 128040393Sbostic /* 128140393Sbostic * Allow variables in the old value to be undefined, but leave their 128240393Sbostic * invocation alone -- this is done by forcing oldVars to be false. 128340393Sbostic * XXX: This can cause recursive variables, but that's not hard to do, 128440393Sbostic * and this allows someone to do something like 128540393Sbostic * 128640393Sbostic * CFLAGS = $(.INCLUDES) 128740393Sbostic * CFLAGS := -I.. $(CFLAGS) 128840393Sbostic * 128940393Sbostic * And not get an error. 129040393Sbostic */ 129140393Sbostic Boolean oldOldVars = oldVars; 129240393Sbostic 129340393Sbostic oldVars = FALSE; 129440393Sbostic cp = Var_Subst(cp, ctxt, FALSE); 129540393Sbostic oldVars = oldOldVars; 129640393Sbostic 129740393Sbostic Var_Set(line, cp, ctxt); 129840393Sbostic free(cp); 129940393Sbostic } else if (type == VAR_SHELL) { 130040393Sbostic char result[BUFSIZ]; /* Result of command */ 130140393Sbostic char *args[4]; /* Args for invoking the shell */ 130240393Sbostic int fds[2]; /* Pipe streams */ 130340393Sbostic int cpid; /* Child PID */ 130440393Sbostic int pid; /* PID from wait() */ 130540393Sbostic Boolean freeCmd; /* TRUE if the command needs to be freed, i.e. 130640393Sbostic * if any variable expansion was performed */ 130740393Sbostic 130840393Sbostic /* 130940393Sbostic * Set up arguments for shell 131040393Sbostic */ 131140393Sbostic args[0] = "sh"; 131240393Sbostic args[1] = "-c"; 131340393Sbostic if (index(cp, '$') != (char *)NULL) { 131440393Sbostic /* 131540393Sbostic * There's a dollar sign in the command, so perform variable 131640393Sbostic * expansion on the whole thing. The resulting string will need 131740393Sbostic * freeing when we're done, so set freeCmd to TRUE. 131840393Sbostic */ 131940393Sbostic args[2] = Var_Subst(cp, VAR_CMD, TRUE); 132040393Sbostic freeCmd = TRUE; 132140393Sbostic } else { 132240393Sbostic args[2] = cp; 132340393Sbostic freeCmd = FALSE; 132440393Sbostic } 132540393Sbostic args[3] = (char *)NULL; 132640393Sbostic 132740393Sbostic /* 132840393Sbostic * Open a pipe for fetching its output 132940393Sbostic */ 133040393Sbostic pipe(fds); 133140393Sbostic 133240393Sbostic /* 133340393Sbostic * Fork 133440393Sbostic */ 133540393Sbostic cpid = vfork(); 133640393Sbostic if (cpid == 0) { 133740393Sbostic /* 133840393Sbostic * Close input side of pipe 133940393Sbostic */ 134040393Sbostic close(fds[0]); 134140393Sbostic 134240393Sbostic /* 134340393Sbostic * Duplicate the output stream to the shell's output, then 134440393Sbostic * shut the extra thing down. Note we don't fetch the error 134540393Sbostic * stream...why not? Why? 134640393Sbostic */ 134740393Sbostic dup2(fds[1], 1); 134840393Sbostic close(fds[1]); 134940393Sbostic 135040393Sbostic execv("/bin/sh", args); 135140393Sbostic _exit(1); 135240393Sbostic } else if (cpid < 0) { 135340393Sbostic /* 135440393Sbostic * Couldn't fork -- tell the user and make the variable null 135540393Sbostic */ 135640393Sbostic Parse_Error(PARSE_WARNING, "Couldn't exec \"%s\"", cp); 135740393Sbostic Var_Set(line, "", ctxt); 135840393Sbostic } else { 135940393Sbostic int status; 136040393Sbostic int cc; 136140393Sbostic 136240393Sbostic /* 136340393Sbostic * No need for the writing half 136440393Sbostic */ 136540393Sbostic close(fds[1]); 136640393Sbostic 136740393Sbostic /* 136840393Sbostic * Wait for the process to exit. 136940393Sbostic * 137040393Sbostic * XXX: If the child writes more than a pipe's worth, we will 137140393Sbostic * deadlock. 137240393Sbostic */ 137340393Sbostic while(((pid = wait(&status)) != cpid) && (pid >= 0)) { 137440393Sbostic ; 137540393Sbostic } 137640393Sbostic 137740393Sbostic /* 137840393Sbostic * Read all the characters the child wrote. 137940393Sbostic */ 138040393Sbostic cc = read(fds[0], result, sizeof(result)); 138140393Sbostic 138240393Sbostic if (cc < 0) { 138340393Sbostic /* 138440393Sbostic * Couldn't read the child's output -- tell the user and 138540393Sbostic * set the variable to null 138640393Sbostic */ 138740393Sbostic Parse_Error(PARSE_WARNING, "Couldn't read shell's output"); 138840393Sbostic cc = 0; 138940393Sbostic } 139040393Sbostic 139140393Sbostic if (status) { 139240393Sbostic /* 139340393Sbostic * Child returned an error -- tell the user but still use 139440393Sbostic * the result. 139540393Sbostic */ 139640393Sbostic Parse_Error(PARSE_WARNING, "\"%s\" returned non-zero", cp); 139740393Sbostic } 139840393Sbostic /* 139940393Sbostic * Null-terminate the result, convert newlines to spaces and 140040393Sbostic * install it in the variable. 140140393Sbostic */ 140240393Sbostic result[cc] = '\0'; 140340393Sbostic cp = &result[cc] - 1; 140440393Sbostic 140540393Sbostic if (*cp == '\n') { 140640393Sbostic /* 140740393Sbostic * A final newline is just stripped 140840393Sbostic */ 140940393Sbostic *cp-- = '\0'; 141040393Sbostic } 141140393Sbostic while (cp >= result) { 141240393Sbostic if (*cp == '\n') { 141340393Sbostic *cp = ' '; 141440393Sbostic } 141540393Sbostic cp--; 141640393Sbostic } 141740393Sbostic Var_Set(line, result, ctxt); 141840393Sbostic 141940393Sbostic /* 142040393Sbostic * Close the input side of the pipe. 142140393Sbostic */ 142240393Sbostic close(fds[0]); 142340393Sbostic } 142440393Sbostic if (freeCmd) { 142540393Sbostic free(args[2]); 142640393Sbostic } 142740393Sbostic } else { 142840393Sbostic /* 142940393Sbostic * Normal assignment -- just do it. 143040393Sbostic */ 143140393Sbostic Var_Set (line, cp, ctxt); 143240393Sbostic } 143340393Sbostic } 1434*40424Sbostic 143540393Sbostic /*- 143640393Sbostic *--------------------------------------------------------------------- 143740393Sbostic * ParseAddCmd -- 143840393Sbostic * Lst_ForEach function to add a command line to all targets 143940393Sbostic * 144040393Sbostic * Results: 144140393Sbostic * Always 0 144240393Sbostic * 144340393Sbostic * Side Effects: 144440393Sbostic * A new element is added to the commands list of the node. 144540393Sbostic *--------------------------------------------------------------------- 144640393Sbostic */ 144740393Sbostic static int 144840393Sbostic ParseAddCmd (gn, cmd) 144940393Sbostic GNode *gn; /* the node to which the command is to be 145040393Sbostic * added */ 145140393Sbostic char *cmd; /* the command to add */ 145240393Sbostic { 145340393Sbostic if (gn->type & OP_HAS_COMMANDS) { 145440393Sbostic Parse_Error(PARSE_WARNING, "Extra command line for \"%s\" ignored", 145540393Sbostic gn->name); 145640393Sbostic } else { 145740393Sbostic (void)Lst_AtEnd (gn->commands, (ClientData)cmd); 145840393Sbostic } 145940393Sbostic 146040393Sbostic return (0); 146140393Sbostic } 1462*40424Sbostic 146340393Sbostic /*- 146440393Sbostic *----------------------------------------------------------------------- 146540393Sbostic * ParseHasCommands -- 146640393Sbostic * Callback procedure for Parse_File when destroying the list of 146740393Sbostic * targets on the last dependency line. Marks a target as already 146840393Sbostic * having commands if it does, to keep from having shell commands 146940393Sbostic * on multiple dependency lines. 147040393Sbostic * 147140393Sbostic * Results: 147240393Sbostic * Always 0. 147340393Sbostic * 147440393Sbostic * Side Effects: 147540393Sbostic * OP_HAS_COMMANDS may be set for the target. 147640393Sbostic * 147740393Sbostic *----------------------------------------------------------------------- 147840393Sbostic */ 147940393Sbostic static int 148040393Sbostic ParseHasCommands(gn) 148140393Sbostic GNode *gn; /* Node to examine */ 148240393Sbostic { 148340393Sbostic if (!Lst_IsEmpty(gn->commands)) { 148440393Sbostic gn->type |= OP_HAS_COMMANDS; 148540393Sbostic } 148640393Sbostic return(0); 148740393Sbostic } 1488*40424Sbostic 148940393Sbostic /*- 149040393Sbostic *----------------------------------------------------------------------- 149140393Sbostic * Parse_AddIncludeDir -- 149240393Sbostic * Add a directory to the path searched for included makefiles 149340393Sbostic * bracketed by double-quotes. Used by functions in main.c 149440393Sbostic * 149540393Sbostic * Results: 149640393Sbostic * None. 149740393Sbostic * 149840393Sbostic * Side Effects: 149940393Sbostic * The directory is appended to the list. 150040393Sbostic * 150140393Sbostic *----------------------------------------------------------------------- 150240393Sbostic */ 150340393Sbostic void 150440393Sbostic Parse_AddIncludeDir (dir) 150540393Sbostic char *dir; /* The name of the directory to add */ 150640393Sbostic { 150740393Sbostic Dir_AddDir (parseIncPath, dir); 150840393Sbostic } 1509*40424Sbostic 151040393Sbostic /*- 151140393Sbostic *--------------------------------------------------------------------- 151240393Sbostic * ParseDoInclude -- 151340393Sbostic * Push to another file. 151440393Sbostic * 151540393Sbostic * The input is the line minus the #include. A file spec is a string 151640393Sbostic * enclosed in <> or "". The former is looked for only in sysIncPath. 151740393Sbostic * The latter in . and the directories specified by -I command line 151840393Sbostic * options 151940393Sbostic * 152040393Sbostic * Results: 152140393Sbostic * None 152240393Sbostic * 152340393Sbostic * Side Effects: 152440393Sbostic * A structure is added to the includes Lst and readProc, lineno, 152540393Sbostic * fname and curFILE are altered for the new file 152640393Sbostic *--------------------------------------------------------------------- 152740393Sbostic */ 152840393Sbostic static void 152940393Sbostic ParseDoInclude (file) 153040393Sbostic char *file; /* file specification */ 153140393Sbostic { 153240393Sbostic char *fullname; /* full pathname of file */ 153340393Sbostic IFile *oldFile; /* state associated with current file */ 153440393Sbostic Lst path; /* the path to use to find the file */ 153540393Sbostic char endc; /* the character which ends the file spec */ 153640393Sbostic char *cp; /* current position in file spec */ 153740393Sbostic Boolean isSystem; /* TRUE if makefile is a system makefile */ 153840393Sbostic 153940393Sbostic /* 154040393Sbostic * Skip to delimiter character so we know where to look 154140393Sbostic */ 154240393Sbostic while ((*file == ' ') || (*file == '\t')) { 154340393Sbostic file++; 154440393Sbostic } 154540393Sbostic 154640393Sbostic if ((*file != '"') && (*file != '<')) { 154740393Sbostic /* 154840393Sbostic * XXX: Should give some sort of error message, I suppose, but because 154940393Sbostic * # is used for both comments and directives, we can't be sure if 155040393Sbostic * the thing might not just be a comment, so we just return... 155140393Sbostic */ 155240393Sbostic return; 155340393Sbostic } 155440393Sbostic 155540393Sbostic /* 155640393Sbostic * Set the search path on which to find the include file based on the 155740393Sbostic * characters which bracket its name. Angle-brackets imply it's 155840393Sbostic * a system Makefile while double-quotes imply it's a user makefile 155940393Sbostic */ 156040393Sbostic if (*file == '<') { 156140393Sbostic isSystem = TRUE; 156240393Sbostic endc = '>'; 156340393Sbostic } else { 156440393Sbostic isSystem = FALSE; 156540393Sbostic endc = '"'; 156640393Sbostic } 156740393Sbostic 156840393Sbostic /* 156940393Sbostic * Skip to matching delimiter 157040393Sbostic */ 157140393Sbostic for (cp = ++file; *cp && *cp != endc; cp++) { 157240393Sbostic continue; 157340393Sbostic } 157440393Sbostic 157540393Sbostic if (*cp != endc) { 157640393Sbostic Parse_Error (PARSE_FATAL, 157740393Sbostic "Unclosed %cinclude filename. '%c' expected", 157840393Sbostic SPECIAL_CHAR, endc); 157940393Sbostic return; 158040393Sbostic } 158140393Sbostic *cp = '\0'; 158240393Sbostic 158340393Sbostic /* 158440393Sbostic * Substitute for any variables in the file name before trying to 158540393Sbostic * find the thing. 158640393Sbostic */ 158740393Sbostic file = Var_Subst (file, VAR_CMD, FALSE); 158840393Sbostic 158940393Sbostic /* 159040393Sbostic * Now we know the file's name and its search path, we attempt to 159140393Sbostic * find the durn thing. A return of NULL indicates the file don't 159240393Sbostic * exist. 159340393Sbostic */ 159440393Sbostic if (!isSystem) { 159540393Sbostic /* 159640393Sbostic * Include files contained in double-quotes are first searched for 159740393Sbostic * relative to the including file's location. We don't want to 159840393Sbostic * cd there, of course, so we just tack on the old file's 159940393Sbostic * leading path components and call Dir_FindFile to see if 160040393Sbostic * we can locate the beast. 160140393Sbostic */ 160240393Sbostic char *prefEnd; 160340393Sbostic 160440393Sbostic prefEnd = rindex (fname, '/'); 160540393Sbostic if (prefEnd != (char *)NULL) { 160640393Sbostic char *newName; 160740393Sbostic 160840393Sbostic *prefEnd = '\0'; 160940393Sbostic newName = Str_Concat (fname, file, STR_ADDSLASH); 161040393Sbostic fullname = Dir_FindFile (newName, parseIncPath); 161140393Sbostic if (fullname == (char *)NULL) { 161240393Sbostic fullname = Dir_FindFile(newName, dirSearchPath); 161340393Sbostic } 161440393Sbostic free (newName); 161540393Sbostic *prefEnd = '/'; 161640393Sbostic } else { 161740393Sbostic fullname = (char *)NULL; 161840393Sbostic } 161940393Sbostic } else { 162040393Sbostic fullname = (char *)NULL; 162140393Sbostic } 162240393Sbostic 162340393Sbostic if (fullname == (char *)NULL) { 162440393Sbostic /* 162540393Sbostic * System makefile or makefile wasn't found in same directory as 162640393Sbostic * included makefile. Search for it first on the -I search path, 162740393Sbostic * then on the .PATH search path, if not found in a -I directory. 162840393Sbostic * XXX: Suffix specific? 162940393Sbostic */ 163040393Sbostic fullname = Dir_FindFile (file, parseIncPath); 163140393Sbostic if (fullname == (char *)NULL) { 163240393Sbostic fullname = Dir_FindFile(file, dirSearchPath); 163340393Sbostic } 163440393Sbostic } 163540393Sbostic 163640393Sbostic if (fullname == (char *)NULL) { 163740393Sbostic /* 163840393Sbostic * Still haven't found the makefile. Look for it on the system 163940393Sbostic * path as a last resort. 164040393Sbostic */ 164140393Sbostic fullname = Dir_FindFile(file, sysIncPath); 164240393Sbostic } 164340393Sbostic 164440393Sbostic if (fullname == (char *) NULL) { 164540393Sbostic *cp = endc; 164640393Sbostic Parse_Error (PARSE_FATAL, "Could not find %s", file); 164740393Sbostic return; 164840393Sbostic } 164940393Sbostic 165040393Sbostic /* 165140393Sbostic * Once we find the absolute path to the file, we get to save all the 165240393Sbostic * state from the current file before we can start reading this 165340393Sbostic * include file. The state is stored in an IFile structure which 165440393Sbostic * is placed on a list with other IFile structures. The list makes 165540393Sbostic * a very nice stack to track how we got here... 165640393Sbostic */ 165740393Sbostic oldFile = (IFile *) malloc (sizeof (IFile)); 165840393Sbostic oldFile->fname = fname; 165940393Sbostic 166040393Sbostic oldFile->F = curFILE; 166140393Sbostic oldFile->lineno = lineno; 166240393Sbostic 166340393Sbostic (void) Lst_AtFront (includes, (ClientData)oldFile); 166440393Sbostic 166540393Sbostic /* 166640393Sbostic * Once the previous state has been saved, we can get down to reading 166740393Sbostic * the new file. We set up the name of the file to be the absolute 166840393Sbostic * name of the include file so error messages refer to the right 166940393Sbostic * place. Naturally enough, we start reading at line number 0. 167040393Sbostic */ 167140393Sbostic fname = fullname; 167240393Sbostic lineno = 0; 167340393Sbostic 167440393Sbostic curFILE = fopen (fullname, "r"); 167540393Sbostic if (curFILE == (FILE * ) NULL) { 167640393Sbostic Parse_Error (PARSE_FATAL, "Cannot open %s", fullname); 167740393Sbostic /* 167840393Sbostic * Pop to previous file 167940393Sbostic */ 168040393Sbostic (void) ParseEOF(); 168140393Sbostic } 168240393Sbostic } 1683*40424Sbostic 168440393Sbostic /*- 168540393Sbostic *--------------------------------------------------------------------- 168640393Sbostic * ParseEOF -- 168740393Sbostic * Called when EOF is reached in the current file. If we were reading 168840393Sbostic * an include file, the includes stack is popped and things set up 168940393Sbostic * to go back to reading the previous file at the previous location. 169040393Sbostic * 169140393Sbostic * Results: 169240393Sbostic * CONTINUE if there's more to do. DONE if not. 169340393Sbostic * 169440393Sbostic * Side Effects: 169540393Sbostic * The old curFILE, is closed. The includes list is shortened. 169640393Sbostic * lineno, curFILE, and fname are changed if CONTINUE is returned. 169740393Sbostic *--------------------------------------------------------------------- 169840393Sbostic */ 169940393Sbostic static int 170040393Sbostic ParseEOF () 170140393Sbostic { 170240393Sbostic IFile *ifile; /* the state on the top of the includes stack */ 170340393Sbostic 170440393Sbostic if (Lst_IsEmpty (includes)) { 170540393Sbostic return (DONE); 170640393Sbostic } 170740393Sbostic 170840393Sbostic ifile = (IFile *) Lst_DeQueue (includes); 170940393Sbostic free (fname); 171040393Sbostic fname = ifile->fname; 171140393Sbostic lineno = ifile->lineno; 171240393Sbostic fclose (curFILE); 171340393Sbostic curFILE = ifile->F; 171440393Sbostic free ((Address)ifile); 171540393Sbostic return (CONTINUE); 171640393Sbostic } 1717*40424Sbostic 171840393Sbostic /*- 171940393Sbostic *--------------------------------------------------------------------- 172040393Sbostic * ParseReadc -- 172140393Sbostic * Read a character from the current file and update the line number 172240393Sbostic * counter as necessary 172340393Sbostic * 172440393Sbostic * Results: 172540393Sbostic * The character that was read 172640393Sbostic * 172740393Sbostic * Side Effects: 172840393Sbostic * The lineno counter is incremented if the character is a newline 172940393Sbostic *--------------------------------------------------------------------- 173040393Sbostic */ 173140393Sbostic #ifdef notdef 173240393Sbostic static int parseReadChar; 173340393Sbostic 173440393Sbostic #define ParseReadc() (((parseReadChar = getc(curFILE)) == '\n') ? \ 173540393Sbostic (lineno++, '\n') : parseReadChar) 173640393Sbostic #else 173740393Sbostic #define ParseReadc() (getc(curFILE)) 173840393Sbostic #endif /* notdef */ 173940393Sbostic 1740*40424Sbostic 174140393Sbostic /*- 174240393Sbostic *--------------------------------------------------------------------- 174340393Sbostic * ParseReadLine -- 174440393Sbostic * Read an entire line from the input file. Called only by Parse_File. 174540393Sbostic * To facilitate escaped newlines and what have you, a character is 174640393Sbostic * buffered in 'lastc', which is '\0' when no characters have been 174740393Sbostic * read. When we break out of the loop, c holds the terminating 174840393Sbostic * character and lastc holds a character that should be added to 174940393Sbostic * the line (unless we don't read anything but a terminator). 175040393Sbostic * 175140393Sbostic * Results: 175240393Sbostic * A line w/o its newline 175340393Sbostic * 175440393Sbostic * Side Effects: 175540393Sbostic * Only those associated with reading a character 175640393Sbostic *--------------------------------------------------------------------- 175740393Sbostic */ 175840393Sbostic static char * 175940393Sbostic ParseReadLine () 176040393Sbostic { 176140393Sbostic Buffer buf; /* Buffer for current line */ 176240393Sbostic register int c; /* the current character */ 176340393Sbostic register int lastc; /* The most-recent character */ 176440393Sbostic Boolean semiNL; /* treat semi-colons as newlines */ 176540393Sbostic Boolean ignDepOp; /* TRUE if should ignore dependency operators 176640393Sbostic * for the purposes of setting semiNL */ 176740393Sbostic Boolean ignComment; /* TRUE if should ignore comments (in a 176840393Sbostic * shell command */ 176940393Sbostic char *line; /* Result */ 177040393Sbostic int lineLength; /* Length of result */ 177140393Sbostic 177240393Sbostic semiNL = FALSE; 177340393Sbostic ignDepOp = FALSE; 177440393Sbostic ignComment = FALSE; 177540393Sbostic 177640393Sbostic /* 177740393Sbostic * Handle special-characters at the beginning of the line. Either a 177840393Sbostic * leading tab (shell command) or pound-sign (possible conditional) 177940393Sbostic * forces us to ignore comments and dependency operators and treat 178040393Sbostic * semi-colons as semi-colons (by leaving semiNL FALSE). This also 178140393Sbostic * discards completely blank lines. 178240393Sbostic */ 178340393Sbostic while(1) { 178440393Sbostic c = ParseReadc(); 178540393Sbostic 178640393Sbostic if ((c == '\t') || (c == SPECIAL_CHAR)) { 178740393Sbostic ignComment = ignDepOp = TRUE; 178840393Sbostic break; 178940393Sbostic } else if (c == '\n') { 179040393Sbostic lineno++; 179140393Sbostic } else { 179240393Sbostic /* 179340393Sbostic * Anything else breaks out without doing anything 179440393Sbostic */ 179540393Sbostic break; 179640393Sbostic } 179740393Sbostic } 179840393Sbostic 179940393Sbostic if (c != EOF) { 180040393Sbostic lastc = c; 180140393Sbostic buf = Buf_Init(BSIZE); 180240393Sbostic 180340393Sbostic while (((c = ParseReadc ()) != '\n' || (lastc == '\\')) && 180440393Sbostic (c != EOF)) 180540393Sbostic { 180640393Sbostic test_char: 180740393Sbostic switch(c) { 180840393Sbostic case '\n': 180940393Sbostic /* 181040393Sbostic * Escaped newline: read characters until a non-space or an 181140393Sbostic * unescaped newline and replace them all by a single space. 181240393Sbostic * This is done by storing the space over the backslash and 181340393Sbostic * dropping through with the next nonspace. If it is a 181440393Sbostic * semi-colon and semiNL is TRUE, it will be recognized as a 181540393Sbostic * newline in the code below this... 181640393Sbostic */ 181740393Sbostic lineno++; 181840393Sbostic lastc = ' '; 181940393Sbostic while ((c = ParseReadc ()) == ' ' || c == '\t') { 182040393Sbostic continue; 182140393Sbostic } 182240393Sbostic if (c == EOF || c == '\n') { 182340393Sbostic goto line_read; 182440393Sbostic } else { 182540393Sbostic /* 182640393Sbostic * Check for comments, semiNL's, etc. -- easier than 182740393Sbostic * ungetc(c, curFILE); continue; 182840393Sbostic */ 182940393Sbostic goto test_char; 183040393Sbostic } 183140393Sbostic break; 183240393Sbostic case ';': 183340393Sbostic /* 183440393Sbostic * Semi-colon: Need to see if it should be interpreted as a 183540393Sbostic * newline 183640393Sbostic */ 183740393Sbostic if (semiNL) { 183840393Sbostic /* 183940393Sbostic * To make sure the command that may be following this 184040393Sbostic * semi-colon begins with a tab, we push one back into the 184140393Sbostic * input stream. This will overwrite the semi-colon in the 184240393Sbostic * buffer. If there is no command following, this does no 184340393Sbostic * harm, since the newline remains in the buffer and the 184440393Sbostic * whole line is ignored. 184540393Sbostic */ 184640393Sbostic ungetc('\t', curFILE); 184740393Sbostic goto line_read; 184840393Sbostic } 184940393Sbostic break; 185040393Sbostic case '=': 185140393Sbostic if (!semiNL) { 185240393Sbostic /* 185340393Sbostic * Haven't seen a dependency operator before this, so this 185440393Sbostic * must be a variable assignment -- don't pay attention to 185540393Sbostic * dependency operators after this. 185640393Sbostic */ 185740393Sbostic ignDepOp = TRUE; 185840393Sbostic } else if (lastc == ':' || lastc == '!') { 185940393Sbostic /* 186040393Sbostic * Well, we've seen a dependency operator already, but it 186140393Sbostic * was the previous character, so this is really just an 186240393Sbostic * expanded variable assignment. Revert semi-colons to 186340393Sbostic * being just semi-colons again and ignore any more 186440393Sbostic * dependency operators. 186540393Sbostic * 186640393Sbostic * XXX: Note that a line like "foo : a:=b" will blow up, 186740393Sbostic * but who'd write a line like that anyway? 186840393Sbostic */ 186940393Sbostic ignDepOp = TRUE; semiNL = FALSE; 187040393Sbostic } 187140393Sbostic break; 187240393Sbostic case '#': 187340393Sbostic if (!ignComment) { 187440393Sbostic if (backwards || (lastc != '\\')) { 187540393Sbostic /* 187640393Sbostic * If the character is a hash mark and it isn't escaped 187740393Sbostic * (or we're being compatible), the thing is a comment. 187840393Sbostic * Skip to the end of the line. 187940393Sbostic */ 188040393Sbostic do { 188140393Sbostic c = ParseReadc(); 188240393Sbostic } while ((c != '\n') && (c != EOF)); 188340393Sbostic goto line_read; 188440393Sbostic } else { 188540393Sbostic /* 188640393Sbostic * Don't add the backslash. Just let the # get copied 188740393Sbostic * over. 188840393Sbostic */ 188940393Sbostic lastc = c; 189040393Sbostic continue; 189140393Sbostic } 189240393Sbostic } 189340393Sbostic break; 189440393Sbostic case ':': 189540393Sbostic case '!': 189640393Sbostic if (!ignDepOp && (c == ':' || c == '!')) { 189740393Sbostic /* 189840393Sbostic * A semi-colon is recognized as a newline only on 189940393Sbostic * dependency lines. Dependency lines are lines with a 190040393Sbostic * colon or an exclamation point. Ergo... 190140393Sbostic */ 190240393Sbostic semiNL = TRUE; 190340393Sbostic } 190440393Sbostic break; 190540393Sbostic } 190640393Sbostic /* 190740393Sbostic * Copy in the previous character and save this one in lastc. 190840393Sbostic */ 190940393Sbostic Buf_AddByte (buf, (Byte)lastc); 191040393Sbostic lastc = c; 191140393Sbostic 191240393Sbostic } 191340393Sbostic line_read: 191440393Sbostic lineno++; 191540393Sbostic 191640393Sbostic if (lastc != '\0') { 191740393Sbostic Buf_AddByte (buf, (Byte)lastc); 191840393Sbostic } 191940393Sbostic Buf_AddByte (buf, (Byte)'\0'); 192040393Sbostic line = (char *)Buf_GetAll (buf, &lineLength); 192140393Sbostic Buf_Destroy (buf, FALSE); 192240393Sbostic 192340393Sbostic if (line[0] == SPECIAL_CHAR) { 192440393Sbostic /* 192540393Sbostic * The line might be a conditional. Ask the conditional module 192640393Sbostic * about it and act accordingly 192740393Sbostic */ 192840393Sbostic switch (Cond_Eval (line)) { 192940393Sbostic case COND_SKIP: 193040393Sbostic do { 193140393Sbostic /* 193240393Sbostic * Skip to next conditional that evaluates to COND_PARSE. 193340393Sbostic */ 193440393Sbostic free (line); 193540393Sbostic c = ParseReadc(); 193640393Sbostic /* 193740393Sbostic * Skip lines until get to one that begins with a 193840393Sbostic * special char. 193940393Sbostic */ 194040393Sbostic while ((c != SPECIAL_CHAR) && (c != EOF)) { 194140393Sbostic while (((c != '\n') || (lastc == '\\')) && 194240393Sbostic (c != EOF)) 194340393Sbostic { 194440393Sbostic /* 194540393Sbostic * Advance to next unescaped newline 194640393Sbostic */ 194740393Sbostic if ((lastc = c) == '\n') { 194840393Sbostic lineno++; 194940393Sbostic } 195040393Sbostic c = ParseReadc(); 195140393Sbostic } 195240393Sbostic lineno++; 195340393Sbostic 195440393Sbostic lastc = c; 195540393Sbostic c = ParseReadc (); 195640393Sbostic } 195740393Sbostic 195840393Sbostic if (c == EOF) { 195940393Sbostic Parse_Error (PARSE_FATAL, "Unclosed conditional"); 196040393Sbostic return ((char *)NULL); 196140393Sbostic } 196240393Sbostic 196340393Sbostic /* 196440393Sbostic * Read the entire line into buf 196540393Sbostic */ 196640393Sbostic buf = Buf_Init (BSIZE); 196740393Sbostic do { 196840393Sbostic Buf_AddByte (buf, (Byte)c); 196940393Sbostic c = ParseReadc(); 197040393Sbostic } while ((c != '\n') && (c != EOF)); 197140393Sbostic lineno++; 197240393Sbostic 197340393Sbostic Buf_AddByte (buf, (Byte)'\0'); 197440393Sbostic line = (char *)Buf_GetAll (buf, &lineLength); 197540393Sbostic Buf_Destroy (buf, FALSE); 197640393Sbostic } while (Cond_Eval(line) != COND_PARSE); 197740393Sbostic /*FALLTHRU*/ 197840393Sbostic case COND_PARSE: 197940393Sbostic free (line); 198040393Sbostic line = ParseReadLine(); 198140393Sbostic break; 198240393Sbostic } 198340393Sbostic } 198440393Sbostic 198540393Sbostic return (line); 198640393Sbostic } else { 198740393Sbostic /* 198840393Sbostic * Hit end-of-file, so return a NULL line to indicate this. 198940393Sbostic */ 199040393Sbostic return((char *)NULL); 199140393Sbostic } 199240393Sbostic } 1993*40424Sbostic 199440393Sbostic /*- 199540393Sbostic *----------------------------------------------------------------------- 199640393Sbostic * ParseFinishLine -- 199740393Sbostic * Handle the end of a dependency group. 199840393Sbostic * 199940393Sbostic * Results: 200040393Sbostic * Nothing. 200140393Sbostic * 200240393Sbostic * Side Effects: 200340393Sbostic * inLine set FALSE. 'targets' list destroyed. 200440393Sbostic * 200540393Sbostic *----------------------------------------------------------------------- 200640393Sbostic */ 200740393Sbostic static void 200840393Sbostic ParseFinishLine() 200940393Sbostic { 201040393Sbostic extern int Suff_EndTransform(); 201140393Sbostic 201240393Sbostic if (inLine) { 201340393Sbostic Lst_ForEach(targets, Suff_EndTransform, (ClientData)NULL); 201440393Sbostic Lst_Destroy (targets, ParseHasCommands); 201540393Sbostic inLine = FALSE; 201640393Sbostic } 201740393Sbostic } 201840393Sbostic 2019*40424Sbostic 202040393Sbostic /*- 202140393Sbostic *--------------------------------------------------------------------- 202240393Sbostic * Parse_File -- 202340393Sbostic * Parse a file into its component parts, incorporating it into the 202440393Sbostic * current dependency graph. This is the main function and controls 202540393Sbostic * almost every other function in this module 202640393Sbostic * 202740393Sbostic * Results: 202840393Sbostic * None 202940393Sbostic * 203040393Sbostic * Side Effects: 203140393Sbostic * Loads. Nodes are added to the list of all targets, nodes and links 203240393Sbostic * are added to the dependency graph. etc. etc. etc. 203340393Sbostic *--------------------------------------------------------------------- 203440393Sbostic */ 203540393Sbostic void 203640393Sbostic Parse_File(name, stream) 203740393Sbostic char *name; /* the name of the file being read */ 203840393Sbostic FILE * stream; /* Stream open to makefile to parse */ 203940393Sbostic { 204040393Sbostic register char *cp, /* pointer into the line */ 204140393Sbostic *line; /* the line we're working on */ 204240393Sbostic 204340393Sbostic inLine = FALSE; 204440393Sbostic fname = name; 204540393Sbostic curFILE = stream; 204640393Sbostic lineno = 0; 204740393Sbostic fatals = 0; 204840393Sbostic 204940393Sbostic do { 205040393Sbostic while (line = ParseReadLine ()) { 205140393Sbostic if (*line == SPECIAL_CHAR) { 205240393Sbostic /* 205340393Sbostic * Lines that begin with the special character are either 205440393Sbostic * include or undef directives. 205540393Sbostic */ 205640393Sbostic for (cp = line + 1; isspace (*cp); cp++) { 205740393Sbostic continue; 205840393Sbostic } 205940393Sbostic if (strncmp (cp, "include", 7) == 0) { 206040393Sbostic ParseDoInclude (cp + 7); 206140393Sbostic goto nextLine; 206240393Sbostic } else if (strncmp(cp, "undef", 5) == 0) { 206340393Sbostic char *cp2; 206440393Sbostic for (cp += 5; isspace(*cp); cp++) { 206540393Sbostic continue; 206640393Sbostic } 206740393Sbostic 206840393Sbostic for (cp2 = cp; !isspace(*cp2) && (*cp2 != '\0'); cp2++) { 206940393Sbostic continue; 207040393Sbostic } 207140393Sbostic 207240393Sbostic *cp2 = '\0'; 207340393Sbostic 207440393Sbostic Var_Delete(cp, VAR_GLOBAL); 207540393Sbostic goto nextLine; 207640393Sbostic } 207740393Sbostic } 207840393Sbostic if (*line == '#') { 207940393Sbostic /* 208040393Sbostic * If we're this far, the line must be a comment, even if 208140393Sbostic * SPECIAL_CHAR is '#' 208240393Sbostic */ 208340393Sbostic goto nextLine; 208440393Sbostic } 208540393Sbostic 208640393Sbostic if (*line == '\t' 208740393Sbostic #ifdef POSIX 208840393Sbostic || *line == ' ' 208940393Sbostic #endif 209040393Sbostic ) 209140393Sbostic { 209240393Sbostic /* 209340393Sbostic * If a line starts with a tab (or space in POSIX-land), it 209440393Sbostic * can only hope to be a creation command. 209540393Sbostic */ 209640393Sbostic shellCommand: 209740393Sbostic for (cp = line + 1; isspace (*cp); cp++) { 209840393Sbostic continue; 209940393Sbostic } 210040393Sbostic if (*cp) { 210140393Sbostic if (inLine) { 210240393Sbostic /* 210340393Sbostic * So long as it's not a blank line and we're actually 210440393Sbostic * in a dependency spec, add the command to the list of 210540393Sbostic * commands of all targets in the dependency spec 210640393Sbostic */ 210740393Sbostic Lst_ForEach (targets, ParseAddCmd, (ClientData)cp); 210840393Sbostic continue; 210940393Sbostic } else { 211040393Sbostic Parse_Error (PARSE_FATAL, 211140393Sbostic "Unassociated shell command \"%.20s\"", 211240393Sbostic cp); 211340393Sbostic } 211440393Sbostic } 211540393Sbostic } else if (Parse_IsVar (line)) { 211640393Sbostic ParseFinishLine(); 211740393Sbostic Parse_DoVar (line, VAR_GLOBAL); 211840393Sbostic } else { 211940393Sbostic /* 212040393Sbostic * We now know it's a dependency line so it needs to have all 212140393Sbostic * variables expanded before being parsed. Tell the variable 212240393Sbostic * module to complain if some variable is undefined... 212340393Sbostic * To make life easier on novices, if the line is indented we 212440393Sbostic * first make sure the line has a dependency operator in it. 212540393Sbostic * If it doesn't have an operator and we're in a dependency 212640393Sbostic * line's script, we assume it's actually a shell command 212740393Sbostic * and add it to the current list of targets. 212840393Sbostic * 212940393Sbostic * Note that POSIX declares all lines that start with 213040393Sbostic * whitespace are shell commands, so there's no need to check 213140393Sbostic * here... 213240393Sbostic */ 213340393Sbostic Boolean nonSpace = FALSE; 213440393Sbostic 213540393Sbostic cp = line; 213640393Sbostic #ifndef POSIX 213740393Sbostic if (line[0] == ' ') { 213840393Sbostic while ((*cp != ':') && (*cp != '!') && (*cp != '\0')) { 213940393Sbostic if (!isspace(*cp)) { 214040393Sbostic nonSpace = TRUE; 214140393Sbostic } 214240393Sbostic cp++; 214340393Sbostic } 214440393Sbostic } 214540393Sbostic 214640393Sbostic if (*cp == '\0') { 214740393Sbostic if (inLine) { 214840393Sbostic Parse_Error (PARSE_WARNING, 214940393Sbostic "Shell command needs a leading tab"); 215040393Sbostic goto shellCommand; 215140393Sbostic } else if (nonSpace) { 215240393Sbostic Parse_Error (PARSE_FATAL, "Missing operator"); 215340393Sbostic } 215440393Sbostic } else { 215540393Sbostic #endif 215640393Sbostic ParseFinishLine(); 215740393Sbostic 215840393Sbostic cp = Var_Subst (line, VAR_CMD, TRUE); 215940393Sbostic free (line); 216040393Sbostic line = cp; 216140393Sbostic 216240393Sbostic /* 216340393Sbostic * Need a non-circular list for the target nodes 216440393Sbostic */ 216540393Sbostic targets = Lst_Init (FALSE); 216640393Sbostic inLine = TRUE; 216740393Sbostic 216840393Sbostic ParseDoDependency (line); 216940393Sbostic #ifndef POSIX 217040393Sbostic } 217140393Sbostic #endif 217240393Sbostic } 217340393Sbostic 217440393Sbostic nextLine: 217540393Sbostic 217640393Sbostic free (line); 217740393Sbostic } 217840393Sbostic /* 217940393Sbostic * Reached EOF, but it may be just EOF of an include file... 218040393Sbostic */ 218140393Sbostic } while (ParseEOF() == CONTINUE); 218240393Sbostic 218340393Sbostic /* 218440393Sbostic * Make sure conditionals are clean 218540393Sbostic */ 218640393Sbostic Cond_End(); 218740393Sbostic 218840393Sbostic if (fatals) { 218940393Sbostic fprintf (stderr, "Fatal errors encountered -- cannot continue\n"); 219040393Sbostic exit (1); 219140393Sbostic } 219240393Sbostic } 2193*40424Sbostic 219440393Sbostic /*- 219540393Sbostic *--------------------------------------------------------------------- 219640393Sbostic * Parse_Init -- 219740393Sbostic * initialize the parsing module 219840393Sbostic * 219940393Sbostic * Results: 220040393Sbostic * none 220140393Sbostic * 220240393Sbostic * Side Effects: 220340393Sbostic * the parseIncPath list is initialized... 220440393Sbostic *--------------------------------------------------------------------- 220540393Sbostic */ 220640393Sbostic Parse_Init () 220740393Sbostic { 220840393Sbostic char *cp; 220940393Sbostic char *start; 221040393Sbostic static char syspath[] = DEFSYSPATH; /* Avoid faults on read-only string 221140393Sbostic * constant... */ 221240393Sbostic 221340393Sbostic mainNode = NILGNODE; 221440393Sbostic parseIncPath = Lst_Init (FALSE); 221540393Sbostic sysIncPath = Lst_Init (FALSE); 221640393Sbostic includes = Lst_Init (FALSE); 221740393Sbostic 221840393Sbostic /* 221940393Sbostic * Add the directories from the DEFSYSPATH (more than one may be given 222040393Sbostic * as dir1:...:dirn) to the system include path. 222140393Sbostic */ 222240393Sbostic for (start = syspath; *start != '\0'; start = cp) { 222340393Sbostic for (cp = start; *cp != '\0' && *cp != ':'; cp++) { 222440393Sbostic ; 222540393Sbostic } 222640393Sbostic if (*cp == '\0') { 222740393Sbostic Dir_AddDir(sysIncPath, start); 222840393Sbostic } else { 222940393Sbostic *cp++ = '\0'; 223040393Sbostic Dir_AddDir(sysIncPath, start); 223140393Sbostic } 223240393Sbostic } 223340393Sbostic } 2234*40424Sbostic 223540393Sbostic /*- 223640393Sbostic *----------------------------------------------------------------------- 223740393Sbostic * Parse_MainName -- 223840393Sbostic * Return a Lst of the main target to create for main()'s sake. If 223940393Sbostic * no such target exists, we Punt with an obnoxious error message. 224040393Sbostic * 224140393Sbostic * Results: 224240393Sbostic * A Lst of the single node to create. 224340393Sbostic * 224440393Sbostic * Side Effects: 224540393Sbostic * None. 224640393Sbostic * 224740393Sbostic *----------------------------------------------------------------------- 224840393Sbostic */ 224940393Sbostic Lst 225040393Sbostic Parse_MainName() 225140393Sbostic { 225240393Sbostic Lst main; /* result list */ 225340393Sbostic 225440393Sbostic main = Lst_Init (FALSE); 225540393Sbostic 225640393Sbostic if (mainNode == NILGNODE) { 225740393Sbostic Punt ("I don't know what to DO!\n"); 225840393Sbostic /*NOTREACHED*/ 225940393Sbostic } else if (mainNode->type & OP_DOUBLEDEP) { 226040393Sbostic Lst_Concat(main, mainNode->cohorts, LST_CONCNEW); 226140393Sbostic } 226240393Sbostic (void) Lst_AtEnd (main, (ClientData)mainNode); 226340393Sbostic return (main); 226440393Sbostic } 2265