1*40393Sbostic /*- 2*40393Sbostic * parse.c -- 3*40393Sbostic * Functions to parse a makefile. 4*40393Sbostic * 5*40393Sbostic * One function, Parse_Init, must be called before any functions 6*40393Sbostic * in this module are used. After that, the function Parse_File is the 7*40393Sbostic * main entry point and controls most of the other functions in this 8*40393Sbostic * module. 9*40393Sbostic * 10*40393Sbostic * Most important structures are kept in Lsts. Directories for 11*40393Sbostic * the #include "..." function are kept in the 'parseIncPath' Lst, while 12*40393Sbostic * those for the #include <...> are kept in the 'sysIncPath' Lst. The 13*40393Sbostic * targets currently being defined are kept in the 'targets' Lst. 14*40393Sbostic * 15*40393Sbostic * The variables 'fname' and 'lineno' are used to track the name 16*40393Sbostic * of the current file and the line number in that file so that error 17*40393Sbostic * messages can be more meaningful. 18*40393Sbostic * 19*40393Sbostic * Copyright (c) 1988, 1989 by the Regents of the University of California 20*40393Sbostic * Copyright (c) 1988, 1989 by Adam de Boor 21*40393Sbostic * Copyright (c) 1989 by Berkeley Softworks 22*40393Sbostic * 23*40393Sbostic * Permission to use, copy, modify, and distribute this 24*40393Sbostic * software and its documentation for any non-commercial purpose 25*40393Sbostic * and without fee is hereby granted, provided that the above copyright 26*40393Sbostic * notice appears in all copies. The University of California, 27*40393Sbostic * Berkeley Softworks and Adam de Boor make no representations about 28*40393Sbostic * the suitability of this software for any purpose. It is provided 29*40393Sbostic * "as is" without express or implied warranty. 30*40393Sbostic * 31*40393Sbostic * Interface: 32*40393Sbostic * Parse_Init Initialization function which must be 33*40393Sbostic * called before anything else in this module 34*40393Sbostic * is used. 35*40393Sbostic * 36*40393Sbostic * Parse_File Function used to parse a makefile. It must 37*40393Sbostic * be given the name of the file, which should 38*40393Sbostic * already have been opened, and a function 39*40393Sbostic * to call to read a character from the file. 40*40393Sbostic * 41*40393Sbostic * Parse_IsVar Returns TRUE if the given line is a 42*40393Sbostic * variable assignment. Used by MainParseArgs 43*40393Sbostic * to determine if an argument is a target 44*40393Sbostic * or a variable assignment. Used internally 45*40393Sbostic * for pretty much the same thing... 46*40393Sbostic * 47*40393Sbostic * Parse_Error Function called when an error occurs in 48*40393Sbostic * parsing. Used by the variable and 49*40393Sbostic * conditional modules. 50*40393Sbostic * Parse_MainName Returns a Lst of the main target to create. 51*40393Sbostic */ 52*40393Sbostic #ifndef lint 53*40393Sbostic static char *rcsid = "$Id: parse.c,v 1.75 89/11/14 13:42:56 adam Exp $ SPRITE (Berkeley)"; 54*40393Sbostic #endif lint 55*40393Sbostic 56*40393Sbostic #include <stdio.h> 57*40393Sbostic #include <ctype.h> 58*40393Sbostic #include "make.h" 59*40393Sbostic #include "buf.h" 60*40393Sbostic 61*40393Sbostic /* 62*40393Sbostic * These values are returned by ParseEOF to tell Parse_File whether to 63*40393Sbostic * CONTINUE parsing, i.e. it had only reached the end of an include file, 64*40393Sbostic * or if it's DONE. 65*40393Sbostic */ 66*40393Sbostic #define CONTINUE 1 67*40393Sbostic #define DONE 0 68*40393Sbostic static int ParseEOF(); 69*40393Sbostic 70*40393Sbostic static Lst targets; /* targets we're working on */ 71*40393Sbostic static Boolean inLine; /* true if currently in a dependency 72*40393Sbostic * line or its commands */ 73*40393Sbostic 74*40393Sbostic static char *fname; /* name of current file (for errors) */ 75*40393Sbostic static int lineno; /* line number in current file */ 76*40393Sbostic static FILE *curFILE; /* current makefile */ 77*40393Sbostic 78*40393Sbostic static int fatals = 0; 79*40393Sbostic 80*40393Sbostic static GNode *mainNode; /* The main target to create. This is the 81*40393Sbostic * first target on the first dependency 82*40393Sbostic * line in the first makefile */ 83*40393Sbostic /* 84*40393Sbostic * Definitions for handling #include specifications 85*40393Sbostic */ 86*40393Sbostic typedef struct IFile { 87*40393Sbostic char *fname; /* name of previous file */ 88*40393Sbostic int lineno; /* saved line number */ 89*40393Sbostic FILE * F; /* the open stream */ 90*40393Sbostic } IFile; 91*40393Sbostic 92*40393Sbostic static Lst includes; /* stack of IFiles generated by 93*40393Sbostic * #includes */ 94*40393Sbostic Lst parseIncPath; /* list of directories for "..." includes */ 95*40393Sbostic Lst sysIncPath; /* list of directories for <...> includes */ 96*40393Sbostic 97*40393Sbostic /*- 98*40393Sbostic * anyExport is used to trace if any target will need exportation. If none 99*40393Sbostic * does, then any .EXPORT target can be ignored and the process needn't 100*40393Sbostic * be slowed down by trying to connect to some load-balancing system. 101*40393Sbostic */ 102*40393Sbostic static Boolean anyExport = FALSE; 103*40393Sbostic 104*40393Sbostic /*- 105*40393Sbostic * specType contains the SPECial TYPE of the current target. It is 106*40393Sbostic * Not if the target is unspecial. If it *is* special, however, the children 107*40393Sbostic * are linked as children of the parent but not vice versa. This variable is 108*40393Sbostic * set in ParseDoDependency 109*40393Sbostic */ 110*40393Sbostic typedef enum { 111*40393Sbostic Begin, /* .BEGIN */ 112*40393Sbostic Default, /* .DEFAULT */ 113*40393Sbostic End, /* .END */ 114*40393Sbostic Export, /* .EXPORT */ 115*40393Sbostic Ignore, /* .IGNORE */ 116*40393Sbostic Includes, /* .INCLUDES */ 117*40393Sbostic Interrupt, /* .INTERRUPT */ 118*40393Sbostic Libs, /* .LIBS */ 119*40393Sbostic MFlags, /* .MFLAGS or .MAKEFLAGS */ 120*40393Sbostic Main, /* .MAIN and we don't have anything user-specified to 121*40393Sbostic * make */ 122*40393Sbostic NoExport, /* .NOEXPORT */ 123*40393Sbostic Not, /* Not special */ 124*40393Sbostic NotParallel, /* .NOTPARALELL */ 125*40393Sbostic Null, /* .NULL */ 126*40393Sbostic Order, /* .ORDER */ 127*40393Sbostic Path, /* .PATH */ 128*40393Sbostic Precious, /* .PRECIOUS */ 129*40393Sbostic Shell, /* .SHELL */ 130*40393Sbostic Silent, /* .SILENT */ 131*40393Sbostic SingleShell, /* .SINGLESHELL */ 132*40393Sbostic Suffixes, /* .SUFFIXES */ 133*40393Sbostic Attribute, /* Generic attribute */ 134*40393Sbostic } ParseSpecial; 135*40393Sbostic 136*40393Sbostic ParseSpecial specType; 137*40393Sbostic 138*40393Sbostic /* 139*40393Sbostic * Predecessor node for handling .ORDER. Initialized to NILGNODE when .ORDER 140*40393Sbostic * seen, then set to each successive source on the line. 141*40393Sbostic */ 142*40393Sbostic static GNode *predecessor; 143*40393Sbostic 144*40393Sbostic /* 145*40393Sbostic * The parseKeywords table is searched using binary search when deciding 146*40393Sbostic * if a target or source is special. The 'spec' field is the ParseSpecial 147*40393Sbostic * type of the keyword ("Not" if the keyword isn't special as a target) while 148*40393Sbostic * the 'op' field is the operator to apply to the list of targets if the 149*40393Sbostic * keyword is used as a source ("0" if the keyword isn't special as a source) 150*40393Sbostic */ 151*40393Sbostic static struct { 152*40393Sbostic char *name; /* Name of keyword */ 153*40393Sbostic ParseSpecial spec; /* Type when used as a target */ 154*40393Sbostic int op; /* Operator when used as a source */ 155*40393Sbostic } parseKeywords[] = { 156*40393Sbostic { ".BEGIN", Begin, 0 }, 157*40393Sbostic { ".DEFAULT", Default, 0 }, 158*40393Sbostic { ".DONTCARE", Attribute, OP_DONTCARE }, 159*40393Sbostic { ".END", End, 0 }, 160*40393Sbostic { ".EXEC", Attribute, OP_EXEC }, 161*40393Sbostic { ".EXPORT", Export, OP_EXPORT }, 162*40393Sbostic { ".EXPORTSAME", Attribute, OP_EXPORTSAME }, 163*40393Sbostic { ".IGNORE", Ignore, OP_IGNORE }, 164*40393Sbostic { ".INCLUDES", Includes, 0 }, 165*40393Sbostic { ".INTERRUPT", Interrupt, 0 }, 166*40393Sbostic { ".INVISIBLE", Attribute, OP_INVISIBLE }, 167*40393Sbostic { ".JOIN", Attribute, OP_JOIN }, 168*40393Sbostic { ".LIBS", Libs, 0 }, 169*40393Sbostic { ".M68020", Attribute, OP_M68020 }, 170*40393Sbostic { ".MAIN", Main, 0 }, 171*40393Sbostic { ".MAKE", Attribute, OP_MAKE }, 172*40393Sbostic { ".MAKEFLAGS", MFlags, 0 }, 173*40393Sbostic { ".MFLAGS", MFlags, 0 }, 174*40393Sbostic { ".NOEXPORT", NoExport, OP_NOEXPORT }, 175*40393Sbostic { ".NOTMAIN", Attribute, OP_NOTMAIN }, 176*40393Sbostic { ".NOTPARALLEL", NotParallel, 0 }, 177*40393Sbostic { ".NULL", Null, 0 }, 178*40393Sbostic { ".ORDER", Order, 0 }, 179*40393Sbostic { ".PATH", Path, 0 }, 180*40393Sbostic { ".PRECIOUS", Precious, OP_PRECIOUS }, 181*40393Sbostic { ".RECURSIVE", Attribute, OP_MAKE }, 182*40393Sbostic { ".SHELL", Shell, 0 }, 183*40393Sbostic { ".SILENT", Silent, OP_SILENT }, 184*40393Sbostic { ".SINGLESHELL", SingleShell, 0 }, 185*40393Sbostic { ".SUFFIXES", Suffixes, 0 }, 186*40393Sbostic { ".USE", Attribute, OP_USE }, 187*40393Sbostic }; 188*40393Sbostic 189*40393Sbostic /*- 190*40393Sbostic *---------------------------------------------------------------------- 191*40393Sbostic * ParseFindKeyword -- 192*40393Sbostic * Look in the table of keywords for one matching the given string. 193*40393Sbostic * 194*40393Sbostic * Results: 195*40393Sbostic * The index of the keyword, or -1 if it isn't there. 196*40393Sbostic * 197*40393Sbostic * Side Effects: 198*40393Sbostic * None 199*40393Sbostic *---------------------------------------------------------------------- 200*40393Sbostic */ 201*40393Sbostic static int 202*40393Sbostic ParseFindKeyword (str) 203*40393Sbostic char *str; /* String to find */ 204*40393Sbostic { 205*40393Sbostic register int start, 206*40393Sbostic end, 207*40393Sbostic cur; 208*40393Sbostic register int diff; 209*40393Sbostic 210*40393Sbostic start = 0; 211*40393Sbostic end = (sizeof(parseKeywords)/sizeof(parseKeywords[0])) - 1; 212*40393Sbostic 213*40393Sbostic do { 214*40393Sbostic cur = start + ((end - start) / 2); 215*40393Sbostic diff = strcmp (str, parseKeywords[cur].name); 216*40393Sbostic 217*40393Sbostic if (diff == 0) { 218*40393Sbostic return (cur); 219*40393Sbostic } else if (diff < 0) { 220*40393Sbostic end = cur - 1; 221*40393Sbostic } else { 222*40393Sbostic start = cur + 1; 223*40393Sbostic } 224*40393Sbostic } while (start <= end); 225*40393Sbostic return (-1); 226*40393Sbostic } 227*40393Sbostic 228*40393Sbostic /*- 229*40393Sbostic *--------------------------------------------------------------------- 230*40393Sbostic * Parse_Error -- 231*40393Sbostic * Error message abort function for parsing. Prints out the context 232*40393Sbostic * of the error (line number and file) as well as the message with 233*40393Sbostic * two optional arguments. 234*40393Sbostic * 235*40393Sbostic * Results: 236*40393Sbostic * None 237*40393Sbostic * 238*40393Sbostic * Side Effects: 239*40393Sbostic * "fatals" is incremented if the level is PARSE_FATAL. 240*40393Sbostic *--------------------------------------------------------------------- 241*40393Sbostic */ 242*40393Sbostic /* VARARGS1 */ 243*40393Sbostic void 244*40393Sbostic Parse_Error (type, fmt, arg1, arg2) 245*40393Sbostic int type; /* Error type: PARSE_WARNING if just a warning, 246*40393Sbostic * PARSE_FATAL if can't continue (after parsing) */ 247*40393Sbostic char *fmt; /* printf format string */ 248*40393Sbostic int arg1; /* First optional argument for the fmt string */ 249*40393Sbostic int arg2; /* Second optional argument for the fmt string */ 250*40393Sbostic { 251*40393Sbostic if ((type != PARSE_WARNING) || !noWarnings) { 252*40393Sbostic fprintf (stderr, "\"%s\", line %d: ", fname, lineno); 253*40393Sbostic if (type == PARSE_WARNING) { 254*40393Sbostic fprintf (stderr, "Warning: "); 255*40393Sbostic } 256*40393Sbostic fprintf (stderr, fmt, arg1, arg2); 257*40393Sbostic putc ('\n', stderr); 258*40393Sbostic 259*40393Sbostic if (type == PARSE_FATAL) { 260*40393Sbostic fatals += 1; 261*40393Sbostic } 262*40393Sbostic } 263*40393Sbostic } 264*40393Sbostic 265*40393Sbostic /*- 266*40393Sbostic *----------------------------------------------------------------------- 267*40393Sbostic * Parse_AnyExport -- 268*40393Sbostic * Return TRUE if any target was labeled for exportation. 269*40393Sbostic * 270*40393Sbostic * Results: 271*40393Sbostic * TRUE or FALSE... 272*40393Sbostic * 273*40393Sbostic * Side Effects: 274*40393Sbostic * None. 275*40393Sbostic * 276*40393Sbostic *----------------------------------------------------------------------- 277*40393Sbostic */ 278*40393Sbostic Boolean 279*40393Sbostic Parse_AnyExport() 280*40393Sbostic { 281*40393Sbostic return (anyExport); 282*40393Sbostic } 283*40393Sbostic 284*40393Sbostic /*- 285*40393Sbostic *--------------------------------------------------------------------- 286*40393Sbostic * ParseLinkSrc -- 287*40393Sbostic * Link the parent node to its new child. Used in a Lst_ForEach by 288*40393Sbostic * ParseDoDependency. If the specType isn't 'Not', the parent 289*40393Sbostic * isn't linked as a parent of the child. 290*40393Sbostic * 291*40393Sbostic * Results: 292*40393Sbostic * Always = 0 293*40393Sbostic * 294*40393Sbostic * Side Effects: 295*40393Sbostic * New elements are added to the parents list of cgn and the 296*40393Sbostic * children list of cgn. the unmade field of pgn is updated 297*40393Sbostic * to reflect the additional child. 298*40393Sbostic *--------------------------------------------------------------------- 299*40393Sbostic */ 300*40393Sbostic static int 301*40393Sbostic ParseLinkSrc (pgn, cgn) 302*40393Sbostic GNode *pgn; /* The parent node */ 303*40393Sbostic GNode *cgn; /* The child node */ 304*40393Sbostic { 305*40393Sbostic if (Lst_Member (pgn->children, (ClientData)cgn) == NILLNODE) { 306*40393Sbostic (void)Lst_AtEnd (pgn->children, (ClientData)cgn); 307*40393Sbostic if (specType == Not) { 308*40393Sbostic (void)Lst_AtEnd (cgn->parents, (ClientData)pgn); 309*40393Sbostic } 310*40393Sbostic pgn->unmade += 1; 311*40393Sbostic } 312*40393Sbostic return (0); 313*40393Sbostic } 314*40393Sbostic 315*40393Sbostic /*- 316*40393Sbostic *--------------------------------------------------------------------- 317*40393Sbostic * ParseDoOp -- 318*40393Sbostic * Apply the parsed operator to the given target node. Used in a 319*40393Sbostic * Lst_ForEach call by ParseDoDependency once all targets have 320*40393Sbostic * been found and their operator parsed. If the previous and new 321*40393Sbostic * operators are incompatible, a major error is taken. 322*40393Sbostic * 323*40393Sbostic * Results: 324*40393Sbostic * Always 0 325*40393Sbostic * 326*40393Sbostic * Side Effects: 327*40393Sbostic * The type field of the node is altered to reflect any new bits in 328*40393Sbostic * the op. 329*40393Sbostic *--------------------------------------------------------------------- 330*40393Sbostic */ 331*40393Sbostic static int 332*40393Sbostic ParseDoOp (gn, op) 333*40393Sbostic GNode *gn; /* The node to which the operator is to be 334*40393Sbostic * applied */ 335*40393Sbostic int op; /* The operator to apply */ 336*40393Sbostic { 337*40393Sbostic /* 338*40393Sbostic * If the dependency mask of the operator and the node don't match and 339*40393Sbostic * the node has actually had an operator applied to it before, and 340*40393Sbostic * the operator actually has some dependency information in it, complain. 341*40393Sbostic */ 342*40393Sbostic if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) && 343*40393Sbostic !OP_NOP(gn->type) && !OP_NOP(op)) 344*40393Sbostic { 345*40393Sbostic Parse_Error (PARSE_FATAL, "Inconsistent operator for %s", gn->name); 346*40393Sbostic return (1); 347*40393Sbostic } 348*40393Sbostic 349*40393Sbostic if ((op == OP_DOUBLEDEP) && ((gn->type & OP_OPMASK) == OP_DOUBLEDEP)) { 350*40393Sbostic /* 351*40393Sbostic * If the node was the object of a :: operator, we need to create a 352*40393Sbostic * new instance of it for the children and commands on this dependency 353*40393Sbostic * line. The new instance is placed on the 'cohorts' list of the 354*40393Sbostic * initial one (note the initial one is not on its own cohorts list) 355*40393Sbostic * and the new instance is linked to all parents of the initial 356*40393Sbostic * instance. 357*40393Sbostic */ 358*40393Sbostic register GNode *cohort; 359*40393Sbostic LstNode ln; 360*40393Sbostic 361*40393Sbostic cohort = Targ_NewGN(gn->name); 362*40393Sbostic /* 363*40393Sbostic * Duplicate links to parents so graph traversal is simple. Perhaps 364*40393Sbostic * some type bits should be duplicated? 365*40393Sbostic * 366*40393Sbostic * Make the cohort invisible as well to avoid duplicating it into 367*40393Sbostic * other variables. True, parents of this target won't tend to do 368*40393Sbostic * anything with their local variables, but better safe than 369*40393Sbostic * sorry. 370*40393Sbostic */ 371*40393Sbostic Lst_ForEach(gn->parents, ParseLinkSrc, (ClientData)cohort); 372*40393Sbostic cohort->type = OP_DOUBLEDEP|OP_INVISIBLE; 373*40393Sbostic (void)Lst_AtEnd(gn->cohorts, (ClientData)cohort); 374*40393Sbostic 375*40393Sbostic /* 376*40393Sbostic * Replace the node in the targets list with the new copy 377*40393Sbostic */ 378*40393Sbostic ln = Lst_Member(targets, (ClientData)gn); 379*40393Sbostic Lst_Replace(ln, (ClientData)cohort); 380*40393Sbostic gn = cohort; 381*40393Sbostic } 382*40393Sbostic /* 383*40393Sbostic * We don't want to nuke any previous flags (whatever they were) so we 384*40393Sbostic * just OR the new operator into the old 385*40393Sbostic */ 386*40393Sbostic gn->type |= op; 387*40393Sbostic 388*40393Sbostic return (0); 389*40393Sbostic } 390*40393Sbostic 391*40393Sbostic /*- 392*40393Sbostic *--------------------------------------------------------------------- 393*40393Sbostic * ParseDoSrc -- 394*40393Sbostic * Given the name of a source, figure out if it is an attribute 395*40393Sbostic * and apply it to the targets if it is. Else decide if there is 396*40393Sbostic * some attribute which should be applied *to* the source because 397*40393Sbostic * of some special target and apply it if so. Otherwise, make the 398*40393Sbostic * source be a child of the targets in the list 'targets' 399*40393Sbostic * 400*40393Sbostic * Results: 401*40393Sbostic * None 402*40393Sbostic * 403*40393Sbostic * Side Effects: 404*40393Sbostic * Operator bits may be added to the list of targets or to the source. 405*40393Sbostic * The targets may have a new source added to their lists of children. 406*40393Sbostic *--------------------------------------------------------------------- 407*40393Sbostic */ 408*40393Sbostic static void 409*40393Sbostic ParseDoSrc (tOp, src) 410*40393Sbostic int tOp; /* operator (if any) from special targets */ 411*40393Sbostic char *src; /* name of the source to handle */ 412*40393Sbostic { 413*40393Sbostic int op; /* operator (if any) from special source */ 414*40393Sbostic GNode *gn; 415*40393Sbostic 416*40393Sbostic op = 0; 417*40393Sbostic if (*src == '.' && isupper (src[1])) { 418*40393Sbostic int keywd = ParseFindKeyword(src); 419*40393Sbostic if (keywd != -1) { 420*40393Sbostic op = parseKeywords[keywd].op; 421*40393Sbostic } 422*40393Sbostic } 423*40393Sbostic if (op != 0) { 424*40393Sbostic Lst_ForEach (targets, ParseDoOp, (ClientData)op); 425*40393Sbostic if (op == OP_EXPORT) { 426*40393Sbostic anyExport = TRUE; 427*40393Sbostic } 428*40393Sbostic } else if (specType == Main) { 429*40393Sbostic /* 430*40393Sbostic * If we have noted the existence of a .MAIN, it means we need 431*40393Sbostic * to add the sources of said target to the list of things 432*40393Sbostic * to create. The string 'src' is likely to be free, so we 433*40393Sbostic * must make a new copy of it. Note that this will only be 434*40393Sbostic * invoked if the user didn't specify a target on the command 435*40393Sbostic * line. This is to allow #ifmake's to succeed, or something... 436*40393Sbostic */ 437*40393Sbostic (void) Lst_AtEnd (create, (ClientData)Str_New(src)); 438*40393Sbostic /* 439*40393Sbostic * Add the name to the .TARGETS variable as well, so the user cna 440*40393Sbostic * employ that, if desired. 441*40393Sbostic */ 442*40393Sbostic Var_Append(".TARGETS", src, VAR_GLOBAL); 443*40393Sbostic } else if (specType == Order) { 444*40393Sbostic /* 445*40393Sbostic * Create proper predecessor/successor links between the previous 446*40393Sbostic * source and the current one. 447*40393Sbostic */ 448*40393Sbostic gn = Targ_FindNode(src, TARG_CREATE); 449*40393Sbostic if (predecessor != NILGNODE) { 450*40393Sbostic (void)Lst_AtEnd(predecessor->successors, (ClientData)gn); 451*40393Sbostic (void)Lst_AtEnd(gn->preds, (ClientData)predecessor); 452*40393Sbostic } 453*40393Sbostic /* 454*40393Sbostic * The current source now becomes the predecessor for the next one. 455*40393Sbostic */ 456*40393Sbostic predecessor = gn; 457*40393Sbostic } else { 458*40393Sbostic /* 459*40393Sbostic * If the source is not an attribute, we need to find/create 460*40393Sbostic * a node for it. After that we can apply any operator to it 461*40393Sbostic * from a special target or link it to its parents, as 462*40393Sbostic * appropriate. 463*40393Sbostic * 464*40393Sbostic * In the case of a source that was the object of a :: operator, 465*40393Sbostic * the attribute is applied to all of its instances (as kept in 466*40393Sbostic * the 'cohorts' list of the node) or all the cohorts are linked 467*40393Sbostic * to all the targets. 468*40393Sbostic */ 469*40393Sbostic gn = Targ_FindNode (src, TARG_CREATE); 470*40393Sbostic if (tOp) { 471*40393Sbostic gn->type |= tOp; 472*40393Sbostic } else { 473*40393Sbostic Lst_ForEach (targets, ParseLinkSrc, (ClientData)gn); 474*40393Sbostic } 475*40393Sbostic if ((gn->type & OP_OPMASK) == OP_DOUBLEDEP) { 476*40393Sbostic register GNode *cohort; 477*40393Sbostic register LstNode ln; 478*40393Sbostic 479*40393Sbostic for (ln=Lst_First(gn->cohorts); ln != NILLNODE; ln = Lst_Succ(ln)){ 480*40393Sbostic cohort = (GNode *)Lst_Datum(ln); 481*40393Sbostic if (tOp) { 482*40393Sbostic cohort->type |= tOp; 483*40393Sbostic } else { 484*40393Sbostic Lst_ForEach(targets, ParseLinkSrc, (ClientData)cohort); 485*40393Sbostic } 486*40393Sbostic } 487*40393Sbostic } 488*40393Sbostic } 489*40393Sbostic } 490*40393Sbostic 491*40393Sbostic /*- 492*40393Sbostic *----------------------------------------------------------------------- 493*40393Sbostic * ParseFindMain -- 494*40393Sbostic * Find a real target in the list and set it to be the main one. 495*40393Sbostic * Called by ParseDoDependency when a main target hasn't been found 496*40393Sbostic * yet. 497*40393Sbostic * 498*40393Sbostic * Results: 499*40393Sbostic * 0 if main not found yet, 1 if it is. 500*40393Sbostic * 501*40393Sbostic * Side Effects: 502*40393Sbostic * mainNode is changed and Targ_SetMain is called. 503*40393Sbostic * 504*40393Sbostic *----------------------------------------------------------------------- 505*40393Sbostic */ 506*40393Sbostic static int 507*40393Sbostic ParseFindMain(gn) 508*40393Sbostic GNode *gn; /* Node to examine */ 509*40393Sbostic { 510*40393Sbostic if ((gn->type & (OP_NOTMAIN|OP_USE|OP_EXEC|OP_TRANSFORM)) == 0) { 511*40393Sbostic mainNode = gn; 512*40393Sbostic Targ_SetMain(gn); 513*40393Sbostic return (1); 514*40393Sbostic } else { 515*40393Sbostic return (0); 516*40393Sbostic } 517*40393Sbostic } 518*40393Sbostic 519*40393Sbostic /*- 520*40393Sbostic *----------------------------------------------------------------------- 521*40393Sbostic * ParseAddDir -- 522*40393Sbostic * Front-end for Dir_AddDir to make sure Lst_ForEach keeps going 523*40393Sbostic * 524*40393Sbostic * Results: 525*40393Sbostic * === 0 526*40393Sbostic * 527*40393Sbostic * Side Effects: 528*40393Sbostic * See Dir_AddDir. 529*40393Sbostic * 530*40393Sbostic *----------------------------------------------------------------------- 531*40393Sbostic */ 532*40393Sbostic static int 533*40393Sbostic ParseAddDir(path, name) 534*40393Sbostic Lst path; 535*40393Sbostic char *name; 536*40393Sbostic { 537*40393Sbostic Dir_AddDir(path, name); 538*40393Sbostic return(0); 539*40393Sbostic } 540*40393Sbostic 541*40393Sbostic /*- 542*40393Sbostic *----------------------------------------------------------------------- 543*40393Sbostic * ParseClearPath -- 544*40393Sbostic * Front-end for Dir_ClearPath to make sure Lst_ForEach keeps going 545*40393Sbostic * 546*40393Sbostic * Results: 547*40393Sbostic * === 0 548*40393Sbostic * 549*40393Sbostic * Side Effects: 550*40393Sbostic * See Dir_ClearPath 551*40393Sbostic * 552*40393Sbostic *----------------------------------------------------------------------- 553*40393Sbostic */ 554*40393Sbostic static int 555*40393Sbostic ParseClearPath(path) 556*40393Sbostic Lst path; 557*40393Sbostic { 558*40393Sbostic Dir_ClearPath(path); 559*40393Sbostic return(0); 560*40393Sbostic } 561*40393Sbostic 562*40393Sbostic /*- 563*40393Sbostic *--------------------------------------------------------------------- 564*40393Sbostic * ParseDoDependency -- 565*40393Sbostic * Parse the dependency line in line. 566*40393Sbostic * 567*40393Sbostic * Results: 568*40393Sbostic * None 569*40393Sbostic * 570*40393Sbostic * Side Effects: 571*40393Sbostic * The nodes of the sources are linked as children to the nodes of the 572*40393Sbostic * targets. Some nodes may be created. 573*40393Sbostic * 574*40393Sbostic * We parse a dependency line by first extracting words from the line and 575*40393Sbostic * finding nodes in the list of all targets with that name. This is done 576*40393Sbostic * until a character is encountered which is an operator character. Currently 577*40393Sbostic * these are only ! and :. At this point the operator is parsed and the 578*40393Sbostic * pointer into the line advanced until the first source is encountered. 579*40393Sbostic * The parsed operator is applied to each node in the 'targets' list, 580*40393Sbostic * which is where the nodes found for the targets are kept, by means of 581*40393Sbostic * the ParseDoOp function. 582*40393Sbostic * The sources are read in much the same way as the targets were except 583*40393Sbostic * that now they are expanded using the wildcarding scheme of the C-Shell 584*40393Sbostic * and all instances of the resulting words in the list of all targets 585*40393Sbostic * are found. Each of the resulting nodes is then linked to each of the 586*40393Sbostic * targets as one of its children. 587*40393Sbostic * Certain targets are handled specially. These are the ones detailed 588*40393Sbostic * by the specType variable. 589*40393Sbostic * The storing of transformation rules is also taken care of here. 590*40393Sbostic * A target is recognized as a transformation rule by calling 591*40393Sbostic * Suff_IsTransform. If it is a transformation rule, its node is gotten 592*40393Sbostic * from the suffix module via Suff_AddTransform rather than the standard 593*40393Sbostic * Targ_FindNode in the target module. 594*40393Sbostic *--------------------------------------------------------------------- 595*40393Sbostic */ 596*40393Sbostic static void 597*40393Sbostic ParseDoDependency (line) 598*40393Sbostic char *line; /* the line to parse */ 599*40393Sbostic { 600*40393Sbostic register char *cp; /* our current position */ 601*40393Sbostic register GNode *gn; /* a general purpose temporary node */ 602*40393Sbostic register int op; /* the operator on the line */ 603*40393Sbostic char savec; /* a place to save a character */ 604*40393Sbostic Lst paths; /* List of search paths to alter when parsing 605*40393Sbostic * a list of .PATH targets */ 606*40393Sbostic int tOp; /* operator from special target */ 607*40393Sbostic Lst sources; /* list of source names after expansion */ 608*40393Sbostic Lst curTargs; /* list of target names to be found and added 609*40393Sbostic * to the targets list */ 610*40393Sbostic 611*40393Sbostic tOp = 0; 612*40393Sbostic 613*40393Sbostic specType = Not; 614*40393Sbostic paths = (Lst)NULL; 615*40393Sbostic 616*40393Sbostic curTargs = Lst_Init(FALSE); 617*40393Sbostic 618*40393Sbostic do { 619*40393Sbostic for (cp = line; 620*40393Sbostic *cp && !isspace (*cp) && 621*40393Sbostic (*cp != '!') && (*cp != ':') && (*cp != '('); 622*40393Sbostic cp++) 623*40393Sbostic { 624*40393Sbostic if (*cp == '$') { 625*40393Sbostic /* 626*40393Sbostic * Must be a dynamic source (would have been expanded 627*40393Sbostic * otherwise), so call the Var module to parse the puppy 628*40393Sbostic * so we can safely advance beyond it...There should be 629*40393Sbostic * no errors in this, as they would have been discovered 630*40393Sbostic * in the initial Var_Subst and we wouldn't be here. 631*40393Sbostic */ 632*40393Sbostic int length; 633*40393Sbostic Boolean freeIt; 634*40393Sbostic char *result; 635*40393Sbostic 636*40393Sbostic result=Var_Parse(cp, VAR_CMD, TRUE, &length, &freeIt); 637*40393Sbostic 638*40393Sbostic if (freeIt) { 639*40393Sbostic free(result); 640*40393Sbostic } 641*40393Sbostic cp += length-1; 642*40393Sbostic } 643*40393Sbostic continue; 644*40393Sbostic } 645*40393Sbostic if (*cp == '(') { 646*40393Sbostic /* 647*40393Sbostic * Archives must be handled specially to make sure the OP_ARCHV 648*40393Sbostic * flag is set in their 'type' field, for one thing, and because 649*40393Sbostic * things like "archive(file1.o file2.o file3.o)" are permissible. 650*40393Sbostic * Arch_ParseArchive will set 'line' to be the first non-blank 651*40393Sbostic * after the archive-spec. It creates/finds nodes for the members 652*40393Sbostic * and places them on the given list, returning SUCCESS if all 653*40393Sbostic * went well and FAILURE if there was an error in the 654*40393Sbostic * specification. On error, line should remain untouched. 655*40393Sbostic */ 656*40393Sbostic if (Arch_ParseArchive (&line, targets, VAR_CMD) != SUCCESS) { 657*40393Sbostic Parse_Error (PARSE_FATAL, 658*40393Sbostic "Error in archive specification: \"%s\"", line); 659*40393Sbostic return; 660*40393Sbostic } else { 661*40393Sbostic continue; 662*40393Sbostic } 663*40393Sbostic } 664*40393Sbostic savec = *cp; 665*40393Sbostic 666*40393Sbostic if (!*cp) { 667*40393Sbostic /* 668*40393Sbostic * Ending a dependency line without an operator is a Bozo 669*40393Sbostic * no-no 670*40393Sbostic */ 671*40393Sbostic Parse_Error (PARSE_FATAL, "Need an operator"); 672*40393Sbostic return; 673*40393Sbostic } 674*40393Sbostic *cp = '\0'; 675*40393Sbostic /* 676*40393Sbostic * Have a word in line. See if it's a special target and set 677*40393Sbostic * specType to match it. 678*40393Sbostic */ 679*40393Sbostic if (*line == '.' && isupper (line[1])) { 680*40393Sbostic /* 681*40393Sbostic * See if the target is a special target that must have it 682*40393Sbostic * or its sources handled specially. 683*40393Sbostic */ 684*40393Sbostic int keywd = ParseFindKeyword(line); 685*40393Sbostic if (keywd != -1) { 686*40393Sbostic if (specType == Path && parseKeywords[keywd].spec != Path) { 687*40393Sbostic Parse_Error(PARSE_FATAL, "Mismatched special targets"); 688*40393Sbostic return; 689*40393Sbostic } 690*40393Sbostic 691*40393Sbostic specType = parseKeywords[keywd].spec; 692*40393Sbostic tOp = parseKeywords[keywd].op; 693*40393Sbostic 694*40393Sbostic /* 695*40393Sbostic * Certain special targets have special semantics: 696*40393Sbostic * .PATH Have to set the dirSearchPath 697*40393Sbostic * variable too 698*40393Sbostic * .EXPORT Doesn't really apply the 699*40393Sbostic * .EXPORT operator to its 700*40393Sbostic * sources, so we reset tOp. 701*40393Sbostic * .MAIN Its sources are only used if 702*40393Sbostic * nothing has been specified to 703*40393Sbostic * create. 704*40393Sbostic * .DEFAULT Need to create a node to hang 705*40393Sbostic * commands on, but we don't want 706*40393Sbostic * it in the graph, nor do we want 707*40393Sbostic * it to be the Main Target, so we 708*40393Sbostic * create it, set OP_NOTMAIN and 709*40393Sbostic * add it to the list, setting 710*40393Sbostic * DEFAULT to the new node for 711*40393Sbostic * later use. We claim the node is 712*40393Sbostic * A transformation rule to make 713*40393Sbostic * life easier later, when we'll 714*40393Sbostic * use Make_HandleUse to actually 715*40393Sbostic * apply the .DEFAULT commands. 716*40393Sbostic * .BEGIN 717*40393Sbostic * .END 718*40393Sbostic * .INTERRUPT Are not to be considered the 719*40393Sbostic * main target. 720*40393Sbostic * .NOTPARALLEL Make only one target at a time. 721*40393Sbostic * .SINGLESHELL Create a shell for each command. 722*40393Sbostic * .ORDER Must set initial predecessor to NIL 723*40393Sbostic */ 724*40393Sbostic switch (specType) { 725*40393Sbostic case Path: 726*40393Sbostic if (paths == NULL) { 727*40393Sbostic paths = Lst_Init(FALSE); 728*40393Sbostic } 729*40393Sbostic (void)Lst_AtEnd(paths, (ClientData)dirSearchPath); 730*40393Sbostic break; 731*40393Sbostic case Export: 732*40393Sbostic tOp = 0; 733*40393Sbostic break; 734*40393Sbostic case Main: 735*40393Sbostic if (!Lst_IsEmpty(create)) { 736*40393Sbostic specType = Not; 737*40393Sbostic } 738*40393Sbostic break; 739*40393Sbostic case Begin: 740*40393Sbostic case End: 741*40393Sbostic case Interrupt: 742*40393Sbostic gn = Targ_FindNode(line, TARG_CREATE); 743*40393Sbostic gn->type |= OP_NOTMAIN; 744*40393Sbostic (void)Lst_AtEnd(targets, (ClientData)gn); 745*40393Sbostic break; 746*40393Sbostic case Default: 747*40393Sbostic gn = Targ_NewGN(".DEFAULT"); 748*40393Sbostic gn->type |= (OP_NOTMAIN|OP_TRANSFORM); 749*40393Sbostic (void)Lst_AtEnd(targets, (ClientData)gn); 750*40393Sbostic DEFAULT = gn; 751*40393Sbostic break; 752*40393Sbostic case NotParallel: 753*40393Sbostic { 754*40393Sbostic extern int maxJobs; 755*40393Sbostic 756*40393Sbostic maxJobs = 1; 757*40393Sbostic break; 758*40393Sbostic } 759*40393Sbostic case SingleShell: 760*40393Sbostic backwards = 1; 761*40393Sbostic break; 762*40393Sbostic case Order: 763*40393Sbostic predecessor = NILGNODE; 764*40393Sbostic break; 765*40393Sbostic } 766*40393Sbostic } else if (strncmp (line, ".PATH", 5) == 0) { 767*40393Sbostic /* 768*40393Sbostic * .PATH<suffix> has to be handled specially. 769*40393Sbostic * Call on the suffix module to give us a path to 770*40393Sbostic * modify. 771*40393Sbostic */ 772*40393Sbostic Lst path; 773*40393Sbostic 774*40393Sbostic specType = Path; 775*40393Sbostic path = Suff_GetPath (&line[5]); 776*40393Sbostic if (path == NILLST) { 777*40393Sbostic Parse_Error (PARSE_FATAL, 778*40393Sbostic "Suffix '%s' not defined (yet)", 779*40393Sbostic &line[5]); 780*40393Sbostic return; 781*40393Sbostic } else { 782*40393Sbostic if (paths == (Lst)NULL) { 783*40393Sbostic paths = Lst_Init(FALSE); 784*40393Sbostic } 785*40393Sbostic (void)Lst_AtEnd(paths, (ClientData)path); 786*40393Sbostic } 787*40393Sbostic } 788*40393Sbostic } 789*40393Sbostic 790*40393Sbostic /* 791*40393Sbostic * Have word in line. Get or create its node and stick it at 792*40393Sbostic * the end of the targets list 793*40393Sbostic */ 794*40393Sbostic if ((specType == Not) && (*line != '\0')) { 795*40393Sbostic if (Dir_HasWildcards(line)) { 796*40393Sbostic /* 797*40393Sbostic * Targets are to be sought only in the current directory, 798*40393Sbostic * so create an empty path for the thing. Note we need to 799*40393Sbostic * use Dir_Destroy in the destruction of the path as the 800*40393Sbostic * Dir module could have added a directory to the path... 801*40393Sbostic */ 802*40393Sbostic Lst emptyPath = Lst_Init(FALSE); 803*40393Sbostic 804*40393Sbostic Dir_Expand(line, emptyPath, curTargs); 805*40393Sbostic 806*40393Sbostic Lst_Destroy(emptyPath, Dir_Destroy); 807*40393Sbostic } else { 808*40393Sbostic /* 809*40393Sbostic * No wildcards, but we want to avoid code duplication, 810*40393Sbostic * so create a list with the word on it. 811*40393Sbostic */ 812*40393Sbostic (void)Lst_AtEnd(curTargs, (ClientData)line); 813*40393Sbostic } 814*40393Sbostic 815*40393Sbostic while(!Lst_IsEmpty(curTargs)) { 816*40393Sbostic char *targName = (char *)Lst_DeQueue(curTargs); 817*40393Sbostic 818*40393Sbostic if (!Suff_IsTransform (targName)) { 819*40393Sbostic gn = Targ_FindNode (targName, TARG_CREATE); 820*40393Sbostic } else { 821*40393Sbostic gn = Suff_AddTransform (targName); 822*40393Sbostic } 823*40393Sbostic 824*40393Sbostic (void)Lst_AtEnd (targets, (ClientData)gn); 825*40393Sbostic } 826*40393Sbostic } else if (specType == Path && *line != '.' && *line != '\0') { 827*40393Sbostic Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line); 828*40393Sbostic } 829*40393Sbostic 830*40393Sbostic *cp = savec; 831*40393Sbostic /* 832*40393Sbostic * If it is a special type and not .PATH, it's the only target we 833*40393Sbostic * allow on this line... 834*40393Sbostic */ 835*40393Sbostic if (specType != Not && specType != Path) { 836*40393Sbostic Boolean warn = FALSE; 837*40393Sbostic 838*40393Sbostic while ((*cp != '!') && (*cp != ':') && *cp) { 839*40393Sbostic if (*cp != ' ' && *cp != '\t') { 840*40393Sbostic warn = TRUE; 841*40393Sbostic } 842*40393Sbostic cp++; 843*40393Sbostic } 844*40393Sbostic if (warn) { 845*40393Sbostic Parse_Error(PARSE_WARNING, "Extra target ignored"); 846*40393Sbostic } 847*40393Sbostic } else { 848*40393Sbostic while (*cp && isspace (*cp)) { 849*40393Sbostic cp++; 850*40393Sbostic } 851*40393Sbostic } 852*40393Sbostic line = cp; 853*40393Sbostic } while ((*line != '!') && (*line != ':') && *line); 854*40393Sbostic 855*40393Sbostic /* 856*40393Sbostic * Don't need the list of target names anymore... 857*40393Sbostic */ 858*40393Sbostic Lst_Destroy(curTargs, NOFREE); 859*40393Sbostic 860*40393Sbostic if (!Lst_IsEmpty(targets)) { 861*40393Sbostic switch(specType) { 862*40393Sbostic default: 863*40393Sbostic Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. Mundane ones ignored"); 864*40393Sbostic break; 865*40393Sbostic case Default: 866*40393Sbostic case Begin: 867*40393Sbostic case End: 868*40393Sbostic case Interrupt: 869*40393Sbostic /* 870*40393Sbostic * These four create nodes on which to hang commands, so 871*40393Sbostic * targets shouldn't be empty... 872*40393Sbostic */ 873*40393Sbostic case Not: 874*40393Sbostic /* 875*40393Sbostic * Nothing special here -- targets can be empty if it wants. 876*40393Sbostic */ 877*40393Sbostic break; 878*40393Sbostic } 879*40393Sbostic } 880*40393Sbostic 881*40393Sbostic /* 882*40393Sbostic * Have now parsed all the target names. Must parse the operator next. The 883*40393Sbostic * result is left in op . 884*40393Sbostic */ 885*40393Sbostic if (*cp == '!') { 886*40393Sbostic op = OP_FORCE; 887*40393Sbostic } else if (*cp == ':') { 888*40393Sbostic if (cp[1] == ':') { 889*40393Sbostic op = OP_DOUBLEDEP; 890*40393Sbostic cp++; 891*40393Sbostic } else { 892*40393Sbostic op = OP_DEPENDS; 893*40393Sbostic } 894*40393Sbostic } else { 895*40393Sbostic Parse_Error (PARSE_FATAL, "Missing dependency operator"); 896*40393Sbostic return; 897*40393Sbostic } 898*40393Sbostic 899*40393Sbostic cp++; /* Advance beyond operator */ 900*40393Sbostic 901*40393Sbostic Lst_ForEach (targets, ParseDoOp, (ClientData)op); 902*40393Sbostic 903*40393Sbostic /* 904*40393Sbostic * Get to the first source 905*40393Sbostic */ 906*40393Sbostic while (*cp && isspace (*cp)) { 907*40393Sbostic cp++; 908*40393Sbostic } 909*40393Sbostic line = cp; 910*40393Sbostic 911*40393Sbostic /* 912*40393Sbostic * Several special targets take different actions if present with no 913*40393Sbostic * sources: 914*40393Sbostic * a .SUFFIXES line with no sources clears out all old suffixes 915*40393Sbostic * a .PRECIOUS line makes all targets precious 916*40393Sbostic * a .IGNORE line ignores errors for all targets 917*40393Sbostic * a .SILENT line creates silence when making all targets 918*40393Sbostic * a .PATH removes all directories from the search path(s). 919*40393Sbostic * a .NOEXPORT turns off exportation for all jobs. 920*40393Sbostic */ 921*40393Sbostic if (!*line) { 922*40393Sbostic switch (specType) { 923*40393Sbostic case Suffixes: 924*40393Sbostic Suff_ClearSuffixes (); 925*40393Sbostic break; 926*40393Sbostic case Precious: 927*40393Sbostic allPrecious = TRUE; 928*40393Sbostic break; 929*40393Sbostic case Ignore: 930*40393Sbostic ignoreErrors = TRUE; 931*40393Sbostic break; 932*40393Sbostic case Silent: 933*40393Sbostic beSilent = TRUE; 934*40393Sbostic break; 935*40393Sbostic case Path: 936*40393Sbostic Lst_ForEach(paths, ParseClearPath, (ClientData)NULL); 937*40393Sbostic break; 938*40393Sbostic case NoExport: 939*40393Sbostic noExport = TRUE; 940*40393Sbostic break; 941*40393Sbostic } 942*40393Sbostic } else if (specType == MFlags) { 943*40393Sbostic /* 944*40393Sbostic * Call on functions in main.c to deal with these arguments and 945*40393Sbostic * set the initial character to a null-character so the loop to 946*40393Sbostic * get sources won't get anything 947*40393Sbostic */ 948*40393Sbostic Main_ParseArgLine (line); 949*40393Sbostic *line = '\0'; 950*40393Sbostic } else if (specType == Shell) { 951*40393Sbostic if (Job_ParseShell (line) != SUCCESS) { 952*40393Sbostic Parse_Error (PARSE_FATAL, "improper shell specification"); 953*40393Sbostic return; 954*40393Sbostic } 955*40393Sbostic *line = '\0'; 956*40393Sbostic } else if ((specType == NotParallel) || (specType == SingleShell)) { 957*40393Sbostic *line = '\0'; 958*40393Sbostic } 959*40393Sbostic 960*40393Sbostic /* 961*40393Sbostic * NOW GO FOR THE SOURCES 962*40393Sbostic */ 963*40393Sbostic if ((specType == Suffixes) || (specType == Path) || 964*40393Sbostic (specType == Includes) || (specType == Libs) || 965*40393Sbostic (specType == Export) || (specType == Null)) 966*40393Sbostic { 967*40393Sbostic while (*line) { 968*40393Sbostic /* 969*40393Sbostic * If the target was one that doesn't take files as its sources 970*40393Sbostic * but takes something like suffixes, we take each 971*40393Sbostic * space-separated word on the line as a something and deal 972*40393Sbostic * with it accordingly. 973*40393Sbostic * 974*40393Sbostic * If the target was .SUFFIXES, we take each source as a 975*40393Sbostic * suffix and add it to the list of suffixes maintained by the 976*40393Sbostic * Suff module. 977*40393Sbostic * 978*40393Sbostic * If the target was a .PATH, we add the source as a directory 979*40393Sbostic * to search on the search path. 980*40393Sbostic * 981*40393Sbostic * If it was .INCLUDES, the source is taken to be the suffix of 982*40393Sbostic * files which will be #included and whose search path should 983*40393Sbostic * be present in the .INCLUDES variable. 984*40393Sbostic * 985*40393Sbostic * If it was .LIBS, the source is taken to be the suffix of 986*40393Sbostic * files which are considered libraries and whose search path 987*40393Sbostic * should be present in the .LIBS variable. 988*40393Sbostic * 989*40393Sbostic * If it was .EXPORT, the source is the location of the export 990*40393Sbostic * server and is passed to the Rmt module as such. 991*40393Sbostic * 992*40393Sbostic * If it was .NULL, the source is the suffix to use when a file 993*40393Sbostic * has no valid suffix. 994*40393Sbostic */ 995*40393Sbostic char savec; 996*40393Sbostic while (*cp && !isspace (*cp)) { 997*40393Sbostic cp++; 998*40393Sbostic } 999*40393Sbostic savec = *cp; 1000*40393Sbostic *cp = '\0'; 1001*40393Sbostic switch (specType) { 1002*40393Sbostic case Suffixes: 1003*40393Sbostic Suff_AddSuffix (line); 1004*40393Sbostic break; 1005*40393Sbostic case Path: 1006*40393Sbostic Lst_ForEach(paths, ParseAddDir, (ClientData)line); 1007*40393Sbostic break; 1008*40393Sbostic case Includes: 1009*40393Sbostic Suff_AddInclude (line); 1010*40393Sbostic break; 1011*40393Sbostic case Libs: 1012*40393Sbostic Suff_AddLib (line); 1013*40393Sbostic break; 1014*40393Sbostic case Export: 1015*40393Sbostic Rmt_AddServer (line); 1016*40393Sbostic break; 1017*40393Sbostic case Null: 1018*40393Sbostic Suff_SetNull (line); 1019*40393Sbostic break; 1020*40393Sbostic } 1021*40393Sbostic *cp = savec; 1022*40393Sbostic if (savec != '\0') { 1023*40393Sbostic cp++; 1024*40393Sbostic } 1025*40393Sbostic while (*cp && isspace (*cp)) { 1026*40393Sbostic cp++; 1027*40393Sbostic } 1028*40393Sbostic line = cp; 1029*40393Sbostic } 1030*40393Sbostic if (paths) { 1031*40393Sbostic Lst_Destroy(paths, NOFREE); 1032*40393Sbostic } 1033*40393Sbostic } else { 1034*40393Sbostic while (*line) { 1035*40393Sbostic /* 1036*40393Sbostic * The targets take real sources, so we must beware of archive 1037*40393Sbostic * specifications (i.e. things with left parentheses in them) 1038*40393Sbostic * and handle them accordingly. 1039*40393Sbostic */ 1040*40393Sbostic while (*cp && !isspace (*cp)) { 1041*40393Sbostic if ((*cp == '(') && (cp > line) && (cp[-1] != '$')) { 1042*40393Sbostic /* 1043*40393Sbostic * Only stop for a left parenthesis if it isn't at the 1044*40393Sbostic * start of a word (that'll be for variable changes 1045*40393Sbostic * later) and isn't preceded by a dollar sign (a dynamic 1046*40393Sbostic * source). 1047*40393Sbostic */ 1048*40393Sbostic break; 1049*40393Sbostic } else { 1050*40393Sbostic cp++; 1051*40393Sbostic } 1052*40393Sbostic } 1053*40393Sbostic 1054*40393Sbostic if (*cp == '(') { 1055*40393Sbostic GNode *gn; 1056*40393Sbostic 1057*40393Sbostic sources = Lst_Init (FALSE); 1058*40393Sbostic if (Arch_ParseArchive (&line, sources, VAR_CMD) != SUCCESS) { 1059*40393Sbostic Parse_Error (PARSE_FATAL, 1060*40393Sbostic "Error in source archive spec \"%s\"", line); 1061*40393Sbostic return; 1062*40393Sbostic } 1063*40393Sbostic 1064*40393Sbostic while (!Lst_IsEmpty (sources)) { 1065*40393Sbostic gn = (GNode *) Lst_DeQueue (sources); 1066*40393Sbostic ParseDoSrc (tOp, gn->name); 1067*40393Sbostic } 1068*40393Sbostic Lst_Destroy (sources, NOFREE); 1069*40393Sbostic cp = line; 1070*40393Sbostic } else { 1071*40393Sbostic if (*cp) { 1072*40393Sbostic *cp = '\0'; 1073*40393Sbostic cp += 1; 1074*40393Sbostic } 1075*40393Sbostic 1076*40393Sbostic ParseDoSrc (tOp, line); 1077*40393Sbostic } 1078*40393Sbostic while (*cp && isspace (*cp)) { 1079*40393Sbostic cp++; 1080*40393Sbostic } 1081*40393Sbostic line = cp; 1082*40393Sbostic } 1083*40393Sbostic } 1084*40393Sbostic 1085*40393Sbostic if (mainNode == NILGNODE) { 1086*40393Sbostic /* 1087*40393Sbostic * If we have yet to decide on a main target to make, in the 1088*40393Sbostic * absence of any user input, we want the first target on 1089*40393Sbostic * the first dependency line that is actually a real target 1090*40393Sbostic * (i.e. isn't a .USE or .EXEC rule) to be made. 1091*40393Sbostic */ 1092*40393Sbostic Lst_ForEach (targets, ParseFindMain, (ClientData)0); 1093*40393Sbostic } 1094*40393Sbostic 1095*40393Sbostic } 1096*40393Sbostic 1097*40393Sbostic /*- 1098*40393Sbostic *--------------------------------------------------------------------- 1099*40393Sbostic * Parse_IsVar -- 1100*40393Sbostic * Return TRUE if the passed line is a variable assignment. A variable 1101*40393Sbostic * assignment consists of a single word followed by optional whitespace 1102*40393Sbostic * followed by either a += or an = operator. 1103*40393Sbostic * This function is used both by the Parse_File function and main when 1104*40393Sbostic * parsing the command-line arguments. 1105*40393Sbostic * 1106*40393Sbostic * Results: 1107*40393Sbostic * TRUE if it is. FALSE if it ain't 1108*40393Sbostic * 1109*40393Sbostic * Side Effects: 1110*40393Sbostic * none 1111*40393Sbostic *--------------------------------------------------------------------- 1112*40393Sbostic */ 1113*40393Sbostic Boolean 1114*40393Sbostic Parse_IsVar (line) 1115*40393Sbostic register char *line; /* the line to check */ 1116*40393Sbostic { 1117*40393Sbostic register Boolean wasSpace = FALSE; /* set TRUE if found a space */ 1118*40393Sbostic register Boolean haveName = FALSE; /* Set TRUE if have a variable name */ 1119*40393Sbostic 1120*40393Sbostic /* 1121*40393Sbostic * Skip to variable name 1122*40393Sbostic */ 1123*40393Sbostic while ((*line == ' ') || (*line == '\t')) { 1124*40393Sbostic line++; 1125*40393Sbostic } 1126*40393Sbostic 1127*40393Sbostic while (*line != '=') { 1128*40393Sbostic if (*line == '\0') { 1129*40393Sbostic /* 1130*40393Sbostic * end-of-line -- can't be a variable assignment. 1131*40393Sbostic */ 1132*40393Sbostic return (FALSE); 1133*40393Sbostic } else if ((*line == ' ') || (*line == '\t')) { 1134*40393Sbostic /* 1135*40393Sbostic * there can be as much white space as desired so long as there is 1136*40393Sbostic * only one word before the operator 1137*40393Sbostic */ 1138*40393Sbostic wasSpace = TRUE; 1139*40393Sbostic } else if (wasSpace && haveName) { 1140*40393Sbostic /* 1141*40393Sbostic * Stop when an = operator is found. 1142*40393Sbostic */ 1143*40393Sbostic if ((*line == '+') || (*line == ':') || (*line == '?') || 1144*40393Sbostic (*line == '!')) { 1145*40393Sbostic break; 1146*40393Sbostic } 1147*40393Sbostic 1148*40393Sbostic /* 1149*40393Sbostic * This is the start of another word, so not assignment. 1150*40393Sbostic */ 1151*40393Sbostic return (FALSE); 1152*40393Sbostic } else { 1153*40393Sbostic haveName = TRUE; 1154*40393Sbostic wasSpace = FALSE; 1155*40393Sbostic } 1156*40393Sbostic line++; 1157*40393Sbostic } 1158*40393Sbostic 1159*40393Sbostic /* 1160*40393Sbostic * A final check: if we stopped on a +, ?, ! or :, the next character must 1161*40393Sbostic * be an = or it ain't a valid assignment 1162*40393Sbostic */ 1163*40393Sbostic if (((*line == '+') || 1164*40393Sbostic (*line == '?') || 1165*40393Sbostic (*line == ':') || 1166*40393Sbostic (*line == '!')) && 1167*40393Sbostic (line[1] != '=')) 1168*40393Sbostic { 1169*40393Sbostic return (FALSE); 1170*40393Sbostic } else { 1171*40393Sbostic return (haveName); 1172*40393Sbostic } 1173*40393Sbostic } 1174*40393Sbostic 1175*40393Sbostic /*- 1176*40393Sbostic *--------------------------------------------------------------------- 1177*40393Sbostic * Parse_DoVar -- 1178*40393Sbostic * Take the variable assignment in the passed line and do it in the 1179*40393Sbostic * global context. 1180*40393Sbostic * 1181*40393Sbostic * Note: There is a lexical ambiguity with assignment modifier characters 1182*40393Sbostic * in variable names. This routine interprets the character before the = 1183*40393Sbostic * as a modifier. Therefore, an assignment like 1184*40393Sbostic * C++=/usr/bin/CC 1185*40393Sbostic * is interpreted as "C+ +=" instead of "C++ =". 1186*40393Sbostic * 1187*40393Sbostic * Results: 1188*40393Sbostic * none 1189*40393Sbostic * 1190*40393Sbostic * Side Effects: 1191*40393Sbostic * the variable structure of the given variable name is altered in the 1192*40393Sbostic * global context. 1193*40393Sbostic *--------------------------------------------------------------------- 1194*40393Sbostic */ 1195*40393Sbostic void 1196*40393Sbostic Parse_DoVar (line, ctxt) 1197*40393Sbostic char *line; /* a line guaranteed to be a variable 1198*40393Sbostic * assignment. This reduces error checks */ 1199*40393Sbostic GNode *ctxt; /* Context in which to do the assignment */ 1200*40393Sbostic { 1201*40393Sbostic register char *cp; /* pointer into line */ 1202*40393Sbostic enum { 1203*40393Sbostic VAR_SUBST, VAR_APPEND, VAR_SHELL, VAR_NORMAL 1204*40393Sbostic } type; /* Type of assignment */ 1205*40393Sbostic char *opc; /* ptr to operator character to 1206*40393Sbostic * null-terminate the variable name */ 1207*40393Sbostic 1208*40393Sbostic /* 1209*40393Sbostic * Skip to variable name 1210*40393Sbostic */ 1211*40393Sbostic while ((*line == ' ') || (*line == '\t')) { 1212*40393Sbostic line++; 1213*40393Sbostic } 1214*40393Sbostic 1215*40393Sbostic /* 1216*40393Sbostic * Skip to operator character, nulling out whitespace as we go 1217*40393Sbostic */ 1218*40393Sbostic for (cp = line + 1; *cp != '='; cp++) { 1219*40393Sbostic if (isspace (*cp)) { 1220*40393Sbostic *cp = '\0'; 1221*40393Sbostic } 1222*40393Sbostic } 1223*40393Sbostic opc = cp-1; /* operator is the previous character */ 1224*40393Sbostic *cp++ = '\0'; /* nuke the = */ 1225*40393Sbostic 1226*40393Sbostic /* 1227*40393Sbostic * Check operator type 1228*40393Sbostic */ 1229*40393Sbostic switch (*opc) { 1230*40393Sbostic case '+': 1231*40393Sbostic type = VAR_APPEND; 1232*40393Sbostic *opc = '\0'; 1233*40393Sbostic break; 1234*40393Sbostic 1235*40393Sbostic case '?': 1236*40393Sbostic /* 1237*40393Sbostic * If the variable already has a value, we don't do anything. 1238*40393Sbostic */ 1239*40393Sbostic *opc = '\0'; 1240*40393Sbostic if (Var_Exists(line, ctxt)) { 1241*40393Sbostic return; 1242*40393Sbostic } else { 1243*40393Sbostic type = VAR_NORMAL; 1244*40393Sbostic } 1245*40393Sbostic break; 1246*40393Sbostic 1247*40393Sbostic case ':': 1248*40393Sbostic type = VAR_SUBST; 1249*40393Sbostic *opc = '\0'; 1250*40393Sbostic break; 1251*40393Sbostic 1252*40393Sbostic case '!': 1253*40393Sbostic type = VAR_SHELL; 1254*40393Sbostic *opc = '\0'; 1255*40393Sbostic break; 1256*40393Sbostic 1257*40393Sbostic default: 1258*40393Sbostic type = VAR_NORMAL; 1259*40393Sbostic break; 1260*40393Sbostic } 1261*40393Sbostic 1262*40393Sbostic while (isspace (*cp)) { 1263*40393Sbostic cp++; 1264*40393Sbostic } 1265*40393Sbostic 1266*40393Sbostic if (type == VAR_APPEND) { 1267*40393Sbostic Var_Append (line, cp, ctxt); 1268*40393Sbostic } else if (type == VAR_SUBST) { 1269*40393Sbostic /* 1270*40393Sbostic * Allow variables in the old value to be undefined, but leave their 1271*40393Sbostic * invocation alone -- this is done by forcing oldVars to be false. 1272*40393Sbostic * XXX: This can cause recursive variables, but that's not hard to do, 1273*40393Sbostic * and this allows someone to do something like 1274*40393Sbostic * 1275*40393Sbostic * CFLAGS = $(.INCLUDES) 1276*40393Sbostic * CFLAGS := -I.. $(CFLAGS) 1277*40393Sbostic * 1278*40393Sbostic * And not get an error. 1279*40393Sbostic */ 1280*40393Sbostic Boolean oldOldVars = oldVars; 1281*40393Sbostic 1282*40393Sbostic oldVars = FALSE; 1283*40393Sbostic cp = Var_Subst(cp, ctxt, FALSE); 1284*40393Sbostic oldVars = oldOldVars; 1285*40393Sbostic 1286*40393Sbostic Var_Set(line, cp, ctxt); 1287*40393Sbostic free(cp); 1288*40393Sbostic } else if (type == VAR_SHELL) { 1289*40393Sbostic char result[BUFSIZ]; /* Result of command */ 1290*40393Sbostic char *args[4]; /* Args for invoking the shell */ 1291*40393Sbostic int fds[2]; /* Pipe streams */ 1292*40393Sbostic int cpid; /* Child PID */ 1293*40393Sbostic int pid; /* PID from wait() */ 1294*40393Sbostic Boolean freeCmd; /* TRUE if the command needs to be freed, i.e. 1295*40393Sbostic * if any variable expansion was performed */ 1296*40393Sbostic 1297*40393Sbostic /* 1298*40393Sbostic * Set up arguments for shell 1299*40393Sbostic */ 1300*40393Sbostic args[0] = "sh"; 1301*40393Sbostic args[1] = "-c"; 1302*40393Sbostic if (index(cp, '$') != (char *)NULL) { 1303*40393Sbostic /* 1304*40393Sbostic * There's a dollar sign in the command, so perform variable 1305*40393Sbostic * expansion on the whole thing. The resulting string will need 1306*40393Sbostic * freeing when we're done, so set freeCmd to TRUE. 1307*40393Sbostic */ 1308*40393Sbostic args[2] = Var_Subst(cp, VAR_CMD, TRUE); 1309*40393Sbostic freeCmd = TRUE; 1310*40393Sbostic } else { 1311*40393Sbostic args[2] = cp; 1312*40393Sbostic freeCmd = FALSE; 1313*40393Sbostic } 1314*40393Sbostic args[3] = (char *)NULL; 1315*40393Sbostic 1316*40393Sbostic /* 1317*40393Sbostic * Open a pipe for fetching its output 1318*40393Sbostic */ 1319*40393Sbostic pipe(fds); 1320*40393Sbostic 1321*40393Sbostic /* 1322*40393Sbostic * Fork 1323*40393Sbostic */ 1324*40393Sbostic cpid = vfork(); 1325*40393Sbostic if (cpid == 0) { 1326*40393Sbostic /* 1327*40393Sbostic * Close input side of pipe 1328*40393Sbostic */ 1329*40393Sbostic close(fds[0]); 1330*40393Sbostic 1331*40393Sbostic /* 1332*40393Sbostic * Duplicate the output stream to the shell's output, then 1333*40393Sbostic * shut the extra thing down. Note we don't fetch the error 1334*40393Sbostic * stream...why not? Why? 1335*40393Sbostic */ 1336*40393Sbostic dup2(fds[1], 1); 1337*40393Sbostic close(fds[1]); 1338*40393Sbostic 1339*40393Sbostic execv("/bin/sh", args); 1340*40393Sbostic _exit(1); 1341*40393Sbostic } else if (cpid < 0) { 1342*40393Sbostic /* 1343*40393Sbostic * Couldn't fork -- tell the user and make the variable null 1344*40393Sbostic */ 1345*40393Sbostic Parse_Error(PARSE_WARNING, "Couldn't exec \"%s\"", cp); 1346*40393Sbostic Var_Set(line, "", ctxt); 1347*40393Sbostic } else { 1348*40393Sbostic int status; 1349*40393Sbostic int cc; 1350*40393Sbostic 1351*40393Sbostic /* 1352*40393Sbostic * No need for the writing half 1353*40393Sbostic */ 1354*40393Sbostic close(fds[1]); 1355*40393Sbostic 1356*40393Sbostic /* 1357*40393Sbostic * Wait for the process to exit. 1358*40393Sbostic * 1359*40393Sbostic * XXX: If the child writes more than a pipe's worth, we will 1360*40393Sbostic * deadlock. 1361*40393Sbostic */ 1362*40393Sbostic while(((pid = wait(&status)) != cpid) && (pid >= 0)) { 1363*40393Sbostic ; 1364*40393Sbostic } 1365*40393Sbostic 1366*40393Sbostic /* 1367*40393Sbostic * Read all the characters the child wrote. 1368*40393Sbostic */ 1369*40393Sbostic cc = read(fds[0], result, sizeof(result)); 1370*40393Sbostic 1371*40393Sbostic if (cc < 0) { 1372*40393Sbostic /* 1373*40393Sbostic * Couldn't read the child's output -- tell the user and 1374*40393Sbostic * set the variable to null 1375*40393Sbostic */ 1376*40393Sbostic Parse_Error(PARSE_WARNING, "Couldn't read shell's output"); 1377*40393Sbostic cc = 0; 1378*40393Sbostic } 1379*40393Sbostic 1380*40393Sbostic if (status) { 1381*40393Sbostic /* 1382*40393Sbostic * Child returned an error -- tell the user but still use 1383*40393Sbostic * the result. 1384*40393Sbostic */ 1385*40393Sbostic Parse_Error(PARSE_WARNING, "\"%s\" returned non-zero", cp); 1386*40393Sbostic } 1387*40393Sbostic /* 1388*40393Sbostic * Null-terminate the result, convert newlines to spaces and 1389*40393Sbostic * install it in the variable. 1390*40393Sbostic */ 1391*40393Sbostic result[cc] = '\0'; 1392*40393Sbostic cp = &result[cc] - 1; 1393*40393Sbostic 1394*40393Sbostic if (*cp == '\n') { 1395*40393Sbostic /* 1396*40393Sbostic * A final newline is just stripped 1397*40393Sbostic */ 1398*40393Sbostic *cp-- = '\0'; 1399*40393Sbostic } 1400*40393Sbostic while (cp >= result) { 1401*40393Sbostic if (*cp == '\n') { 1402*40393Sbostic *cp = ' '; 1403*40393Sbostic } 1404*40393Sbostic cp--; 1405*40393Sbostic } 1406*40393Sbostic Var_Set(line, result, ctxt); 1407*40393Sbostic 1408*40393Sbostic /* 1409*40393Sbostic * Close the input side of the pipe. 1410*40393Sbostic */ 1411*40393Sbostic close(fds[0]); 1412*40393Sbostic } 1413*40393Sbostic if (freeCmd) { 1414*40393Sbostic free(args[2]); 1415*40393Sbostic } 1416*40393Sbostic } else { 1417*40393Sbostic /* 1418*40393Sbostic * Normal assignment -- just do it. 1419*40393Sbostic */ 1420*40393Sbostic Var_Set (line, cp, ctxt); 1421*40393Sbostic } 1422*40393Sbostic } 1423*40393Sbostic 1424*40393Sbostic /*- 1425*40393Sbostic *--------------------------------------------------------------------- 1426*40393Sbostic * ParseAddCmd -- 1427*40393Sbostic * Lst_ForEach function to add a command line to all targets 1428*40393Sbostic * 1429*40393Sbostic * Results: 1430*40393Sbostic * Always 0 1431*40393Sbostic * 1432*40393Sbostic * Side Effects: 1433*40393Sbostic * A new element is added to the commands list of the node. 1434*40393Sbostic *--------------------------------------------------------------------- 1435*40393Sbostic */ 1436*40393Sbostic static int 1437*40393Sbostic ParseAddCmd (gn, cmd) 1438*40393Sbostic GNode *gn; /* the node to which the command is to be 1439*40393Sbostic * added */ 1440*40393Sbostic char *cmd; /* the command to add */ 1441*40393Sbostic { 1442*40393Sbostic if (gn->type & OP_HAS_COMMANDS) { 1443*40393Sbostic Parse_Error(PARSE_WARNING, "Extra command line for \"%s\" ignored", 1444*40393Sbostic gn->name); 1445*40393Sbostic } else { 1446*40393Sbostic (void)Lst_AtEnd (gn->commands, (ClientData)cmd); 1447*40393Sbostic } 1448*40393Sbostic 1449*40393Sbostic return (0); 1450*40393Sbostic } 1451*40393Sbostic 1452*40393Sbostic /*- 1453*40393Sbostic *----------------------------------------------------------------------- 1454*40393Sbostic * ParseHasCommands -- 1455*40393Sbostic * Callback procedure for Parse_File when destroying the list of 1456*40393Sbostic * targets on the last dependency line. Marks a target as already 1457*40393Sbostic * having commands if it does, to keep from having shell commands 1458*40393Sbostic * on multiple dependency lines. 1459*40393Sbostic * 1460*40393Sbostic * Results: 1461*40393Sbostic * Always 0. 1462*40393Sbostic * 1463*40393Sbostic * Side Effects: 1464*40393Sbostic * OP_HAS_COMMANDS may be set for the target. 1465*40393Sbostic * 1466*40393Sbostic *----------------------------------------------------------------------- 1467*40393Sbostic */ 1468*40393Sbostic static int 1469*40393Sbostic ParseHasCommands(gn) 1470*40393Sbostic GNode *gn; /* Node to examine */ 1471*40393Sbostic { 1472*40393Sbostic if (!Lst_IsEmpty(gn->commands)) { 1473*40393Sbostic gn->type |= OP_HAS_COMMANDS; 1474*40393Sbostic } 1475*40393Sbostic return(0); 1476*40393Sbostic } 1477*40393Sbostic 1478*40393Sbostic /*- 1479*40393Sbostic *----------------------------------------------------------------------- 1480*40393Sbostic * Parse_AddIncludeDir -- 1481*40393Sbostic * Add a directory to the path searched for included makefiles 1482*40393Sbostic * bracketed by double-quotes. Used by functions in main.c 1483*40393Sbostic * 1484*40393Sbostic * Results: 1485*40393Sbostic * None. 1486*40393Sbostic * 1487*40393Sbostic * Side Effects: 1488*40393Sbostic * The directory is appended to the list. 1489*40393Sbostic * 1490*40393Sbostic *----------------------------------------------------------------------- 1491*40393Sbostic */ 1492*40393Sbostic void 1493*40393Sbostic Parse_AddIncludeDir (dir) 1494*40393Sbostic char *dir; /* The name of the directory to add */ 1495*40393Sbostic { 1496*40393Sbostic Dir_AddDir (parseIncPath, dir); 1497*40393Sbostic } 1498*40393Sbostic 1499*40393Sbostic /*- 1500*40393Sbostic *--------------------------------------------------------------------- 1501*40393Sbostic * ParseDoInclude -- 1502*40393Sbostic * Push to another file. 1503*40393Sbostic * 1504*40393Sbostic * The input is the line minus the #include. A file spec is a string 1505*40393Sbostic * enclosed in <> or "". The former is looked for only in sysIncPath. 1506*40393Sbostic * The latter in . and the directories specified by -I command line 1507*40393Sbostic * options 1508*40393Sbostic * 1509*40393Sbostic * Results: 1510*40393Sbostic * None 1511*40393Sbostic * 1512*40393Sbostic * Side Effects: 1513*40393Sbostic * A structure is added to the includes Lst and readProc, lineno, 1514*40393Sbostic * fname and curFILE are altered for the new file 1515*40393Sbostic *--------------------------------------------------------------------- 1516*40393Sbostic */ 1517*40393Sbostic static void 1518*40393Sbostic ParseDoInclude (file) 1519*40393Sbostic char *file; /* file specification */ 1520*40393Sbostic { 1521*40393Sbostic char *fullname; /* full pathname of file */ 1522*40393Sbostic IFile *oldFile; /* state associated with current file */ 1523*40393Sbostic Lst path; /* the path to use to find the file */ 1524*40393Sbostic char endc; /* the character which ends the file spec */ 1525*40393Sbostic char *cp; /* current position in file spec */ 1526*40393Sbostic Boolean isSystem; /* TRUE if makefile is a system makefile */ 1527*40393Sbostic 1528*40393Sbostic /* 1529*40393Sbostic * Skip to delimiter character so we know where to look 1530*40393Sbostic */ 1531*40393Sbostic while ((*file == ' ') || (*file == '\t')) { 1532*40393Sbostic file++; 1533*40393Sbostic } 1534*40393Sbostic 1535*40393Sbostic if ((*file != '"') && (*file != '<')) { 1536*40393Sbostic /* 1537*40393Sbostic * XXX: Should give some sort of error message, I suppose, but because 1538*40393Sbostic * # is used for both comments and directives, we can't be sure if 1539*40393Sbostic * the thing might not just be a comment, so we just return... 1540*40393Sbostic */ 1541*40393Sbostic return; 1542*40393Sbostic } 1543*40393Sbostic 1544*40393Sbostic /* 1545*40393Sbostic * Set the search path on which to find the include file based on the 1546*40393Sbostic * characters which bracket its name. Angle-brackets imply it's 1547*40393Sbostic * a system Makefile while double-quotes imply it's a user makefile 1548*40393Sbostic */ 1549*40393Sbostic if (*file == '<') { 1550*40393Sbostic isSystem = TRUE; 1551*40393Sbostic endc = '>'; 1552*40393Sbostic } else { 1553*40393Sbostic isSystem = FALSE; 1554*40393Sbostic endc = '"'; 1555*40393Sbostic } 1556*40393Sbostic 1557*40393Sbostic /* 1558*40393Sbostic * Skip to matching delimiter 1559*40393Sbostic */ 1560*40393Sbostic for (cp = ++file; *cp && *cp != endc; cp++) { 1561*40393Sbostic continue; 1562*40393Sbostic } 1563*40393Sbostic 1564*40393Sbostic if (*cp != endc) { 1565*40393Sbostic Parse_Error (PARSE_FATAL, 1566*40393Sbostic "Unclosed %cinclude filename. '%c' expected", 1567*40393Sbostic SPECIAL_CHAR, endc); 1568*40393Sbostic return; 1569*40393Sbostic } 1570*40393Sbostic *cp = '\0'; 1571*40393Sbostic 1572*40393Sbostic /* 1573*40393Sbostic * Substitute for any variables in the file name before trying to 1574*40393Sbostic * find the thing. 1575*40393Sbostic */ 1576*40393Sbostic file = Var_Subst (file, VAR_CMD, FALSE); 1577*40393Sbostic 1578*40393Sbostic /* 1579*40393Sbostic * Now we know the file's name and its search path, we attempt to 1580*40393Sbostic * find the durn thing. A return of NULL indicates the file don't 1581*40393Sbostic * exist. 1582*40393Sbostic */ 1583*40393Sbostic if (!isSystem) { 1584*40393Sbostic /* 1585*40393Sbostic * Include files contained in double-quotes are first searched for 1586*40393Sbostic * relative to the including file's location. We don't want to 1587*40393Sbostic * cd there, of course, so we just tack on the old file's 1588*40393Sbostic * leading path components and call Dir_FindFile to see if 1589*40393Sbostic * we can locate the beast. 1590*40393Sbostic */ 1591*40393Sbostic char *prefEnd; 1592*40393Sbostic 1593*40393Sbostic prefEnd = rindex (fname, '/'); 1594*40393Sbostic if (prefEnd != (char *)NULL) { 1595*40393Sbostic char *newName; 1596*40393Sbostic 1597*40393Sbostic *prefEnd = '\0'; 1598*40393Sbostic newName = Str_Concat (fname, file, STR_ADDSLASH); 1599*40393Sbostic fullname = Dir_FindFile (newName, parseIncPath); 1600*40393Sbostic if (fullname == (char *)NULL) { 1601*40393Sbostic fullname = Dir_FindFile(newName, dirSearchPath); 1602*40393Sbostic } 1603*40393Sbostic free (newName); 1604*40393Sbostic *prefEnd = '/'; 1605*40393Sbostic } else { 1606*40393Sbostic fullname = (char *)NULL; 1607*40393Sbostic } 1608*40393Sbostic } else { 1609*40393Sbostic fullname = (char *)NULL; 1610*40393Sbostic } 1611*40393Sbostic 1612*40393Sbostic if (fullname == (char *)NULL) { 1613*40393Sbostic /* 1614*40393Sbostic * System makefile or makefile wasn't found in same directory as 1615*40393Sbostic * included makefile. Search for it first on the -I search path, 1616*40393Sbostic * then on the .PATH search path, if not found in a -I directory. 1617*40393Sbostic * XXX: Suffix specific? 1618*40393Sbostic */ 1619*40393Sbostic fullname = Dir_FindFile (file, parseIncPath); 1620*40393Sbostic if (fullname == (char *)NULL) { 1621*40393Sbostic fullname = Dir_FindFile(file, dirSearchPath); 1622*40393Sbostic } 1623*40393Sbostic } 1624*40393Sbostic 1625*40393Sbostic if (fullname == (char *)NULL) { 1626*40393Sbostic /* 1627*40393Sbostic * Still haven't found the makefile. Look for it on the system 1628*40393Sbostic * path as a last resort. 1629*40393Sbostic */ 1630*40393Sbostic fullname = Dir_FindFile(file, sysIncPath); 1631*40393Sbostic } 1632*40393Sbostic 1633*40393Sbostic if (fullname == (char *) NULL) { 1634*40393Sbostic *cp = endc; 1635*40393Sbostic Parse_Error (PARSE_FATAL, "Could not find %s", file); 1636*40393Sbostic return; 1637*40393Sbostic } 1638*40393Sbostic 1639*40393Sbostic /* 1640*40393Sbostic * Once we find the absolute path to the file, we get to save all the 1641*40393Sbostic * state from the current file before we can start reading this 1642*40393Sbostic * include file. The state is stored in an IFile structure which 1643*40393Sbostic * is placed on a list with other IFile structures. The list makes 1644*40393Sbostic * a very nice stack to track how we got here... 1645*40393Sbostic */ 1646*40393Sbostic oldFile = (IFile *) malloc (sizeof (IFile)); 1647*40393Sbostic oldFile->fname = fname; 1648*40393Sbostic 1649*40393Sbostic oldFile->F = curFILE; 1650*40393Sbostic oldFile->lineno = lineno; 1651*40393Sbostic 1652*40393Sbostic (void) Lst_AtFront (includes, (ClientData)oldFile); 1653*40393Sbostic 1654*40393Sbostic /* 1655*40393Sbostic * Once the previous state has been saved, we can get down to reading 1656*40393Sbostic * the new file. We set up the name of the file to be the absolute 1657*40393Sbostic * name of the include file so error messages refer to the right 1658*40393Sbostic * place. Naturally enough, we start reading at line number 0. 1659*40393Sbostic */ 1660*40393Sbostic fname = fullname; 1661*40393Sbostic lineno = 0; 1662*40393Sbostic 1663*40393Sbostic curFILE = fopen (fullname, "r"); 1664*40393Sbostic if (curFILE == (FILE * ) NULL) { 1665*40393Sbostic Parse_Error (PARSE_FATAL, "Cannot open %s", fullname); 1666*40393Sbostic /* 1667*40393Sbostic * Pop to previous file 1668*40393Sbostic */ 1669*40393Sbostic (void) ParseEOF(); 1670*40393Sbostic } 1671*40393Sbostic } 1672*40393Sbostic 1673*40393Sbostic /*- 1674*40393Sbostic *--------------------------------------------------------------------- 1675*40393Sbostic * ParseEOF -- 1676*40393Sbostic * Called when EOF is reached in the current file. If we were reading 1677*40393Sbostic * an include file, the includes stack is popped and things set up 1678*40393Sbostic * to go back to reading the previous file at the previous location. 1679*40393Sbostic * 1680*40393Sbostic * Results: 1681*40393Sbostic * CONTINUE if there's more to do. DONE if not. 1682*40393Sbostic * 1683*40393Sbostic * Side Effects: 1684*40393Sbostic * The old curFILE, is closed. The includes list is shortened. 1685*40393Sbostic * lineno, curFILE, and fname are changed if CONTINUE is returned. 1686*40393Sbostic *--------------------------------------------------------------------- 1687*40393Sbostic */ 1688*40393Sbostic static int 1689*40393Sbostic ParseEOF () 1690*40393Sbostic { 1691*40393Sbostic IFile *ifile; /* the state on the top of the includes stack */ 1692*40393Sbostic 1693*40393Sbostic if (Lst_IsEmpty (includes)) { 1694*40393Sbostic return (DONE); 1695*40393Sbostic } 1696*40393Sbostic 1697*40393Sbostic ifile = (IFile *) Lst_DeQueue (includes); 1698*40393Sbostic free (fname); 1699*40393Sbostic fname = ifile->fname; 1700*40393Sbostic lineno = ifile->lineno; 1701*40393Sbostic fclose (curFILE); 1702*40393Sbostic curFILE = ifile->F; 1703*40393Sbostic free ((Address)ifile); 1704*40393Sbostic return (CONTINUE); 1705*40393Sbostic } 1706*40393Sbostic 1707*40393Sbostic /*- 1708*40393Sbostic *--------------------------------------------------------------------- 1709*40393Sbostic * ParseReadc -- 1710*40393Sbostic * Read a character from the current file and update the line number 1711*40393Sbostic * counter as necessary 1712*40393Sbostic * 1713*40393Sbostic * Results: 1714*40393Sbostic * The character that was read 1715*40393Sbostic * 1716*40393Sbostic * Side Effects: 1717*40393Sbostic * The lineno counter is incremented if the character is a newline 1718*40393Sbostic *--------------------------------------------------------------------- 1719*40393Sbostic */ 1720*40393Sbostic #ifdef notdef 1721*40393Sbostic static int parseReadChar; 1722*40393Sbostic 1723*40393Sbostic #define ParseReadc() (((parseReadChar = getc(curFILE)) == '\n') ? \ 1724*40393Sbostic (lineno++, '\n') : parseReadChar) 1725*40393Sbostic #else 1726*40393Sbostic #define ParseReadc() (getc(curFILE)) 1727*40393Sbostic #endif /* notdef */ 1728*40393Sbostic 1729*40393Sbostic 1730*40393Sbostic /*- 1731*40393Sbostic *--------------------------------------------------------------------- 1732*40393Sbostic * ParseReadLine -- 1733*40393Sbostic * Read an entire line from the input file. Called only by Parse_File. 1734*40393Sbostic * To facilitate escaped newlines and what have you, a character is 1735*40393Sbostic * buffered in 'lastc', which is '\0' when no characters have been 1736*40393Sbostic * read. When we break out of the loop, c holds the terminating 1737*40393Sbostic * character and lastc holds a character that should be added to 1738*40393Sbostic * the line (unless we don't read anything but a terminator). 1739*40393Sbostic * 1740*40393Sbostic * Results: 1741*40393Sbostic * A line w/o its newline 1742*40393Sbostic * 1743*40393Sbostic * Side Effects: 1744*40393Sbostic * Only those associated with reading a character 1745*40393Sbostic *--------------------------------------------------------------------- 1746*40393Sbostic */ 1747*40393Sbostic static char * 1748*40393Sbostic ParseReadLine () 1749*40393Sbostic { 1750*40393Sbostic Buffer buf; /* Buffer for current line */ 1751*40393Sbostic register int c; /* the current character */ 1752*40393Sbostic register int lastc; /* The most-recent character */ 1753*40393Sbostic Boolean semiNL; /* treat semi-colons as newlines */ 1754*40393Sbostic Boolean ignDepOp; /* TRUE if should ignore dependency operators 1755*40393Sbostic * for the purposes of setting semiNL */ 1756*40393Sbostic Boolean ignComment; /* TRUE if should ignore comments (in a 1757*40393Sbostic * shell command */ 1758*40393Sbostic char *line; /* Result */ 1759*40393Sbostic int lineLength; /* Length of result */ 1760*40393Sbostic 1761*40393Sbostic semiNL = FALSE; 1762*40393Sbostic ignDepOp = FALSE; 1763*40393Sbostic ignComment = FALSE; 1764*40393Sbostic 1765*40393Sbostic /* 1766*40393Sbostic * Handle special-characters at the beginning of the line. Either a 1767*40393Sbostic * leading tab (shell command) or pound-sign (possible conditional) 1768*40393Sbostic * forces us to ignore comments and dependency operators and treat 1769*40393Sbostic * semi-colons as semi-colons (by leaving semiNL FALSE). This also 1770*40393Sbostic * discards completely blank lines. 1771*40393Sbostic */ 1772*40393Sbostic while(1) { 1773*40393Sbostic c = ParseReadc(); 1774*40393Sbostic 1775*40393Sbostic if ((c == '\t') || (c == SPECIAL_CHAR)) { 1776*40393Sbostic ignComment = ignDepOp = TRUE; 1777*40393Sbostic break; 1778*40393Sbostic } else if (c == '\n') { 1779*40393Sbostic lineno++; 1780*40393Sbostic } else { 1781*40393Sbostic /* 1782*40393Sbostic * Anything else breaks out without doing anything 1783*40393Sbostic */ 1784*40393Sbostic break; 1785*40393Sbostic } 1786*40393Sbostic } 1787*40393Sbostic 1788*40393Sbostic if (c != EOF) { 1789*40393Sbostic lastc = c; 1790*40393Sbostic buf = Buf_Init(BSIZE); 1791*40393Sbostic 1792*40393Sbostic while (((c = ParseReadc ()) != '\n' || (lastc == '\\')) && 1793*40393Sbostic (c != EOF)) 1794*40393Sbostic { 1795*40393Sbostic test_char: 1796*40393Sbostic switch(c) { 1797*40393Sbostic case '\n': 1798*40393Sbostic /* 1799*40393Sbostic * Escaped newline: read characters until a non-space or an 1800*40393Sbostic * unescaped newline and replace them all by a single space. 1801*40393Sbostic * This is done by storing the space over the backslash and 1802*40393Sbostic * dropping through with the next nonspace. If it is a 1803*40393Sbostic * semi-colon and semiNL is TRUE, it will be recognized as a 1804*40393Sbostic * newline in the code below this... 1805*40393Sbostic */ 1806*40393Sbostic lineno++; 1807*40393Sbostic lastc = ' '; 1808*40393Sbostic while ((c = ParseReadc ()) == ' ' || c == '\t') { 1809*40393Sbostic continue; 1810*40393Sbostic } 1811*40393Sbostic if (c == EOF || c == '\n') { 1812*40393Sbostic goto line_read; 1813*40393Sbostic } else { 1814*40393Sbostic /* 1815*40393Sbostic * Check for comments, semiNL's, etc. -- easier than 1816*40393Sbostic * ungetc(c, curFILE); continue; 1817*40393Sbostic */ 1818*40393Sbostic goto test_char; 1819*40393Sbostic } 1820*40393Sbostic break; 1821*40393Sbostic case ';': 1822*40393Sbostic /* 1823*40393Sbostic * Semi-colon: Need to see if it should be interpreted as a 1824*40393Sbostic * newline 1825*40393Sbostic */ 1826*40393Sbostic if (semiNL) { 1827*40393Sbostic /* 1828*40393Sbostic * To make sure the command that may be following this 1829*40393Sbostic * semi-colon begins with a tab, we push one back into the 1830*40393Sbostic * input stream. This will overwrite the semi-colon in the 1831*40393Sbostic * buffer. If there is no command following, this does no 1832*40393Sbostic * harm, since the newline remains in the buffer and the 1833*40393Sbostic * whole line is ignored. 1834*40393Sbostic */ 1835*40393Sbostic ungetc('\t', curFILE); 1836*40393Sbostic goto line_read; 1837*40393Sbostic } 1838*40393Sbostic break; 1839*40393Sbostic case '=': 1840*40393Sbostic if (!semiNL) { 1841*40393Sbostic /* 1842*40393Sbostic * Haven't seen a dependency operator before this, so this 1843*40393Sbostic * must be a variable assignment -- don't pay attention to 1844*40393Sbostic * dependency operators after this. 1845*40393Sbostic */ 1846*40393Sbostic ignDepOp = TRUE; 1847*40393Sbostic } else if (lastc == ':' || lastc == '!') { 1848*40393Sbostic /* 1849*40393Sbostic * Well, we've seen a dependency operator already, but it 1850*40393Sbostic * was the previous character, so this is really just an 1851*40393Sbostic * expanded variable assignment. Revert semi-colons to 1852*40393Sbostic * being just semi-colons again and ignore any more 1853*40393Sbostic * dependency operators. 1854*40393Sbostic * 1855*40393Sbostic * XXX: Note that a line like "foo : a:=b" will blow up, 1856*40393Sbostic * but who'd write a line like that anyway? 1857*40393Sbostic */ 1858*40393Sbostic ignDepOp = TRUE; semiNL = FALSE; 1859*40393Sbostic } 1860*40393Sbostic break; 1861*40393Sbostic case '#': 1862*40393Sbostic if (!ignComment) { 1863*40393Sbostic if (backwards || (lastc != '\\')) { 1864*40393Sbostic /* 1865*40393Sbostic * If the character is a hash mark and it isn't escaped 1866*40393Sbostic * (or we're being compatible), the thing is a comment. 1867*40393Sbostic * Skip to the end of the line. 1868*40393Sbostic */ 1869*40393Sbostic do { 1870*40393Sbostic c = ParseReadc(); 1871*40393Sbostic } while ((c != '\n') && (c != EOF)); 1872*40393Sbostic goto line_read; 1873*40393Sbostic } else { 1874*40393Sbostic /* 1875*40393Sbostic * Don't add the backslash. Just let the # get copied 1876*40393Sbostic * over. 1877*40393Sbostic */ 1878*40393Sbostic lastc = c; 1879*40393Sbostic continue; 1880*40393Sbostic } 1881*40393Sbostic } 1882*40393Sbostic break; 1883*40393Sbostic case ':': 1884*40393Sbostic case '!': 1885*40393Sbostic if (!ignDepOp && (c == ':' || c == '!')) { 1886*40393Sbostic /* 1887*40393Sbostic * A semi-colon is recognized as a newline only on 1888*40393Sbostic * dependency lines. Dependency lines are lines with a 1889*40393Sbostic * colon or an exclamation point. Ergo... 1890*40393Sbostic */ 1891*40393Sbostic semiNL = TRUE; 1892*40393Sbostic } 1893*40393Sbostic break; 1894*40393Sbostic } 1895*40393Sbostic /* 1896*40393Sbostic * Copy in the previous character and save this one in lastc. 1897*40393Sbostic */ 1898*40393Sbostic Buf_AddByte (buf, (Byte)lastc); 1899*40393Sbostic lastc = c; 1900*40393Sbostic 1901*40393Sbostic } 1902*40393Sbostic line_read: 1903*40393Sbostic lineno++; 1904*40393Sbostic 1905*40393Sbostic if (lastc != '\0') { 1906*40393Sbostic Buf_AddByte (buf, (Byte)lastc); 1907*40393Sbostic } 1908*40393Sbostic Buf_AddByte (buf, (Byte)'\0'); 1909*40393Sbostic line = (char *)Buf_GetAll (buf, &lineLength); 1910*40393Sbostic Buf_Destroy (buf, FALSE); 1911*40393Sbostic 1912*40393Sbostic if (line[0] == SPECIAL_CHAR) { 1913*40393Sbostic /* 1914*40393Sbostic * The line might be a conditional. Ask the conditional module 1915*40393Sbostic * about it and act accordingly 1916*40393Sbostic */ 1917*40393Sbostic switch (Cond_Eval (line)) { 1918*40393Sbostic case COND_SKIP: 1919*40393Sbostic do { 1920*40393Sbostic /* 1921*40393Sbostic * Skip to next conditional that evaluates to COND_PARSE. 1922*40393Sbostic */ 1923*40393Sbostic free (line); 1924*40393Sbostic c = ParseReadc(); 1925*40393Sbostic /* 1926*40393Sbostic * Skip lines until get to one that begins with a 1927*40393Sbostic * special char. 1928*40393Sbostic */ 1929*40393Sbostic while ((c != SPECIAL_CHAR) && (c != EOF)) { 1930*40393Sbostic while (((c != '\n') || (lastc == '\\')) && 1931*40393Sbostic (c != EOF)) 1932*40393Sbostic { 1933*40393Sbostic /* 1934*40393Sbostic * Advance to next unescaped newline 1935*40393Sbostic */ 1936*40393Sbostic if ((lastc = c) == '\n') { 1937*40393Sbostic lineno++; 1938*40393Sbostic } 1939*40393Sbostic c = ParseReadc(); 1940*40393Sbostic } 1941*40393Sbostic lineno++; 1942*40393Sbostic 1943*40393Sbostic lastc = c; 1944*40393Sbostic c = ParseReadc (); 1945*40393Sbostic } 1946*40393Sbostic 1947*40393Sbostic if (c == EOF) { 1948*40393Sbostic Parse_Error (PARSE_FATAL, "Unclosed conditional"); 1949*40393Sbostic return ((char *)NULL); 1950*40393Sbostic } 1951*40393Sbostic 1952*40393Sbostic /* 1953*40393Sbostic * Read the entire line into buf 1954*40393Sbostic */ 1955*40393Sbostic buf = Buf_Init (BSIZE); 1956*40393Sbostic do { 1957*40393Sbostic Buf_AddByte (buf, (Byte)c); 1958*40393Sbostic c = ParseReadc(); 1959*40393Sbostic } while ((c != '\n') && (c != EOF)); 1960*40393Sbostic lineno++; 1961*40393Sbostic 1962*40393Sbostic Buf_AddByte (buf, (Byte)'\0'); 1963*40393Sbostic line = (char *)Buf_GetAll (buf, &lineLength); 1964*40393Sbostic Buf_Destroy (buf, FALSE); 1965*40393Sbostic } while (Cond_Eval(line) != COND_PARSE); 1966*40393Sbostic /*FALLTHRU*/ 1967*40393Sbostic case COND_PARSE: 1968*40393Sbostic free (line); 1969*40393Sbostic line = ParseReadLine(); 1970*40393Sbostic break; 1971*40393Sbostic } 1972*40393Sbostic } 1973*40393Sbostic 1974*40393Sbostic return (line); 1975*40393Sbostic } else { 1976*40393Sbostic /* 1977*40393Sbostic * Hit end-of-file, so return a NULL line to indicate this. 1978*40393Sbostic */ 1979*40393Sbostic return((char *)NULL); 1980*40393Sbostic } 1981*40393Sbostic } 1982*40393Sbostic 1983*40393Sbostic /*- 1984*40393Sbostic *----------------------------------------------------------------------- 1985*40393Sbostic * ParseFinishLine -- 1986*40393Sbostic * Handle the end of a dependency group. 1987*40393Sbostic * 1988*40393Sbostic * Results: 1989*40393Sbostic * Nothing. 1990*40393Sbostic * 1991*40393Sbostic * Side Effects: 1992*40393Sbostic * inLine set FALSE. 'targets' list destroyed. 1993*40393Sbostic * 1994*40393Sbostic *----------------------------------------------------------------------- 1995*40393Sbostic */ 1996*40393Sbostic static void 1997*40393Sbostic ParseFinishLine() 1998*40393Sbostic { 1999*40393Sbostic extern int Suff_EndTransform(); 2000*40393Sbostic 2001*40393Sbostic if (inLine) { 2002*40393Sbostic Lst_ForEach(targets, Suff_EndTransform, (ClientData)NULL); 2003*40393Sbostic Lst_Destroy (targets, ParseHasCommands); 2004*40393Sbostic inLine = FALSE; 2005*40393Sbostic } 2006*40393Sbostic } 2007*40393Sbostic 2008*40393Sbostic 2009*40393Sbostic /*- 2010*40393Sbostic *--------------------------------------------------------------------- 2011*40393Sbostic * Parse_File -- 2012*40393Sbostic * Parse a file into its component parts, incorporating it into the 2013*40393Sbostic * current dependency graph. This is the main function and controls 2014*40393Sbostic * almost every other function in this module 2015*40393Sbostic * 2016*40393Sbostic * Results: 2017*40393Sbostic * None 2018*40393Sbostic * 2019*40393Sbostic * Side Effects: 2020*40393Sbostic * Loads. Nodes are added to the list of all targets, nodes and links 2021*40393Sbostic * are added to the dependency graph. etc. etc. etc. 2022*40393Sbostic *--------------------------------------------------------------------- 2023*40393Sbostic */ 2024*40393Sbostic void 2025*40393Sbostic Parse_File(name, stream) 2026*40393Sbostic char *name; /* the name of the file being read */ 2027*40393Sbostic FILE * stream; /* Stream open to makefile to parse */ 2028*40393Sbostic { 2029*40393Sbostic register char *cp, /* pointer into the line */ 2030*40393Sbostic *line; /* the line we're working on */ 2031*40393Sbostic 2032*40393Sbostic inLine = FALSE; 2033*40393Sbostic fname = name; 2034*40393Sbostic curFILE = stream; 2035*40393Sbostic lineno = 0; 2036*40393Sbostic fatals = 0; 2037*40393Sbostic 2038*40393Sbostic do { 2039*40393Sbostic while (line = ParseReadLine ()) { 2040*40393Sbostic if (*line == SPECIAL_CHAR) { 2041*40393Sbostic /* 2042*40393Sbostic * Lines that begin with the special character are either 2043*40393Sbostic * include or undef directives. 2044*40393Sbostic */ 2045*40393Sbostic for (cp = line + 1; isspace (*cp); cp++) { 2046*40393Sbostic continue; 2047*40393Sbostic } 2048*40393Sbostic if (strncmp (cp, "include", 7) == 0) { 2049*40393Sbostic ParseDoInclude (cp + 7); 2050*40393Sbostic goto nextLine; 2051*40393Sbostic } else if (strncmp(cp, "undef", 5) == 0) { 2052*40393Sbostic char *cp2; 2053*40393Sbostic for (cp += 5; isspace(*cp); cp++) { 2054*40393Sbostic continue; 2055*40393Sbostic } 2056*40393Sbostic 2057*40393Sbostic for (cp2 = cp; !isspace(*cp2) && (*cp2 != '\0'); cp2++) { 2058*40393Sbostic continue; 2059*40393Sbostic } 2060*40393Sbostic 2061*40393Sbostic *cp2 = '\0'; 2062*40393Sbostic 2063*40393Sbostic Var_Delete(cp, VAR_GLOBAL); 2064*40393Sbostic goto nextLine; 2065*40393Sbostic } 2066*40393Sbostic } 2067*40393Sbostic if (*line == '#') { 2068*40393Sbostic /* 2069*40393Sbostic * If we're this far, the line must be a comment, even if 2070*40393Sbostic * SPECIAL_CHAR is '#' 2071*40393Sbostic */ 2072*40393Sbostic goto nextLine; 2073*40393Sbostic } 2074*40393Sbostic 2075*40393Sbostic if (*line == '\t' 2076*40393Sbostic #ifdef POSIX 2077*40393Sbostic || *line == ' ' 2078*40393Sbostic #endif 2079*40393Sbostic ) 2080*40393Sbostic { 2081*40393Sbostic /* 2082*40393Sbostic * If a line starts with a tab (or space in POSIX-land), it 2083*40393Sbostic * can only hope to be a creation command. 2084*40393Sbostic */ 2085*40393Sbostic shellCommand: 2086*40393Sbostic for (cp = line + 1; isspace (*cp); cp++) { 2087*40393Sbostic continue; 2088*40393Sbostic } 2089*40393Sbostic if (*cp) { 2090*40393Sbostic if (inLine) { 2091*40393Sbostic /* 2092*40393Sbostic * So long as it's not a blank line and we're actually 2093*40393Sbostic * in a dependency spec, add the command to the list of 2094*40393Sbostic * commands of all targets in the dependency spec 2095*40393Sbostic */ 2096*40393Sbostic Lst_ForEach (targets, ParseAddCmd, (ClientData)cp); 2097*40393Sbostic continue; 2098*40393Sbostic } else { 2099*40393Sbostic Parse_Error (PARSE_FATAL, 2100*40393Sbostic "Unassociated shell command \"%.20s\"", 2101*40393Sbostic cp); 2102*40393Sbostic } 2103*40393Sbostic } 2104*40393Sbostic } else if (Parse_IsVar (line)) { 2105*40393Sbostic ParseFinishLine(); 2106*40393Sbostic Parse_DoVar (line, VAR_GLOBAL); 2107*40393Sbostic } else { 2108*40393Sbostic /* 2109*40393Sbostic * We now know it's a dependency line so it needs to have all 2110*40393Sbostic * variables expanded before being parsed. Tell the variable 2111*40393Sbostic * module to complain if some variable is undefined... 2112*40393Sbostic * To make life easier on novices, if the line is indented we 2113*40393Sbostic * first make sure the line has a dependency operator in it. 2114*40393Sbostic * If it doesn't have an operator and we're in a dependency 2115*40393Sbostic * line's script, we assume it's actually a shell command 2116*40393Sbostic * and add it to the current list of targets. 2117*40393Sbostic * 2118*40393Sbostic * Note that POSIX declares all lines that start with 2119*40393Sbostic * whitespace are shell commands, so there's no need to check 2120*40393Sbostic * here... 2121*40393Sbostic */ 2122*40393Sbostic Boolean nonSpace = FALSE; 2123*40393Sbostic 2124*40393Sbostic cp = line; 2125*40393Sbostic #ifndef POSIX 2126*40393Sbostic if (line[0] == ' ') { 2127*40393Sbostic while ((*cp != ':') && (*cp != '!') && (*cp != '\0')) { 2128*40393Sbostic if (!isspace(*cp)) { 2129*40393Sbostic nonSpace = TRUE; 2130*40393Sbostic } 2131*40393Sbostic cp++; 2132*40393Sbostic } 2133*40393Sbostic } 2134*40393Sbostic 2135*40393Sbostic if (*cp == '\0') { 2136*40393Sbostic if (inLine) { 2137*40393Sbostic Parse_Error (PARSE_WARNING, 2138*40393Sbostic "Shell command needs a leading tab"); 2139*40393Sbostic goto shellCommand; 2140*40393Sbostic } else if (nonSpace) { 2141*40393Sbostic Parse_Error (PARSE_FATAL, "Missing operator"); 2142*40393Sbostic } 2143*40393Sbostic } else { 2144*40393Sbostic #endif 2145*40393Sbostic ParseFinishLine(); 2146*40393Sbostic 2147*40393Sbostic cp = Var_Subst (line, VAR_CMD, TRUE); 2148*40393Sbostic free (line); 2149*40393Sbostic line = cp; 2150*40393Sbostic 2151*40393Sbostic /* 2152*40393Sbostic * Need a non-circular list for the target nodes 2153*40393Sbostic */ 2154*40393Sbostic targets = Lst_Init (FALSE); 2155*40393Sbostic inLine = TRUE; 2156*40393Sbostic 2157*40393Sbostic ParseDoDependency (line); 2158*40393Sbostic #ifndef POSIX 2159*40393Sbostic } 2160*40393Sbostic #endif 2161*40393Sbostic } 2162*40393Sbostic 2163*40393Sbostic nextLine: 2164*40393Sbostic 2165*40393Sbostic free (line); 2166*40393Sbostic } 2167*40393Sbostic /* 2168*40393Sbostic * Reached EOF, but it may be just EOF of an include file... 2169*40393Sbostic */ 2170*40393Sbostic } while (ParseEOF() == CONTINUE); 2171*40393Sbostic 2172*40393Sbostic /* 2173*40393Sbostic * Make sure conditionals are clean 2174*40393Sbostic */ 2175*40393Sbostic Cond_End(); 2176*40393Sbostic 2177*40393Sbostic if (fatals) { 2178*40393Sbostic fprintf (stderr, "Fatal errors encountered -- cannot continue\n"); 2179*40393Sbostic exit (1); 2180*40393Sbostic } 2181*40393Sbostic } 2182*40393Sbostic 2183*40393Sbostic /*- 2184*40393Sbostic *--------------------------------------------------------------------- 2185*40393Sbostic * Parse_Init -- 2186*40393Sbostic * initialize the parsing module 2187*40393Sbostic * 2188*40393Sbostic * Results: 2189*40393Sbostic * none 2190*40393Sbostic * 2191*40393Sbostic * Side Effects: 2192*40393Sbostic * the parseIncPath list is initialized... 2193*40393Sbostic *--------------------------------------------------------------------- 2194*40393Sbostic */ 2195*40393Sbostic Parse_Init () 2196*40393Sbostic { 2197*40393Sbostic char *cp; 2198*40393Sbostic char *start; 2199*40393Sbostic static char syspath[] = DEFSYSPATH; /* Avoid faults on read-only string 2200*40393Sbostic * constant... */ 2201*40393Sbostic 2202*40393Sbostic mainNode = NILGNODE; 2203*40393Sbostic parseIncPath = Lst_Init (FALSE); 2204*40393Sbostic sysIncPath = Lst_Init (FALSE); 2205*40393Sbostic includes = Lst_Init (FALSE); 2206*40393Sbostic 2207*40393Sbostic /* 2208*40393Sbostic * Add the directories from the DEFSYSPATH (more than one may be given 2209*40393Sbostic * as dir1:...:dirn) to the system include path. 2210*40393Sbostic */ 2211*40393Sbostic for (start = syspath; *start != '\0'; start = cp) { 2212*40393Sbostic for (cp = start; *cp != '\0' && *cp != ':'; cp++) { 2213*40393Sbostic ; 2214*40393Sbostic } 2215*40393Sbostic if (*cp == '\0') { 2216*40393Sbostic Dir_AddDir(sysIncPath, start); 2217*40393Sbostic } else { 2218*40393Sbostic *cp++ = '\0'; 2219*40393Sbostic Dir_AddDir(sysIncPath, start); 2220*40393Sbostic } 2221*40393Sbostic } 2222*40393Sbostic } 2223*40393Sbostic 2224*40393Sbostic /*- 2225*40393Sbostic *----------------------------------------------------------------------- 2226*40393Sbostic * Parse_MainName -- 2227*40393Sbostic * Return a Lst of the main target to create for main()'s sake. If 2228*40393Sbostic * no such target exists, we Punt with an obnoxious error message. 2229*40393Sbostic * 2230*40393Sbostic * Results: 2231*40393Sbostic * A Lst of the single node to create. 2232*40393Sbostic * 2233*40393Sbostic * Side Effects: 2234*40393Sbostic * None. 2235*40393Sbostic * 2236*40393Sbostic *----------------------------------------------------------------------- 2237*40393Sbostic */ 2238*40393Sbostic Lst 2239*40393Sbostic Parse_MainName() 2240*40393Sbostic { 2241*40393Sbostic Lst main; /* result list */ 2242*40393Sbostic 2243*40393Sbostic main = Lst_Init (FALSE); 2244*40393Sbostic 2245*40393Sbostic if (mainNode == NILGNODE) { 2246*40393Sbostic Punt ("I don't know what to DO!\n"); 2247*40393Sbostic /*NOTREACHED*/ 2248*40393Sbostic } else if (mainNode->type & OP_DOUBLEDEP) { 2249*40393Sbostic Lst_Concat(main, mainNode->cohorts, LST_CONCNEW); 2250*40393Sbostic } 2251*40393Sbostic (void) Lst_AtEnd (main, (ClientData)mainNode); 2252*40393Sbostic return (main); 2253*40393Sbostic } 2254