source: trunk/src/kmk/parse.c@ 45

Last change on this file since 45 was 45, checked in by bird, 22 years ago

KMK changes..

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