Changeset 51 in kBuild for trunk/src/kmk/parse.c
- Timestamp:
- Apr 7, 2003 1:30:32 AM (22 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kmk/parse.c
r46 r51 1 1 /* 2 2 * Copyright (c) 1988, 1989, 1990, 1993 3 * 3 * The Regents of the University of California. All rights reserved. 4 4 * Copyright (c) 1989 by Berkeley Softworks 5 5 * All rights reserved. … … 18 18 * 3. All advertising materials mentioning features or use of this software 19 19 * must display the following acknowledgement: 20 * 21 * 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 22 * 4. Neither the name of the University nor the names of its contributors 23 23 * may be used to endorse or promote products derived from this software … … 39 39 #ifndef lint 40 40 #if 0 41 static char sccsid[] = "@(#)parse.c 41 static char sccsid[] = "@(#)parse.c 8.3 (Berkeley) 3/19/94"; 42 42 #else 43 43 static const char rcsid[] = 44 44 "$FreeBSD: src/usr.bin/make/parse.c,v 1.22 1999/08/28 01:03:35 peter Exp $"; 45 45 #endif 46 #define KLIBFILEDEF rcsid 46 47 #endif /* not lint */ 47 48 48 49 /*- 49 50 * parse.c -- 50 * 51 * 52 * 53 * 54 * 55 * 56 * 57 * 58 * 59 * 60 * 61 * 62 * 63 * 64 * 51 * Functions to parse a makefile. 52 * 53 * One function, Parse_Init, must be called before any functions 54 * in this module are used. After that, the function Parse_File is the 55 * main entry point and controls most of the other functions in this 56 * module. 57 * 58 * Most important structures are kept in Lsts. Directories for 59 * the #include "..." function are kept in the 'parseIncPath' Lst, while 60 * those for the #include <...> are kept in the 'sysIncPath' Lst. The 61 * targets currently being defined are kept in the 'targets' Lst. 62 * 63 * The variables 'fname' and 'lineno' are used to track the name 64 * of the current file and the line number in that file so that error 65 * messages can be more meaningful. 65 66 * 66 67 * Interface: 67 * Parse_InitInitialization function which must be68 * 69 * 70 * 71 * Parse_EndCleanup the module72 * 73 * Parse_FileFunction used to parse a makefile. It must74 * 75 * 76 * 77 * 78 * Parse_IsVarReturns TRUE if the given line is a79 * 80 * 81 * 82 * 83 * 84 * Parse_ErrorFunction called when an error occurs in85 * 86 * 87 * Parse_MainNameReturns a Lst of the main target to create.88 */ 89 90 #if defined(__STDC__) || defined(__IBMC__)68 * Parse_Init Initialization function which must be 69 * called before anything else in this module 70 * is used. 71 * 72 * Parse_End Cleanup the module 73 * 74 * Parse_File Function used to parse a makefile. It must 75 * be given the name of the file, which should 76 * already have been opened, and a function 77 * to call to read a character from the file. 78 * 79 * Parse_IsVar Returns TRUE if the given line is a 80 * variable assignment. Used by MainParseArgs 81 * to determine if an argument is a target 82 * or a variable assignment. Used internally 83 * for pretty much the same thing... 84 * 85 * Parse_Error Function called when an error occurs in 86 * parsing. Used by the variable and 87 * conditional modules. 88 * Parse_MainName Returns a Lst of the main target to create. 89 */ 90 91 #ifdef __STDC__ 91 92 #include <stdarg.h> 92 93 #else … … 109 110 * or if it's DONE. 110 111 */ 111 #define CONTINUE1112 #define DONE0113 static Lst targets;/* targets we're working on */114 /*static Lst targCmds; *//* command lines for targets */115 static Boolean inLine;/* true if currently in a dependency116 112 #define CONTINUE 1 113 #define DONE 0 114 static Lst targets; /* targets we're working on */ 115 /*static Lst targCmds; */ /* command lines for targets */ 116 static Boolean inLine; /* true if currently in a dependency 117 * line or its commands */ 117 118 #if defined(USE_INLINEFILES) 118 119 static Boolean inInlineFile; /* true if currently in a inline file.*/ … … 123 124 } PTR; 124 125 125 static char *fname;/* name of current file (for errors) */126 static int lineno; 127 static FILE *curFILE = NULL;/* current makefile */128 129 static PTR *curPTR = NULL;/* current makefile */130 131 static int 132 133 static GNode *mainNode;/* The main target to create. This is the134 135 126 static char *fname; /* name of current file (for errors) */ 127 static int lineno; /* line number in current file */ 128 static FILE *curFILE = NULL; /* current makefile */ 129 130 static PTR *curPTR = NULL; /* current makefile */ 131 132 static int fatals = 0; 133 134 static GNode *mainNode; /* The main target to create. This is the 135 * first target on the first dependency 136 * line in the first makefile */ 136 137 /* 137 138 * Definitions for handling #include specifications 138 139 */ 139 140 typedef struct IFile { 140 char *fname; 141 int lineno; 142 FILE * F; 143 PTR * p;/* the char pointer */141 char *fname; /* name of previous file */ 142 int lineno; /* saved line number */ 143 FILE * F; /* the open stream */ 144 PTR * p; /* the char pointer */ 144 145 } IFile; 145 146 146 static Lst includes; 147 148 Lst parseIncPath;/* list of directories for "..." includes */149 Lst sysIncPath;/* list of directories for <...> includes */147 static Lst includes; /* stack of IFiles generated by 148 * #includes */ 149 Lst parseIncPath; /* list of directories for "..." includes */ 150 Lst sysIncPath; /* list of directories for <...> includes */ 150 151 151 152 /*- … … 156 157 */ 157 158 typedef enum { 158 Begin, 159 Default, 160 End, 161 Ignore, 162 Includes, 163 Interrupt, 159 Begin, /* .BEGIN */ 160 Default, /* .DEFAULT */ 161 End, /* .END */ 162 Ignore, /* .IGNORE */ 163 Includes, /* .INCLUDES */ 164 Interrupt, /* .INTERRUPT */ 164 165 #ifdef USE_ARCHIVES 165 Libs, 166 #endif 167 MFlags, 168 Main, 169 170 NoExport, 171 Not, 166 Libs, /* .LIBS */ 167 #endif 168 MFlags, /* .MFLAGS or .MAKEFLAGS */ 169 Main, /* .MAIN and we don't have anything user-specified to 170 * make */ 171 NoExport, /* .NOEXPORT */ 172 Not, /* Not special */ 172 173 NotParallel, /* .NOTPARALELL */ 173 Null, 174 Order, 175 Parallel, 176 ExPath, 177 Phony, 174 Null, /* .NULL */ 175 Order, /* .ORDER */ 176 Parallel, /* .PARALLEL */ 177 ExPath, /* .PATH */ 178 Phony, /* .PHONY */ 178 179 #ifdef POSIX 179 Posix, 180 #endif 181 Precious, 182 ExShell, 183 Silent, 180 Posix, /* .POSIX */ 181 #endif 182 Precious, /* .PRECIOUS */ 183 ExShell, /* .SHELL */ 184 Silent, /* .SILENT */ 184 185 SingleShell, /* .SINGLESHELL */ 185 Suffixes, 186 Wait, 187 Attribute 186 Suffixes, /* .SUFFIXES */ 187 Wait, /* .WAIT */ 188 Attribute /* Generic attribute */ 188 189 } ParseSpecial; 189 190 … … 195 196 * seen, then set to each successive source on the line. 196 197 */ 197 static GNode 198 static GNode *predecessor; 198 199 199 200 /* … … 205 206 */ 206 207 static struct { 207 char *name;/* Name of keyword */208 ParseSpecial spec; 209 int op;/* Operator when used as a source */208 char *name; /* Name of keyword */ 209 ParseSpecial spec; /* Type when used as a target */ 210 int op; /* Operator when used as a source */ 210 211 } parseKeywords[] = { 211 { ".BEGIN", Begin,0 },212 { ".DEFAULT", Default,0 },213 { ".END", End,0 },214 { ".EXEC", Attribute,OP_EXEC },215 { ".IGNORE", Ignore,OP_IGNORE },216 { ".INCLUDES", Includes,0 },217 { ".INTERRUPT", Interrupt,0 },218 { ".INVISIBLE", Attribute,OP_INVISIBLE },219 { ".JOIN", Attribute,OP_JOIN },212 { ".BEGIN", Begin, 0 }, 213 { ".DEFAULT", Default, 0 }, 214 { ".END", End, 0 }, 215 { ".EXEC", Attribute, OP_EXEC }, 216 { ".IGNORE", Ignore, OP_IGNORE }, 217 { ".INCLUDES", Includes, 0 }, 218 { ".INTERRUPT", Interrupt, 0 }, 219 { ".INVISIBLE", Attribute, OP_INVISIBLE }, 220 { ".JOIN", Attribute, OP_JOIN }, 220 221 #ifdef USE_ARCHIVES 221 { ".LIBS", Libs,0 },222 #endif 223 { ".MAIN", Main,0 },224 { ".MAKE", Attribute,OP_MAKE },225 { ".MAKEFLAGS", MFlags,0 },226 { ".MFLAGS", MFlags,0 },227 { ".NOTMAIN", Attribute,OP_NOTMAIN },228 { ".NOTPARALLEL", NotParallel, 229 { ".NO_PARALLEL", NotParallel, 230 { ".NULL", Null,0 },231 { ".OPTIONAL", Attribute,OP_OPTIONAL },232 { ".ORDER", Order,0 },233 { ".PARALLEL", Parallel,0 },234 { ".PATH", ExPath,0 },235 { ".PHONY", Phony,OP_PHONY },222 { ".LIBS", Libs, 0 }, 223 #endif 224 { ".MAIN", Main, 0 }, 225 { ".MAKE", Attribute, OP_MAKE }, 226 { ".MAKEFLAGS", MFlags, 0 }, 227 { ".MFLAGS", MFlags, 0 }, 228 { ".NOTMAIN", Attribute, OP_NOTMAIN }, 229 { ".NOTPARALLEL", NotParallel, 0 }, 230 { ".NO_PARALLEL", NotParallel, 0 }, 231 { ".NULL", Null, 0 }, 232 { ".OPTIONAL", Attribute, OP_OPTIONAL }, 233 { ".ORDER", Order, 0 }, 234 { ".PARALLEL", Parallel, 0 }, 235 { ".PATH", ExPath, 0 }, 236 { ".PHONY", Phony, OP_PHONY }, 236 237 #ifdef POSIX 237 { ".POSIX", Posix,0 },238 #endif 239 { ".PRECIOUS", Precious,OP_PRECIOUS },240 { ".RECURSIVE", Attribute,OP_MAKE },241 { ".SHELL", ExShell,0 },242 { ".SILENT", Silent,OP_SILENT },243 { ".SINGLESHELL", SingleShell, 244 { ".SUFFIXES", Suffixes,0 },245 { ".USE", Attribute,OP_USE },246 { ".WAIT", Wait,0 },238 { ".POSIX", Posix, 0 }, 239 #endif 240 { ".PRECIOUS", Precious, OP_PRECIOUS }, 241 { ".RECURSIVE", Attribute, OP_MAKE }, 242 { ".SHELL", ExShell, 0 }, 243 { ".SILENT", Silent, OP_SILENT }, 244 { ".SINGLESHELL", SingleShell, 0 }, 245 { ".SUFFIXES", Suffixes, 0 }, 246 { ".USE", Attribute, OP_USE }, 247 { ".WAIT", Wait, 0 }, 247 248 }; 248 249 … … 277 278 *---------------------------------------------------------------------- 278 279 * ParseFindKeyword -- 279 * 280 * Look in the table of keywords for one matching the given string. 280 281 * 281 282 * Results: 282 * 283 * The index of the keyword, or -1 if it isn't there. 283 284 * 284 285 * Side Effects: 285 * 286 * None 286 287 *---------------------------------------------------------------------- 287 288 */ 288 289 static int 289 290 ParseFindKeyword (str) 290 char *str;/* String to find */291 char *str; /* String to find */ 291 292 { 292 293 register int start, 293 294 294 end, 295 cur; 295 296 register int diff; 296 297 … … 299 300 300 301 do { 301 302 303 304 305 306 307 308 309 310 302 cur = start + ((end - start) / 2); 303 diff = strcmp (str, parseKeywords[cur].name); 304 305 if (diff == 0) { 306 return (cur); 307 } else if (diff < 0) { 308 end = cur - 1; 309 } else { 310 start = cur + 1; 311 } 311 312 } while (start <= end); 312 313 return (-1); … … 315 316 /*- 316 317 * Parse_Error -- 317 * 318 * 319 * 318 * Error message abort function for parsing. Prints out the context 319 * of the error (line number and file) as well as the message with 320 * two optional arguments. 320 321 * 321 322 * Results: 322 * 323 * None 323 324 * 324 325 * Side Effects: 325 * 326 * "fatals" is incremented if the level is PARSE_FATAL. 326 327 */ 327 328 /* VARARGS */ … … 331 332 #else 332 333 Parse_Error(va_alist) 333 334 #endif 335 { 336 334 va_dcl 335 #endif 336 { 337 va_list ap; 337 338 #if defined(__STDC__) || defined(__IBMC__) 338 339 va_start(ap, fmt); 339 340 #else 340 int type;/* Error type (PARSE_WARNING, PARSE_FATAL) */341 342 343 344 345 346 #endif 347 348 349 350 351 352 353 354 355 356 341 int type; /* Error type (PARSE_WARNING, PARSE_FATAL) */ 342 char *fmt; 343 344 va_start(ap); 345 type = va_arg(ap, int); 346 fmt = va_arg(ap, char *); 347 #endif 348 349 (void)fprintf(stderr, "\"%s\", line %d: ", fname, lineno); 350 if (type == PARSE_WARNING) 351 (void)fprintf(stderr, "warning: "); 352 (void)vfprintf(stderr, fmt, ap); 353 va_end(ap); 354 (void)fprintf(stderr, "\n"); 355 (void)fflush(stderr); 356 if (type == PARSE_FATAL) 357 fatals += 1; 357 358 } 358 359 … … 360 361 *--------------------------------------------------------------------- 361 362 * ParseLinkSrc -- 362 * 363 * 364 * 363 * Link the parent node to its new child. Used in a Lst_ForEach by 364 * ParseDoDependency. If the specType isn't 'Not', the parent 365 * isn't linked as a parent of the child. 365 366 * 366 367 * Results: 367 * 368 * Always = 0 368 369 * 369 370 * Side Effects: 370 * 371 * 372 * 371 * New elements are added to the parents list of cgn and the 372 * children list of cgn. the unmade field of pgn is updated 373 * to reflect the additional child. 373 374 *--------------------------------------------------------------------- 374 375 */ 375 376 static int 376 377 ParseLinkSrc (pgnp, cgnp) 377 ClientData pgnp; 378 ClientData cgnp; 378 ClientData pgnp; /* The parent node */ 379 ClientData cgnp; /* The child node */ 379 380 { 380 381 GNode *pgn = (GNode *) pgnp; 381 382 GNode *cgn = (GNode *) cgnp; 382 383 if (Lst_Member (pgn->children, (ClientData)cgn) == NILLNODE) { 383 384 385 386 387 384 (void)Lst_AtEnd (pgn->children, (ClientData)cgn); 385 if (specType == Not) { 386 (void)Lst_AtEnd (cgn->parents, (ClientData)pgn); 387 } 388 pgn->unmade += 1; 388 389 } 389 390 return (0); … … 393 394 *--------------------------------------------------------------------- 394 395 * ParseDoOp -- 395 * 396 * 397 * 398 * 396 * Apply the parsed operator to the given target node. Used in a 397 * Lst_ForEach call by ParseDoDependency once all targets have 398 * been found and their operator parsed. If the previous and new 399 * operators are incompatible, a major error is taken. 399 400 * 400 401 * Results: 401 * 402 * Always 0 402 403 * 403 404 * Side Effects: 404 * 405 * 405 * The type field of the node is altered to reflect any new bits in 406 * the op. 406 407 *--------------------------------------------------------------------- 407 408 */ 408 409 static int 409 410 ParseDoOp (gnp, opp) 410 ClientData gnp; 411 412 ClientData opp; 411 ClientData gnp; /* The node to which the operator is to be 412 * applied */ 413 ClientData opp; /* The operator to apply */ 413 414 { 414 415 GNode *gn = (GNode *) gnp; … … 420 421 */ 421 422 if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) && 422 423 !OP_NOP(gn->type) && !OP_NOP(op)) 423 424 { 424 425 425 Parse_Error (PARSE_FATAL, "Inconsistent operator for %s", gn->name); 426 return (1); 426 427 } 427 428 428 429 if ((op == OP_DOUBLEDEP) && ((gn->type & OP_OPMASK) == OP_DOUBLEDEP)) { 429 430 431 432 433 434 435 436 437 register GNode*cohort;438 LstNodeln;439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 430 /* 431 * If the node was the object of a :: operator, we need to create a 432 * new instance of it for the children and commands on this dependency 433 * line. The new instance is placed on the 'cohorts' list of the 434 * initial one (note the initial one is not on its own cohorts list) 435 * and the new instance is linked to all parents of the initial 436 * instance. 437 */ 438 register GNode *cohort; 439 LstNode ln; 440 441 cohort = Targ_NewGN(gn->name); 442 /* 443 * Duplicate links to parents so graph traversal is simple. Perhaps 444 * some type bits should be duplicated? 445 * 446 * Make the cohort invisible as well to avoid duplicating it into 447 * other variables. True, parents of this target won't tend to do 448 * anything with their local variables, but better safe than 449 * sorry. 450 */ 451 Lst_ForEach(gn->parents, ParseLinkSrc, (ClientData)cohort); 452 cohort->type = OP_DOUBLEDEP|OP_INVISIBLE; 453 (void)Lst_AtEnd(gn->cohorts, (ClientData)cohort); 454 455 /* 456 * Replace the node in the targets list with the new copy 457 */ 458 ln = Lst_Member(targets, (ClientData)gn); 459 Lst_Replace(ln, (ClientData)cohort); 460 gn = cohort; 460 461 } 461 462 /* … … 471 472 *--------------------------------------------------------------------- 472 473 * ParseAddDep -- 473 * 474 * 475 * 474 * Check if the pair of GNodes given needs to be synchronized. 475 * This has to be when two nodes are on different sides of a 476 * .WAIT directive. 476 477 * 477 478 * Results: 478 * 479 * 479 * Returns 1 if the two targets need to be ordered, 0 otherwise. 480 * If it returns 1, the search can stop 480 481 * 481 482 * Side Effects: 482 * 483 * A dependency can be added between the two nodes. 483 484 * 484 485 *--------------------------------------------------------------------- … … 493 494 494 495 if (p->order < s->order) { 495 496 497 498 499 500 501 502 496 /* 497 * XXX: This can cause loops, and loops can cause unmade targets, 498 * but checking is tedious, and the debugging output can show the 499 * problem 500 */ 501 (void)Lst_AtEnd(p->successors, (ClientData)s); 502 (void)Lst_AtEnd(s->preds, (ClientData)p); 503 return 0; 503 504 } 504 505 else 505 506 return 1; 506 507 } 507 508 … … 510 511 *--------------------------------------------------------------------- 511 512 * ParseDoSrc -- 512 * 513 * 514 * 515 * 516 * 513 * Given the name of a source, figure out if it is an attribute 514 * and apply it to the targets if it is. Else decide if there is 515 * some attribute which should be applied *to* the source because 516 * of some special target and apply it if so. Otherwise, make the 517 * source be a child of the targets in the list 'targets' 517 518 * 518 519 * Results: 519 * 520 * None 520 521 * 521 522 * Side Effects: 522 * 523 * 523 * Operator bits may be added to the list of targets or to the source. 524 * The targets may have a new source added to their lists of children. 524 525 *--------------------------------------------------------------------- 525 526 */ 526 527 static void 527 528 ParseDoSrc (tOp, src, allsrc) 528 int tOp;/* operator (if any) from special targets */529 char *src;/* name of the source to handle */530 Lst allsrc;/* List of all sources to wait for */531 { 532 GNode 529 int tOp; /* operator (if any) from special targets */ 530 char *src; /* name of the source to handle */ 531 Lst allsrc; /* List of all sources to wait for */ 532 { 533 GNode *gn = NULL; 533 534 534 535 if (*src == '.' && isupper (src[1])) { 535 536 537 538 539 540 541 542 543 544 545 546 536 int keywd = ParseFindKeyword(src); 537 if (keywd != -1) { 538 int op = parseKeywords[keywd].op; 539 if (op != 0) { 540 Lst_ForEach (targets, ParseDoOp, (ClientData)&op); 541 return; 542 } 543 if (parseKeywords[keywd].spec == Wait) { 544 waiting++; 545 return; 546 } 547 } 547 548 } 548 549 549 550 switch (specType) { 550 551 case Main: 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 552 /* 553 * If we have noted the existence of a .MAIN, it means we need 554 * to add the sources of said target to the list of things 555 * to create. The string 'src' is likely to be efree, so we 556 * must make a new copy of it. Note that this will only be 557 * invoked if the user didn't specify a target on the command 558 * line. This is to allow #ifmake's to succeed, or something... 559 */ 560 (void) Lst_AtEnd (create, (ClientData)estrdup(src)); 561 /* 562 * Add the name to the .TARGETS variable as well, so the user cna 563 * employ that, if desired. 564 */ 565 Var_Append(".TARGETS", src, VAR_GLOBAL); 566 return; 566 567 567 568 case Order: 568 569 570 571 572 573 574 575 576 577 578 579 580 581 569 /* 570 * Create proper predecessor/successor links between the previous 571 * source and the current one. 572 */ 573 gn = Targ_FindNode(src, TARG_CREATE); 574 if (predecessor != NILGNODE) { 575 (void)Lst_AtEnd(predecessor->successors, (ClientData)gn); 576 (void)Lst_AtEnd(gn->preds, (ClientData)predecessor); 577 } 578 /* 579 * The current source now becomes the predecessor for the next one. 580 */ 581 predecessor = gn; 582 break; 582 583 583 584 default: 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 register GNode*cohort;603 register LstNodeln;604 605 606 607 608 609 610 611 612 613 614 585 /* 586 * If the source is not an attribute, we need to find/create 587 * a node for it. After that we can apply any operator to it 588 * from a special target or link it to its parents, as 589 * appropriate. 590 * 591 * In the case of a source that was the object of a :: operator, 592 * the attribute is applied to all of its instances (as kept in 593 * the 'cohorts' list of the node) or all the cohorts are linked 594 * to all the targets. 595 */ 596 gn = Targ_FindNode (src, TARG_CREATE); 597 if (tOp) { 598 gn->type |= tOp; 599 } else { 600 Lst_ForEach (targets, ParseLinkSrc, (ClientData)gn); 601 } 602 if ((gn->type & OP_OPMASK) == OP_DOUBLEDEP) { 603 register GNode *cohort; 604 register LstNode ln; 605 606 for (ln=Lst_First(gn->cohorts); ln != NILLNODE; ln = Lst_Succ(ln)){ 607 cohort = (GNode *)Lst_Datum(ln); 608 if (tOp) { 609 cohort->type |= tOp; 610 } else { 611 Lst_ForEach(targets, ParseLinkSrc, (ClientData)cohort); 612 } 613 } 614 } 615 break; 615 616 } 616 617 … … 618 619 (void)Lst_AtEnd(allsrc, (ClientData)gn); 619 620 if (waiting) { 620 621 Lst_ForEach(allsrc, ParseAddDep, (ClientData)gn); 621 622 } 622 623 } … … 625 626 *----------------------------------------------------------------------- 626 627 * ParseFindMain -- 627 * 628 * 629 * 628 * Find a real target in the list and set it to be the main one. 629 * Called by ParseDoDependency when a main target hasn't been found 630 * yet. 630 631 * 631 632 * Results: 632 * 633 * 0 if main not found yet, 1 if it is. 633 634 * 634 635 * Side Effects: 635 * 636 * mainNode is changed and Targ_SetMain is called. 636 637 * 637 638 *----------------------------------------------------------------------- … … 639 640 static int 640 641 ParseFindMain(gnp, dummy) 641 ClientData gnp;/* Node to examine */642 ClientData gnp; /* Node to examine */ 642 643 ClientData dummy; 643 644 { 644 GNode 645 GNode *gn = (GNode *) gnp; 645 646 if ((gn->type & (OP_NOTMAIN|OP_USE|OP_EXEC|OP_TRANSFORM)) == 0) { 646 647 648 647 mainNode = gn; 648 Targ_SetMain(gn); 649 return (dummy ? 1 : 1); 649 650 } else { 650 651 return (dummy ? 0 : 0); 651 652 } 652 653 } … … 655 656 *----------------------------------------------------------------------- 656 657 * ParseAddDir -- 657 * 658 * Front-end for Dir_AddDir to make sure Lst_ForEach keeps going 658 659 * 659 660 * Results: 660 * 661 * === 0 661 662 * 662 663 * Side Effects: 663 * 664 * See Dir_AddDir. 664 665 * 665 666 *----------------------------------------------------------------------- … … 667 668 static int 668 669 ParseAddDir(path, name) 669 ClientData 670 ClientData path; 670 671 ClientData name; 671 672 { … … 677 678 *----------------------------------------------------------------------- 678 679 * ParseClearPath -- 679 * 680 * Front-end for Dir_ClearPath to make sure Lst_ForEach keeps going 680 681 * 681 682 * Results: 682 * 683 * === 0 683 684 * 684 685 * Side Effects: 685 * 686 * See Dir_ClearPath 686 687 * 687 688 *----------------------------------------------------------------------- … … 699 700 *--------------------------------------------------------------------- 700 701 * ParseDoDependency -- 701 * 702 * Parse the dependency line in line. 702 703 * 703 704 * Results: 704 * 705 * None 705 706 * 706 707 * Side Effects: 707 * 708 * 709 * 710 * 708 * The nodes of the sources are linked as children to the nodes of the 709 * targets. Some nodes may be created. 710 * 711 * We parse a dependency line by first extracting words from the line and 711 712 * finding nodes in the list of all targets with that name. This is done 712 713 * until a character is encountered which is an operator character. Currently 713 714 * these are only ! and :. At this point the operator is parsed and the 714 715 * pointer into the line advanced until the first source is encountered. 715 * 716 * The parsed operator is applied to each node in the 'targets' list, 716 717 * which is where the nodes found for the targets are kept, by means of 717 718 * the ParseDoOp function. 718 * 719 * The sources are read in much the same way as the targets were except 719 720 * that now they are expanded using the wildcarding scheme of the C-Shell 720 721 * and all instances of the resulting words in the list of all targets 721 722 * are found. Each of the resulting nodes is then linked to each of the 722 723 * targets as one of its children. 723 * 724 * Certain targets are handled specially. These are the ones detailed 724 725 * by the specType variable. 725 * 726 * The storing of transformation rules is also taken care of here. 726 727 * A target is recognized as a transformation rule by calling 727 728 * Suff_IsTransform. If it is a transformation rule, its node is gotten … … 732 733 static void 733 734 ParseDoDependency (line) 734 char *line; 735 { 736 char *cp;/* our current position */737 GNode *gn;/* a general purpose temporary node */738 int op; 739 char savec; 740 Lst paths;/* List of search paths to alter when parsing741 742 int tOp;/* operator from special target */735 char *line; /* the line to parse */ 736 { 737 char *cp; /* our current position */ 738 GNode *gn; /* a general purpose temporary node */ 739 int op; /* the operator on the line */ 740 char savec; /* a place to save a character */ 741 Lst paths; /* List of search paths to alter when parsing 742 * a list of .PATH targets */ 743 int tOp; /* operator from special target */ 743 744 #ifdef USE_ARCHIVES 744 Lst sources;/* list of archive source names after745 746 #endif 747 Lst curTargs;/* list of target names to be found and added748 749 Lst curSrcs;/* list of sources in order */745 Lst sources; /* list of archive source names after 746 * expansion */ 747 #endif 748 Lst curTargs; /* list of target names to be found and added 749 * to the targets list */ 750 Lst curSrcs; /* list of sources in order */ 750 751 751 752 tOp = 0; … … 759 760 760 761 do { 761 762 763 764 765 766 767 768 769 770 771 772 773 774 intlength;775 BooleanfreeIt;776 char*result;777 778 779 780 781 782 783 784 785 786 787 762 for (cp = line; 763 *cp && !isspace (*cp) && 764 (*cp != '!') && (*cp != ':') && (*cp != '('); 765 cp++) 766 { 767 if (*cp == '$') { 768 /* 769 * Must be a dynamic source (would have been expanded 770 * otherwise), so call the Var module to parse the puppy 771 * so we can safely advance beyond it...There should be 772 * no errors in this, as they would have been discovered 773 * in the initial Var_Subst and we wouldn't be here. 774 */ 775 int length; 776 Boolean freeIt; 777 char *result; 778 779 result=Var_Parse(cp, VAR_CMD, TRUE, &length, &freeIt); 780 781 if (freeIt) { 782 efree(result); 783 } 784 cp += length-1; 785 } 786 continue; 787 } 788 if (*cp == '(') { 788 789 #ifdef USE_ARCHIVES 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 790 /* 791 * Archives must be handled specially to make sure the OP_ARCHV 792 * flag is set in their 'type' field, for one thing, and because 793 * things like "archive(file1.o file2.o file3.o)" are permissible. 794 * Arch_ParseArchive will set 'line' to be the first non-blank 795 * after the archive-spec. It creates/finds nodes for the members 796 * and places them on the given list, returning SUCCESS if all 797 * went well and FAILURE if there was an error in the 798 * specification. On error, line should remain untouched. 799 */ 800 if (Arch_ParseArchive (&line, targets, VAR_CMD) != SUCCESS) { 801 Parse_Error (PARSE_FATAL, 802 "Error in archive specification: \"%s\"", line); 803 return; 804 } else 805 continue; 805 806 #else 806 807 Parse_Error(PARSE_FATAL, "Archives are not supported!", line); 807 808 return; 808 809 #endif /* USE_ARCHIVES */ 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 * .PATHHave to set the dirSearchPath843 *variable too844 * .MAINIts sources are only used if845 *nothing has been specified to846 *create.847 * .DEFAULTNeed to create a node to hang848 *commands on, but we don't want849 *it in the graph, nor do we want850 *it to be the Main Target, so we851 *create it, set OP_NOTMAIN and852 *add it to the list, setting853 *DEFAULT to the new node for854 *later use. We claim the node is855 *A transformation rule to make856 *life easier later, when we'll857 *use Make_HandleUse to actually858 *apply the .DEFAULT commands.859 * .PHONYThe list of targets860 *.BEGIN861 *.END862 * .INTERRUPTAre not to be considered the863 *main target.864 * .NOTPARALLELMake only one target at a time.865 * .SINGLESHELLCreate a shell for each command.866 * .ORDERMust set initial predecessor to NIL867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 Lstpath;916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 LstemptyPath = Lst_Init(FALSE);946 947 948 949 950 951 952 953 954 955 956 957 958 959 char*targName = (char *)Lst_DeQueue(curTargs);960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 810 } 811 savec = *cp; 812 813 if (!*cp) { 814 /* 815 * Ending a dependency line without an operator is a Bozo 816 * no-no 817 */ 818 Parse_Error (PARSE_FATAL, "Need an operator"); 819 return; 820 } 821 *cp = '\0'; 822 /* 823 * Have a word in line. See if it's a special target and set 824 * specType to match it. 825 */ 826 if (*line == '.' && isupper (line[1])) { 827 /* 828 * See if the target is a special target that must have it 829 * or its sources handled specially. 830 */ 831 int keywd = ParseFindKeyword(line); 832 if (keywd != -1) { 833 if (specType == ExPath && parseKeywords[keywd].spec != ExPath) { 834 Parse_Error(PARSE_FATAL, "Mismatched special targets"); 835 return; 836 } 837 838 specType = parseKeywords[keywd].spec; 839 tOp = parseKeywords[keywd].op; 840 841 /* 842 * Certain special targets have special semantics: 843 * .PATH Have to set the dirSearchPath 844 * variable too 845 * .MAIN Its sources are only used if 846 * nothing has been specified to 847 * create. 848 * .DEFAULT Need to create a node to hang 849 * commands on, but we don't want 850 * it in the graph, nor do we want 851 * it to be the Main Target, so we 852 * create it, set OP_NOTMAIN and 853 * add it to the list, setting 854 * DEFAULT to the new node for 855 * later use. We claim the node is 856 * A transformation rule to make 857 * life easier later, when we'll 858 * use Make_HandleUse to actually 859 * apply the .DEFAULT commands. 860 * .PHONY The list of targets 861 * .BEGIN 862 * .END 863 * .INTERRUPT Are not to be considered the 864 * main target. 865 * .NOTPARALLEL Make only one target at a time. 866 * .SINGLESHELL Create a shell for each command. 867 * .ORDER Must set initial predecessor to NIL 868 */ 869 switch (specType) { 870 case ExPath: 871 if (paths == NULL) { 872 paths = Lst_Init(FALSE); 873 } 874 (void)Lst_AtEnd(paths, (ClientData)dirSearchPath); 875 break; 876 case Main: 877 if (!Lst_IsEmpty(create)) { 878 specType = Not; 879 } 880 break; 881 case Begin: 882 case End: 883 case Interrupt: 884 gn = Targ_FindNode(line, TARG_CREATE); 885 gn->type |= OP_NOTMAIN; 886 (void)Lst_AtEnd(targets, (ClientData)gn); 887 break; 888 case Default: 889 gn = Targ_NewGN(".DEFAULT"); 890 gn->type |= (OP_NOTMAIN|OP_TRANSFORM); 891 (void)Lst_AtEnd(targets, (ClientData)gn); 892 DEFAULT = gn; 893 break; 894 case NotParallel: 895 { 896 extern int maxJobs; 897 898 maxJobs = 1; 899 break; 900 } 901 case SingleShell: 902 compatMake = 1; 903 break; 904 case Order: 905 predecessor = NILGNODE; 906 break; 907 default: 908 break; 909 } 910 } else if (strncmp (line, ".PATH", 5) == 0) { 911 /* 912 * .PATH<suffix> has to be handled specially. 913 * Call on the suffix module to give us a path to 914 * modify. 915 */ 916 Lst path; 917 918 specType = ExPath; 919 path = Suff_GetPath (&line[5]); 920 if (path == NILLST) { 921 Parse_Error (PARSE_FATAL, 922 "Suffix '%s' not defined (yet)", 923 &line[5]); 924 return; 925 } else { 926 if (paths == (Lst)NULL) { 927 paths = Lst_Init(FALSE); 928 } 929 (void)Lst_AtEnd(paths, (ClientData)path); 930 } 931 } 932 } 933 934 /* 935 * Have word in line. Get or create its node and stick it at 936 * the end of the targets list 937 */ 938 if ((specType == Not) && (*line != '\0')) { 939 if (Dir_HasWildcards(line)) { 940 /* 941 * Targets are to be sought only in the current directory, 942 * so create an empty path for the thing. Note we need to 943 * use Dir_Destroy in the destruction of the path as the 944 * Dir module could have added a directory to the path... 945 */ 946 Lst emptyPath = Lst_Init(FALSE); 947 948 Dir_Expand(line, emptyPath, curTargs); 949 950 Lst_Destroy(emptyPath, Dir_Destroy); 951 } else { 952 /* 953 * No wildcards, but we want to avoid code duplication, 954 * so create a list with the word on it. 955 */ 956 (void)Lst_AtEnd(curTargs, (ClientData)line); 957 } 958 959 while(!Lst_IsEmpty(curTargs)) { 960 char *targName = (char *)Lst_DeQueue(curTargs); 961 962 if (!Suff_IsTransform (targName)) { 963 gn = Targ_FindNode (targName, TARG_CREATE); 964 } else { 965 gn = Suff_AddTransform (targName); 966 } 967 968 (void)Lst_AtEnd (targets, (ClientData)gn); 969 } 970 } else if (specType == ExPath && *line != '.' && *line != '\0') { 971 Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line); 972 } 973 974 *cp = savec; 975 /* 976 * If it is a special type and not .PATH, it's the only target we 977 * allow on this line... 978 */ 979 if (specType != Not && specType != ExPath) { 980 Boolean warn = FALSE; 981 982 while ((*cp != '!') && (*cp != ':') && *cp) { 983 if (*cp != ' ' && *cp != '\t') { 984 warn = TRUE; 985 } 986 cp++; 987 } 988 if (warn) { 989 Parse_Error(PARSE_WARNING, "Extra target ignored"); 990 } 991 } else { 992 while (*cp && isspace (*cp)) { 993 cp++; 994 } 995 } 996 line = cp; 996 997 } while ((*line != '!') && (*line != ':') && *line); 997 998 … … 1002 1003 1003 1004 if (!Lst_IsEmpty(targets)) { 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1005 switch(specType) { 1006 default: 1007 Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. Mundane ones ignored"); 1008 break; 1009 case Default: 1010 case Begin: 1011 case End: 1012 case Interrupt: 1013 /* 1014 * These four create nodes on which to hang commands, so 1015 * targets shouldn't be empty... 1016 */ 1017 case Not: 1018 /* 1019 * Nothing special here -- targets can be empty if it wants. 1020 */ 1021 break; 1022 } 1022 1023 } 1023 1024 … … 1027 1028 */ 1028 1029 if (*cp == '!') { 1029 1030 op = OP_FORCE; 1030 1031 } else if (*cp == ':') { 1031 1032 1033 1034 1035 1036 1032 if (cp[1] == ':') { 1033 op = OP_DOUBLEDEP; 1034 cp++; 1035 } else { 1036 op = OP_DEPENDS; 1037 } 1037 1038 } else { 1038 1039 1040 } 1041 1042 cp++; 1039 Parse_Error (PARSE_FATAL, "Missing dependency operator"); 1040 return; 1041 } 1042 1043 cp++; /* Advance beyond operator */ 1043 1044 1044 1045 Lst_ForEach (targets, ParseDoOp, (ClientData)&op); … … 1048 1049 */ 1049 1050 while (*cp && isspace (*cp)) { 1050 1051 cp++; 1051 1052 } 1052 1053 line = cp; … … 1055 1056 * Several special targets take different actions if present with no 1056 1057 * sources: 1057 * 1058 * 1059 * 1060 * 1061 * 1058 * a .SUFFIXES line with no sources clears out all old suffixes 1059 * a .PRECIOUS line makes all targets precious 1060 * a .IGNORE line ignores errors for all targets 1061 * a .SILENT line creates silence when making all targets 1062 * a .PATH removes all directories from the search path(s). 1062 1063 */ 1063 1064 if (!*line) { 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1065 switch (specType) { 1066 case Suffixes: 1067 Suff_ClearSuffixes (); 1068 break; 1069 case Precious: 1070 allPrecious = TRUE; 1071 break; 1072 case Ignore: 1073 ignoreErrors = TRUE; 1074 break; 1075 case Silent: 1076 beSilent = TRUE; 1077 break; 1078 case ExPath: 1079 Lst_ForEach(paths, ParseClearPath, (ClientData)NULL); 1080 break; 1080 1081 #ifdef POSIX 1081 1082 1083 1084 #endif 1085 1086 1087 1082 case Posix: 1083 Var_Set("%POSIX", "1003.2", VAR_GLOBAL); 1084 break; 1085 #endif 1086 default: 1087 break; 1088 } 1088 1089 } else if (specType == MFlags) { 1089 1090 1091 1092 1093 1094 1095 1090 /* 1091 * Call on functions in main.c to deal with these arguments and 1092 * set the initial character to a null-character so the loop to 1093 * get sources won't get anything 1094 */ 1095 Main_ParseArgLine (line); 1096 *line = '\0'; 1096 1097 } else if (specType == ExShell) { 1097 1098 #ifdef KMK … … 1099 1100 return; 1100 1101 #else 1101 1102 1103 1104 1102 if (Job_ParseShell (line) != SUCCESS) { 1103 Parse_Error (PARSE_FATAL, "improper shell specification"); 1104 return; 1105 } 1105 1106 #endif 1106 1107 *line = '\0'; 1107 1108 } else if ((specType == NotParallel) || (specType == SingleShell)) { 1108 1109 *line = '\0'; 1109 1110 } 1110 1111 … … 1113 1114 */ 1114 1115 if ((specType == Suffixes) || (specType == ExPath) || 1115 1116 (specType == Includes) || 1116 1117 #ifdef USE_ARCHIVES 1117 1118 (specType == Libs) || 1118 1119 #endif 1119 1120 (specType == Null)) 1120 1121 { 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1122 while (*line) { 1123 /* 1124 * If the target was one that doesn't take files as its sources 1125 * but takes something like suffixes, we take each 1126 * space-separated word on the line as a something and deal 1127 * with it accordingly. 1128 * 1129 * If the target was .SUFFIXES, we take each source as a 1130 * suffix and add it to the list of suffixes maintained by the 1131 * Suff module. 1132 * 1133 * If the target was a .PATH, we add the source as a directory 1134 * to search on the search path. 1135 * 1136 * If it was .INCLUDES, the source is taken to be the suffix of 1137 * files which will be #included and whose search path should 1138 * be present in the .INCLUDES variable. 1139 * 1140 * If it was .LIBS, the source is taken to be the suffix of 1141 * files which are considered libraries and whose search path 1142 * should be present in the .LIBS variable. 1143 * 1144 * If it was .NULL, the source is the suffix to use when a file 1145 * has no valid suffix. 1146 */ 1147 char savec; 1148 while (*cp && !isspace (*cp)) { 1149 cp++; 1150 } 1151 savec = *cp; 1152 *cp = '\0'; 1153 switch (specType) { 1154 case Suffixes: 1155 Suff_AddSuffix (line); 1156 break; 1157 case ExPath: 1158 Lst_ForEach(paths, ParseAddDir, (ClientData)line); 1159 break; 1160 case Includes: 1161 Suff_AddInclude (line); 1162 break; 1162 1163 #ifdef USE_ARCHIVES 1163 1164 1165 1166 #endif 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1164 case Libs: 1165 Suff_AddLib (line); 1166 break; 1167 #endif 1168 case Null: 1169 Suff_SetNull (line); 1170 break; 1171 default: 1172 break; 1173 } 1174 *cp = savec; 1175 if (savec != '\0') { 1176 cp++; 1177 } 1178 while (*cp && isspace (*cp)) { 1179 cp++; 1180 } 1181 line = cp; 1182 } 1183 if (paths) { 1184 Lst_Destroy(paths, NOFREE); 1185 } 1185 1186 } else { 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1187 while (*line) { 1188 /* 1189 * The targets take real sources, so we must beware of archive 1190 * specifications (i.e. things with left parentheses in them) 1191 * and handle them accordingly. 1192 */ 1193 while (*cp && !isspace (*cp)) { 1194 if ((*cp == '(') && (cp > line) && (cp[-1] != '$')) { 1195 /* 1196 * Only stop for a left parenthesis if it isn't at the 1197 * start of a word (that'll be for variable changes 1198 * later) and isn't preceded by a dollar sign (a dynamic 1199 * source). 1200 */ 1201 break; 1202 } else { 1203 cp++; 1204 } 1205 } 1206 1207 if (*cp == '(') { 1207 1208 #ifdef USE_ARCHIVES 1208 GNode*gn;1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1209 GNode *gn; 1210 1211 sources = Lst_Init (FALSE); 1212 if (Arch_ParseArchive (&line, sources, VAR_CMD) != SUCCESS) { 1213 Parse_Error (PARSE_FATAL, 1214 "Error in source archive spec \"%s\"", line); 1215 return; 1216 } 1217 1218 while (!Lst_IsEmpty (sources)) { 1219 gn = (GNode *) Lst_DeQueue (sources); 1220 ParseDoSrc (tOp, gn->name, curSrcs); 1221 } 1222 Lst_Destroy (sources, NOFREE); 1223 cp = line; 1223 1224 #else 1224 1225 Parse_Error(PARSE_FATAL, "Archives are not supported!", line); 1225 1226 return; 1226 1227 #endif /* USE_ARCHIVES */ 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1228 } else { 1229 if (*cp) { 1230 *cp = '\0'; 1231 cp += 1; 1232 } 1233 1234 ParseDoSrc (tOp, line, curSrcs); 1235 } 1236 while (*cp && isspace (*cp)) { 1237 cp++; 1238 } 1239 line = cp; 1240 } 1240 1241 } 1241 1242 1242 1243 if (mainNode == NILGNODE) { 1243 1244 1245 1246 1247 1248 1249 1244 /* 1245 * If we have yet to decide on a main target to make, in the 1246 * absence of any user input, we want the first target on 1247 * the first dependency line that is actually a real target 1248 * (i.e. isn't a .USE or .EXEC rule) to be made. 1249 */ 1250 Lst_ForEach (targets, ParseFindMain, (ClientData)0); 1250 1251 } 1251 1252 … … 1259 1260 *--------------------------------------------------------------------- 1260 1261 * Parse_IsVar -- 1261 * 1262 * 1263 * 1264 * 1265 * 1262 * Return TRUE if the passed line is a variable assignment. A variable 1263 * assignment consists of a single word followed by optional whitespace 1264 * followed by either a += or an = operator. 1265 * This function is used both by the Parse_File function and main when 1266 * parsing the command-line arguments. 1266 1267 * 1267 1268 * Results: 1268 * 1269 * TRUE if it is. FALSE if it ain't 1269 1270 * 1270 1271 * Side Effects: 1271 * 1272 * none 1272 1273 *--------------------------------------------------------------------- 1273 1274 */ 1274 1275 Boolean 1275 1276 Parse_IsVar (line) 1276 register char *line; 1277 { 1278 register Boolean wasSpace = FALSE; 1279 register Boolean haveName = FALSE; 1277 register char *line; /* the line to check */ 1278 { 1279 register Boolean wasSpace = FALSE; /* set TRUE if found a space */ 1280 register Boolean haveName = FALSE; /* Set TRUE if have a variable name */ 1280 1281 int level = 0; 1281 1282 #define ISEQOPERATOR(c) \ 1282 1283 (((c) == '+') || ((c) == ':') || ((c) == '?') || ((c) == '!')) 1283 1284 1284 1285 /* … … 1286 1287 */ 1287 1288 for (;(*line == ' ') || (*line == '\t'); line++) 1288 1289 continue; 1289 1290 1290 1291 for (; *line != '=' || level != 0; line++) 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1292 switch (*line) { 1293 case '\0': 1294 /* 1295 * end-of-line -- can't be a variable assignment. 1296 */ 1297 return FALSE; 1298 1299 case ' ': 1300 case '\t': 1301 /* 1302 * there can be as much white space as desired so long as there is 1303 * only one word before the operator 1304 */ 1305 wasSpace = TRUE; 1306 break; 1307 1308 case '(': 1309 case '{': 1310 level++; 1311 break; 1312 1313 case '}': 1314 case ')': 1315 level--; 1316 break; 1317 1318 default: 1319 if (wasSpace && haveName) { 1320 if (ISEQOPERATOR(*line)) { 1321 /* 1322 * We must have a finished word 1323 */ 1324 if (level != 0) 1325 return FALSE; 1326 1327 /* 1328 * When an = operator [+?!:] is found, the next 1329 * character must be an = or it ain't a valid 1330 * assignment. 1331 */ 1332 if (line[1] == '=') 1333 return haveName; 1333 1334 #ifdef SUNSHCMD 1334 1335 1336 1337 1338 1339 #endif 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1335 /* 1336 * This is a shell command 1337 */ 1338 if (strncmp(line, ":sh", 3) == 0) 1339 return haveName; 1340 #endif 1341 } 1342 /* 1343 * This is the start of another word, so not assignment. 1344 */ 1345 return FALSE; 1346 } 1347 else { 1348 haveName = TRUE; 1349 wasSpace = FALSE; 1350 } 1351 break; 1352 } 1352 1353 1353 1354 return haveName; … … 1357 1358 *--------------------------------------------------------------------- 1358 1359 * Parse_DoVar -- 1359 * 1360 * 1361 * 1362 * 1363 * 1364 * 1365 * 1366 * 1360 * Take the variable assignment in the passed line and do it in the 1361 * global context. 1362 * 1363 * Note: There is a lexical ambiguity with assignment modifier characters 1364 * in variable names. This routine interprets the character before the = 1365 * as a modifier. Therefore, an assignment like 1366 * C++=/usr/bin/CC 1367 * is interpreted as "C+ +=" instead of "C++ =". 1367 1368 * 1368 1369 * Results: 1369 * 1370 * none 1370 1371 * 1371 1372 * Side Effects: 1372 * 1373 * 1373 * the variable structure of the given variable name is altered in the 1374 * global context. 1374 1375 *--------------------------------------------------------------------- 1375 1376 */ 1376 1377 void 1377 1378 Parse_DoVar (line, ctxt) 1378 char *line; 1379 1380 GNode *ctxt;/* Context in which to do the assignment */1381 { 1382 char *cp;/* pointer into line */1379 char *line; /* a line guaranteed to be a variable 1380 * assignment. This reduces error checks */ 1381 GNode *ctxt; /* Context in which to do the assignment */ 1382 { 1383 char *cp; /* pointer into line */ 1383 1384 enum { 1384 1385 } type;/* Type of assignment */1386 char *opc; 1387 1385 VAR_SUBST, VAR_APPEND, VAR_SHELL, VAR_NORMAL 1386 } type; /* Type of assignment */ 1387 char *opc; /* ptr to operator character to 1388 * null-terminate the variable name */ 1388 1389 /* 1389 1390 * Avoid clobbered variable warnings by forcing the compiler … … 1399 1400 */ 1400 1401 while ((*line == ' ') || (*line == '\t')) { 1401 1402 line++; 1402 1403 } 1403 1404 … … 1406 1407 */ 1407 1408 for (cp = line + 1; *cp != '='; cp++) { 1408 1409 1410 1411 } 1412 opc = cp-1; 1413 *cp++ = '\0'; 1409 if (isspace (*cp)) { 1410 *cp = '\0'; 1411 } 1412 } 1413 opc = cp-1; /* operator is the previous character */ 1414 *cp++ = '\0'; /* nuke the = */ 1414 1415 1415 1416 /* … … 1417 1418 */ 1418 1419 switch (*opc) { 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1420 case '+': 1421 type = VAR_APPEND; 1422 *opc = '\0'; 1423 break; 1424 1425 case '?': 1426 /* 1427 * If the variable already has a value, we don't do anything. 1428 */ 1429 *opc = '\0'; 1430 if (Var_Exists(line, ctxt)) { 1431 return; 1432 } else { 1433 type = VAR_NORMAL; 1434 } 1435 break; 1436 1437 case ':': 1438 type = VAR_SUBST; 1439 *opc = '\0'; 1440 break; 1441 1442 case '!': 1443 type = VAR_SHELL; 1444 *opc = '\0'; 1445 break; 1446 1447 default: 1447 1448 #ifdef SUNSHCMD 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 #endif 1460 1461 1449 while (*opc != ':') 1450 if (opc == line) 1451 break; 1452 else 1453 --opc; 1454 1455 if (strncmp(opc, ":sh", 3) == 0) { 1456 type = VAR_SHELL; 1457 *opc = '\0'; 1458 break; 1459 } 1460 #endif 1461 type = VAR_NORMAL; 1462 break; 1462 1463 } 1463 1464 1464 1465 while (isspace (*cp)) { 1465 1466 cp++; 1466 1467 } 1467 1468 1468 1469 if (type == VAR_APPEND) { 1469 1470 Var_Append (line, cp, ctxt); 1470 1471 } else if (type == VAR_SUBST) { 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 BooleanoldOldVars = oldVars;1483 1484 1485 1486 1487 1488 1489 1472 /* 1473 * Allow variables in the old value to be undefined, but leave their 1474 * invocation alone -- this is done by forcing oldVars to be false. 1475 * XXX: This can cause recursive variables, but that's not hard to do, 1476 * and this allows someone to do something like 1477 * 1478 * CFLAGS = $(.INCLUDES) 1479 * CFLAGS := -I.. $(CFLAGS) 1480 * 1481 * And not get an error. 1482 */ 1483 Boolean oldOldVars = oldVars; 1484 1485 oldVars = FALSE; 1486 cp = Var_Subst(NULL, cp, ctxt, FALSE); 1487 oldVars = oldOldVars; 1488 1489 Var_Set(line, cp, ctxt); 1490 efree(cp); 1490 1491 } else if (type == VAR_SHELL) { 1491 BooleanfreeCmd = FALSE; /* TRUE if the command needs to be freed, i.e.1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1492 Boolean freeCmd = FALSE; /* TRUE if the command needs to be freed, i.e. 1493 * if any variable expansion was performed */ 1494 char *res, *err; 1495 1496 if (strchr(cp, '$') != NULL) { 1497 /* 1498 * There's a dollar sign in the command, so perform variable 1499 * expansion on the whole thing. The resulting string will need 1500 * freeing when we're done, so set freeCmd to TRUE. 1501 */ 1502 cp = Var_Subst(NULL, cp, VAR_CMD, TRUE); 1503 freeCmd = TRUE; 1504 } 1505 1506 res = Cmd_Exec(cp, &err); 1507 Var_Set(line, res, ctxt); 1508 efree(res); 1509 1510 if (err) 1511 Parse_Error(PARSE_WARNING, err, cp); 1512 1513 if (freeCmd) 1514 efree(cp); 1514 1515 } else { 1515 1516 1517 1518 1516 /* 1517 * Normal assignment -- just do it. 1518 */ 1519 Var_Set(line, cp, ctxt); 1519 1520 } 1520 1521 } … … 1523 1524 /*- 1524 1525 * ParseAddCmd -- 1525 * 1526 * Lst_ForEach function to add a command line to all targets 1526 1527 * 1527 1528 * Results: 1528 * 1529 * Always 0 1529 1530 * 1530 1531 * Side Effects: 1531 * 1532 * A new element is added to the commands list of the node. 1532 1533 */ 1533 1534 static int 1534 1535 ParseAddCmd(gnp, cmd) 1535 ClientData gnp; 1536 ClientData cmd; 1536 ClientData gnp; /* the node to which the command is to be added */ 1537 ClientData cmd; /* the command to add */ 1537 1538 { 1538 1539 GNode *gn = (GNode *) gnp; 1539 1540 /* if target already supplied, ignore commands */ 1540 1541 if (!(gn->type & OP_HAS_COMMANDS)) 1541 1542 (void)Lst_AtEnd(gn->commands, cmd); 1542 1543 return(0); 1543 1544 } … … 1548 1549 /*- 1549 1550 * ParseAppendInline -- 1550 * 1551 * Lst_ForEach function to append the line to the last command 1551 1552 * 1552 1553 * Results: 1553 * 1554 * Always 0 1554 1555 * 1555 1556 * Side Effects: 1556 * 1557 * A new element is added to the last commands list of the node. 1557 1558 */ 1558 1559 static int 1559 1560 ParseAppendInline(gnp, line) 1560 ClientData gnp; 1561 ClientData line; 1561 ClientData gnp; /* the node to which the command is to be added */ 1562 ClientData line; /* the command to add */ 1562 1563 { 1563 1564 GNode *gn = (GNode *)gnp; … … 1585 1586 * 1586 1587 * Results: 1587 * 1588 * returns TRUE if it is, FALSE if not. 1588 1589 * 1589 1590 * Side Effects: 1590 * 1591 * OP_HAS_COMMANDS may be set for the target. 1591 1592 * 1592 1593 *----------------------------------------------------------------------- … … 1641 1642 *----------------------------------------------------------------------- 1642 1643 * ParseHasCommands -- 1643 * 1644 * 1645 * 1646 * 1644 * Callback procedure for Parse_File when destroying the list of 1645 * targets on the last dependency line. Marks a target as already 1646 * having commands if it does, to keep from having shell commands 1647 * on multiple dependency lines. 1647 1648 * 1648 1649 * Results: 1649 * 1650 * None 1650 1651 * 1651 1652 * Side Effects: 1652 * 1653 * OP_HAS_COMMANDS may be set for the target. 1653 1654 * 1654 1655 *----------------------------------------------------------------------- … … 1656 1657 static void 1657 1658 ParseHasCommands(gnp) 1658 ClientData gnp;/* Node to examine */1659 ClientData gnp; /* Node to examine */ 1659 1660 { 1660 1661 GNode *gn = (GNode *) gnp; 1661 1662 if (!Lst_IsEmpty(gn->commands)) { 1662 1663 gn->type |= OP_HAS_COMMANDS; 1663 1664 } 1664 1665 } … … 1667 1668 *----------------------------------------------------------------------- 1668 1669 * Parse_AddIncludeDir -- 1669 * 1670 * 1670 * Add a directory to the path searched for included makefiles 1671 * bracketed by double-quotes. Used by functions in main.c 1671 1672 * 1672 1673 * Results: 1673 * 1674 * None. 1674 1675 * 1675 1676 * Side Effects: 1676 * 1677 * The directory is appended to the list. 1677 1678 * 1678 1679 *----------------------------------------------------------------------- … … 1680 1681 void 1681 1682 Parse_AddIncludeDir (dir) 1682 char *dir;/* The name of the directory to add */1683 char *dir; /* The name of the directory to add */ 1683 1684 { 1684 1685 Dir_AddDir (parseIncPath, dir); … … 1687 1688 /*--------------------------------------------------------------------- 1688 1689 * ParseDoError -- 1689 * 1690 * 1691 * 1692 * 1693 * 1690 * Handle error directive 1691 * 1692 * The input is the line minus the ".error". We substitute variables, 1693 * print the message and exit(1) or just print a warning if the ".error" 1694 * directive is malformed. 1694 1695 * 1695 1696 *--------------------------------------------------------------------- … … 1697 1698 static void 1698 1699 ParseDoError(errmsg) 1699 char *errmsg; 1700 { 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1700 char *errmsg; /* error message */ 1701 { 1702 if (!isspace(*errmsg)) { 1703 Parse_Error(PARSE_WARNING, "invalid syntax: .error%s", errmsg); 1704 return; 1705 } 1706 1707 while (isspace(*errmsg)) 1708 errmsg++; 1709 1710 errmsg = Var_Subst(NULL, errmsg, VAR_GLOBAL, FALSE); 1711 1712 /* use fprintf/exit instead of Parse_Error to terminate immediately */ 1713 fprintf(stderr, "\"%s\", line %d: %s\n", fname, lineno, errmsg); 1714 exit(1); 1714 1715 } 1715 1716 … … 1717 1718 *--------------------------------------------------------------------- 1718 1719 * ParseDoInclude -- 1719 * 1720 * 1721 * 1722 * 1723 * 1724 * 1720 * Push to another file. 1721 * 1722 * The input is the line minus the #include. A file spec is a string 1723 * enclosed in <> or "". The former is looked for only in sysIncPath. 1724 * The latter in . and the directories specified by -I command line 1725 * options 1725 1726 * 1726 1727 * Results: 1727 * 1728 * None 1728 1729 * 1729 1730 * Side Effects: 1730 * 1731 * 1731 * A structure is added to the includes Lst and readProc, lineno, 1732 * fname and curFILE are altered for the new file 1732 1733 *--------------------------------------------------------------------- 1733 1734 */ 1734 1735 static void 1735 1736 ParseDoInclude (file, chPre) 1736 char *file; 1737 char *file; /* file specification */ 1737 1738 char chPre; /* Preprocessor char */ 1738 1739 { 1739 char *fullname; 1740 IFile *oldFile; 1741 char endc; 1742 char *cp; 1743 Boolean isSystem;/* TRUE if makefile is a system makefile */1740 char *fullname; /* full pathname of file */ 1741 IFile *oldFile; /* state associated with current file */ 1742 char endc; /* the character which ends the file spec */ 1743 char *cp; /* current position in file spec */ 1744 Boolean isSystem; /* TRUE if makefile is a system makefile */ 1744 1745 1745 1746 /* … … 1747 1748 */ 1748 1749 while ((*file == ' ') || (*file == '\t')) { 1749 1750 file++; 1750 1751 } 1751 1752 1752 1753 #ifndef NMAKE 1753 1754 if ((*file != '"') && (*file != '<')) { 1754 1755 1756 1755 Parse_Error (PARSE_FATAL, 1756 "%cinclude filename must be delimited by '\"' or '<'", chPre); 1757 return; 1757 1758 } 1758 1759 #endif … … 1764 1765 */ 1765 1766 if (*file == '<') { 1766 1767 1767 isSystem = TRUE; 1768 endc = '>'; 1768 1769 } else { 1769 1770 isSystem = FALSE; 1770 1771 #ifdef NMAKE 1771 1772 if (*file == '"') 1772 1773 endc = '"'; 1773 1774 else 1774 1775 { … … 1777 1778 } 1778 1779 #else 1779 1780 endc = '"'; 1780 1781 #endif 1781 1782 } … … 1785 1786 */ 1786 1787 for (cp = ++file; *cp && *cp != endc; cp++) { 1787 1788 continue; 1788 1789 } 1789 1790 … … 1793 1794 if (*cp != endc) { 1794 1795 #endif 1795 1796 1797 1798 1796 Parse_Error (PARSE_FATAL, 1797 "Unclosed %cinclude filename. '%c' expected", 1798 chPre, endc); 1799 return; 1799 1800 } 1800 1801 *cp = '\0'; … … 1812 1813 */ 1813 1814 if (!isSystem) { 1814 1815 1816 1817 1818 1819 1820 1821 char*prefEnd, *Fname;1822 1823 1824 1825 1826 1827 1828 char*newName;1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1815 /* 1816 * Include files contained in double-quotes are first searched for 1817 * relative to the including file's location. We don't want to 1818 * cd there, of course, so we just tack on the old file's 1819 * leading path components and call Dir_FindFile to see if 1820 * we can locate the beast. 1821 */ 1822 char *prefEnd, *Fname; 1823 1824 /* Make a temporary copy of this, to be safe. */ 1825 Fname = estrdup(fname); 1826 1827 prefEnd = strrchr (Fname, '/'); 1828 if (prefEnd != (char *)NULL) { 1829 char *newName; 1830 1831 *prefEnd = '\0'; 1832 if (file[0] == '/') 1833 newName = estrdup(file); 1834 else 1835 newName = str_concat (Fname, file, STR_ADDSLASH); 1836 fullname = Dir_FindFile (newName, parseIncPath); 1837 if (fullname == (char *)NULL) { 1838 fullname = Dir_FindFile(newName, dirSearchPath); 1839 } 1840 efree (newName); 1841 *prefEnd = '/'; 1842 } else { 1843 fullname = (char *)NULL; 1844 } 1845 efree (Fname); 1845 1846 } else { 1846 1847 fullname = (char *)NULL; 1847 1848 } 1848 1849 1849 1850 if (fullname == (char *)NULL) { 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1851 /* 1852 * System makefile or makefile wasn't found in same directory as 1853 * included makefile. Search for it first on the -I search path, 1854 * then on the .PATH search path, if not found in a -I directory. 1855 * XXX: Suffix specific? 1856 */ 1857 fullname = Dir_FindFile (file, parseIncPath); 1858 if (fullname == (char *)NULL) { 1859 fullname = Dir_FindFile(file, dirSearchPath); 1860 } 1860 1861 } 1861 1862 1862 1863 if (fullname == (char *)NULL) { 1863 1864 1865 1866 1867 1864 /* 1865 * Still haven't found the makefile. Look for it on the system 1866 * path as a last resort. 1867 */ 1868 fullname = Dir_FindFile(file, sysIncPath); 1868 1869 } 1869 1870 1870 1871 if (fullname == (char *) NULL) { 1871 1872 1873 1872 *cp = endc; 1873 Parse_Error (PARSE_FATAL, "Could not find '%s'", file); 1874 return; 1874 1875 } 1875 1876 … … 1904 1905 curPTR = NULL; 1905 1906 if (curFILE == (FILE * ) NULL) { 1906 1907 1908 1909 1910 1907 Parse_Error (PARSE_FATAL, "Cannot open %s", fullname); 1908 /* 1909 * Pop to previous file 1910 */ 1911 (void) ParseEOF(0); 1911 1912 } 1912 1913 } … … 1917 1918 *--------------------------------------------------------------------- 1918 1919 * Parse_FromString -- 1919 * 1920 * Start Parsing from the given string 1920 1921 * 1921 1922 * Results: 1922 * 1923 * None 1923 1924 * 1924 1925 * Side Effects: 1925 * 1926 * 1926 * A structure is added to the includes Lst and readProc, lineno, 1927 * fname and curFILE are altered for the new file 1927 1928 *--------------------------------------------------------------------- 1928 1929 */ … … 1931 1932 char *str; 1932 1933 { 1933 IFile *oldFile; 1934 IFile *oldFile; /* state associated with this file */ 1934 1935 1935 1936 if (DEBUG(FOR)) 1936 1937 (void) fprintf(stderr, "%s\n----\n", str); 1937 1938 1938 1939 oldFile = (IFile *) emalloc (sizeof (IFile)); … … 1956 1957 *--------------------------------------------------------------------- 1957 1958 * ParseTraditionalInclude -- 1958 * 1959 * 1960 * 1961 * 1959 * Push to another file. 1960 * 1961 * The input is the line minus the "include". The file name is 1962 * the string following the "include". 1962 1963 * 1963 1964 * Results: 1964 * 1965 * None 1965 1966 * 1966 1967 * Side Effects: 1967 * 1968 * 1968 * A structure is added to the includes Lst and readProc, lineno, 1969 * fname and curFILE are altered for the new file 1969 1970 *--------------------------------------------------------------------- 1970 1971 */ 1971 1972 static void 1972 1973 ParseTraditionalInclude (file) 1973 char *file; 1974 { 1975 char *fullname; 1976 IFile *oldFile; 1977 char *cp; 1978 char 1974 char *file; /* file specification */ 1975 { 1976 char *fullname; /* full pathname of file */ 1977 IFile *oldFile; /* state associated with current file */ 1978 char *cp; /* current position in file spec */ 1979 char *prefEnd; 1979 1980 1980 1981 /* … … 1982 1983 */ 1983 1984 while ((*file == ' ') || (*file == '\t')) { 1984 1985 file++; 1985 1986 } 1986 1987 1987 1988 if (*file == '\0') { 1988 1989 1990 1989 Parse_Error (PARSE_FATAL, 1990 "Filename missing from \"include\""); 1991 return; 1991 1992 } 1992 1993 … … 1995 1996 */ 1996 1997 for (cp = file; *cp && *cp != '\n' && *cp != '\t' && *cp != ' '; cp++) { 1997 1998 continue; 1998 1999 } 1999 2000 … … 2019 2020 prefEnd = strrchr (fname, '/'); 2020 2021 if (prefEnd != (char *)NULL) { 2021 char*newName;2022 2023 2024 2025 2026 2027 2028 2029 2030 2022 char *newName; 2023 2024 *prefEnd = '\0'; 2025 newName = str_concat (fname, file, STR_ADDSLASH); 2026 fullname = Dir_FindFile (newName, parseIncPath); 2027 if (fullname == (char *)NULL) { 2028 fullname = Dir_FindFile(newName, dirSearchPath); 2029 } 2030 efree (newName); 2031 *prefEnd = '/'; 2031 2032 } else { 2032 2033 fullname = (char *)NULL; 2033 2034 } 2034 2035 2035 2036 if (fullname == (char *)NULL) { 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2037 /* 2038 * System makefile or makefile wasn't found in same directory as 2039 * included makefile. Search for it first on the -I search path, 2040 * then on the .PATH search path, if not found in a -I directory. 2041 * XXX: Suffix specific? 2042 */ 2043 fullname = Dir_FindFile (file, parseIncPath); 2044 if (fullname == (char *)NULL) { 2045 fullname = Dir_FindFile(file, dirSearchPath); 2046 } 2046 2047 } 2047 2048 2048 2049 if (fullname == (char *)NULL) { 2049 2050 2051 2052 2053 2050 /* 2051 * Still haven't found the makefile. Look for it on the system 2052 * path as a last resort. 2053 */ 2054 fullname = Dir_FindFile(file, sysIncPath); 2054 2055 } 2055 2056 2056 2057 if (fullname == (char *) NULL) { 2057 2058 2058 Parse_Error (PARSE_FATAL, "Could not find %s", file); 2059 return; 2059 2060 } 2060 2061 … … 2087 2088 curPTR = NULL; 2088 2089 if (curFILE == (FILE * ) NULL) { 2089 2090 2091 2092 2093 2090 Parse_Error (PARSE_FATAL, "Cannot open %s", fullname); 2091 /* 2092 * Pop to previous file 2093 */ 2094 (void) ParseEOF(1); 2094 2095 } 2095 2096 } … … 2099 2100 *--------------------------------------------------------------------- 2100 2101 * ParseEOF -- 2101 * 2102 * 2103 * 2102 * Called when EOF is reached in the current file. If we were reading 2103 * an include file, the includes stack is popped and things set up 2104 * to go back to reading the previous file at the previous location. 2104 2105 * 2105 2106 * Results: 2106 * 2107 * CONTINUE if there's more to do. DONE if not. 2107 2108 * 2108 2109 * Side Effects: 2109 * 2110 * 2110 * The old curFILE, is closed. The includes list is shortened. 2111 * lineno, curFILE, and fname are changed if CONTINUE is returned. 2111 2112 *--------------------------------------------------------------------- 2112 2113 */ … … 2115 2116 int opened; 2116 2117 { 2117 IFile *ifile; 2118 IFile *ifile; /* the state on the top of the includes stack */ 2118 2119 2119 2120 if (Lst_IsEmpty (includes)) { 2120 2121 return (DONE); 2121 2122 } 2122 2123 … … 2126 2127 lineno = ifile->lineno; 2127 2128 if (opened && curFILE) 2128 2129 (void) fclose (curFILE); 2129 2130 if (curPTR) { 2130 2131 2131 efree((Address) curPTR->str); 2132 efree((Address) curPTR); 2132 2133 } 2133 2134 curFILE = ifile->F; … … 2140 2141 *--------------------------------------------------------------------- 2141 2142 * ParseReadc -- 2142 * 2143 * Read a character from the current file 2143 2144 * 2144 2145 * Results: 2145 * 2146 * The character that was read 2146 2147 * 2147 2148 * Side Effects: … … 2152 2153 { 2153 2154 if (curFILE) 2154 2155 return fgetc(curFILE); 2155 2156 2156 2157 if (curPTR && *curPTR->ptr) 2157 2158 return *curPTR->ptr++; 2158 2159 return EOF; 2159 2160 } … … 2163 2164 *--------------------------------------------------------------------- 2164 2165 * ParseUnreadc -- 2165 * 2166 * Put back a character to the current file 2166 2167 * 2167 2168 * Results: 2168 * 2169 * None. 2169 2170 * 2170 2171 * Side Effects: … … 2176 2177 { 2177 2178 if (curFILE) { 2178 2179 2179 ungetc(c, curFILE); 2180 return; 2180 2181 } 2181 2182 if (curPTR) { 2182 2183 2183 *--(curPTR->ptr) = c; 2184 return; 2184 2185 } 2185 2186 } … … 2187 2188 2188 2189 /* ParseSkipLine(): 2189 * 2190 * Grab the next line 2190 2191 */ 2191 2192 static char * 2192 2193 ParseSkipLine(skip) 2193 int skip; 2194 int skip; /* Skip lines that don't start with . */ 2194 2195 { 2195 2196 char *line; … … 2242 2243 *--------------------------------------------------------------------- 2243 2244 * ParseReadLine -- 2244 * 2245 * 2246 * 2247 * 2248 * 2249 * 2245 * Read an entire line from the input file. Called only by Parse_File. 2246 * To facilitate escaped newlines and what have you, a character is 2247 * buffered in 'lastc', which is '\0' when no characters have been 2248 * read. When we break out of the loop, c holds the terminating 2249 * character and lastc holds a character that should be added to 2250 * the line (unless we don't read anything but a terminator). 2250 2251 * 2251 2252 * Results: 2252 * 2253 * A line w/o its newline 2253 2254 * 2254 2255 * Side Effects: 2255 * 2256 * Only those associated with reading a character 2256 2257 *--------------------------------------------------------------------- 2257 2258 */ … … 2259 2260 ParseReadLine () 2260 2261 { 2261 Buffer buf;/* Buffer for current line */2262 register int c; 2263 register int lastc; 2264 Boolean semiNL;/* treat semi-colons as newlines */2265 Boolean ignDepOp;/* TRUE if should ignore dependency operators2266 2267 Boolean ignComment;/* TRUE if should ignore comments (in a2268 2269 char *line;/* Result */2270 char *ep; 2271 int lineLength;/* Length of result */2262 Buffer buf; /* Buffer for current line */ 2263 register int c; /* the current character */ 2264 register int lastc; /* The most-recent character */ 2265 Boolean semiNL; /* treat semi-colons as newlines */ 2266 Boolean ignDepOp; /* TRUE if should ignore dependency operators 2267 * for the purposes of setting semiNL */ 2268 Boolean ignComment; /* TRUE if should ignore comments (in a 2269 * shell command */ 2270 char *line; /* Result */ 2271 char *ep; /* to strip trailing blanks */ 2272 int lineLength; /* Length of result */ 2272 2273 2273 2274 semiNL = FALSE; … … 2287 2288 */ 2288 2289 for (;;) { 2289 2290 c = ParseReadc(); 2290 2291 #ifdef USE_INLINEFILES 2291 2292 if (inInlineFile) … … 2293 2294 #endif 2294 2295 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2296 if (c == '\t') { 2297 ignComment = ignDepOp = TRUE; 2298 break; 2299 } else if (c == '\n') { 2300 lineno++; 2301 } else if (c == '#') { 2302 ParseUnreadc(c); 2303 break; 2304 } else { 2305 /* 2306 * Anything else breaks out without doing anything 2307 */ 2308 break; 2309 } 2309 2310 } 2310 2311 2311 2312 if (c != EOF) { 2312 2313 2313 lastc = c; 2314 buf = Buf_Init(MAKE_BSIZE); 2314 2315 2315 2316 /* @todo any inline changes here? */ 2316 2317 #ifdef NMAKE 2317 2318 while (((c = ParseReadc ()) != '\n' || (lastc == '\\') || (lastc == '^')) && (c != EOF)) 2318 2319 #else 2319 2320 while (((c = ParseReadc ()) != '\n' || (lastc == '\\')) && (c != EOF)) 2320 2321 #endif 2321 2322 { 2322 2323 test_char: 2323 2324 2324 switch(c) { 2325 case '\n': 2325 2326 #ifdef USE_INLINEFILES 2326 2327 /* No newline escaping in inline files, unless it's a directive. */ … … 2336 2337 } 2337 2338 #endif 2338 2339 2339 2340 /* 2340 2341 2342 2343 2344 2345 2346 2347 2348 2341 * Escaped newline: read characters until a non-space or an 2342 * unescaped newline and replace them all by a single space. 2343 * This is done by storing the space over the backslash and 2344 * dropping through with the next nonspace. If it is a 2345 * semi-colon and semiNL is TRUE, it will be recognized as a 2346 * newline in the code below this... 2347 */ 2348 lineno++; 2349 lastc = ' '; 2349 2350 #ifdef NMAKE 2350 2351 if (lastc == '^') 2351 2352 lastc = '\n'; 2352 2353 2353 2354 do { 2354 2355 while ((c = ParseReadc ()) == ' ' || c == '\t') { 2355 2356 2356 continue; 2357 } 2357 2358 if (c != '#') 2358 2359 break; 2359 2360 /* comment - skip line */ 2360 2361 while ((c = ParseReadc ()) != '\n' && c != EOF) { 2361 2362 2362 continue; 2363 } 2363 2364 if (c == EOF) 2364 2365 break; 2365 2366 } while (1); 2366 2367 #else 2367 2368 2369 2370 #endif 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2368 while ((c = ParseReadc ()) == ' ' || c == '\t') { 2369 continue; 2370 } 2371 #endif 2372 if (c == EOF || c == '\n') { 2373 goto line_read; 2374 } else { 2375 /* 2376 * Check for comments, semiNL's, etc. -- easier than 2377 * ParseUnreadc(c); continue; 2378 */ 2379 goto test_char; 2380 } 2381 /*NOTREACHED*/ 2382 break; 2382 2383 2383 2384 /* We don't need this, and don't want it! */ 2384 2385 #ifndef KMK 2385 2386 case ';': 2386 2387 #ifdef USE_INLINEFILES 2387 2388 if (inInlineFile) 2388 2389 break; 2389 2390 #endif 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2391 /* 2392 * Semi-colon: Need to see if it should be interpreted as a 2393 * newline 2394 */ 2395 if (semiNL) { 2396 /* 2397 * To make sure the command that may be following this 2398 * semi-colon begins with a tab, we push one back into the 2399 * input stream. This will overwrite the semi-colon in the 2400 * buffer. If there is no command following, this does no 2401 * harm, since the newline remains in the buffer and the 2402 * whole line is ignored. 2403 */ 2404 ParseUnreadc('\t'); 2405 goto line_read; 2406 } 2407 break; 2408 case '=': 2408 2409 #ifdef USE_INLINEFILES 2409 2410 if (inInlineFile) … … 2411 2412 #endif 2412 2413 if (!semiNL) { 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2414 /* 2415 * Haven't seen a dependency operator before this, so this 2416 * must be a variable assignment -- don't pay attention to 2417 * dependency operators after this. 2418 */ 2419 ignDepOp = TRUE; 2420 } else if (lastc == ':' || lastc == '!') { 2421 /* 2422 * Well, we've seen a dependency operator already, but it 2423 * was the previous character, so this is really just an 2424 * expanded variable assignment. Revert semi-colons to 2425 * being just semi-colons again and ignore any more 2426 * dependency operators. 2427 * 2428 * XXX: Note that a line like "foo : a:=b" will blow up, 2429 * but who'd write a line like that anyway? 2430 */ 2431 ignDepOp = TRUE; semiNL = FALSE; 2432 } 2433 break; 2434 case '#': 2435 if (!ignComment) { 2436 if ( 2436 2437 #if 0 2437 2438 #endif 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2438 compatMake && 2439 #endif 2440 (lastc != '\\')) { 2441 /* 2442 * If the character is a hash mark and it isn't escaped 2443 * (or we're being compatible), the thing is a comment. 2444 * Skip to the end of the line. 2445 */ 2446 do { 2447 c = ParseReadc(); 2448 } while ((c != '\n') && (c != EOF)); 2449 goto line_read; 2450 } else { 2451 /* 2452 * Don't add the backslash. Just let the # get copied 2453 * over. 2454 */ 2455 lastc = c; 2456 continue; 2457 } 2458 } 2459 break; 2460 case ':': 2461 case '!': 2461 2462 #ifdef USE_INLINEFILES 2462 2463 if (inInlineFile) 2463 2464 break; 2464 2465 #endif 2465 2466 2467 2468 2469 2470 2471 2472 2473 2466 if (!ignDepOp && (c == ':' || c == '!')) { 2467 /* 2468 * A semi-colon is recognized as a newline only on 2469 * dependency lines. Dependency lines are lines with a 2470 * colon or an exclamation point. Ergo... 2471 */ 2472 semiNL = TRUE; 2473 } 2474 break; 2474 2475 #endif /* !KMK */ 2475 2476 2477 2478 2479 2480 2481 2482 2476 } 2477 /* 2478 * Copy in the previous character and save this one in lastc. 2479 */ 2480 Buf_AddByte (buf, (Byte)lastc); 2481 lastc = c; 2482 2483 } 2483 2484 line_read: 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2485 lineno++; 2486 2487 if (lastc != '\0') { 2488 Buf_AddByte (buf, (Byte)lastc); 2489 } 2490 Buf_AddByte (buf, (Byte)'\0'); 2491 line = (char *)Buf_GetAll (buf, &lineLength); 2492 Buf_Destroy (buf, FALSE); 2493 2494 /* 2495 * Strip trailing blanks and tabs from the line. 2496 * Do not strip a blank or tab that is preceeded by 2497 * a '\' 2498 */ 2498 2499 #ifdef USE_INLINEFILES 2499 2500 if (!inInlineFile) { 2500 2501 #endif 2501 2502 2503 2504 2505 2506 2507 2508 2509 2502 ep = line; 2503 while (*ep) 2504 ++ep; 2505 while (ep > line + 1 && (ep[-1] == ' ' || ep[-1] == '\t')) { 2506 if (ep > line + 1 && ep[-2] == '\\') 2507 break; 2508 --ep; 2509 } 2510 *ep = 0; 2510 2511 #ifdef USE_INLINEFILES 2511 2512 } … … 2513 2514 2514 2515 #ifdef NMAKE 2515 2516 if (line[0] == '.' || line[0] == '!') { 2516 2517 #else 2517 2518 #endif 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2518 if (line[0] == '.') { 2519 #endif 2520 /* 2521 * The line might be a conditional. Ask the conditional module 2522 * about it and act accordingly 2523 */ 2524 switch (Cond_Eval (line)) { 2525 case COND_SKIP: 2526 /* 2527 * Skip to next conditional that evaluates to COND_PARSE. 2528 */ 2529 do { 2530 efree (line); 2531 line = ParseSkipLine(1); 2532 } while (line && Cond_Eval(line) != COND_PARSE); 2533 if (line == NULL) 2534 break; 2535 /*FALLTHRU*/ 2536 case COND_PARSE: 2537 efree ((Address) line); 2538 line = ParseReadLine(); 2539 break; 2540 case COND_INVALID: 2541 if (For_Eval(line)) { 2542 int ok; 2543 efree(line); 2544 do { 2545 /* 2546 * Skip after the matching end 2547 */ 2548 line = ParseSkipLine(0); 2549 if (line == NULL) { 2550 Parse_Error (PARSE_FATAL, 2551 "Unexpected end of file in for loop.\n"); 2552 break; 2553 } 2554 ok = For_Eval(line); 2555 efree(line); 2556 } 2557 while (ok); 2558 if (line != NULL) 2559 For_Run(); 2560 line = ParseReadLine(); 2561 } 2562 break; 2563 } 2564 } 2565 return (line); 2565 2566 2566 2567 } else { 2567 2568 2569 2570 2568 /* 2569 * Hit end-of-file, so return a NULL line to indicate this. 2570 */ 2571 return((char *)NULL); 2571 2572 } 2572 2573 } … … 2575 2576 *----------------------------------------------------------------------- 2576 2577 * ParseFinishLine -- 2577 * 2578 * Handle the end of a dependency group. 2578 2579 * 2579 2580 * Results: 2580 * 2581 * Nothing. 2581 2582 * 2582 2583 * Side Effects: 2583 * 2584 * inLine set FALSE. 'targets' list destroyed. 2584 2585 * 2585 2586 *----------------------------------------------------------------------- … … 2589 2590 { 2590 2591 if (inLine) { 2591 2592 2593 2594 2592 Lst_ForEach(targets, Suff_EndTransform, (ClientData)NULL); 2593 Lst_Destroy (targets, ParseHasCommands); 2594 targets = NULL; 2595 inLine = FALSE; 2595 2596 } 2596 2597 } … … 2600 2601 *--------------------------------------------------------------------- 2601 2602 * Parse_File -- 2602 * 2603 * 2604 * 2603 * Parse a file into its component parts, incorporating it into the 2604 * current dependency graph. This is the main function and controls 2605 * almost every other function in this module 2605 2606 * 2606 2607 * Results: 2607 * 2608 * None 2608 2609 * 2609 2610 * Side Effects: 2610 * 2611 * 2611 * Loads. Nodes are added to the list of all targets, nodes and links 2612 * are added to the dependency graph. etc. etc. etc. 2612 2613 *--------------------------------------------------------------------- 2613 2614 */ 2614 2615 void 2615 2616 Parse_File(name, stream) 2616 char *name; 2617 FILE * stream;/* Stream open to makefile to parse */2618 { 2619 register char *cp, 2620 *line; 2617 char *name; /* the name of the file being read */ 2618 FILE * stream; /* Stream open to makefile to parse */ 2619 { 2620 register char *cp, /* pointer into the line */ 2621 *line; /* the line we're working on */ 2621 2622 2622 2623 inLine = FALSE; … … 2630 2631 2631 2632 do { 2632 2633 while ((line = ParseReadLine ()) != NULL) { 2633 2634 if (DEBUG(PARSE)) 2634 2635 printf("%s(%d): inLine=%d inInlineFile=%d\n%s\n", fname, lineno, inLine, inInlineFile, line); 2635 2636 #ifdef NMAKE 2636 2637 if (*line == '.' || *line == '!') { 2637 2638 #else 2638 2639 if (*line == '.') { 2639 2640 #endif 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 goto nextLine; 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2641 /* 2642 * Lines that begin with the special character are either 2643 * include or undef directives. 2644 */ 2645 for (cp = line + 1; isspace (*cp); cp++) { 2646 continue; 2647 } 2648 if (strncmp (cp, "include", 7) == 0) { 2649 ParseDoInclude (cp + 7, *line); 2650 goto nextLine; 2651 } else if (strncmp (cp, "error", 5) == 0) { 2652 ParseDoError(cp + 5); 2653 goto nextLine; 2654 } else if (strncmp(cp, "undef", 5) == 0) { 2655 char *cp2; 2656 for (cp += 5; isspace((unsigned char) *cp); cp++) { 2657 continue; 2658 } 2659 2660 for (cp2 = cp; !isspace((unsigned char) *cp2) && 2661 (*cp2 != '\0'); cp2++) { 2662 continue; 2663 } 2664 2665 *cp2 = '\0'; 2666 2667 Var_Delete(cp, VAR_GLOBAL); 2668 goto nextLine; 2669 } 2670 } 2670 2671 2671 2672 #ifdef USE_INLINEFILES … … 2705 2706 /*Lst_AtEnd(targCmds, (ClientData) line); */ 2706 2707 } 2707 2708 goto nextLine; 2708 2709 } 2709 2710 #endif 2710 2711 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2712 if (*line == '#') { 2713 /* If we're this far, the line must be a comment. */ 2714 goto nextLine; 2715 } 2716 2717 if (*line == '\t') { 2718 /* 2719 * If a line starts with a tab, it can only hope to be 2720 * a creation command. 2721 */ 2721 2722 #if !defined(POSIX) || defined(USE_NO_STUPID_TABS) 2722 2723 #endif 2724 2725 2726 2727 2728 2723 shellCommand: 2724 #endif 2725 for (cp = line + 1; isspace (*cp); cp++) { 2726 continue; 2727 } 2728 if (*cp) { 2729 if (inLine) { 2729 2730 #ifdef USE_INLINEFILES 2730 2731 if (ParseCmdIsComponent(cp, "<<")) … … 2736 2737 } 2737 2738 #endif 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2739 /* 2740 * So long as it's not a blank line and we're actually 2741 * in a dependency spec, add the command to the list of 2742 * commands of all targets in the dependency spec 2743 */ 2744 Lst_ForEach (targets, ParseAddCmd, cp); 2745 /*Lst_AtEnd(targCmds, (ClientData) line);*/ 2746 continue; 2747 } else { 2748 Parse_Error (PARSE_FATAL, 2749 "Unassociated shell command \"%s\"", 2750 cp); 2751 } 2752 } 2752 2753 #ifdef SYSVINCLUDE 2753 2754 2755 2756 2757 2758 2759 2760 2761 #endif 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2754 } else if (strncmp (line, "include", 7) == 0 && 2755 isspace((unsigned char) line[7]) && 2756 strchr(line, ':') == NULL) { 2757 /* 2758 * It's an S3/S5-style "include". 2759 */ 2760 ParseTraditionalInclude (line + 7); 2761 goto nextLine; 2762 #endif 2763 } else if (Parse_IsVar (line)) { 2764 ParseFinishLine(); 2765 Parse_DoVar (line, VAR_GLOBAL); 2766 } else { 2767 /* 2768 * We now know it's a dependency line so it needs to have all 2769 * variables expanded before being parsed. Tell the variable 2770 * module to complain if some variable is undefined... 2771 * To make life easier on novices, if the line is indented we 2772 * first make sure the line has a dependency operator in it. 2773 * If it doesn't have an operator and we're in a dependency 2774 * line's script, we assume it's actually a shell command 2775 * and add it to the current list of targets. 2776 */ 2776 2777 #if !defined(POSIX) || defined(USE_NO_STUPID_TABS) 2777 BooleannonSpace = FALSE;2778 #endif 2779 2780 2781 2782 2783 2784 2785 2786 2787 2778 Boolean nonSpace = FALSE; 2779 #endif 2780 2781 cp = line; 2782 if (isspace((unsigned char) line[0])) { 2783 while ((*cp != '\0') && isspace((unsigned char) *cp)) { 2784 cp++; 2785 } 2786 if (*cp == '\0') { 2787 goto nextLine; 2788 } 2788 2789 #if !defined(POSIX) || defined(USE_NO_STUPID_TABS) 2789 2790 2791 2792 2793 #endif 2794 2790 while ((*cp != ':') && (*cp != '!') && (*cp != '\0')) { 2791 nonSpace = TRUE; 2792 cp++; 2793 } 2794 #endif 2795 } 2795 2796 2796 2797 #if !defined(POSIX) || defined(USE_NO_STUPID_TABS) 2797 2798 2798 if (*cp == '\0') { 2799 if (inLine) { 2799 2800 #if !defined(USE_NO_STUPID_TABS) 2800 2801 2802 #endif 2803 2804 2805 2806 2807 2808 #endif 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2801 Parse_Error (PARSE_WARNING, 2802 "Shell command needs a leading tab"); 2803 #endif 2804 goto shellCommand; 2805 } else if (nonSpace) { 2806 Parse_Error (PARSE_FATAL, "Missing operator"); 2807 } 2808 } else { 2809 #endif 2810 ParseFinishLine(); 2811 2812 cp = Var_Subst (NULL, line, VAR_CMD, TRUE); 2813 efree (line); 2814 line = cp; 2815 2816 /* 2817 * Need a non-circular list for the target nodes 2818 */ 2819 if (targets) 2820 Lst_Destroy(targets, NOFREE); 2821 2822 targets = Lst_Init (FALSE); 2823 inLine = TRUE; 2824 2825 ParseDoDependency (line); 2825 2826 #if !defined(POSIX) || defined(USE_NO_STUPID_TABS) 2826 2827 #endif 2828 2829 2830 2831 2832 2833 2834 2835 2836 2827 } 2828 #endif 2829 } 2830 2831 nextLine: 2832 2833 efree (line); 2834 } 2835 /* 2836 * Reached EOF, but it may be just EOF of an include file... 2837 */ 2837 2838 } while (ParseEOF(1) == CONTINUE); 2838 2839 … … 2843 2844 2844 2845 if (fatals) 2845 2846 errx(1, "fatal errors encountered -- cannot continue"); 2846 2847 } 2847 2848 … … 2849 2850 *--------------------------------------------------------------------- 2850 2851 * Parse_Init -- 2851 * 2852 * initialize the parsing module 2852 2853 * 2853 2854 * Results: 2854 * 2855 * none 2855 2856 * 2856 2857 * Side Effects: 2857 * 2858 * the parseIncPath list is initialized... 2858 2859 *--------------------------------------------------------------------- 2859 2860 */ … … 2873 2874 /*Lst_Destroy(targCmds, (void (*) __P((ClientData))) efree);*/ 2874 2875 if (targets) 2875 2876 Lst_Destroy(targets, NOFREE); 2876 2877 Lst_Destroy(sysIncPath, Dir_Destroy); 2877 2878 Lst_Destroy(parseIncPath, Dir_Destroy); 2878 Lst_Destroy(includes, NOFREE); 2879 Lst_Destroy(includes, NOFREE); /* Should be empty now */ 2879 2880 } 2880 2881 … … 2883 2884 *----------------------------------------------------------------------- 2884 2885 * Parse_MainName -- 2885 * 2886 * 2886 * Return a Lst of the main target to create for main()'s sake. If 2887 * no such target exists, we Punt with an obnoxious error message. 2887 2888 * 2888 2889 * Results: 2889 * 2890 * A Lst of the single node to create. 2890 2891 * 2891 2892 * Side Effects: 2892 * 2893 * None. 2893 2894 * 2894 2895 *----------------------------------------------------------------------- … … 2897 2898 Parse_MainName() 2898 2899 { 2899 Lst listmain; 2900 Lst listmain; /* result list */ 2900 2901 2901 2902 listmain = Lst_Init (FALSE); 2902 2903 2903 2904 if (mainNode == NILGNODE) { 2904 2905 2905 Punt ("no target to make."); 2906 /*NOTREACHED*/ 2906 2907 } else if (mainNode->type & OP_DOUBLEDEP) { 2907 2908 2908 (void) Lst_AtEnd (listmain, (ClientData)mainNode); 2909 Lst_Concat(listmain, mainNode->cohorts, LST_CONCNEW); 2909 2910 } 2910 2911 else 2911 2912 (void) Lst_AtEnd (listmain, (ClientData)mainNode); 2912 2913 return (listmain); 2913 2914 }
Note:
See TracChangeset
for help on using the changeset viewer.