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