VirtualBox

source: kBuild/trunk/src/kmk/parse.c@ 64

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

kMk and porting to kLib.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 91.5 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#define KLIBFILEDEF rcsid
47#endif /* not lint */
48
49/*-
50 * parse.c --
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.
66 *
67 * Interface:
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__
92#include <stdarg.h>
93#else
94#include <varargs.h>
95#endif
96#include <ctype.h>
97#include <err.h>
98#include <stdio.h>
99#include "make.h"
100#include "hash.h"
101#include "dir.h"
102#include "job.h"
103#include "buf.h"
104#include "pathnames.h"
105
106
107/*
108 * These values are returned by ParseEOF to tell Parse_File whether to
109 * CONTINUE parsing, i.e. it had only reached the end of an include file,
110 * or if it's DONE.
111 */
112#define CONTINUE 1
113#define DONE 0
114static Lst targets; /* targets we're working on */
115/*static Lst targCmds; */ /* command lines for targets */
116static Boolean inLine; /* true if currently in a dependency
117 * line or its commands */
118#if defined(USE_INLINEFILES)
119static Boolean inInlineFile; /* true if currently in a inline file.*/
120#endif
121typedef struct {
122 char *str;
123 char *ptr;
124} PTR;
125
126static char *fname; /* name of current file (for errors) */
127static int lineno; /* line number in current file */
128static FILE *curFILE = NULL; /* current makefile */
129
130static PTR *curPTR = NULL; /* current makefile */
131
132static int fatals = 0;
133
134static GNode *mainNode; /* The main target to create. This is the
135 * first target on the first dependency
136 * line in the first makefile */
137/*
138 * Definitions for handling #include specifications
139 */
140typedef struct IFile {
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 */
145} IFile;
146
147static Lst includes; /* stack of IFiles generated by
148 * #includes */
149Lst parseIncPath; /* list of directories for "..." includes */
150Lst sysIncPath; /* list of directories for <...> includes */
151
152/*-
153 * specType contains the SPECial TYPE of the current target. It is
154 * Not if the target is unspecial. If it *is* special, however, the children
155 * are linked as children of the parent but not vice versa. This variable is
156 * set in ParseDoDependency
157 */
158typedef enum {
159 Begin, /* .BEGIN */
160 Default, /* .DEFAULT */
161 End, /* .END */
162 Ignore, /* .IGNORE */
163 Includes, /* .INCLUDES */
164 Interrupt, /* .INTERRUPT */
165#ifdef USE_ARCHIVES
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 */
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#ifdef USE_ARCHIVES
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 },
237#ifdef POSIX
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 },
248};
249
250static int ParseFindKeyword __P((char *));
251static int ParseLinkSrc __P((ClientData, ClientData));
252static int ParseDoOp __P((ClientData, ClientData));
253static int ParseAddDep __P((ClientData, ClientData));
254static void ParseDoSrc __P((int, char *, Lst));
255static int ParseFindMain __P((ClientData, ClientData));
256static int ParseAddDir __P((ClientData, ClientData));
257static int ParseClearPath __P((ClientData, ClientData));
258static void ParseDoDependency __P((char *));
259static int ParseAddCmd __P((ClientData, ClientData));
260#ifdef USE_INLINEFILES
261static int ParseAppendInline __P((ClientData, ClientData));
262static Boolean ParseCmdIsComponent __P((const char *, const char *));
263#endif
264static int ParseReadc __P((void));
265static void ParseUnreadc __P((int));
266static void ParseHasCommands __P((ClientData));
267static void ParseDoInclude __P((char *, char));
268static void ParseDoError __P((char *));
269#ifdef SYSVINCLUDE
270static void ParseTraditionalInclude __P((char *));
271#endif
272static int ParseEOF __P((int));
273static char *ParseReadLine __P((void));
274static char *ParseSkipLine __P((int));
275static void ParseFinishLine __P((void));
276
277/*-
278 *----------------------------------------------------------------------
279 * ParseFindKeyword --
280 * Look in the table of keywords for one matching the given string.
281 *
282 * Results:
283 * The index of the keyword, or -1 if it isn't there.
284 *
285 * Side Effects:
286 * None
287 *----------------------------------------------------------------------
288 */
289static int
290ParseFindKeyword (str)
291 char *str; /* String to find */
292{
293 register int start,
294 end,
295 cur;
296 register int diff;
297
298 start = 0;
299 end = (sizeof(parseKeywords)/sizeof(parseKeywords[0])) - 1;
300
301 do {
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 }
312 } while (start <= end);
313 return (-1);
314}
315
316/*-
317 * Parse_Error --
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.
321 *
322 * Results:
323 * None
324 *
325 * Side Effects:
326 * "fatals" is incremented if the level is PARSE_FATAL.
327 */
328/* VARARGS */
329void
330#if defined(__STDC__) || defined(__IBMC__)
331Parse_Error(int type, char *fmt, ...)
332#else
333Parse_Error(va_alist)
334 va_dcl
335#endif
336{
337 va_list ap;
338#if defined(__STDC__) || defined(__IBMC__)
339 va_start(ap, fmt);
340#else
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;
358}
359
360/*-
361 *---------------------------------------------------------------------
362 * ParseLinkSrc --
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.
366 *
367 * Results:
368 * Always = 0
369 *
370 * Side Effects:
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.
374 *---------------------------------------------------------------------
375 */
376static int
377ParseLinkSrc (pgnp, cgnp)
378 ClientData pgnp; /* The parent node */
379 ClientData cgnp; /* The child node */
380{
381 GNode *pgn = (GNode *) pgnp;
382 GNode *cgn = (GNode *) cgnp;
383 if (Lst_Member (pgn->children, (ClientData)cgn) == NILLNODE) {
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;
389 }
390 return (0);
391}
392
393/*-
394 *---------------------------------------------------------------------
395 * ParseDoOp --
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.
400 *
401 * Results:
402 * Always 0
403 *
404 * Side Effects:
405 * The type field of the node is altered to reflect any new bits in
406 * the op.
407 *---------------------------------------------------------------------
408 */
409static int
410ParseDoOp (gnp, opp)
411 ClientData gnp; /* The node to which the operator is to be
412 * applied */
413 ClientData opp; /* The operator to apply */
414{
415 GNode *gn = (GNode *) gnp;
416 int op = *(int *) opp;
417 /*
418 * If the dependency mask of the operator and the node don't match and
419 * the node has actually had an operator applied to it before, and
420 * the operator actually has some dependency information in it, complain.
421 */
422 if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) &&
423 !OP_NOP(gn->type) && !OP_NOP(op))
424 {
425 Parse_Error (PARSE_FATAL, "Inconsistent operator for %s", gn->name);
426 return (1);
427 }
428
429 if ((op == OP_DOUBLEDEP) && ((gn->type & OP_OPMASK) == OP_DOUBLEDEP)) {
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;
461 }
462 /*
463 * We don't want to nuke any previous flags (whatever they were) so we
464 * just OR the new operator into the old
465 */
466 gn->type |= op;
467
468 return (0);
469}
470
471/*-
472 *---------------------------------------------------------------------
473 * ParseAddDep --
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.
477 *
478 * Results:
479 * Returns 1 if the two targets need to be ordered, 0 otherwise.
480 * If it returns 1, the search can stop
481 *
482 * Side Effects:
483 * A dependency can be added between the two nodes.
484 *
485 *---------------------------------------------------------------------
486 */
487static int
488ParseAddDep(pp, sp)
489 ClientData pp;
490 ClientData sp;
491{
492 GNode *p = (GNode *) pp;
493 GNode *s = (GNode *) sp;
494
495 if (p->order < s->order) {
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;
504 }
505 else
506 return 1;
507}
508
509
510/*-
511 *---------------------------------------------------------------------
512 * ParseDoSrc --
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'
518 *
519 * Results:
520 * None
521 *
522 * Side Effects:
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.
525 *---------------------------------------------------------------------
526 */
527static void
528ParseDoSrc (tOp, src, allsrc)
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;
534
535 if (*src == '.' && isupper (src[1])) {
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 }
548 }
549
550 switch (specType) {
551 case Main:
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;
567
568 case Order:
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;
583
584 default:
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;
616 }
617
618 gn->order = waiting;
619 (void)Lst_AtEnd(allsrc, (ClientData)gn);
620 if (waiting) {
621 Lst_ForEach(allsrc, ParseAddDep, (ClientData)gn);
622 }
623}
624
625/*-
626 *-----------------------------------------------------------------------
627 * ParseFindMain --
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.
631 *
632 * Results:
633 * 0 if main not found yet, 1 if it is.
634 *
635 * Side Effects:
636 * mainNode is changed and Targ_SetMain is called.
637 *
638 *-----------------------------------------------------------------------
639 */
640static int
641ParseFindMain(gnp, dummy)
642 ClientData gnp; /* Node to examine */
643 ClientData dummy;
644{
645 GNode *gn = (GNode *) gnp;
646 if ((gn->type & (OP_NOTMAIN|OP_USE|OP_EXEC|OP_TRANSFORM)) == 0) {
647 mainNode = gn;
648 Targ_SetMain(gn);
649 return (dummy ? 1 : 1);
650 } else {
651 return (dummy ? 0 : 0);
652 }
653}
654
655/*-
656 *-----------------------------------------------------------------------
657 * ParseAddDir --
658 * Front-end for Dir_AddDir to make sure Lst_ForEach keeps going
659 *
660 * Results:
661 * === 0
662 *
663 * Side Effects:
664 * See Dir_AddDir.
665 *
666 *-----------------------------------------------------------------------
667 */
668static int
669ParseAddDir(path, name)
670 ClientData path;
671 ClientData name;
672{
673 Dir_AddDir((Lst) path, (char *) name);
674 return(0);
675}
676
677/*-
678 *-----------------------------------------------------------------------
679 * ParseClearPath --
680 * Front-end for Dir_ClearPath to make sure Lst_ForEach keeps going
681 *
682 * Results:
683 * === 0
684 *
685 * Side Effects:
686 * See Dir_ClearPath
687 *
688 *-----------------------------------------------------------------------
689 */
690static int
691ParseClearPath(path, dummy)
692 ClientData path;
693 ClientData dummy;
694{
695 Dir_ClearPath((Lst) path);
696 return(dummy ? 0 : 0);
697}
698
699/*-
700 *---------------------------------------------------------------------
701 * ParseDoDependency --
702 * Parse the dependency line in line.
703 *
704 * Results:
705 * None
706 *
707 * Side Effects:
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
712 * finding nodes in the list of all targets with that name. This is done
713 * until a character is encountered which is an operator character. Currently
714 * these are only ! and :. At this point the operator is parsed and the
715 * pointer into the line advanced until the first source is encountered.
716 * The parsed operator is applied to each node in the 'targets' list,
717 * which is where the nodes found for the targets are kept, by means of
718 * the ParseDoOp function.
719 * The sources are read in much the same way as the targets were except
720 * that now they are expanded using the wildcarding scheme of the C-Shell
721 * and all instances of the resulting words in the list of all targets
722 * are found. Each of the resulting nodes is then linked to each of the
723 * targets as one of its children.
724 * Certain targets are handled specially. These are the ones detailed
725 * by the specType variable.
726 * The storing of transformation rules is also taken care of here.
727 * A target is recognized as a transformation rule by calling
728 * Suff_IsTransform. If it is a transformation rule, its node is gotten
729 * from the suffix module via Suff_AddTransform rather than the standard
730 * Targ_FindNode in the target module.
731 *---------------------------------------------------------------------
732 */
733static void
734ParseDoDependency (line)
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 */
744#ifdef USE_ARCHIVES
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 */
751
752 tOp = 0;
753
754 specType = Not;
755 waiting = 0;
756 paths = (Lst)NULL;
757
758 curTargs = Lst_Init(FALSE);
759 curSrcs = Lst_Init(FALSE);
760
761 do {
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 == '(') {
789#ifdef USE_ARCHIVES
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;
806#else
807 Parse_Error(PARSE_FATAL, "Archives are not supported!", line);
808 return;
809#endif /* USE_ARCHIVES */
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;
997 } while ((*line != '!') && (*line != ':') && *line);
998
999 /*
1000 * Don't need the list of target names anymore...
1001 */
1002 Lst_Destroy(curTargs, NOFREE);
1003
1004 if (!Lst_IsEmpty(targets)) {
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 }
1023 }
1024
1025 /*
1026 * Have now parsed all the target names. Must parse the operator next. The
1027 * result is left in op .
1028 */
1029 if (*cp == '!') {
1030 op = OP_FORCE;
1031 } else if (*cp == ':') {
1032 if (cp[1] == ':') {
1033 op = OP_DOUBLEDEP;
1034 cp++;
1035 } else {
1036 op = OP_DEPENDS;
1037 }
1038 } else {
1039 Parse_Error (PARSE_FATAL, "Missing dependency operator");
1040 return;
1041 }
1042
1043 cp++; /* Advance beyond operator */
1044
1045 Lst_ForEach (targets, ParseDoOp, (ClientData)&op);
1046
1047 /*
1048 * Get to the first source
1049 */
1050 while (*cp && isspace (*cp)) {
1051 cp++;
1052 }
1053 line = cp;
1054
1055 /*
1056 * Several special targets take different actions if present with no
1057 * sources:
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).
1063 */
1064 if (!*line) {
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;
1081#ifdef POSIX
1082 case Posix:
1083 Var_Set("%POSIX", "1003.2", VAR_GLOBAL);
1084 break;
1085#endif
1086 default:
1087 break;
1088 }
1089 } else if (specType == MFlags) {
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';
1097 } else if (specType == ExShell) {
1098 #ifdef KMK
1099 Parse_Error(PARSE_FATAL, "shell specification not supported by kMk!");
1100 return;
1101 #else
1102 if (Job_ParseShell (line) != SUCCESS) {
1103 Parse_Error (PARSE_FATAL, "improper shell specification");
1104 return;
1105 }
1106 #endif
1107 *line = '\0';
1108 } else if ((specType == NotParallel) || (specType == SingleShell)) {
1109 *line = '\0';
1110 }
1111
1112 /*
1113 * NOW GO FOR THE SOURCES
1114 */
1115 if ((specType == Suffixes) || (specType == ExPath) ||
1116 (specType == Includes) ||
1117#ifdef USE_ARCHIVES
1118 (specType == Libs) ||
1119#endif
1120 (specType == Null))
1121 {
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;
1163#ifdef USE_ARCHIVES
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 }
1186 } else {
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 == '(') {
1208#ifdef USE_ARCHIVES
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;
1224#else
1225 Parse_Error(PARSE_FATAL, "Archives are not supported!", line);
1226 return;
1227#endif /* USE_ARCHIVES */
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 }
1241 }
1242
1243 if (mainNode == NILGNODE) {
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);
1251 }
1252
1253 /*
1254 * Finally, destroy the list of sources
1255 */
1256 Lst_Destroy(curSrcs, NOFREE);
1257}
1258
1259/*-
1260 *---------------------------------------------------------------------
1261 * Parse_IsVar --
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.
1267 *
1268 * Results:
1269 * TRUE if it is. FALSE if it ain't
1270 *
1271 * Side Effects:
1272 * none
1273 *---------------------------------------------------------------------
1274 */
1275Boolean
1276Parse_IsVar (line)
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 */
1281 int level = 0;
1282#define ISEQOPERATOR(c) \
1283 (((c) == '+') || ((c) == ':') || ((c) == '?') || ((c) == '!'))
1284
1285 /*
1286 * Skip to variable name
1287 */
1288 for (;(*line == ' ') || (*line == '\t'); line++)
1289 continue;
1290
1291 for (; *line != '=' || level != 0; line++)
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;
1334#ifdef SUNSHCMD
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 }
1353
1354 return haveName;
1355}
1356
1357/*-
1358 *---------------------------------------------------------------------
1359 * Parse_DoVar --
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++ =".
1368 *
1369 * Results:
1370 * none
1371 *
1372 * Side Effects:
1373 * the variable structure of the given variable name is altered in the
1374 * global context.
1375 *---------------------------------------------------------------------
1376 */
1377void
1378Parse_DoVar (line, ctxt)
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 */
1384 enum {
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 */
1389 /*
1390 * Avoid clobbered variable warnings by forcing the compiler
1391 * to ``unregister'' variables
1392 */
1393#if __GNUC__
1394 (void) &cp;
1395 (void) &line;
1396#endif
1397
1398 /*
1399 * Skip to variable name
1400 */
1401 while ((*line == ' ') || (*line == '\t')) {
1402 line++;
1403 }
1404
1405 /*
1406 * Skip to operator character, nulling out whitespace as we go
1407 */
1408 for (cp = line + 1; *cp != '='; cp++) {
1409 if (isspace (*cp)) {
1410 *cp = '\0';
1411 }
1412 }
1413 opc = cp-1; /* operator is the previous character */
1414 *cp++ = '\0'; /* nuke the = */
1415
1416 /*
1417 * Check operator type
1418 */
1419 switch (*opc) {
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:
1448#ifdef SUNSHCMD
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;
1463 }
1464
1465 while (isspace (*cp)) {
1466 cp++;
1467 }
1468
1469 if (type == VAR_APPEND) {
1470 Var_Append (line, cp, ctxt);
1471 } else if (type == VAR_SUBST) {
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);
1491 } else if (type == VAR_SHELL) {
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);
1515 } else {
1516 /*
1517 * Normal assignment -- just do it.
1518 */
1519 Var_Set(line, cp, ctxt);
1520 }
1521}
1522
1523
1524/*-
1525 * ParseAddCmd --
1526 * Lst_ForEach function to add a command line to all targets
1527 *
1528 * Results:
1529 * Always 0
1530 *
1531 * Side Effects:
1532 * A new element is added to the commands list of the node.
1533 */
1534static int
1535ParseAddCmd(gnp, cmd)
1536 ClientData gnp; /* the node to which the command is to be added */
1537 ClientData cmd; /* the command to add */
1538{
1539 GNode *gn = (GNode *) gnp;
1540 /* if target already supplied, ignore commands */
1541 if (!(gn->type & OP_HAS_COMMANDS))
1542 (void)Lst_AtEnd(gn->commands, cmd);
1543 return(0);
1544}
1545
1546
1547
1548#ifdef USE_INLINEFILES
1549/*-
1550 * ParseAppendInline --
1551 * Lst_ForEach function to append the line to the last command
1552 *
1553 * Results:
1554 * Always 0
1555 *
1556 * Side Effects:
1557 * A new element is added to the last commands list of the node.
1558 */
1559static int
1560ParseAppendInline(gnp, line)
1561 ClientData gnp; /* the node to which the command is to be added */
1562 ClientData line; /* the command to add */
1563{
1564 GNode *gn = (GNode *)gnp;
1565 /* if target already supplied, ignore commands */
1566 if (!(gn->type & OP_HAS_COMMANDS))
1567 {
1568 unsigned cch;
1569 char * cmd;
1570 unsigned cchNew;
1571 cmd = (char*)Lst_Datum(Lst_Last(gn->commands));
1572 cch = strlen(cmd);
1573 cchNew = strlen(line);
1574 cmd = erealloc(cmd, cch + 1 + cchNew + 1);
1575 cmd[cch] = '\n';
1576 memcpy(&cmd[cch + 1], line, cchNew + 1);
1577 Lst_Replace(Lst_Last(gn->commands), cmd);
1578 }
1579 return(0);
1580}
1581
1582/*-
1583 *-----------------------------------------------------------------------
1584 * ParseCmdIsComponent --
1585 * Checks if the comp is a component in the cmdline.
1586 *
1587 * Results:
1588 * returns TRUE if it is, FALSE if not.
1589 *
1590 * Side Effects:
1591 * OP_HAS_COMMANDS may be set for the target.
1592 *
1593 *-----------------------------------------------------------------------
1594 */
1595static Boolean
1596ParseCmdIsComponent(cmdline, comp)
1597 const char *cmdline;
1598 const char *comp;
1599{
1600#if 0 /* @todo FIX THIS */
1601 const char * psz;
1602 char chQuote;
1603 int cchComp;
1604 register char ch;
1605
1606 /** ASSUMES NOT ESCAPED (but then the shell doesn't support escaping anyway) */
1607 if (!strstr(cmdline, comp))
1608 return FALSE;
1609
1610 cchComp = strlen(comp);
1611 for (chQuote = '\0', ch = *cmdline, psz = NULL; ch; ch = *++cmdline)
1612 {
1613 if (ch == '\'' || ch == '\"')
1614 {
1615 if (chQuote)
1616 { /* end of story */
1617 if (cmdline - psz == cchComp && !strncmp(psz, comp, cchComp))
1618 return TRUE;
1619 chQuote = '\0';
1620 psz = NULL;
1621 }
1622 else
1623 {
1624 chQuote = ch;
1625 if (!psz)
1626 psz = cmdline + 1;
1627 }
1628 } else if (!chQuote && !psz && !isspace(ch))
1629 psz = cmdline;
1630 }
1631
1632 return FALSE;
1633
1634#else
1635 return strstr(cmdline, comp) != NULL;
1636
1637#endif
1638}
1639#endif
1640
1641/*-
1642 *-----------------------------------------------------------------------
1643 * ParseHasCommands --
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.
1648 *
1649 * Results:
1650 * None
1651 *
1652 * Side Effects:
1653 * OP_HAS_COMMANDS may be set for the target.
1654 *
1655 *-----------------------------------------------------------------------
1656 */
1657static void
1658ParseHasCommands(gnp)
1659 ClientData gnp; /* Node to examine */
1660{
1661 GNode *gn = (GNode *) gnp;
1662 if (!Lst_IsEmpty(gn->commands)) {
1663 gn->type |= OP_HAS_COMMANDS;
1664 }
1665}
1666
1667/*-
1668 *-----------------------------------------------------------------------
1669 * Parse_AddIncludeDir --
1670 * Add a directory to the path searched for included makefiles
1671 * bracketed by double-quotes. Used by functions in main.c
1672 *
1673 * Results:
1674 * None.
1675 *
1676 * Side Effects:
1677 * The directory is appended to the list.
1678 *
1679 *-----------------------------------------------------------------------
1680 */
1681void
1682Parse_AddIncludeDir (dir)
1683 char *dir; /* The name of the directory to add */
1684{
1685 Dir_AddDir (parseIncPath, dir);
1686}
1687
1688/*---------------------------------------------------------------------
1689 * ParseDoError --
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.
1695 *
1696 *---------------------------------------------------------------------
1697 */
1698static void
1699ParseDoError(errmsg)
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);
1715}
1716
1717/*-
1718 *---------------------------------------------------------------------
1719 * ParseDoInclude --
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
1726 *
1727 * Results:
1728 * None
1729 *
1730 * Side Effects:
1731 * A structure is added to the includes Lst and readProc, lineno,
1732 * fname and curFILE are altered for the new file
1733 *---------------------------------------------------------------------
1734 */
1735static void
1736ParseDoInclude (file, chPre)
1737 char *file; /* file specification */
1738 char chPre; /* Preprocessor char */
1739{
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 */
1745
1746 /*
1747 * Skip to delimiter character so we know where to look
1748 */
1749 while ((*file == ' ') || (*file == '\t')) {
1750 file++;
1751 }
1752
1753 #ifndef NMAKE
1754 if ((*file != '"') && (*file != '<')) {
1755 Parse_Error (PARSE_FATAL,
1756 "%cinclude filename must be delimited by '\"' or '<'", chPre);
1757 return;
1758 }
1759 #endif
1760
1761 /*
1762 * Set the search path on which to find the include file based on the
1763 * characters which bracket its name. Angle-brackets imply it's
1764 * a system Makefile while double-quotes imply it's a user makefile
1765 */
1766 if (*file == '<') {
1767 isSystem = TRUE;
1768 endc = '>';
1769 } else {
1770 isSystem = FALSE;
1771 #ifdef NMAKE
1772 if (*file == '"')
1773 endc = '"';
1774 else
1775 {
1776 endc = '\0';
1777 file--;
1778 }
1779 #else
1780 endc = '"';
1781 #endif
1782 }
1783
1784 /*
1785 * Skip to matching delimiter
1786 */
1787 for (cp = ++file; *cp && *cp != endc; cp++) {
1788 continue;
1789 }
1790
1791 #ifdef NMAKE
1792 if (endc && *cp != endc) {
1793 #else
1794 if (*cp != endc) {
1795 #endif
1796 Parse_Error (PARSE_FATAL,
1797 "Unclosed %cinclude filename. '%c' expected",
1798 chPre, endc);
1799 return;
1800 }
1801 *cp = '\0';
1802
1803 /*
1804 * Substitute for any variables in the file name before trying to
1805 * find the thing.
1806 */
1807 file = Var_Subst (NULL, file, VAR_CMD, FALSE);
1808
1809 /*
1810 * Now we know the file's name and its search path, we attempt to
1811 * find the durn thing. A return of NULL indicates the file don't
1812 * exist.
1813 */
1814 if (!isSystem) {
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);
1846 } else {
1847 fullname = (char *)NULL;
1848 }
1849
1850 if (fullname == (char *)NULL) {
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 }
1861 }
1862
1863 if (fullname == (char *)NULL) {
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);
1869 }
1870
1871 if (fullname == (char *) NULL) {
1872 *cp = endc;
1873 Parse_Error (PARSE_FATAL, "Could not find '%s'", file);
1874 return;
1875 }
1876
1877 efree(file);
1878
1879 /*
1880 * Once we find the absolute path to the file, we get to save all the
1881 * state from the current file before we can start reading this
1882 * include file. The state is stored in an IFile structure which
1883 * is placed on a list with other IFile structures. The list makes
1884 * a very nice stack to track how we got here...
1885 */
1886 oldFile = (IFile *) emalloc (sizeof (IFile));
1887 oldFile->fname = fname;
1888
1889 oldFile->F = curFILE;
1890 oldFile->p = curPTR;
1891 oldFile->lineno = lineno;
1892
1893 (void) Lst_AtFront (includes, (ClientData)oldFile);
1894
1895 /*
1896 * Once the previous state has been saved, we can get down to reading
1897 * the new file. We set up the name of the file to be the absolute
1898 * name of the include file so error messages refer to the right
1899 * place. Naturally enough, we start reading at line number 0.
1900 */
1901 fname = fullname;
1902 lineno = 0;
1903
1904 curFILE = fopen (fullname, "r");
1905 curPTR = NULL;
1906 if (curFILE == (FILE * ) NULL) {
1907 Parse_Error (PARSE_FATAL, "Cannot open %s", fullname);
1908 /*
1909 * Pop to previous file
1910 */
1911 (void) ParseEOF(0);
1912 }
1913}
1914
1915
1916
1917/*-
1918 *---------------------------------------------------------------------
1919 * Parse_FromString --
1920 * Start Parsing from the given string
1921 *
1922 * Results:
1923 * None
1924 *
1925 * Side Effects:
1926 * A structure is added to the includes Lst and readProc, lineno,
1927 * fname and curFILE are altered for the new file
1928 *---------------------------------------------------------------------
1929 */
1930void
1931Parse_FromString(str)
1932 char *str;
1933{
1934 IFile *oldFile; /* state associated with this file */
1935
1936 if (DEBUG(FOR))
1937 (void) fprintf(stderr, "%s\n----\n", str);
1938
1939 oldFile = (IFile *) emalloc (sizeof (IFile));
1940 oldFile->lineno = lineno;
1941 oldFile->fname = fname;
1942 oldFile->F = curFILE;
1943 oldFile->p = curPTR;
1944
1945 (void) Lst_AtFront (includes, (ClientData)oldFile);
1946
1947 curFILE = NULL;
1948 curPTR = (PTR *) emalloc (sizeof (PTR));
1949 curPTR->str = curPTR->ptr = str;
1950 lineno = 0;
1951 fname = estrdup(fname);
1952}
1953
1954
1955#ifdef SYSVINCLUDE
1956/*-
1957 *---------------------------------------------------------------------
1958 * ParseTraditionalInclude --
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".
1963 *
1964 * Results:
1965 * None
1966 *
1967 * Side Effects:
1968 * A structure is added to the includes Lst and readProc, lineno,
1969 * fname and curFILE are altered for the new file
1970 *---------------------------------------------------------------------
1971 */
1972static void
1973ParseTraditionalInclude (file)
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;
1980
1981 /*
1982 * Skip over whitespace
1983 */
1984 while ((*file == ' ') || (*file == '\t')) {
1985 file++;
1986 }
1987
1988 if (*file == '\0') {
1989 Parse_Error (PARSE_FATAL,
1990 "Filename missing from \"include\"");
1991 return;
1992 }
1993
1994 /*
1995 * Skip to end of line or next whitespace
1996 */
1997 for (cp = file; *cp && *cp != '\n' && *cp != '\t' && *cp != ' '; cp++) {
1998 continue;
1999 }
2000
2001 *cp = '\0';
2002
2003 /*
2004 * Substitute for any variables in the file name before trying to
2005 * find the thing.
2006 */
2007 file = Var_Subst (NULL, file, VAR_CMD, FALSE);
2008
2009 /*
2010 * Now we know the file's name, we attempt to find the durn thing.
2011 * A return of NULL indicates the file don't exist.
2012 *
2013 * Include files are first searched for relative to the including
2014 * file's location. We don't want to cd there, of course, so we
2015 * just tack on the old file's leading path components and call
2016 * Dir_FindFile to see if we can locate the beast.
2017 * XXX - this *does* search in the current directory, right?
2018 */
2019
2020 prefEnd = strrchr (fname, '/');
2021 if (prefEnd != (char *)NULL) {
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 = '/';
2032 } else {
2033 fullname = (char *)NULL;
2034 }
2035
2036 if (fullname == (char *)NULL) {
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 }
2047 }
2048
2049 if (fullname == (char *)NULL) {
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);
2055 }
2056
2057 if (fullname == (char *) NULL) {
2058 Parse_Error (PARSE_FATAL, "Could not find %s", file);
2059 return;
2060 }
2061
2062 /*
2063 * Once we find the absolute path to the file, we get to save all the
2064 * state from the current file before we can start reading this
2065 * include file. The state is stored in an IFile structure which
2066 * is placed on a list with other IFile structures. The list makes
2067 * a very nice stack to track how we got here...
2068 */
2069 oldFile = (IFile *) emalloc (sizeof (IFile));
2070 oldFile->fname = fname;
2071
2072 oldFile->F = curFILE;
2073 oldFile->p = curPTR;
2074 oldFile->lineno = lineno;
2075
2076 (void) Lst_AtFront (includes, (ClientData)oldFile);
2077
2078 /*
2079 * Once the previous state has been saved, we can get down to reading
2080 * the new file. We set up the name of the file to be the absolute
2081 * name of the include file so error messages refer to the right
2082 * place. Naturally enough, we start reading at line number 0.
2083 */
2084 fname = fullname;
2085 lineno = 0;
2086
2087 curFILE = fopen (fullname, "r");
2088 curPTR = NULL;
2089 if (curFILE == (FILE * ) NULL) {
2090 Parse_Error (PARSE_FATAL, "Cannot open %s", fullname);
2091 /*
2092 * Pop to previous file
2093 */
2094 (void) ParseEOF(1);
2095 }
2096}
2097#endif
2098
2099/*-
2100 *---------------------------------------------------------------------
2101 * ParseEOF --
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.
2105 *
2106 * Results:
2107 * CONTINUE if there's more to do. DONE if not.
2108 *
2109 * Side Effects:
2110 * The old curFILE, is closed. The includes list is shortened.
2111 * lineno, curFILE, and fname are changed if CONTINUE is returned.
2112 *---------------------------------------------------------------------
2113 */
2114static int
2115ParseEOF (opened)
2116 int opened;
2117{
2118 IFile *ifile; /* the state on the top of the includes stack */
2119
2120 if (Lst_IsEmpty (includes)) {
2121 return (DONE);
2122 }
2123
2124 ifile = (IFile *) Lst_DeQueue (includes);
2125 efree ((Address) fname);
2126 fname = ifile->fname;
2127 lineno = ifile->lineno;
2128 if (opened && curFILE)
2129 (void) fclose (curFILE);
2130 if (curPTR) {
2131 efree((Address) curPTR->str);
2132 efree((Address) curPTR);
2133 }
2134 curFILE = ifile->F;
2135 curPTR = ifile->p;
2136 efree ((Address)ifile);
2137 return (CONTINUE);
2138}
2139
2140/*-
2141 *---------------------------------------------------------------------
2142 * ParseReadc --
2143 * Read a character from the current file
2144 *
2145 * Results:
2146 * The character that was read
2147 *
2148 * Side Effects:
2149 *---------------------------------------------------------------------
2150 */
2151static int
2152ParseReadc()
2153{
2154 if (curFILE)
2155 return fgetc(curFILE);
2156
2157 if (curPTR && *curPTR->ptr)
2158 return *curPTR->ptr++;
2159 return EOF;
2160}
2161
2162
2163/*-
2164 *---------------------------------------------------------------------
2165 * ParseUnreadc --
2166 * Put back a character to the current file
2167 *
2168 * Results:
2169 * None.
2170 *
2171 * Side Effects:
2172 *---------------------------------------------------------------------
2173 */
2174static void
2175ParseUnreadc(c)
2176 int c;
2177{
2178 if (curFILE) {
2179 ungetc(c, curFILE);
2180 return;
2181 }
2182 if (curPTR) {
2183 *--(curPTR->ptr) = c;
2184 return;
2185 }
2186}
2187
2188
2189/* ParseSkipLine():
2190 * Grab the next line
2191 */
2192static char *
2193ParseSkipLine(skip)
2194 int skip; /* Skip lines that don't start with . */
2195{
2196 char *line;
2197 int c, lastc, lineLength = 0;
2198 Buffer buf;
2199
2200 buf = Buf_Init(MAKE_BSIZE);
2201
2202 do {
2203 Buf_Discard(buf, lineLength);
2204 lastc = '\0';
2205
2206 while (((c = ParseReadc()) != '\n' || lastc == '\\')
2207 && c != EOF) {
2208 if (c == '\n') {
2209 Buf_ReplaceLastByte(buf, (Byte)' ');
2210 lineno++;
2211
2212 while ((c = ParseReadc()) == ' ' || c == '\t');
2213
2214 if (c == EOF)
2215 break;
2216 }
2217
2218 Buf_AddByte(buf, (Byte)c);
2219 lastc = c;
2220 }
2221
2222 if (c == EOF) {
2223 Parse_Error(PARSE_FATAL, "Unclosed conditional/for loop");
2224 Buf_Destroy(buf, TRUE);
2225 return((char *)NULL);
2226 }
2227
2228 lineno++;
2229 Buf_AddByte(buf, (Byte)'\0');
2230 line = (char *)Buf_GetAll(buf, &lineLength);
2231 #ifdef NMAKE
2232 } while (skip == 1 && line[0] != '.' && line[0] != '!');
2233 #else
2234 } while (skip == 1 && line[0] != '.');
2235 #endif
2236
2237 Buf_Destroy(buf, FALSE);
2238 return line;
2239}
2240
2241
2242/*-
2243 *---------------------------------------------------------------------
2244 * ParseReadLine --
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).
2251 *
2252 * Results:
2253 * A line w/o its newline
2254 *
2255 * Side Effects:
2256 * Only those associated with reading a character
2257 *---------------------------------------------------------------------
2258 */
2259static char *
2260ParseReadLine ()
2261{
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 */
2273
2274 semiNL = FALSE;
2275 ignDepOp = FALSE;
2276 #ifdef USE_INLINEFILES
2277 ignComment = inInlineFile;
2278 #else
2279 ignComment = FALSE;
2280 #endif
2281
2282 /*
2283 * Handle special-characters at the beginning of the line. Either a
2284 * leading tab (shell command) or pound-sign (possible conditional)
2285 * forces us to ignore comments and dependency operators and treat
2286 * semi-colons as semi-colons (by leaving semiNL FALSE). This also
2287 * discards completely blank lines.
2288 */
2289 for (;;) {
2290 c = ParseReadc();
2291 #ifdef USE_INLINEFILES
2292 if (inInlineFile)
2293 break;
2294 #endif
2295
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 }
2310 }
2311
2312 if (c != EOF) {
2313 lastc = c;
2314 buf = Buf_Init(MAKE_BSIZE);
2315
2316 /* @todo any inline changes here? */
2317 #ifdef NMAKE
2318 while (((c = ParseReadc ()) != '\n' || (lastc == '\\') || (lastc == '^')) && (c != EOF))
2319 #else
2320 while (((c = ParseReadc ()) != '\n' || (lastc == '\\')) && (c != EOF))
2321 #endif
2322 {
2323test_char:
2324 switch(c) {
2325 case '\n':
2326 #ifdef USE_INLINEFILES
2327 /* No newline escaping in inline files, unless it's a directive. */
2328 if (inInlineFile) {
2329 int cb;
2330 char *psz = Buf_GetAll(buf, &cb);
2331 #ifdef NMAKE
2332 if (cb > 0 && *psz != '.' && *psz != '!')
2333 #else
2334 if (cb > 0 && *psz != '.')
2335 #endif
2336 break;
2337 }
2338 #endif
2339
2340 /*
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 = ' ';
2350#ifdef NMAKE
2351 if (lastc == '^')
2352 lastc = '\n';
2353
2354 do {
2355 while ((c = ParseReadc ()) == ' ' || c == '\t') {
2356 continue;
2357 }
2358 if (c != '#')
2359 break;
2360 /* comment - skip line */
2361 while ((c = ParseReadc ()) != '\n' && c != EOF) {
2362 continue;
2363 }
2364 if (c == EOF)
2365 break;
2366 } while (1);
2367#else
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;
2383
2384/* We don't need this, and don't want it! */
2385#ifndef KMK
2386 case ';':
2387 #ifdef USE_INLINEFILES
2388 if (inInlineFile)
2389 break;
2390 #endif
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 '=':
2409 #ifdef USE_INLINEFILES
2410 if (inInlineFile)
2411 break;
2412 #endif
2413 if (!semiNL) {
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 (
2437#if 0
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 '!':
2462 #ifdef USE_INLINEFILES
2463 if (inInlineFile)
2464 break;
2465 #endif
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;
2475#endif /* !KMK */
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 }
2484 line_read:
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 */
2499#ifdef USE_INLINEFILES
2500 if (!inInlineFile) {
2501#endif
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;
2511#ifdef USE_INLINEFILES
2512 }
2513#endif
2514
2515#ifdef NMAKE
2516 if (line[0] == '.' || line[0] == '!') {
2517#else
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);
2566
2567 } else {
2568 /*
2569 * Hit end-of-file, so return a NULL line to indicate this.
2570 */
2571 return((char *)NULL);
2572 }
2573}
2574
2575/*-
2576 *-----------------------------------------------------------------------
2577 * ParseFinishLine --
2578 * Handle the end of a dependency group.
2579 *
2580 * Results:
2581 * Nothing.
2582 *
2583 * Side Effects:
2584 * inLine set FALSE. 'targets' list destroyed.
2585 *
2586 *-----------------------------------------------------------------------
2587 */
2588static void
2589ParseFinishLine()
2590{
2591 if (inLine) {
2592 Lst_ForEach(targets, Suff_EndTransform, (ClientData)NULL);
2593 Lst_Destroy (targets, ParseHasCommands);
2594 targets = NULL;
2595 inLine = FALSE;
2596 }
2597}
2598
2599
2600/*-
2601 *---------------------------------------------------------------------
2602 * Parse_File --
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
2606 *
2607 * Results:
2608 * None
2609 *
2610 * Side Effects:
2611 * Loads. Nodes are added to the list of all targets, nodes and links
2612 * are added to the dependency graph. etc. etc. etc.
2613 *---------------------------------------------------------------------
2614 */
2615void
2616Parse_File(name, stream)
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 */
2622
2623 inLine = FALSE;
2624 #if defined(USE_INLINEFILES)
2625 inInlineFile = FALSE;
2626 #endif
2627 fname = name;
2628 curFILE = stream;
2629 lineno = 0;
2630 fatals = 0;
2631
2632 do {
2633 while ((line = ParseReadLine ()) != NULL) {
2634 if (DEBUG(PARSE))
2635 printf("%s(%d): inLine=%d inInlineFile=%d\n%s\n", fname, lineno, inLine, inInlineFile, line);
2636 #ifdef NMAKE
2637 if (*line == '.' || *line == '!') {
2638 #else
2639 if (*line == '.') {
2640 #endif
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 }
2671
2672 #ifdef USE_INLINEFILES
2673 if (inInlineFile)
2674 {
2675 cp = line;
2676 if (*cp == '<' && cp[1] == '<')
2677 {
2678 inInlineFile = FALSE;
2679 for (cp = line + 2; isspace(*cp); cp++) {
2680 continue;
2681 }
2682 if (!*cp || *cp == '#') { /* no flag */
2683 line[2] = '\0';
2684 cp = line;
2685 } else if (!strncmp(cp, "KEEP", 4) &&
2686 (!cp[4] || isspace(cp[4]) || cp[4] == '#')) {
2687 cp[4] = '\0';
2688 *--cp = '<';
2689 *--cp = '<';
2690 } else if (!strncmp(cp, "NOKEEP", 6) &&
2691 (!cp[6] || isspace(cp[6]) || cp[6] == '#')) {
2692 cp[6] = '\0';
2693 *--cp = '<';
2694 *--cp = '<';
2695 }
2696 else
2697 {
2698 Parse_Error(PARSE_FATAL, "Invalid termination of inline file \"%s\"", cp);
2699 cp = NULL;
2700 }
2701 }
2702 /* Append to last command */
2703 if (cp)
2704 {
2705 Lst_ForEach(targets, ParseAppendInline, cp);
2706 /*Lst_AtEnd(targCmds, (ClientData) line); */
2707 }
2708 goto nextLine;
2709 }
2710 #endif
2711
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 */
2722#if !defined(POSIX) || defined(USE_NO_STUPID_TABS)
2723 shellCommand:
2724#endif
2725 for (cp = line + 1; isspace (*cp); cp++) {
2726 continue;
2727 }
2728 if (*cp) {
2729 if (inLine) {
2730 #ifdef USE_INLINEFILES
2731 if (ParseCmdIsComponent(cp, "<<"))
2732 {
2733 inInlineFile = TRUE;
2734 Lst_ForEach(targets, ParseAddCmd, estrdup(cp));
2735 /*Lst_AtEnd(targCmds, (ClientData) line);*/
2736 goto nextLine;
2737 }
2738 #endif
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 }
2753#ifdef SYSVINCLUDE
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 */
2777#if !defined(POSIX) || defined(USE_NO_STUPID_TABS)
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 }
2789#if !defined(POSIX) || defined(USE_NO_STUPID_TABS)
2790 while ((*cp != ':') && (*cp != '!') && (*cp != '\0')) {
2791 nonSpace = TRUE;
2792 cp++;
2793 }
2794#endif
2795 }
2796
2797#if !defined(POSIX) || defined(USE_NO_STUPID_TABS)
2798 if (*cp == '\0') {
2799 if (inLine) {
2800#if !defined(USE_NO_STUPID_TABS)
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);
2826#if !defined(POSIX) || defined(USE_NO_STUPID_TABS)
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 */
2838 } while (ParseEOF(1) == CONTINUE);
2839
2840 /*
2841 * Make sure conditionals are clean
2842 */
2843 Cond_End();
2844
2845 if (fatals)
2846 errx(1, "fatal errors encountered -- cannot continue");
2847}
2848
2849/*-
2850 *---------------------------------------------------------------------
2851 * Parse_Init --
2852 * initialize the parsing module
2853 *
2854 * Results:
2855 * none
2856 *
2857 * Side Effects:
2858 * the parseIncPath list is initialized...
2859 *---------------------------------------------------------------------
2860 */
2861void
2862Parse_Init ()
2863{
2864 mainNode = NILGNODE;
2865 parseIncPath = Lst_Init (FALSE);
2866 sysIncPath = Lst_Init (FALSE);
2867 includes = Lst_Init (FALSE);
2868 /*targCmds = Lst_Init (FALSE);*/
2869}
2870
2871void
2872Parse_End()
2873{
2874 /*Lst_Destroy(targCmds, (void (*) __P((ClientData))) efree);*/
2875 if (targets)
2876 Lst_Destroy(targets, NOFREE);
2877 Lst_Destroy(sysIncPath, Dir_Destroy);
2878 Lst_Destroy(parseIncPath, Dir_Destroy);
2879 Lst_Destroy(includes, NOFREE); /* Should be empty now */
2880}
2881
2882
2883/*-
2884 *-----------------------------------------------------------------------
2885 * Parse_MainName --
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.
2888 *
2889 * Results:
2890 * A Lst of the single node to create.
2891 *
2892 * Side Effects:
2893 * None.
2894 *
2895 *-----------------------------------------------------------------------
2896 */
2897Lst
2898Parse_MainName()
2899{
2900 Lst listmain; /* result list */
2901
2902 listmain = Lst_Init (FALSE);
2903
2904 if (mainNode == NILGNODE) {
2905 Punt ("no target to make.");
2906 /*NOTREACHED*/
2907 } else if (mainNode->type & OP_DOUBLEDEP) {
2908 (void) Lst_AtEnd (listmain, (ClientData)mainNode);
2909 Lst_Concat(listmain, mainNode->cohorts, LST_CONCNEW);
2910 }
2911 else
2912 (void) Lst_AtEnd (listmain, (ClientData)mainNode);
2913 return (listmain);
2914}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette