1*0a6a1f1dSLionel Sambuc /* $NetBSD: parse.c,v 1.204 2014/09/18 08:06:13 dholland Exp $ */
22e2caf59SThomas Veerman
32e2caf59SThomas Veerman /*
42e2caf59SThomas Veerman * Copyright (c) 1988, 1989, 1990, 1993
52e2caf59SThomas Veerman * The Regents of the University of California. All rights reserved.
62e2caf59SThomas Veerman *
72e2caf59SThomas Veerman * This code is derived from software contributed to Berkeley by
82e2caf59SThomas Veerman * Adam de Boor.
92e2caf59SThomas Veerman *
102e2caf59SThomas Veerman * Redistribution and use in source and binary forms, with or without
112e2caf59SThomas Veerman * modification, are permitted provided that the following conditions
122e2caf59SThomas Veerman * are met:
132e2caf59SThomas Veerman * 1. Redistributions of source code must retain the above copyright
142e2caf59SThomas Veerman * notice, this list of conditions and the following disclaimer.
152e2caf59SThomas Veerman * 2. Redistributions in binary form must reproduce the above copyright
162e2caf59SThomas Veerman * notice, this list of conditions and the following disclaimer in the
172e2caf59SThomas Veerman * documentation and/or other materials provided with the distribution.
182e2caf59SThomas Veerman * 3. Neither the name of the University nor the names of its contributors
192e2caf59SThomas Veerman * may be used to endorse or promote products derived from this software
202e2caf59SThomas Veerman * without specific prior written permission.
212e2caf59SThomas Veerman *
222e2caf59SThomas Veerman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
232e2caf59SThomas Veerman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
242e2caf59SThomas Veerman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
252e2caf59SThomas Veerman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
262e2caf59SThomas Veerman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
272e2caf59SThomas Veerman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
282e2caf59SThomas Veerman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
292e2caf59SThomas Veerman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
302e2caf59SThomas Veerman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
312e2caf59SThomas Veerman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
322e2caf59SThomas Veerman * SUCH DAMAGE.
332e2caf59SThomas Veerman */
342e2caf59SThomas Veerman
352e2caf59SThomas Veerman /*
362e2caf59SThomas Veerman * Copyright (c) 1989 by Berkeley Softworks
372e2caf59SThomas Veerman * All rights reserved.
382e2caf59SThomas Veerman *
392e2caf59SThomas Veerman * This code is derived from software contributed to Berkeley by
402e2caf59SThomas Veerman * Adam de Boor.
412e2caf59SThomas Veerman *
422e2caf59SThomas Veerman * Redistribution and use in source and binary forms, with or without
432e2caf59SThomas Veerman * modification, are permitted provided that the following conditions
442e2caf59SThomas Veerman * are met:
452e2caf59SThomas Veerman * 1. Redistributions of source code must retain the above copyright
462e2caf59SThomas Veerman * notice, this list of conditions and the following disclaimer.
472e2caf59SThomas Veerman * 2. Redistributions in binary form must reproduce the above copyright
482e2caf59SThomas Veerman * notice, this list of conditions and the following disclaimer in the
492e2caf59SThomas Veerman * documentation and/or other materials provided with the distribution.
502e2caf59SThomas Veerman * 3. All advertising materials mentioning features or use of this software
512e2caf59SThomas Veerman * must display the following acknowledgement:
522e2caf59SThomas Veerman * This product includes software developed by the University of
532e2caf59SThomas Veerman * California, Berkeley and its contributors.
542e2caf59SThomas Veerman * 4. Neither the name of the University nor the names of its contributors
552e2caf59SThomas Veerman * may be used to endorse or promote products derived from this software
562e2caf59SThomas Veerman * without specific prior written permission.
572e2caf59SThomas Veerman *
582e2caf59SThomas Veerman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
592e2caf59SThomas Veerman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
602e2caf59SThomas Veerman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
612e2caf59SThomas Veerman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
622e2caf59SThomas Veerman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
632e2caf59SThomas Veerman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
642e2caf59SThomas Veerman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
652e2caf59SThomas Veerman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
662e2caf59SThomas Veerman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
672e2caf59SThomas Veerman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
682e2caf59SThomas Veerman * SUCH DAMAGE.
692e2caf59SThomas Veerman */
702e2caf59SThomas Veerman
712e2caf59SThomas Veerman #ifndef MAKE_NATIVE
72*0a6a1f1dSLionel Sambuc static char rcsid[] = "$NetBSD: parse.c,v 1.204 2014/09/18 08:06:13 dholland Exp $";
732e2caf59SThomas Veerman #else
742e2caf59SThomas Veerman #include <sys/cdefs.h>
752e2caf59SThomas Veerman #ifndef lint
762e2caf59SThomas Veerman #if 0
772e2caf59SThomas Veerman static char sccsid[] = "@(#)parse.c 8.3 (Berkeley) 3/19/94";
782e2caf59SThomas Veerman #else
79*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: parse.c,v 1.204 2014/09/18 08:06:13 dholland Exp $");
802e2caf59SThomas Veerman #endif
812e2caf59SThomas Veerman #endif /* not lint */
822e2caf59SThomas Veerman #endif
832e2caf59SThomas Veerman
842e2caf59SThomas Veerman /*-
852e2caf59SThomas Veerman * parse.c --
862e2caf59SThomas Veerman * Functions to parse a makefile.
872e2caf59SThomas Veerman *
882e2caf59SThomas Veerman * One function, Parse_Init, must be called before any functions
892e2caf59SThomas Veerman * in this module are used. After that, the function Parse_File is the
902e2caf59SThomas Veerman * main entry point and controls most of the other functions in this
912e2caf59SThomas Veerman * module.
922e2caf59SThomas Veerman *
932e2caf59SThomas Veerman * Most important structures are kept in Lsts. Directories for
942e2caf59SThomas Veerman * the .include "..." function are kept in the 'parseIncPath' Lst, while
952e2caf59SThomas Veerman * those for the .include <...> are kept in the 'sysIncPath' Lst. The
962e2caf59SThomas Veerman * targets currently being defined are kept in the 'targets' Lst.
972e2caf59SThomas Veerman *
982e2caf59SThomas Veerman * The variables 'fname' and 'lineno' are used to track the name
992e2caf59SThomas Veerman * of the current file and the line number in that file so that error
1002e2caf59SThomas Veerman * messages can be more meaningful.
1012e2caf59SThomas Veerman *
1022e2caf59SThomas Veerman * Interface:
1032e2caf59SThomas Veerman * Parse_Init Initialization function which must be
1042e2caf59SThomas Veerman * called before anything else in this module
1052e2caf59SThomas Veerman * is used.
1062e2caf59SThomas Veerman *
1072e2caf59SThomas Veerman * Parse_End Cleanup the module
1082e2caf59SThomas Veerman *
1092e2caf59SThomas Veerman * Parse_File Function used to parse a makefile. It must
1102e2caf59SThomas Veerman * be given the name of the file, which should
1112e2caf59SThomas Veerman * already have been opened, and a function
1122e2caf59SThomas Veerman * to call to read a character from the file.
1132e2caf59SThomas Veerman *
1142e2caf59SThomas Veerman * Parse_IsVar Returns TRUE if the given line is a
1152e2caf59SThomas Veerman * variable assignment. Used by MainParseArgs
1162e2caf59SThomas Veerman * to determine if an argument is a target
1172e2caf59SThomas Veerman * or a variable assignment. Used internally
1182e2caf59SThomas Veerman * for pretty much the same thing...
1192e2caf59SThomas Veerman *
1202e2caf59SThomas Veerman * Parse_Error Function called when an error occurs in
1212e2caf59SThomas Veerman * parsing. Used by the variable and
1222e2caf59SThomas Veerman * conditional modules.
1232e2caf59SThomas Veerman * Parse_MainName Returns a Lst of the main target to create.
1242e2caf59SThomas Veerman */
1252e2caf59SThomas Veerman
1262e2caf59SThomas Veerman #include <sys/types.h>
1272e2caf59SThomas Veerman #include <sys/mman.h>
1282e2caf59SThomas Veerman #include <sys/stat.h>
1292e2caf59SThomas Veerman #include <assert.h>
1302e2caf59SThomas Veerman #include <ctype.h>
1312e2caf59SThomas Veerman #include <errno.h>
1322e2caf59SThomas Veerman #include <fcntl.h>
1332e2caf59SThomas Veerman #include <stdarg.h>
1342e2caf59SThomas Veerman #include <stdio.h>
1352e2caf59SThomas Veerman
13684d9c625SLionel Sambuc #ifndef MAP_FILE
13784d9c625SLionel Sambuc #define MAP_FILE 0
13884d9c625SLionel Sambuc #endif
1392e2caf59SThomas Veerman #ifndef MAP_COPY
1402e2caf59SThomas Veerman #define MAP_COPY MAP_PRIVATE
1412e2caf59SThomas Veerman #endif
1422e2caf59SThomas Veerman
1432e2caf59SThomas Veerman #include "make.h"
1442e2caf59SThomas Veerman #include "hash.h"
1452e2caf59SThomas Veerman #include "dir.h"
1462e2caf59SThomas Veerman #include "job.h"
1472e2caf59SThomas Veerman #include "buf.h"
1482e2caf59SThomas Veerman #include "pathnames.h"
1492e2caf59SThomas Veerman
1502e2caf59SThomas Veerman ////////////////////////////////////////////////////////////
1512e2caf59SThomas Veerman // types and constants
1522e2caf59SThomas Veerman
1532e2caf59SThomas Veerman /*
1542e2caf59SThomas Veerman * Structure for a file being read ("included file")
1552e2caf59SThomas Veerman */
1562e2caf59SThomas Veerman typedef struct IFile {
15784d9c625SLionel Sambuc char *fname; /* name of file */
1582e2caf59SThomas Veerman int lineno; /* current line number in file */
1592e2caf59SThomas Veerman int first_lineno; /* line number of start of text */
1602e2caf59SThomas Veerman int cond_depth; /* 'if' nesting when file opened */
1612e2caf59SThomas Veerman char *P_str; /* point to base of string buffer */
1622e2caf59SThomas Veerman char *P_ptr; /* point to next char of string buffer */
1632e2caf59SThomas Veerman char *P_end; /* point to the end of string buffer */
1642e2caf59SThomas Veerman char *(*nextbuf)(void *, size_t *); /* Function to get more data */
1652e2caf59SThomas Veerman void *nextbuf_arg; /* Opaque arg for nextbuf() */
1662e2caf59SThomas Veerman struct loadedfile *lf; /* loadedfile object, if any */
1672e2caf59SThomas Veerman } IFile;
1682e2caf59SThomas Veerman
1692e2caf59SThomas Veerman
1702e2caf59SThomas Veerman /*
1712e2caf59SThomas Veerman * These values are returned by ParseEOF to tell Parse_File whether to
1722e2caf59SThomas Veerman * CONTINUE parsing, i.e. it had only reached the end of an include file,
1732e2caf59SThomas Veerman * or if it's DONE.
1742e2caf59SThomas Veerman */
1752e2caf59SThomas Veerman #define CONTINUE 1
1762e2caf59SThomas Veerman #define DONE 0
1772e2caf59SThomas Veerman
1782e2caf59SThomas Veerman /*
1792e2caf59SThomas Veerman * Tokens for target attributes
1802e2caf59SThomas Veerman */
1812e2caf59SThomas Veerman typedef enum {
1822e2caf59SThomas Veerman Begin, /* .BEGIN */
1832e2caf59SThomas Veerman Default, /* .DEFAULT */
1842e2caf59SThomas Veerman End, /* .END */
1852e2caf59SThomas Veerman dotError, /* .ERROR */
1862e2caf59SThomas Veerman Ignore, /* .IGNORE */
1872e2caf59SThomas Veerman Includes, /* .INCLUDES */
1882e2caf59SThomas Veerman Interrupt, /* .INTERRUPT */
1892e2caf59SThomas Veerman Libs, /* .LIBS */
1902e2caf59SThomas Veerman Meta, /* .META */
1912e2caf59SThomas Veerman MFlags, /* .MFLAGS or .MAKEFLAGS */
1922e2caf59SThomas Veerman Main, /* .MAIN and we don't have anything user-specified to
1932e2caf59SThomas Veerman * make */
1942e2caf59SThomas Veerman NoExport, /* .NOEXPORT */
1952e2caf59SThomas Veerman NoMeta, /* .NOMETA */
1962e2caf59SThomas Veerman NoMetaCmp, /* .NOMETA_CMP */
1972e2caf59SThomas Veerman NoPath, /* .NOPATH */
1982e2caf59SThomas Veerman Not, /* Not special */
1992e2caf59SThomas Veerman NotParallel, /* .NOTPARALLEL */
2002e2caf59SThomas Veerman Null, /* .NULL */
2012e2caf59SThomas Veerman ExObjdir, /* .OBJDIR */
2022e2caf59SThomas Veerman Order, /* .ORDER */
2032e2caf59SThomas Veerman Parallel, /* .PARALLEL */
2042e2caf59SThomas Veerman ExPath, /* .PATH */
2052e2caf59SThomas Veerman Phony, /* .PHONY */
2062e2caf59SThomas Veerman #ifdef POSIX
2072e2caf59SThomas Veerman Posix, /* .POSIX */
2082e2caf59SThomas Veerman #endif
2092e2caf59SThomas Veerman Precious, /* .PRECIOUS */
2102e2caf59SThomas Veerman ExShell, /* .SHELL */
2112e2caf59SThomas Veerman Silent, /* .SILENT */
2122e2caf59SThomas Veerman SingleShell, /* .SINGLESHELL */
21384d9c625SLionel Sambuc Stale, /* .STALE */
2142e2caf59SThomas Veerman Suffixes, /* .SUFFIXES */
2152e2caf59SThomas Veerman Wait, /* .WAIT */
2162e2caf59SThomas Veerman Attribute /* Generic attribute */
2172e2caf59SThomas Veerman } ParseSpecial;
2182e2caf59SThomas Veerman
2192e2caf59SThomas Veerman /*
2202e2caf59SThomas Veerman * Other tokens
2212e2caf59SThomas Veerman */
2222e2caf59SThomas Veerman #define LPAREN '('
2232e2caf59SThomas Veerman #define RPAREN ')'
2242e2caf59SThomas Veerman
2252e2caf59SThomas Veerman
2262e2caf59SThomas Veerman ////////////////////////////////////////////////////////////
2272e2caf59SThomas Veerman // result data
2282e2caf59SThomas Veerman
2292e2caf59SThomas Veerman /*
2302e2caf59SThomas Veerman * The main target to create. This is the first target on the first
2312e2caf59SThomas Veerman * dependency line in the first makefile.
2322e2caf59SThomas Veerman */
2332e2caf59SThomas Veerman static GNode *mainNode;
2342e2caf59SThomas Veerman
2352e2caf59SThomas Veerman ////////////////////////////////////////////////////////////
2362e2caf59SThomas Veerman // eval state
2372e2caf59SThomas Veerman
2382e2caf59SThomas Veerman /* targets we're working on */
2392e2caf59SThomas Veerman static Lst targets;
2402e2caf59SThomas Veerman
2412e2caf59SThomas Veerman #ifdef CLEANUP
2422e2caf59SThomas Veerman /* command lines for targets */
2432e2caf59SThomas Veerman static Lst targCmds;
2442e2caf59SThomas Veerman #endif
2452e2caf59SThomas Veerman
2462e2caf59SThomas Veerman /*
2472e2caf59SThomas Veerman * specType contains the SPECial TYPE of the current target. It is
2482e2caf59SThomas Veerman * Not if the target is unspecial. If it *is* special, however, the children
2492e2caf59SThomas Veerman * are linked as children of the parent but not vice versa. This variable is
2502e2caf59SThomas Veerman * set in ParseDoDependency
2512e2caf59SThomas Veerman */
2522e2caf59SThomas Veerman static ParseSpecial specType;
2532e2caf59SThomas Veerman
2542e2caf59SThomas Veerman /*
2552e2caf59SThomas Veerman * Predecessor node for handling .ORDER. Initialized to NULL when .ORDER
2562e2caf59SThomas Veerman * seen, then set to each successive source on the line.
2572e2caf59SThomas Veerman */
2582e2caf59SThomas Veerman static GNode *predecessor;
2592e2caf59SThomas Veerman
2602e2caf59SThomas Veerman ////////////////////////////////////////////////////////////
2612e2caf59SThomas Veerman // parser state
2622e2caf59SThomas Veerman
2632e2caf59SThomas Veerman /* true if currently in a dependency line or its commands */
2642e2caf59SThomas Veerman static Boolean inLine;
2652e2caf59SThomas Veerman
2662e2caf59SThomas Veerman /* number of fatal errors */
2672e2caf59SThomas Veerman static int fatals = 0;
2682e2caf59SThomas Veerman
2692e2caf59SThomas Veerman /*
2702e2caf59SThomas Veerman * Variables for doing includes
2712e2caf59SThomas Veerman */
2722e2caf59SThomas Veerman
2732e2caf59SThomas Veerman /* current file being read */
2742e2caf59SThomas Veerman static IFile *curFile;
2752e2caf59SThomas Veerman
2762e2caf59SThomas Veerman /* stack of IFiles generated by .includes */
2772e2caf59SThomas Veerman static Lst includes;
2782e2caf59SThomas Veerman
2792e2caf59SThomas Veerman /* include paths (lists of directories) */
2802e2caf59SThomas Veerman Lst parseIncPath; /* dirs for "..." includes */
2812e2caf59SThomas Veerman Lst sysIncPath; /* dirs for <...> includes */
2822e2caf59SThomas Veerman Lst defIncPath; /* default for sysIncPath */
2832e2caf59SThomas Veerman
2842e2caf59SThomas Veerman ////////////////////////////////////////////////////////////
2852e2caf59SThomas Veerman // parser tables
2862e2caf59SThomas Veerman
2872e2caf59SThomas Veerman /*
2882e2caf59SThomas Veerman * The parseKeywords table is searched using binary search when deciding
2892e2caf59SThomas Veerman * if a target or source is special. The 'spec' field is the ParseSpecial
2902e2caf59SThomas Veerman * type of the keyword ("Not" if the keyword isn't special as a target) while
2912e2caf59SThomas Veerman * the 'op' field is the operator to apply to the list of targets if the
2922e2caf59SThomas Veerman * keyword is used as a source ("0" if the keyword isn't special as a source)
2932e2caf59SThomas Veerman */
2942e2caf59SThomas Veerman static const struct {
2952e2caf59SThomas Veerman const char *name; /* Name of keyword */
2962e2caf59SThomas Veerman ParseSpecial spec; /* Type when used as a target */
2972e2caf59SThomas Veerman int op; /* Operator when used as a source */
2982e2caf59SThomas Veerman } parseKeywords[] = {
2992e2caf59SThomas Veerman { ".BEGIN", Begin, 0 },
3002e2caf59SThomas Veerman { ".DEFAULT", Default, 0 },
3012e2caf59SThomas Veerman { ".END", End, 0 },
3022e2caf59SThomas Veerman { ".ERROR", dotError, 0 },
3032e2caf59SThomas Veerman { ".EXEC", Attribute, OP_EXEC },
3042e2caf59SThomas Veerman { ".IGNORE", Ignore, OP_IGNORE },
3052e2caf59SThomas Veerman { ".INCLUDES", Includes, 0 },
3062e2caf59SThomas Veerman { ".INTERRUPT", Interrupt, 0 },
3072e2caf59SThomas Veerman { ".INVISIBLE", Attribute, OP_INVISIBLE },
3082e2caf59SThomas Veerman { ".JOIN", Attribute, OP_JOIN },
3092e2caf59SThomas Veerman { ".LIBS", Libs, 0 },
3102e2caf59SThomas Veerman { ".MADE", Attribute, OP_MADE },
3112e2caf59SThomas Veerman { ".MAIN", Main, 0 },
3122e2caf59SThomas Veerman { ".MAKE", Attribute, OP_MAKE },
3132e2caf59SThomas Veerman { ".MAKEFLAGS", MFlags, 0 },
3142e2caf59SThomas Veerman { ".META", Meta, OP_META },
3152e2caf59SThomas Veerman { ".MFLAGS", MFlags, 0 },
3162e2caf59SThomas Veerman { ".NOMETA", NoMeta, OP_NOMETA },
3172e2caf59SThomas Veerman { ".NOMETA_CMP", NoMetaCmp, OP_NOMETA_CMP },
3182e2caf59SThomas Veerman { ".NOPATH", NoPath, OP_NOPATH },
3192e2caf59SThomas Veerman { ".NOTMAIN", Attribute, OP_NOTMAIN },
3202e2caf59SThomas Veerman { ".NOTPARALLEL", NotParallel, 0 },
3212e2caf59SThomas Veerman { ".NO_PARALLEL", NotParallel, 0 },
3222e2caf59SThomas Veerman { ".NULL", Null, 0 },
3232e2caf59SThomas Veerman { ".OBJDIR", ExObjdir, 0 },
3242e2caf59SThomas Veerman { ".OPTIONAL", Attribute, OP_OPTIONAL },
3252e2caf59SThomas Veerman { ".ORDER", Order, 0 },
3262e2caf59SThomas Veerman { ".PARALLEL", Parallel, 0 },
3272e2caf59SThomas Veerman { ".PATH", ExPath, 0 },
3282e2caf59SThomas Veerman { ".PHONY", Phony, OP_PHONY },
3292e2caf59SThomas Veerman #ifdef POSIX
3302e2caf59SThomas Veerman { ".POSIX", Posix, 0 },
3312e2caf59SThomas Veerman #endif
3322e2caf59SThomas Veerman { ".PRECIOUS", Precious, OP_PRECIOUS },
3332e2caf59SThomas Veerman { ".RECURSIVE", Attribute, OP_MAKE },
3342e2caf59SThomas Veerman { ".SHELL", ExShell, 0 },
3352e2caf59SThomas Veerman { ".SILENT", Silent, OP_SILENT },
3362e2caf59SThomas Veerman { ".SINGLESHELL", SingleShell, 0 },
33784d9c625SLionel Sambuc { ".STALE", Stale, 0 },
3382e2caf59SThomas Veerman { ".SUFFIXES", Suffixes, 0 },
3392e2caf59SThomas Veerman { ".USE", Attribute, OP_USE },
3402e2caf59SThomas Veerman { ".USEBEFORE", Attribute, OP_USEBEFORE },
3412e2caf59SThomas Veerman { ".WAIT", Wait, 0 },
3422e2caf59SThomas Veerman };
3432e2caf59SThomas Veerman
3442e2caf59SThomas Veerman ////////////////////////////////////////////////////////////
3452e2caf59SThomas Veerman // local functions
3462e2caf59SThomas Veerman
3472e2caf59SThomas Veerman static int ParseIsEscaped(const char *, const char *);
3482e2caf59SThomas Veerman static void ParseErrorInternal(const char *, size_t, int, const char *, ...)
3492bc7c627SLionel Sambuc MAKE_ATTR_PRINTFLIKE(4,5);
3502e2caf59SThomas Veerman static void ParseVErrorInternal(FILE *, const char *, size_t, int, const char *, va_list)
3512bc7c627SLionel Sambuc MAKE_ATTR_PRINTFLIKE(5, 0);
3522e2caf59SThomas Veerman static int ParseFindKeyword(const char *);
3532e2caf59SThomas Veerman static int ParseLinkSrc(void *, void *);
3542e2caf59SThomas Veerman static int ParseDoOp(void *, void *);
3552e2caf59SThomas Veerman static void ParseDoSrc(int, const char *);
3562e2caf59SThomas Veerman static int ParseFindMain(void *, void *);
3572e2caf59SThomas Veerman static int ParseAddDir(void *, void *);
3582e2caf59SThomas Veerman static int ParseClearPath(void *, void *);
3592e2caf59SThomas Veerman static void ParseDoDependency(char *);
3602e2caf59SThomas Veerman static int ParseAddCmd(void *, void *);
3612e2caf59SThomas Veerman static void ParseHasCommands(void *);
3622e2caf59SThomas Veerman static void ParseDoInclude(char *);
3632e2caf59SThomas Veerman static void ParseSetParseFile(const char *);
364*0a6a1f1dSLionel Sambuc static void ParseSetIncludedFile(void);
3652e2caf59SThomas Veerman #ifdef SYSVINCLUDE
3662e2caf59SThomas Veerman static void ParseTraditionalInclude(char *);
3672e2caf59SThomas Veerman #endif
3682e2caf59SThomas Veerman #ifdef GMAKEEXPORT
3692e2caf59SThomas Veerman static void ParseGmakeExport(char *);
3702e2caf59SThomas Veerman #endif
3712e2caf59SThomas Veerman static int ParseEOF(void);
3722e2caf59SThomas Veerman static char *ParseReadLine(void);
3732e2caf59SThomas Veerman static void ParseFinishLine(void);
3742e2caf59SThomas Veerman static void ParseMark(GNode *);
3752e2caf59SThomas Veerman
3762e2caf59SThomas Veerman ////////////////////////////////////////////////////////////
3772e2caf59SThomas Veerman // file loader
3782e2caf59SThomas Veerman
3792e2caf59SThomas Veerman struct loadedfile {
3802e2caf59SThomas Veerman const char *path; /* name, for error reports */
3812e2caf59SThomas Veerman char *buf; /* contents buffer */
3822e2caf59SThomas Veerman size_t len; /* length of contents */
3832e2caf59SThomas Veerman size_t maplen; /* length of mmap area, or 0 */
3842e2caf59SThomas Veerman Boolean used; /* XXX: have we used the data yet */
3852e2caf59SThomas Veerman };
3862e2caf59SThomas Veerman
3872e2caf59SThomas Veerman /*
3882e2caf59SThomas Veerman * Constructor/destructor for loadedfile
3892e2caf59SThomas Veerman */
3902e2caf59SThomas Veerman static struct loadedfile *
loadedfile_create(const char * path)3912e2caf59SThomas Veerman loadedfile_create(const char *path)
3922e2caf59SThomas Veerman {
3932e2caf59SThomas Veerman struct loadedfile *lf;
3942e2caf59SThomas Veerman
3952e2caf59SThomas Veerman lf = bmake_malloc(sizeof(*lf));
3962e2caf59SThomas Veerman lf->path = (path == NULL ? "(stdin)" : path);
3972e2caf59SThomas Veerman lf->buf = NULL;
3982e2caf59SThomas Veerman lf->len = 0;
3992e2caf59SThomas Veerman lf->maplen = 0;
4002e2caf59SThomas Veerman lf->used = FALSE;
4012e2caf59SThomas Veerman return lf;
4022e2caf59SThomas Veerman }
4032e2caf59SThomas Veerman
4042e2caf59SThomas Veerman static void
loadedfile_destroy(struct loadedfile * lf)4052e2caf59SThomas Veerman loadedfile_destroy(struct loadedfile *lf)
4062e2caf59SThomas Veerman {
4072e2caf59SThomas Veerman if (lf->buf != NULL) {
4082e2caf59SThomas Veerman if (lf->maplen > 0) {
4092e2caf59SThomas Veerman munmap(lf->buf, lf->maplen);
4102e2caf59SThomas Veerman } else {
4112e2caf59SThomas Veerman free(lf->buf);
4122e2caf59SThomas Veerman }
4132e2caf59SThomas Veerman }
4142e2caf59SThomas Veerman free(lf);
4152e2caf59SThomas Veerman }
4162e2caf59SThomas Veerman
4172e2caf59SThomas Veerman /*
4182e2caf59SThomas Veerman * nextbuf() operation for loadedfile, as needed by the weird and twisted
4192e2caf59SThomas Veerman * logic below. Once that's cleaned up, we can get rid of lf->used...
4202e2caf59SThomas Veerman */
4212e2caf59SThomas Veerman static char *
loadedfile_nextbuf(void * x,size_t * len)4222e2caf59SThomas Veerman loadedfile_nextbuf(void *x, size_t *len)
4232e2caf59SThomas Veerman {
4242e2caf59SThomas Veerman struct loadedfile *lf = x;
4252e2caf59SThomas Veerman
4262e2caf59SThomas Veerman if (lf->used) {
4272e2caf59SThomas Veerman return NULL;
4282e2caf59SThomas Veerman }
4292e2caf59SThomas Veerman lf->used = TRUE;
4302e2caf59SThomas Veerman *len = lf->len;
4312e2caf59SThomas Veerman return lf->buf;
4322e2caf59SThomas Veerman }
4332e2caf59SThomas Veerman
4342e2caf59SThomas Veerman /*
4352e2caf59SThomas Veerman * Try to get the size of a file.
4362e2caf59SThomas Veerman */
4372e2caf59SThomas Veerman static ReturnStatus
load_getsize(int fd,size_t * ret)4382e2caf59SThomas Veerman load_getsize(int fd, size_t *ret)
4392e2caf59SThomas Veerman {
4402e2caf59SThomas Veerman struct stat st;
4412e2caf59SThomas Veerman
4422e2caf59SThomas Veerman if (fstat(fd, &st) < 0) {
4432e2caf59SThomas Veerman return FAILURE;
4442e2caf59SThomas Veerman }
4452e2caf59SThomas Veerman
4462e2caf59SThomas Veerman if (!S_ISREG(st.st_mode)) {
4472e2caf59SThomas Veerman return FAILURE;
4482e2caf59SThomas Veerman }
4492e2caf59SThomas Veerman
4502e2caf59SThomas Veerman /*
4512e2caf59SThomas Veerman * st_size is an off_t, which is 64 bits signed; *ret is
4522e2caf59SThomas Veerman * size_t, which might be 32 bits unsigned or 64 bits
4532e2caf59SThomas Veerman * unsigned. Rather than being elaborate, just punt on
4542e2caf59SThomas Veerman * files that are more than 2^31 bytes. We should never
4552e2caf59SThomas Veerman * see a makefile that size in practice...
4562e2caf59SThomas Veerman *
4572e2caf59SThomas Veerman * While we're at it reject negative sizes too, just in case.
4582e2caf59SThomas Veerman */
4592e2caf59SThomas Veerman if (st.st_size < 0 || st.st_size > 0x7fffffff) {
4602e2caf59SThomas Veerman return FAILURE;
4612e2caf59SThomas Veerman }
4622e2caf59SThomas Veerman
4632e2caf59SThomas Veerman *ret = (size_t) st.st_size;
4642e2caf59SThomas Veerman return SUCCESS;
4652e2caf59SThomas Veerman }
4662e2caf59SThomas Veerman
4672e2caf59SThomas Veerman /*
4682e2caf59SThomas Veerman * Read in a file.
4692e2caf59SThomas Veerman *
4702e2caf59SThomas Veerman * Until the path search logic can be moved under here instead of
4712e2caf59SThomas Veerman * being in the caller in another source file, we need to have the fd
4722e2caf59SThomas Veerman * passed in already open. Bleh.
4732e2caf59SThomas Veerman *
4742e2caf59SThomas Veerman * If the path is NULL use stdin and (to insure against fd leaks)
4752e2caf59SThomas Veerman * assert that the caller passed in -1.
4762e2caf59SThomas Veerman */
4772e2caf59SThomas Veerman static struct loadedfile *
loadfile(const char * path,int fd)4782e2caf59SThomas Veerman loadfile(const char *path, int fd)
4792e2caf59SThomas Veerman {
4802e2caf59SThomas Veerman struct loadedfile *lf;
4812e2caf59SThomas Veerman long pagesize;
4822e2caf59SThomas Veerman ssize_t result;
4832e2caf59SThomas Veerman size_t bufpos;
4842e2caf59SThomas Veerman
4852e2caf59SThomas Veerman lf = loadedfile_create(path);
4862e2caf59SThomas Veerman
4872e2caf59SThomas Veerman if (path == NULL) {
4882e2caf59SThomas Veerman assert(fd == -1);
4892e2caf59SThomas Veerman fd = STDIN_FILENO;
4902e2caf59SThomas Veerman } else {
4912e2caf59SThomas Veerman #if 0 /* notyet */
4922e2caf59SThomas Veerman fd = open(path, O_RDONLY);
4932e2caf59SThomas Veerman if (fd < 0) {
4942e2caf59SThomas Veerman ...
4952e2caf59SThomas Veerman Error("%s: %s", path, strerror(errno));
4962e2caf59SThomas Veerman exit(1);
4972e2caf59SThomas Veerman }
4982e2caf59SThomas Veerman #endif
4992e2caf59SThomas Veerman }
5002e2caf59SThomas Veerman
5012e2caf59SThomas Veerman if (load_getsize(fd, &lf->len) == SUCCESS) {
5022e2caf59SThomas Veerman /* found a size, try mmap */
5032e2caf59SThomas Veerman pagesize = sysconf(_SC_PAGESIZE);
5042e2caf59SThomas Veerman if (pagesize <= 0) {
5052e2caf59SThomas Veerman pagesize = 0x1000;
5062e2caf59SThomas Veerman }
5072e2caf59SThomas Veerman /* round size up to a page */
5082e2caf59SThomas Veerman lf->maplen = pagesize * ((lf->len + pagesize - 1)/pagesize);
5092e2caf59SThomas Veerman
5102e2caf59SThomas Veerman /*
5112e2caf59SThomas Veerman * XXX hack for dealing with empty files; remove when
5122e2caf59SThomas Veerman * we're no longer limited by interfacing to the old
5132e2caf59SThomas Veerman * logic elsewhere in this file.
5142e2caf59SThomas Veerman */
5152e2caf59SThomas Veerman if (lf->maplen == 0) {
5162e2caf59SThomas Veerman lf->maplen = pagesize;
5172e2caf59SThomas Veerman }
5182e2caf59SThomas Veerman
5192e2caf59SThomas Veerman /*
5202e2caf59SThomas Veerman * FUTURE: remove PROT_WRITE when the parser no longer
5212e2caf59SThomas Veerman * needs to scribble on the input.
5222e2caf59SThomas Veerman */
5232e2caf59SThomas Veerman lf->buf = mmap(NULL, lf->maplen, PROT_READ|PROT_WRITE,
5242e2caf59SThomas Veerman MAP_FILE|MAP_COPY, fd, 0);
5252e2caf59SThomas Veerman if (lf->buf != MAP_FAILED) {
5262e2caf59SThomas Veerman /* succeeded */
5272e2caf59SThomas Veerman if (lf->len == lf->maplen && lf->buf[lf->len - 1] != '\n') {
5282e2caf59SThomas Veerman char *b = malloc(lf->len + 1);
5292e2caf59SThomas Veerman b[lf->len] = '\n';
5302e2caf59SThomas Veerman memcpy(b, lf->buf, lf->len++);
5312e2caf59SThomas Veerman munmap(lf->buf, lf->maplen);
5322e2caf59SThomas Veerman lf->maplen = 0;
5332e2caf59SThomas Veerman lf->buf = b;
5342e2caf59SThomas Veerman }
5352e2caf59SThomas Veerman goto done;
5362e2caf59SThomas Veerman }
5372e2caf59SThomas Veerman }
5382bc7c627SLionel Sambuc
5392e2caf59SThomas Veerman /* cannot mmap; load the traditional way */
5402e2caf59SThomas Veerman
5412e2caf59SThomas Veerman lf->maplen = 0;
5422e2caf59SThomas Veerman lf->len = 1024;
5432e2caf59SThomas Veerman lf->buf = bmake_malloc(lf->len);
5442e2caf59SThomas Veerman
5452e2caf59SThomas Veerman bufpos = 0;
5462e2caf59SThomas Veerman while (1) {
5472e2caf59SThomas Veerman assert(bufpos <= lf->len);
5482e2caf59SThomas Veerman if (bufpos == lf->len) {
5492e2caf59SThomas Veerman lf->len *= 2;
5502e2caf59SThomas Veerman lf->buf = bmake_realloc(lf->buf, lf->len);
5512e2caf59SThomas Veerman }
5522e2caf59SThomas Veerman result = read(fd, lf->buf + bufpos, lf->len - bufpos);
5532e2caf59SThomas Veerman if (result < 0) {
5542e2caf59SThomas Veerman Error("%s: read error: %s", path, strerror(errno));
5552e2caf59SThomas Veerman exit(1);
5562e2caf59SThomas Veerman }
5572e2caf59SThomas Veerman if (result == 0) {
5582e2caf59SThomas Veerman break;
5592e2caf59SThomas Veerman }
5602e2caf59SThomas Veerman bufpos += result;
5612e2caf59SThomas Veerman }
5622e2caf59SThomas Veerman assert(bufpos <= lf->len);
5632e2caf59SThomas Veerman lf->len = bufpos;
5642e2caf59SThomas Veerman
5652e2caf59SThomas Veerman /* truncate malloc region to actual length (maybe not useful) */
5662e2caf59SThomas Veerman if (lf->len > 0) {
5672e2caf59SThomas Veerman lf->buf = bmake_realloc(lf->buf, lf->len);
5682e2caf59SThomas Veerman }
5692e2caf59SThomas Veerman
5702e2caf59SThomas Veerman done:
5712e2caf59SThomas Veerman if (path != NULL) {
5722e2caf59SThomas Veerman close(fd);
5732e2caf59SThomas Veerman }
5742e2caf59SThomas Veerman return lf;
5752e2caf59SThomas Veerman }
5762e2caf59SThomas Veerman
5772e2caf59SThomas Veerman ////////////////////////////////////////////////////////////
5782e2caf59SThomas Veerman // old code
5792e2caf59SThomas Veerman
5802e2caf59SThomas Veerman /*-
5812e2caf59SThomas Veerman *----------------------------------------------------------------------
5822e2caf59SThomas Veerman * ParseIsEscaped --
5832e2caf59SThomas Veerman * Check if the current character is escaped on the current line
5842e2caf59SThomas Veerman *
5852e2caf59SThomas Veerman * Results:
5862e2caf59SThomas Veerman * 0 if the character is not backslash escaped, 1 otherwise
5872e2caf59SThomas Veerman *
5882e2caf59SThomas Veerman * Side Effects:
5892e2caf59SThomas Veerman * None
5902e2caf59SThomas Veerman *----------------------------------------------------------------------
5912e2caf59SThomas Veerman */
5922e2caf59SThomas Veerman static int
ParseIsEscaped(const char * line,const char * c)5932e2caf59SThomas Veerman ParseIsEscaped(const char *line, const char *c)
5942e2caf59SThomas Veerman {
5952e2caf59SThomas Veerman int active = 0;
5962e2caf59SThomas Veerman for (;;) {
5972e2caf59SThomas Veerman if (line == c)
5982e2caf59SThomas Veerman return active;
5992e2caf59SThomas Veerman if (*--c != '\\')
6002e2caf59SThomas Veerman return active;
6012e2caf59SThomas Veerman active = !active;
6022e2caf59SThomas Veerman }
6032e2caf59SThomas Veerman }
6042e2caf59SThomas Veerman
6052e2caf59SThomas Veerman /*-
6062e2caf59SThomas Veerman *----------------------------------------------------------------------
6072e2caf59SThomas Veerman * ParseFindKeyword --
6082e2caf59SThomas Veerman * Look in the table of keywords for one matching the given string.
6092e2caf59SThomas Veerman *
6102e2caf59SThomas Veerman * Input:
6112e2caf59SThomas Veerman * str String to find
6122e2caf59SThomas Veerman *
6132e2caf59SThomas Veerman * Results:
6142e2caf59SThomas Veerman * The index of the keyword, or -1 if it isn't there.
6152e2caf59SThomas Veerman *
6162e2caf59SThomas Veerman * Side Effects:
6172e2caf59SThomas Veerman * None
6182e2caf59SThomas Veerman *----------------------------------------------------------------------
6192e2caf59SThomas Veerman */
6202e2caf59SThomas Veerman static int
ParseFindKeyword(const char * str)6212e2caf59SThomas Veerman ParseFindKeyword(const char *str)
6222e2caf59SThomas Veerman {
6232e2caf59SThomas Veerman int start, end, cur;
6242e2caf59SThomas Veerman int diff;
6252e2caf59SThomas Veerman
6262e2caf59SThomas Veerman start = 0;
6272e2caf59SThomas Veerman end = (sizeof(parseKeywords)/sizeof(parseKeywords[0])) - 1;
6282e2caf59SThomas Veerman
6292e2caf59SThomas Veerman do {
6302e2caf59SThomas Veerman cur = start + ((end - start) / 2);
6312e2caf59SThomas Veerman diff = strcmp(str, parseKeywords[cur].name);
6322e2caf59SThomas Veerman
6332e2caf59SThomas Veerman if (diff == 0) {
6342e2caf59SThomas Veerman return (cur);
6352e2caf59SThomas Veerman } else if (diff < 0) {
6362e2caf59SThomas Veerman end = cur - 1;
6372e2caf59SThomas Veerman } else {
6382e2caf59SThomas Veerman start = cur + 1;
6392e2caf59SThomas Veerman }
6402e2caf59SThomas Veerman } while (start <= end);
6412e2caf59SThomas Veerman return (-1);
6422e2caf59SThomas Veerman }
6432e2caf59SThomas Veerman
6442e2caf59SThomas Veerman /*-
6452e2caf59SThomas Veerman * ParseVErrorInternal --
6462e2caf59SThomas Veerman * Error message abort function for parsing. Prints out the context
6472e2caf59SThomas Veerman * of the error (line number and file) as well as the message with
6482e2caf59SThomas Veerman * two optional arguments.
6492e2caf59SThomas Veerman *
6502e2caf59SThomas Veerman * Results:
6512e2caf59SThomas Veerman * None
6522e2caf59SThomas Veerman *
6532e2caf59SThomas Veerman * Side Effects:
6542e2caf59SThomas Veerman * "fatals" is incremented if the level is PARSE_FATAL.
6552e2caf59SThomas Veerman */
6562e2caf59SThomas Veerman /* VARARGS */
6572e2caf59SThomas Veerman static void
ParseVErrorInternal(FILE * f,const char * cfname,size_t clineno,int type,const char * fmt,va_list ap)6582e2caf59SThomas Veerman ParseVErrorInternal(FILE *f, const char *cfname, size_t clineno, int type,
6592e2caf59SThomas Veerman const char *fmt, va_list ap)
6602e2caf59SThomas Veerman {
6612e2caf59SThomas Veerman static Boolean fatal_warning_error_printed = FALSE;
6622e2caf59SThomas Veerman
6632e2caf59SThomas Veerman (void)fprintf(f, "%s: ", progname);
6642e2caf59SThomas Veerman
6652e2caf59SThomas Veerman if (cfname != NULL) {
6662e2caf59SThomas Veerman (void)fprintf(f, "\"");
6672e2caf59SThomas Veerman if (*cfname != '/' && strcmp(cfname, "(stdin)") != 0) {
6682e2caf59SThomas Veerman char *cp;
6692e2caf59SThomas Veerman const char *dir;
6702e2caf59SThomas Veerman
6712e2caf59SThomas Veerman /*
6722e2caf59SThomas Veerman * Nothing is more annoying than not knowing
6732e2caf59SThomas Veerman * which Makefile is the culprit.
6742e2caf59SThomas Veerman */
6752e2caf59SThomas Veerman dir = Var_Value(".PARSEDIR", VAR_GLOBAL, &cp);
6762e2caf59SThomas Veerman if (dir == NULL || *dir == '\0' ||
6772e2caf59SThomas Veerman (*dir == '.' && dir[1] == '\0'))
6782e2caf59SThomas Veerman dir = Var_Value(".CURDIR", VAR_GLOBAL, &cp);
6792e2caf59SThomas Veerman if (dir == NULL)
6802e2caf59SThomas Veerman dir = ".";
6812e2caf59SThomas Veerman
6822e2caf59SThomas Veerman (void)fprintf(f, "%s/%s", dir, cfname);
6832e2caf59SThomas Veerman } else
6842e2caf59SThomas Veerman (void)fprintf(f, "%s", cfname);
6852e2caf59SThomas Veerman
6862e2caf59SThomas Veerman (void)fprintf(f, "\" line %d: ", (int)clineno);
6872e2caf59SThomas Veerman }
6882e2caf59SThomas Veerman if (type == PARSE_WARNING)
6892e2caf59SThomas Veerman (void)fprintf(f, "warning: ");
6902e2caf59SThomas Veerman (void)vfprintf(f, fmt, ap);
6912e2caf59SThomas Veerman (void)fprintf(f, "\n");
6922e2caf59SThomas Veerman (void)fflush(f);
6932e2caf59SThomas Veerman if (type == PARSE_FATAL || parseWarnFatal)
6942e2caf59SThomas Veerman fatals += 1;
6952e2caf59SThomas Veerman if (parseWarnFatal && !fatal_warning_error_printed) {
6962e2caf59SThomas Veerman Error("parsing warnings being treated as errors");
6972e2caf59SThomas Veerman fatal_warning_error_printed = TRUE;
6982e2caf59SThomas Veerman }
6992e2caf59SThomas Veerman }
7002e2caf59SThomas Veerman
7012e2caf59SThomas Veerman /*-
7022e2caf59SThomas Veerman * ParseErrorInternal --
7032e2caf59SThomas Veerman * Error function
7042e2caf59SThomas Veerman *
7052e2caf59SThomas Veerman * Results:
7062e2caf59SThomas Veerman * None
7072e2caf59SThomas Veerman *
7082e2caf59SThomas Veerman * Side Effects:
7092e2caf59SThomas Veerman * None
7102e2caf59SThomas Veerman */
7112e2caf59SThomas Veerman /* VARARGS */
7122e2caf59SThomas Veerman static void
ParseErrorInternal(const char * cfname,size_t clineno,int type,const char * fmt,...)7132e2caf59SThomas Veerman ParseErrorInternal(const char *cfname, size_t clineno, int type,
7142e2caf59SThomas Veerman const char *fmt, ...)
7152e2caf59SThomas Veerman {
7162e2caf59SThomas Veerman va_list ap;
7172e2caf59SThomas Veerman
7182e2caf59SThomas Veerman va_start(ap, fmt);
7192e2caf59SThomas Veerman (void)fflush(stdout);
7202e2caf59SThomas Veerman ParseVErrorInternal(stderr, cfname, clineno, type, fmt, ap);
7212e2caf59SThomas Veerman va_end(ap);
7222e2caf59SThomas Veerman
7232e2caf59SThomas Veerman if (debug_file != stderr && debug_file != stdout) {
7242e2caf59SThomas Veerman va_start(ap, fmt);
7252e2caf59SThomas Veerman ParseVErrorInternal(debug_file, cfname, clineno, type, fmt, ap);
7262e2caf59SThomas Veerman va_end(ap);
7272e2caf59SThomas Veerman }
7282e2caf59SThomas Veerman }
7292e2caf59SThomas Veerman
7302e2caf59SThomas Veerman /*-
7312e2caf59SThomas Veerman * Parse_Error --
7322e2caf59SThomas Veerman * External interface to ParseErrorInternal; uses the default filename
7332e2caf59SThomas Veerman * Line number.
7342e2caf59SThomas Veerman *
7352e2caf59SThomas Veerman * Results:
7362e2caf59SThomas Veerman * None
7372e2caf59SThomas Veerman *
7382e2caf59SThomas Veerman * Side Effects:
7392e2caf59SThomas Veerman * None
7402e2caf59SThomas Veerman */
7412e2caf59SThomas Veerman /* VARARGS */
7422e2caf59SThomas Veerman void
Parse_Error(int type,const char * fmt,...)7432e2caf59SThomas Veerman Parse_Error(int type, const char *fmt, ...)
7442e2caf59SThomas Veerman {
7452e2caf59SThomas Veerman va_list ap;
7462e2caf59SThomas Veerman const char *fname;
7472e2caf59SThomas Veerman size_t lineno;
7482e2caf59SThomas Veerman
7492e2caf59SThomas Veerman if (curFile == NULL) {
7502e2caf59SThomas Veerman fname = NULL;
7512e2caf59SThomas Veerman lineno = 0;
7522e2caf59SThomas Veerman } else {
7532e2caf59SThomas Veerman fname = curFile->fname;
7542e2caf59SThomas Veerman lineno = curFile->lineno;
7552e2caf59SThomas Veerman }
7562e2caf59SThomas Veerman
7572e2caf59SThomas Veerman va_start(ap, fmt);
7582e2caf59SThomas Veerman (void)fflush(stdout);
7592e2caf59SThomas Veerman ParseVErrorInternal(stderr, fname, lineno, type, fmt, ap);
7602e2caf59SThomas Veerman va_end(ap);
7612e2caf59SThomas Veerman
7622e2caf59SThomas Veerman if (debug_file != stderr && debug_file != stdout) {
7632e2caf59SThomas Veerman va_start(ap, fmt);
7642e2caf59SThomas Veerman ParseVErrorInternal(debug_file, fname, lineno, type, fmt, ap);
7652e2caf59SThomas Veerman va_end(ap);
7662e2caf59SThomas Veerman }
7672e2caf59SThomas Veerman }
7682e2caf59SThomas Veerman
7692e2caf59SThomas Veerman
7702e2caf59SThomas Veerman /*
7712e2caf59SThomas Veerman * ParseMessage
7722e2caf59SThomas Veerman * Parse a .info .warning or .error directive
7732e2caf59SThomas Veerman *
7742e2caf59SThomas Veerman * The input is the line minus the ".". We substitute
7752e2caf59SThomas Veerman * variables, print the message and exit(1) (for .error) or just print
7762e2caf59SThomas Veerman * a warning if the directive is malformed.
7772e2caf59SThomas Veerman */
7782e2caf59SThomas Veerman static Boolean
ParseMessage(char * line)7792e2caf59SThomas Veerman ParseMessage(char *line)
7802e2caf59SThomas Veerman {
7812e2caf59SThomas Veerman int mtype;
7822e2caf59SThomas Veerman
7832e2caf59SThomas Veerman switch(*line) {
7842e2caf59SThomas Veerman case 'i':
7852e2caf59SThomas Veerman mtype = 0;
7862e2caf59SThomas Veerman break;
7872e2caf59SThomas Veerman case 'w':
7882e2caf59SThomas Veerman mtype = PARSE_WARNING;
7892e2caf59SThomas Veerman break;
7902e2caf59SThomas Veerman case 'e':
7912e2caf59SThomas Veerman mtype = PARSE_FATAL;
7922e2caf59SThomas Veerman break;
7932e2caf59SThomas Veerman default:
7942e2caf59SThomas Veerman Parse_Error(PARSE_WARNING, "invalid syntax: \".%s\"", line);
7952e2caf59SThomas Veerman return FALSE;
7962e2caf59SThomas Veerman }
7972e2caf59SThomas Veerman
7982e2caf59SThomas Veerman while (isalpha((u_char)*line))
7992e2caf59SThomas Veerman line++;
8002e2caf59SThomas Veerman if (!isspace((u_char)*line))
8012e2caf59SThomas Veerman return FALSE; /* not for us */
8022e2caf59SThomas Veerman while (isspace((u_char)*line))
8032e2caf59SThomas Veerman line++;
8042e2caf59SThomas Veerman
8052e2caf59SThomas Veerman line = Var_Subst(NULL, line, VAR_CMD, 0);
8062e2caf59SThomas Veerman Parse_Error(mtype, "%s", line);
8072e2caf59SThomas Veerman free(line);
8082e2caf59SThomas Veerman
8092e2caf59SThomas Veerman if (mtype == PARSE_FATAL) {
8102e2caf59SThomas Veerman /* Terminate immediately. */
8112e2caf59SThomas Veerman exit(1);
8122e2caf59SThomas Veerman }
8132e2caf59SThomas Veerman return TRUE;
8142e2caf59SThomas Veerman }
8152e2caf59SThomas Veerman
8162e2caf59SThomas Veerman /*-
8172e2caf59SThomas Veerman *---------------------------------------------------------------------
8182e2caf59SThomas Veerman * ParseLinkSrc --
8192e2caf59SThomas Veerman * Link the parent node to its new child. Used in a Lst_ForEach by
8202e2caf59SThomas Veerman * ParseDoDependency. If the specType isn't 'Not', the parent
8212e2caf59SThomas Veerman * isn't linked as a parent of the child.
8222e2caf59SThomas Veerman *
8232e2caf59SThomas Veerman * Input:
8242e2caf59SThomas Veerman * pgnp The parent node
8252e2caf59SThomas Veerman * cgpn The child node
8262e2caf59SThomas Veerman *
8272e2caf59SThomas Veerman * Results:
8282e2caf59SThomas Veerman * Always = 0
8292e2caf59SThomas Veerman *
8302e2caf59SThomas Veerman * Side Effects:
8312e2caf59SThomas Veerman * New elements are added to the parents list of cgn and the
8322e2caf59SThomas Veerman * children list of cgn. the unmade field of pgn is updated
8332e2caf59SThomas Veerman * to reflect the additional child.
8342e2caf59SThomas Veerman *---------------------------------------------------------------------
8352e2caf59SThomas Veerman */
8362e2caf59SThomas Veerman static int
ParseLinkSrc(void * pgnp,void * cgnp)8372e2caf59SThomas Veerman ParseLinkSrc(void *pgnp, void *cgnp)
8382e2caf59SThomas Veerman {
8392e2caf59SThomas Veerman GNode *pgn = (GNode *)pgnp;
8402e2caf59SThomas Veerman GNode *cgn = (GNode *)cgnp;
8412e2caf59SThomas Veerman
8422e2caf59SThomas Veerman if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (pgn->cohorts))
8432e2caf59SThomas Veerman pgn = (GNode *)Lst_Datum(Lst_Last(pgn->cohorts));
8442e2caf59SThomas Veerman (void)Lst_AtEnd(pgn->children, cgn);
8452e2caf59SThomas Veerman if (specType == Not)
8462e2caf59SThomas Veerman (void)Lst_AtEnd(cgn->parents, pgn);
8472e2caf59SThomas Veerman pgn->unmade += 1;
8482e2caf59SThomas Veerman if (DEBUG(PARSE)) {
849*0a6a1f1dSLionel Sambuc fprintf(debug_file, "# %s: added child %s - %s\n", __func__,
850*0a6a1f1dSLionel Sambuc pgn->name, cgn->name);
8512e2caf59SThomas Veerman Targ_PrintNode(pgn, 0);
8522e2caf59SThomas Veerman Targ_PrintNode(cgn, 0);
8532e2caf59SThomas Veerman }
8542e2caf59SThomas Veerman return (0);
8552e2caf59SThomas Veerman }
8562e2caf59SThomas Veerman
8572e2caf59SThomas Veerman /*-
8582e2caf59SThomas Veerman *---------------------------------------------------------------------
8592e2caf59SThomas Veerman * ParseDoOp --
8602e2caf59SThomas Veerman * Apply the parsed operator to the given target node. Used in a
8612e2caf59SThomas Veerman * Lst_ForEach call by ParseDoDependency once all targets have
8622e2caf59SThomas Veerman * been found and their operator parsed. If the previous and new
8632e2caf59SThomas Veerman * operators are incompatible, a major error is taken.
8642e2caf59SThomas Veerman *
8652e2caf59SThomas Veerman * Input:
8662e2caf59SThomas Veerman * gnp The node to which the operator is to be applied
8672e2caf59SThomas Veerman * opp The operator to apply
8682e2caf59SThomas Veerman *
8692e2caf59SThomas Veerman * Results:
8702e2caf59SThomas Veerman * Always 0
8712e2caf59SThomas Veerman *
8722e2caf59SThomas Veerman * Side Effects:
8732e2caf59SThomas Veerman * The type field of the node is altered to reflect any new bits in
8742e2caf59SThomas Veerman * the op.
8752e2caf59SThomas Veerman *---------------------------------------------------------------------
8762e2caf59SThomas Veerman */
8772e2caf59SThomas Veerman static int
ParseDoOp(void * gnp,void * opp)8782e2caf59SThomas Veerman ParseDoOp(void *gnp, void *opp)
8792e2caf59SThomas Veerman {
8802e2caf59SThomas Veerman GNode *gn = (GNode *)gnp;
8812e2caf59SThomas Veerman int op = *(int *)opp;
8822e2caf59SThomas Veerman /*
8832e2caf59SThomas Veerman * If the dependency mask of the operator and the node don't match and
8842e2caf59SThomas Veerman * the node has actually had an operator applied to it before, and
8852e2caf59SThomas Veerman * the operator actually has some dependency information in it, complain.
8862e2caf59SThomas Veerman */
8872e2caf59SThomas Veerman if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) &&
8882e2caf59SThomas Veerman !OP_NOP(gn->type) && !OP_NOP(op))
8892e2caf59SThomas Veerman {
8902e2caf59SThomas Veerman Parse_Error(PARSE_FATAL, "Inconsistent operator for %s", gn->name);
8912e2caf59SThomas Veerman return (1);
8922e2caf59SThomas Veerman }
8932e2caf59SThomas Veerman
8942e2caf59SThomas Veerman if ((op == OP_DOUBLEDEP) && ((gn->type & OP_OPMASK) == OP_DOUBLEDEP)) {
8952e2caf59SThomas Veerman /*
8962e2caf59SThomas Veerman * If the node was the object of a :: operator, we need to create a
8972e2caf59SThomas Veerman * new instance of it for the children and commands on this dependency
8982e2caf59SThomas Veerman * line. The new instance is placed on the 'cohorts' list of the
8992e2caf59SThomas Veerman * initial one (note the initial one is not on its own cohorts list)
9002e2caf59SThomas Veerman * and the new instance is linked to all parents of the initial
9012e2caf59SThomas Veerman * instance.
9022e2caf59SThomas Veerman */
9032e2caf59SThomas Veerman GNode *cohort;
9042e2caf59SThomas Veerman
9052e2caf59SThomas Veerman /*
9062e2caf59SThomas Veerman * Propagate copied bits to the initial node. They'll be propagated
9072e2caf59SThomas Veerman * back to the rest of the cohorts later.
9082e2caf59SThomas Veerman */
9092e2caf59SThomas Veerman gn->type |= op & ~OP_OPMASK;
9102e2caf59SThomas Veerman
9112e2caf59SThomas Veerman cohort = Targ_FindNode(gn->name, TARG_NOHASH);
91284d9c625SLionel Sambuc if (doing_depend)
91384d9c625SLionel Sambuc ParseMark(cohort);
9142e2caf59SThomas Veerman /*
9152e2caf59SThomas Veerman * Make the cohort invisible as well to avoid duplicating it into
9162e2caf59SThomas Veerman * other variables. True, parents of this target won't tend to do
9172e2caf59SThomas Veerman * anything with their local variables, but better safe than
9182e2caf59SThomas Veerman * sorry. (I think this is pointless now, since the relevant list
9192e2caf59SThomas Veerman * traversals will no longer see this node anyway. -mycroft)
9202e2caf59SThomas Veerman */
9212e2caf59SThomas Veerman cohort->type = op | OP_INVISIBLE;
9222e2caf59SThomas Veerman (void)Lst_AtEnd(gn->cohorts, cohort);
9232e2caf59SThomas Veerman cohort->centurion = gn;
9242e2caf59SThomas Veerman gn->unmade_cohorts += 1;
9252e2caf59SThomas Veerman snprintf(cohort->cohort_num, sizeof cohort->cohort_num, "#%d",
9262e2caf59SThomas Veerman gn->unmade_cohorts);
9272e2caf59SThomas Veerman } else {
9282e2caf59SThomas Veerman /*
9292e2caf59SThomas Veerman * We don't want to nuke any previous flags (whatever they were) so we
9302e2caf59SThomas Veerman * just OR the new operator into the old
9312e2caf59SThomas Veerman */
9322e2caf59SThomas Veerman gn->type |= op;
9332e2caf59SThomas Veerman }
9342e2caf59SThomas Veerman
9352e2caf59SThomas Veerman return (0);
9362e2caf59SThomas Veerman }
9372e2caf59SThomas Veerman
9382e2caf59SThomas Veerman /*-
9392e2caf59SThomas Veerman *---------------------------------------------------------------------
9402e2caf59SThomas Veerman * ParseDoSrc --
9412e2caf59SThomas Veerman * Given the name of a source, figure out if it is an attribute
9422e2caf59SThomas Veerman * and apply it to the targets if it is. Else decide if there is
9432e2caf59SThomas Veerman * some attribute which should be applied *to* the source because
9442e2caf59SThomas Veerman * of some special target and apply it if so. Otherwise, make the
9452e2caf59SThomas Veerman * source be a child of the targets in the list 'targets'
9462e2caf59SThomas Veerman *
9472e2caf59SThomas Veerman * Input:
9482e2caf59SThomas Veerman * tOp operator (if any) from special targets
9492e2caf59SThomas Veerman * src name of the source to handle
9502e2caf59SThomas Veerman *
9512e2caf59SThomas Veerman * Results:
9522e2caf59SThomas Veerman * None
9532e2caf59SThomas Veerman *
9542e2caf59SThomas Veerman * Side Effects:
9552e2caf59SThomas Veerman * Operator bits may be added to the list of targets or to the source.
9562e2caf59SThomas Veerman * The targets may have a new source added to their lists of children.
9572e2caf59SThomas Veerman *---------------------------------------------------------------------
9582e2caf59SThomas Veerman */
9592e2caf59SThomas Veerman static void
ParseDoSrc(int tOp,const char * src)9602e2caf59SThomas Veerman ParseDoSrc(int tOp, const char *src)
9612e2caf59SThomas Veerman {
9622e2caf59SThomas Veerman GNode *gn = NULL;
9632e2caf59SThomas Veerman static int wait_number = 0;
9642e2caf59SThomas Veerman char wait_src[16];
9652e2caf59SThomas Veerman
9662e2caf59SThomas Veerman if (*src == '.' && isupper ((unsigned char)src[1])) {
9672e2caf59SThomas Veerman int keywd = ParseFindKeyword(src);
9682e2caf59SThomas Veerman if (keywd != -1) {
9692e2caf59SThomas Veerman int op = parseKeywords[keywd].op;
9702e2caf59SThomas Veerman if (op != 0) {
9712e2caf59SThomas Veerman Lst_ForEach(targets, ParseDoOp, &op);
9722e2caf59SThomas Veerman return;
9732e2caf59SThomas Veerman }
9742e2caf59SThomas Veerman if (parseKeywords[keywd].spec == Wait) {
9752e2caf59SThomas Veerman /*
9762e2caf59SThomas Veerman * We add a .WAIT node in the dependency list.
9772e2caf59SThomas Veerman * After any dynamic dependencies (and filename globbing)
9782e2caf59SThomas Veerman * have happened, it is given a dependency on the each
9792e2caf59SThomas Veerman * previous child back to and previous .WAIT node.
9802e2caf59SThomas Veerman * The next child won't be scheduled until the .WAIT node
9812e2caf59SThomas Veerman * is built.
9822e2caf59SThomas Veerman * We give each .WAIT node a unique name (mainly for diag).
9832e2caf59SThomas Veerman */
9842e2caf59SThomas Veerman snprintf(wait_src, sizeof wait_src, ".WAIT_%u", ++wait_number);
9852e2caf59SThomas Veerman gn = Targ_FindNode(wait_src, TARG_NOHASH);
98684d9c625SLionel Sambuc if (doing_depend)
98784d9c625SLionel Sambuc ParseMark(gn);
9882e2caf59SThomas Veerman gn->type = OP_WAIT | OP_PHONY | OP_DEPENDS | OP_NOTMAIN;
9892e2caf59SThomas Veerman Lst_ForEach(targets, ParseLinkSrc, gn);
9902e2caf59SThomas Veerman return;
9912e2caf59SThomas Veerman }
9922e2caf59SThomas Veerman }
9932e2caf59SThomas Veerman }
9942e2caf59SThomas Veerman
9952e2caf59SThomas Veerman switch (specType) {
9962e2caf59SThomas Veerman case Main:
9972e2caf59SThomas Veerman /*
9982e2caf59SThomas Veerman * If we have noted the existence of a .MAIN, it means we need
9992e2caf59SThomas Veerman * to add the sources of said target to the list of things
10002e2caf59SThomas Veerman * to create. The string 'src' is likely to be free, so we
10012e2caf59SThomas Veerman * must make a new copy of it. Note that this will only be
10022e2caf59SThomas Veerman * invoked if the user didn't specify a target on the command
10032e2caf59SThomas Veerman * line. This is to allow #ifmake's to succeed, or something...
10042e2caf59SThomas Veerman */
10052e2caf59SThomas Veerman (void)Lst_AtEnd(create, bmake_strdup(src));
10062e2caf59SThomas Veerman /*
10072e2caf59SThomas Veerman * Add the name to the .TARGETS variable as well, so the user can
10082e2caf59SThomas Veerman * employ that, if desired.
10092e2caf59SThomas Veerman */
10102e2caf59SThomas Veerman Var_Append(".TARGETS", src, VAR_GLOBAL);
10112e2caf59SThomas Veerman return;
10122e2caf59SThomas Veerman
10132e2caf59SThomas Veerman case Order:
10142e2caf59SThomas Veerman /*
10152e2caf59SThomas Veerman * Create proper predecessor/successor links between the previous
10162e2caf59SThomas Veerman * source and the current one.
10172e2caf59SThomas Veerman */
10182e2caf59SThomas Veerman gn = Targ_FindNode(src, TARG_CREATE);
101984d9c625SLionel Sambuc if (doing_depend)
102084d9c625SLionel Sambuc ParseMark(gn);
10212e2caf59SThomas Veerman if (predecessor != NULL) {
10222e2caf59SThomas Veerman (void)Lst_AtEnd(predecessor->order_succ, gn);
10232e2caf59SThomas Veerman (void)Lst_AtEnd(gn->order_pred, predecessor);
10242e2caf59SThomas Veerman if (DEBUG(PARSE)) {
1025*0a6a1f1dSLionel Sambuc fprintf(debug_file, "# %s: added Order dependency %s - %s\n",
1026*0a6a1f1dSLionel Sambuc __func__, predecessor->name, gn->name);
10272e2caf59SThomas Veerman Targ_PrintNode(predecessor, 0);
10282e2caf59SThomas Veerman Targ_PrintNode(gn, 0);
10292e2caf59SThomas Veerman }
10302e2caf59SThomas Veerman }
10312e2caf59SThomas Veerman /*
10322e2caf59SThomas Veerman * The current source now becomes the predecessor for the next one.
10332e2caf59SThomas Veerman */
10342e2caf59SThomas Veerman predecessor = gn;
10352e2caf59SThomas Veerman break;
10362e2caf59SThomas Veerman
10372e2caf59SThomas Veerman default:
10382e2caf59SThomas Veerman /*
10392e2caf59SThomas Veerman * If the source is not an attribute, we need to find/create
10402e2caf59SThomas Veerman * a node for it. After that we can apply any operator to it
10412e2caf59SThomas Veerman * from a special target or link it to its parents, as
10422e2caf59SThomas Veerman * appropriate.
10432e2caf59SThomas Veerman *
10442e2caf59SThomas Veerman * In the case of a source that was the object of a :: operator,
10452e2caf59SThomas Veerman * the attribute is applied to all of its instances (as kept in
10462e2caf59SThomas Veerman * the 'cohorts' list of the node) or all the cohorts are linked
10472e2caf59SThomas Veerman * to all the targets.
10482e2caf59SThomas Veerman */
10492e2caf59SThomas Veerman
10502e2caf59SThomas Veerman /* Find/create the 'src' node and attach to all targets */
10512e2caf59SThomas Veerman gn = Targ_FindNode(src, TARG_CREATE);
105284d9c625SLionel Sambuc if (doing_depend)
105384d9c625SLionel Sambuc ParseMark(gn);
10542e2caf59SThomas Veerman if (tOp) {
10552e2caf59SThomas Veerman gn->type |= tOp;
10562e2caf59SThomas Veerman } else {
10572e2caf59SThomas Veerman Lst_ForEach(targets, ParseLinkSrc, gn);
10582e2caf59SThomas Veerman }
10592e2caf59SThomas Veerman break;
10602e2caf59SThomas Veerman }
10612e2caf59SThomas Veerman }
10622e2caf59SThomas Veerman
10632e2caf59SThomas Veerman /*-
10642e2caf59SThomas Veerman *-----------------------------------------------------------------------
10652e2caf59SThomas Veerman * ParseFindMain --
10662e2caf59SThomas Veerman * Find a real target in the list and set it to be the main one.
10672e2caf59SThomas Veerman * Called by ParseDoDependency when a main target hasn't been found
10682e2caf59SThomas Veerman * yet.
10692e2caf59SThomas Veerman *
10702e2caf59SThomas Veerman * Input:
10712e2caf59SThomas Veerman * gnp Node to examine
10722e2caf59SThomas Veerman *
10732e2caf59SThomas Veerman * Results:
10742e2caf59SThomas Veerman * 0 if main not found yet, 1 if it is.
10752e2caf59SThomas Veerman *
10762e2caf59SThomas Veerman * Side Effects:
10772e2caf59SThomas Veerman * mainNode is changed and Targ_SetMain is called.
10782e2caf59SThomas Veerman *
10792e2caf59SThomas Veerman *-----------------------------------------------------------------------
10802e2caf59SThomas Veerman */
10812e2caf59SThomas Veerman static int
ParseFindMain(void * gnp,void * dummy)10822e2caf59SThomas Veerman ParseFindMain(void *gnp, void *dummy)
10832e2caf59SThomas Veerman {
10842e2caf59SThomas Veerman GNode *gn = (GNode *)gnp;
10852e2caf59SThomas Veerman if ((gn->type & OP_NOTARGET) == 0) {
10862e2caf59SThomas Veerman mainNode = gn;
10872e2caf59SThomas Veerman Targ_SetMain(gn);
10882e2caf59SThomas Veerman return (dummy ? 1 : 1);
10892e2caf59SThomas Veerman } else {
10902e2caf59SThomas Veerman return (dummy ? 0 : 0);
10912e2caf59SThomas Veerman }
10922e2caf59SThomas Veerman }
10932e2caf59SThomas Veerman
10942e2caf59SThomas Veerman /*-
10952e2caf59SThomas Veerman *-----------------------------------------------------------------------
10962e2caf59SThomas Veerman * ParseAddDir --
10972e2caf59SThomas Veerman * Front-end for Dir_AddDir to make sure Lst_ForEach keeps going
10982e2caf59SThomas Veerman *
10992e2caf59SThomas Veerman * Results:
11002e2caf59SThomas Veerman * === 0
11012e2caf59SThomas Veerman *
11022e2caf59SThomas Veerman * Side Effects:
11032e2caf59SThomas Veerman * See Dir_AddDir.
11042e2caf59SThomas Veerman *
11052e2caf59SThomas Veerman *-----------------------------------------------------------------------
11062e2caf59SThomas Veerman */
11072e2caf59SThomas Veerman static int
ParseAddDir(void * path,void * name)11082e2caf59SThomas Veerman ParseAddDir(void *path, void *name)
11092e2caf59SThomas Veerman {
11102e2caf59SThomas Veerman (void)Dir_AddDir((Lst) path, (char *)name);
11112e2caf59SThomas Veerman return(0);
11122e2caf59SThomas Veerman }
11132e2caf59SThomas Veerman
11142e2caf59SThomas Veerman /*-
11152e2caf59SThomas Veerman *-----------------------------------------------------------------------
11162e2caf59SThomas Veerman * ParseClearPath --
11172e2caf59SThomas Veerman * Front-end for Dir_ClearPath to make sure Lst_ForEach keeps going
11182e2caf59SThomas Veerman *
11192e2caf59SThomas Veerman * Results:
11202e2caf59SThomas Veerman * === 0
11212e2caf59SThomas Veerman *
11222e2caf59SThomas Veerman * Side Effects:
11232e2caf59SThomas Veerman * See Dir_ClearPath
11242e2caf59SThomas Veerman *
11252e2caf59SThomas Veerman *-----------------------------------------------------------------------
11262e2caf59SThomas Veerman */
11272e2caf59SThomas Veerman static int
ParseClearPath(void * path,void * dummy)11282e2caf59SThomas Veerman ParseClearPath(void *path, void *dummy)
11292e2caf59SThomas Veerman {
11302e2caf59SThomas Veerman Dir_ClearPath((Lst) path);
11312e2caf59SThomas Veerman return(dummy ? 0 : 0);
11322e2caf59SThomas Veerman }
11332e2caf59SThomas Veerman
11342e2caf59SThomas Veerman /*-
11352e2caf59SThomas Veerman *---------------------------------------------------------------------
11362e2caf59SThomas Veerman * ParseDoDependency --
11372e2caf59SThomas Veerman * Parse the dependency line in line.
11382e2caf59SThomas Veerman *
11392e2caf59SThomas Veerman * Input:
11402e2caf59SThomas Veerman * line the line to parse
11412e2caf59SThomas Veerman *
11422e2caf59SThomas Veerman * Results:
11432e2caf59SThomas Veerman * None
11442e2caf59SThomas Veerman *
11452e2caf59SThomas Veerman * Side Effects:
11462e2caf59SThomas Veerman * The nodes of the sources are linked as children to the nodes of the
11472e2caf59SThomas Veerman * targets. Some nodes may be created.
11482e2caf59SThomas Veerman *
11492e2caf59SThomas Veerman * We parse a dependency line by first extracting words from the line and
11502e2caf59SThomas Veerman * finding nodes in the list of all targets with that name. This is done
11512e2caf59SThomas Veerman * until a character is encountered which is an operator character. Currently
11522e2caf59SThomas Veerman * these are only ! and :. At this point the operator is parsed and the
11532e2caf59SThomas Veerman * pointer into the line advanced until the first source is encountered.
11542e2caf59SThomas Veerman * The parsed operator is applied to each node in the 'targets' list,
11552e2caf59SThomas Veerman * which is where the nodes found for the targets are kept, by means of
11562e2caf59SThomas Veerman * the ParseDoOp function.
11572e2caf59SThomas Veerman * The sources are read in much the same way as the targets were except
11582e2caf59SThomas Veerman * that now they are expanded using the wildcarding scheme of the C-Shell
11592e2caf59SThomas Veerman * and all instances of the resulting words in the list of all targets
11602e2caf59SThomas Veerman * are found. Each of the resulting nodes is then linked to each of the
11612e2caf59SThomas Veerman * targets as one of its children.
11622e2caf59SThomas Veerman * Certain targets are handled specially. These are the ones detailed
11632e2caf59SThomas Veerman * by the specType variable.
11642e2caf59SThomas Veerman * The storing of transformation rules is also taken care of here.
11652e2caf59SThomas Veerman * A target is recognized as a transformation rule by calling
11662e2caf59SThomas Veerman * Suff_IsTransform. If it is a transformation rule, its node is gotten
11672e2caf59SThomas Veerman * from the suffix module via Suff_AddTransform rather than the standard
11682e2caf59SThomas Veerman * Targ_FindNode in the target module.
11692e2caf59SThomas Veerman *---------------------------------------------------------------------
11702e2caf59SThomas Veerman */
11712e2caf59SThomas Veerman static void
ParseDoDependency(char * line)11722e2caf59SThomas Veerman ParseDoDependency(char *line)
11732e2caf59SThomas Veerman {
11742e2caf59SThomas Veerman char *cp; /* our current position */
11752e2caf59SThomas Veerman GNode *gn = NULL; /* a general purpose temporary node */
11762e2caf59SThomas Veerman int op; /* the operator on the line */
11772e2caf59SThomas Veerman char savec; /* a place to save a character */
11782e2caf59SThomas Veerman Lst paths; /* List of search paths to alter when parsing
11792e2caf59SThomas Veerman * a list of .PATH targets */
11802e2caf59SThomas Veerman int tOp; /* operator from special target */
11812e2caf59SThomas Veerman Lst sources; /* list of archive source names after
11822e2caf59SThomas Veerman * expansion */
11832e2caf59SThomas Veerman Lst curTargs; /* list of target names to be found and added
11842e2caf59SThomas Veerman * to the targets list */
11852e2caf59SThomas Veerman char *lstart = line;
11862e2caf59SThomas Veerman
11872e2caf59SThomas Veerman if (DEBUG(PARSE))
11882e2caf59SThomas Veerman fprintf(debug_file, "ParseDoDependency(%s)\n", line);
11892e2caf59SThomas Veerman tOp = 0;
11902e2caf59SThomas Veerman
11912e2caf59SThomas Veerman specType = Not;
11922e2caf59SThomas Veerman paths = NULL;
11932e2caf59SThomas Veerman
11942e2caf59SThomas Veerman curTargs = Lst_Init(FALSE);
11952e2caf59SThomas Veerman
1196*0a6a1f1dSLionel Sambuc /*
1197*0a6a1f1dSLionel Sambuc * First, grind through the targets.
1198*0a6a1f1dSLionel Sambuc */
1199*0a6a1f1dSLionel Sambuc
12002e2caf59SThomas Veerman do {
1201*0a6a1f1dSLionel Sambuc /*
1202*0a6a1f1dSLionel Sambuc * Here LINE points to the beginning of the next word, and
1203*0a6a1f1dSLionel Sambuc * LSTART points to the actual beginning of the line.
1204*0a6a1f1dSLionel Sambuc */
1205*0a6a1f1dSLionel Sambuc
1206*0a6a1f1dSLionel Sambuc /* Find the end of the next word. */
12072e2caf59SThomas Veerman for (cp = line; *cp && (ParseIsEscaped(lstart, cp) ||
12082e2caf59SThomas Veerman !(isspace((unsigned char)*cp) ||
12092e2caf59SThomas Veerman *cp == '!' || *cp == ':' || *cp == LPAREN));
12102e2caf59SThomas Veerman cp++) {
12112e2caf59SThomas Veerman if (*cp == '$') {
12122e2caf59SThomas Veerman /*
12132e2caf59SThomas Veerman * Must be a dynamic source (would have been expanded
12142e2caf59SThomas Veerman * otherwise), so call the Var module to parse the puppy
12152e2caf59SThomas Veerman * so we can safely advance beyond it...There should be
12162e2caf59SThomas Veerman * no errors in this, as they would have been discovered
12172e2caf59SThomas Veerman * in the initial Var_Subst and we wouldn't be here.
12182e2caf59SThomas Veerman */
12192e2caf59SThomas Veerman int length;
12202e2caf59SThomas Veerman void *freeIt;
12212e2caf59SThomas Veerman
122284d9c625SLionel Sambuc (void)Var_Parse(cp, VAR_CMD, TRUE, &length, &freeIt);
12232e2caf59SThomas Veerman if (freeIt)
12242e2caf59SThomas Veerman free(freeIt);
12252e2caf59SThomas Veerman cp += length-1;
12262e2caf59SThomas Veerman }
12272e2caf59SThomas Veerman }
12282e2caf59SThomas Veerman
1229*0a6a1f1dSLionel Sambuc /*
1230*0a6a1f1dSLionel Sambuc * If the word is followed by a left parenthesis, it's the
1231*0a6a1f1dSLionel Sambuc * name of an object file inside an archive (ar file).
1232*0a6a1f1dSLionel Sambuc */
12332e2caf59SThomas Veerman if (!ParseIsEscaped(lstart, cp) && *cp == LPAREN) {
12342e2caf59SThomas Veerman /*
12352e2caf59SThomas Veerman * Archives must be handled specially to make sure the OP_ARCHV
12362e2caf59SThomas Veerman * flag is set in their 'type' field, for one thing, and because
12372e2caf59SThomas Veerman * things like "archive(file1.o file2.o file3.o)" are permissible.
12382e2caf59SThomas Veerman * Arch_ParseArchive will set 'line' to be the first non-blank
12392e2caf59SThomas Veerman * after the archive-spec. It creates/finds nodes for the members
12402e2caf59SThomas Veerman * and places them on the given list, returning SUCCESS if all
12412e2caf59SThomas Veerman * went well and FAILURE if there was an error in the
12422e2caf59SThomas Veerman * specification. On error, line should remain untouched.
12432e2caf59SThomas Veerman */
12442e2caf59SThomas Veerman if (Arch_ParseArchive(&line, targets, VAR_CMD) != SUCCESS) {
12452e2caf59SThomas Veerman Parse_Error(PARSE_FATAL,
12462e2caf59SThomas Veerman "Error in archive specification: \"%s\"", line);
12472e2caf59SThomas Veerman goto out;
12482e2caf59SThomas Veerman } else {
1249*0a6a1f1dSLionel Sambuc /* Done with this word; on to the next. */
12502e2caf59SThomas Veerman continue;
12512e2caf59SThomas Veerman }
12522e2caf59SThomas Veerman }
12532e2caf59SThomas Veerman
12542e2caf59SThomas Veerman if (!*cp) {
12552e2caf59SThomas Veerman /*
1256*0a6a1f1dSLionel Sambuc * We got to the end of the line while we were still
1257*0a6a1f1dSLionel Sambuc * looking at targets.
1258*0a6a1f1dSLionel Sambuc *
12592e2caf59SThomas Veerman * Ending a dependency line without an operator is a Bozo
12602e2caf59SThomas Veerman * no-no. As a heuristic, this is also often triggered by
12612e2caf59SThomas Veerman * undetected conflicts from cvs/rcs merges.
12622e2caf59SThomas Veerman */
12632e2caf59SThomas Veerman if ((strncmp(line, "<<<<<<", 6) == 0) ||
12642e2caf59SThomas Veerman (strncmp(line, "======", 6) == 0) ||
12652e2caf59SThomas Veerman (strncmp(line, ">>>>>>", 6) == 0))
12662e2caf59SThomas Veerman Parse_Error(PARSE_FATAL,
12672e2caf59SThomas Veerman "Makefile appears to contain unresolved cvs/rcs/??? merge conflicts");
12682e2caf59SThomas Veerman else
12692e2caf59SThomas Veerman Parse_Error(PARSE_FATAL, lstart[0] == '.' ? "Unknown directive"
12702e2caf59SThomas Veerman : "Need an operator");
12712e2caf59SThomas Veerman goto out;
12722e2caf59SThomas Veerman }
1273*0a6a1f1dSLionel Sambuc
1274*0a6a1f1dSLionel Sambuc /* Insert a null terminator. */
1275*0a6a1f1dSLionel Sambuc savec = *cp;
12762e2caf59SThomas Veerman *cp = '\0';
12772e2caf59SThomas Veerman
12782e2caf59SThomas Veerman /*
1279*0a6a1f1dSLionel Sambuc * Got the word. See if it's a special target and if so set
12802e2caf59SThomas Veerman * specType to match it.
12812e2caf59SThomas Veerman */
12822e2caf59SThomas Veerman if (*line == '.' && isupper ((unsigned char)line[1])) {
12832e2caf59SThomas Veerman /*
12842e2caf59SThomas Veerman * See if the target is a special target that must have it
12852e2caf59SThomas Veerman * or its sources handled specially.
12862e2caf59SThomas Veerman */
12872e2caf59SThomas Veerman int keywd = ParseFindKeyword(line);
12882e2caf59SThomas Veerman if (keywd != -1) {
12892e2caf59SThomas Veerman if (specType == ExPath && parseKeywords[keywd].spec != ExPath) {
12902e2caf59SThomas Veerman Parse_Error(PARSE_FATAL, "Mismatched special targets");
12912e2caf59SThomas Veerman goto out;
12922e2caf59SThomas Veerman }
12932e2caf59SThomas Veerman
12942e2caf59SThomas Veerman specType = parseKeywords[keywd].spec;
12952e2caf59SThomas Veerman tOp = parseKeywords[keywd].op;
12962e2caf59SThomas Veerman
12972e2caf59SThomas Veerman /*
12982e2caf59SThomas Veerman * Certain special targets have special semantics:
12992e2caf59SThomas Veerman * .PATH Have to set the dirSearchPath
13002e2caf59SThomas Veerman * variable too
13012e2caf59SThomas Veerman * .MAIN Its sources are only used if
13022e2caf59SThomas Veerman * nothing has been specified to
13032e2caf59SThomas Veerman * create.
13042e2caf59SThomas Veerman * .DEFAULT Need to create a node to hang
13052e2caf59SThomas Veerman * commands on, but we don't want
13062e2caf59SThomas Veerman * it in the graph, nor do we want
13072e2caf59SThomas Veerman * it to be the Main Target, so we
13082e2caf59SThomas Veerman * create it, set OP_NOTMAIN and
13092e2caf59SThomas Veerman * add it to the list, setting
13102e2caf59SThomas Veerman * DEFAULT to the new node for
13112e2caf59SThomas Veerman * later use. We claim the node is
13122e2caf59SThomas Veerman * A transformation rule to make
13132e2caf59SThomas Veerman * life easier later, when we'll
13142e2caf59SThomas Veerman * use Make_HandleUse to actually
13152e2caf59SThomas Veerman * apply the .DEFAULT commands.
13162e2caf59SThomas Veerman * .PHONY The list of targets
13172e2caf59SThomas Veerman * .NOPATH Don't search for file in the path
131884d9c625SLionel Sambuc * .STALE
13192e2caf59SThomas Veerman * .BEGIN
13202e2caf59SThomas Veerman * .END
13212e2caf59SThomas Veerman * .ERROR
13222e2caf59SThomas Veerman * .INTERRUPT Are not to be considered the
13232e2caf59SThomas Veerman * main target.
13242e2caf59SThomas Veerman * .NOTPARALLEL Make only one target at a time.
13252e2caf59SThomas Veerman * .SINGLESHELL Create a shell for each command.
13262e2caf59SThomas Veerman * .ORDER Must set initial predecessor to NULL
13272e2caf59SThomas Veerman */
13282e2caf59SThomas Veerman switch (specType) {
13292e2caf59SThomas Veerman case ExPath:
13302e2caf59SThomas Veerman if (paths == NULL) {
13312e2caf59SThomas Veerman paths = Lst_Init(FALSE);
13322e2caf59SThomas Veerman }
13332e2caf59SThomas Veerman (void)Lst_AtEnd(paths, dirSearchPath);
13342e2caf59SThomas Veerman break;
13352e2caf59SThomas Veerman case Main:
13362e2caf59SThomas Veerman if (!Lst_IsEmpty(create)) {
13372e2caf59SThomas Veerman specType = Not;
13382e2caf59SThomas Veerman }
13392e2caf59SThomas Veerman break;
13402e2caf59SThomas Veerman case Begin:
13412e2caf59SThomas Veerman case End:
134284d9c625SLionel Sambuc case Stale:
13432e2caf59SThomas Veerman case dotError:
13442e2caf59SThomas Veerman case Interrupt:
13452e2caf59SThomas Veerman gn = Targ_FindNode(line, TARG_CREATE);
134684d9c625SLionel Sambuc if (doing_depend)
134784d9c625SLionel Sambuc ParseMark(gn);
13482e2caf59SThomas Veerman gn->type |= OP_NOTMAIN|OP_SPECIAL;
13492e2caf59SThomas Veerman (void)Lst_AtEnd(targets, gn);
13502e2caf59SThomas Veerman break;
13512e2caf59SThomas Veerman case Default:
13522e2caf59SThomas Veerman gn = Targ_NewGN(".DEFAULT");
13532e2caf59SThomas Veerman gn->type |= (OP_NOTMAIN|OP_TRANSFORM);
13542e2caf59SThomas Veerman (void)Lst_AtEnd(targets, gn);
13552e2caf59SThomas Veerman DEFAULT = gn;
13562e2caf59SThomas Veerman break;
13572e2caf59SThomas Veerman case NotParallel:
13582e2caf59SThomas Veerman maxJobs = 1;
13592e2caf59SThomas Veerman break;
13602e2caf59SThomas Veerman case SingleShell:
13612e2caf59SThomas Veerman compatMake = TRUE;
13622e2caf59SThomas Veerman break;
13632e2caf59SThomas Veerman case Order:
13642e2caf59SThomas Veerman predecessor = NULL;
13652e2caf59SThomas Veerman break;
13662e2caf59SThomas Veerman default:
13672e2caf59SThomas Veerman break;
13682e2caf59SThomas Veerman }
13692e2caf59SThomas Veerman } else if (strncmp(line, ".PATH", 5) == 0) {
13702e2caf59SThomas Veerman /*
13712e2caf59SThomas Veerman * .PATH<suffix> has to be handled specially.
13722e2caf59SThomas Veerman * Call on the suffix module to give us a path to
13732e2caf59SThomas Veerman * modify.
13742e2caf59SThomas Veerman */
13752e2caf59SThomas Veerman Lst path;
13762e2caf59SThomas Veerman
13772e2caf59SThomas Veerman specType = ExPath;
13782e2caf59SThomas Veerman path = Suff_GetPath(&line[5]);
13792e2caf59SThomas Veerman if (path == NULL) {
13802e2caf59SThomas Veerman Parse_Error(PARSE_FATAL,
13812e2caf59SThomas Veerman "Suffix '%s' not defined (yet)",
13822e2caf59SThomas Veerman &line[5]);
13832e2caf59SThomas Veerman goto out;
13842e2caf59SThomas Veerman } else {
13852e2caf59SThomas Veerman if (paths == NULL) {
13862e2caf59SThomas Veerman paths = Lst_Init(FALSE);
13872e2caf59SThomas Veerman }
13882e2caf59SThomas Veerman (void)Lst_AtEnd(paths, path);
13892e2caf59SThomas Veerman }
13902e2caf59SThomas Veerman }
13912e2caf59SThomas Veerman }
13922e2caf59SThomas Veerman
13932e2caf59SThomas Veerman /*
13942e2caf59SThomas Veerman * Have word in line. Get or create its node and stick it at
13952e2caf59SThomas Veerman * the end of the targets list
13962e2caf59SThomas Veerman */
13972e2caf59SThomas Veerman if ((specType == Not) && (*line != '\0')) {
13982e2caf59SThomas Veerman if (Dir_HasWildcards(line)) {
13992e2caf59SThomas Veerman /*
14002e2caf59SThomas Veerman * Targets are to be sought only in the current directory,
14012e2caf59SThomas Veerman * so create an empty path for the thing. Note we need to
14022e2caf59SThomas Veerman * use Dir_Destroy in the destruction of the path as the
14032e2caf59SThomas Veerman * Dir module could have added a directory to the path...
14042e2caf59SThomas Veerman */
14052e2caf59SThomas Veerman Lst emptyPath = Lst_Init(FALSE);
14062e2caf59SThomas Veerman
14072e2caf59SThomas Veerman Dir_Expand(line, emptyPath, curTargs);
14082e2caf59SThomas Veerman
14092e2caf59SThomas Veerman Lst_Destroy(emptyPath, Dir_Destroy);
14102e2caf59SThomas Veerman } else {
14112e2caf59SThomas Veerman /*
14122e2caf59SThomas Veerman * No wildcards, but we want to avoid code duplication,
14132e2caf59SThomas Veerman * so create a list with the word on it.
14142e2caf59SThomas Veerman */
14152e2caf59SThomas Veerman (void)Lst_AtEnd(curTargs, line);
14162e2caf59SThomas Veerman }
14172e2caf59SThomas Veerman
1418*0a6a1f1dSLionel Sambuc /* Apply the targets. */
1419*0a6a1f1dSLionel Sambuc
14202e2caf59SThomas Veerman while(!Lst_IsEmpty(curTargs)) {
14212e2caf59SThomas Veerman char *targName = (char *)Lst_DeQueue(curTargs);
14222e2caf59SThomas Veerman
14232e2caf59SThomas Veerman if (!Suff_IsTransform (targName)) {
14242e2caf59SThomas Veerman gn = Targ_FindNode(targName, TARG_CREATE);
14252e2caf59SThomas Veerman } else {
14262e2caf59SThomas Veerman gn = Suff_AddTransform(targName);
14272e2caf59SThomas Veerman }
142884d9c625SLionel Sambuc if (doing_depend)
142984d9c625SLionel Sambuc ParseMark(gn);
14302e2caf59SThomas Veerman
14312e2caf59SThomas Veerman (void)Lst_AtEnd(targets, gn);
14322e2caf59SThomas Veerman }
14332e2caf59SThomas Veerman } else if (specType == ExPath && *line != '.' && *line != '\0') {
14342e2caf59SThomas Veerman Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line);
14352e2caf59SThomas Veerman }
14362e2caf59SThomas Veerman
1437*0a6a1f1dSLionel Sambuc /* Don't need the inserted null terminator any more. */
14382e2caf59SThomas Veerman *cp = savec;
1439*0a6a1f1dSLionel Sambuc
14402e2caf59SThomas Veerman /*
14412e2caf59SThomas Veerman * If it is a special type and not .PATH, it's the only target we
14422e2caf59SThomas Veerman * allow on this line...
14432e2caf59SThomas Veerman */
14442e2caf59SThomas Veerman if (specType != Not && specType != ExPath) {
14452e2caf59SThomas Veerman Boolean warning = FALSE;
14462e2caf59SThomas Veerman
14472e2caf59SThomas Veerman while (*cp && (ParseIsEscaped(lstart, cp) ||
14482e2caf59SThomas Veerman ((*cp != '!') && (*cp != ':')))) {
14492e2caf59SThomas Veerman if (ParseIsEscaped(lstart, cp) ||
14502e2caf59SThomas Veerman (*cp != ' ' && *cp != '\t')) {
14512e2caf59SThomas Veerman warning = TRUE;
14522e2caf59SThomas Veerman }
14532e2caf59SThomas Veerman cp++;
14542e2caf59SThomas Veerman }
14552e2caf59SThomas Veerman if (warning) {
14562e2caf59SThomas Veerman Parse_Error(PARSE_WARNING, "Extra target ignored");
14572e2caf59SThomas Veerman }
14582e2caf59SThomas Veerman } else {
14592e2caf59SThomas Veerman while (*cp && isspace ((unsigned char)*cp)) {
14602e2caf59SThomas Veerman cp++;
14612e2caf59SThomas Veerman }
14622e2caf59SThomas Veerman }
14632e2caf59SThomas Veerman line = cp;
14642e2caf59SThomas Veerman } while (*line && (ParseIsEscaped(lstart, line) ||
14652e2caf59SThomas Veerman ((*line != '!') && (*line != ':'))));
14662e2caf59SThomas Veerman
14672e2caf59SThomas Veerman /*
14682e2caf59SThomas Veerman * Don't need the list of target names anymore...
14692e2caf59SThomas Veerman */
14702e2caf59SThomas Veerman Lst_Destroy(curTargs, NULL);
14712e2caf59SThomas Veerman curTargs = NULL;
14722e2caf59SThomas Veerman
14732e2caf59SThomas Veerman if (!Lst_IsEmpty(targets)) {
14742e2caf59SThomas Veerman switch(specType) {
14752e2caf59SThomas Veerman default:
14762e2caf59SThomas Veerman Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. Mundane ones ignored");
14772e2caf59SThomas Veerman break;
14782e2caf59SThomas Veerman case Default:
147984d9c625SLionel Sambuc case Stale:
14802e2caf59SThomas Veerman case Begin:
14812e2caf59SThomas Veerman case End:
14822e2caf59SThomas Veerman case dotError:
14832e2caf59SThomas Veerman case Interrupt:
14842e2caf59SThomas Veerman /*
14852e2caf59SThomas Veerman * These four create nodes on which to hang commands, so
14862e2caf59SThomas Veerman * targets shouldn't be empty...
14872e2caf59SThomas Veerman */
14882e2caf59SThomas Veerman case Not:
14892e2caf59SThomas Veerman /*
14902e2caf59SThomas Veerman * Nothing special here -- targets can be empty if it wants.
14912e2caf59SThomas Veerman */
14922e2caf59SThomas Veerman break;
14932e2caf59SThomas Veerman }
14942e2caf59SThomas Veerman }
14952e2caf59SThomas Veerman
14962e2caf59SThomas Veerman /*
14972e2caf59SThomas Veerman * Have now parsed all the target names. Must parse the operator next. The
14982e2caf59SThomas Veerman * result is left in op .
14992e2caf59SThomas Veerman */
15002e2caf59SThomas Veerman if (*cp == '!') {
15012e2caf59SThomas Veerman op = OP_FORCE;
15022e2caf59SThomas Veerman } else if (*cp == ':') {
15032e2caf59SThomas Veerman if (cp[1] == ':') {
15042e2caf59SThomas Veerman op = OP_DOUBLEDEP;
15052e2caf59SThomas Veerman cp++;
15062e2caf59SThomas Veerman } else {
15072e2caf59SThomas Veerman op = OP_DEPENDS;
15082e2caf59SThomas Veerman }
15092e2caf59SThomas Veerman } else {
15102e2caf59SThomas Veerman Parse_Error(PARSE_FATAL, lstart[0] == '.' ? "Unknown directive"
15112e2caf59SThomas Veerman : "Missing dependency operator");
15122e2caf59SThomas Veerman goto out;
15132e2caf59SThomas Veerman }
15142e2caf59SThomas Veerman
1515*0a6a1f1dSLionel Sambuc /* Advance beyond the operator */
1516*0a6a1f1dSLionel Sambuc cp++;
15172e2caf59SThomas Veerman
1518*0a6a1f1dSLionel Sambuc /*
1519*0a6a1f1dSLionel Sambuc * Apply the operator to the target. This is how we remember which
1520*0a6a1f1dSLionel Sambuc * operator a target was defined with. It fails if the operator
1521*0a6a1f1dSLionel Sambuc * used isn't consistent across all references.
1522*0a6a1f1dSLionel Sambuc */
15232e2caf59SThomas Veerman Lst_ForEach(targets, ParseDoOp, &op);
15242e2caf59SThomas Veerman
15252e2caf59SThomas Veerman /*
1526*0a6a1f1dSLionel Sambuc * Onward to the sources.
1527*0a6a1f1dSLionel Sambuc *
1528*0a6a1f1dSLionel Sambuc * LINE will now point to the first source word, if any, or the
1529*0a6a1f1dSLionel Sambuc * end of the string if not.
15302e2caf59SThomas Veerman */
15312e2caf59SThomas Veerman while (*cp && isspace ((unsigned char)*cp)) {
15322e2caf59SThomas Veerman cp++;
15332e2caf59SThomas Veerman }
15342e2caf59SThomas Veerman line = cp;
15352e2caf59SThomas Veerman
15362e2caf59SThomas Veerman /*
15372e2caf59SThomas Veerman * Several special targets take different actions if present with no
15382e2caf59SThomas Veerman * sources:
15392e2caf59SThomas Veerman * a .SUFFIXES line with no sources clears out all old suffixes
15402e2caf59SThomas Veerman * a .PRECIOUS line makes all targets precious
15412e2caf59SThomas Veerman * a .IGNORE line ignores errors for all targets
15422e2caf59SThomas Veerman * a .SILENT line creates silence when making all targets
15432e2caf59SThomas Veerman * a .PATH removes all directories from the search path(s).
15442e2caf59SThomas Veerman */
15452e2caf59SThomas Veerman if (!*line) {
15462e2caf59SThomas Veerman switch (specType) {
15472e2caf59SThomas Veerman case Suffixes:
15482e2caf59SThomas Veerman Suff_ClearSuffixes();
15492e2caf59SThomas Veerman break;
15502e2caf59SThomas Veerman case Precious:
15512e2caf59SThomas Veerman allPrecious = TRUE;
15522e2caf59SThomas Veerman break;
15532e2caf59SThomas Veerman case Ignore:
15542e2caf59SThomas Veerman ignoreErrors = TRUE;
15552e2caf59SThomas Veerman break;
15562e2caf59SThomas Veerman case Silent:
15572e2caf59SThomas Veerman beSilent = TRUE;
15582e2caf59SThomas Veerman break;
15592e2caf59SThomas Veerman case ExPath:
15602e2caf59SThomas Veerman Lst_ForEach(paths, ParseClearPath, NULL);
15612e2caf59SThomas Veerman Dir_SetPATH();
15622e2caf59SThomas Veerman break;
15632e2caf59SThomas Veerman #ifdef POSIX
15642e2caf59SThomas Veerman case Posix:
15652e2caf59SThomas Veerman Var_Set("%POSIX", "1003.2", VAR_GLOBAL, 0);
15662e2caf59SThomas Veerman break;
15672e2caf59SThomas Veerman #endif
15682e2caf59SThomas Veerman default:
15692e2caf59SThomas Veerman break;
15702e2caf59SThomas Veerman }
15712e2caf59SThomas Veerman } else if (specType == MFlags) {
15722e2caf59SThomas Veerman /*
15732e2caf59SThomas Veerman * Call on functions in main.c to deal with these arguments and
15742e2caf59SThomas Veerman * set the initial character to a null-character so the loop to
15752e2caf59SThomas Veerman * get sources won't get anything
15762e2caf59SThomas Veerman */
15772e2caf59SThomas Veerman Main_ParseArgLine(line);
15782e2caf59SThomas Veerman *line = '\0';
15792e2caf59SThomas Veerman } else if (specType == ExShell) {
15802e2caf59SThomas Veerman if (Job_ParseShell(line) != SUCCESS) {
15812e2caf59SThomas Veerman Parse_Error(PARSE_FATAL, "improper shell specification");
15822e2caf59SThomas Veerman goto out;
15832e2caf59SThomas Veerman }
15842e2caf59SThomas Veerman *line = '\0';
15852e2caf59SThomas Veerman } else if ((specType == NotParallel) || (specType == SingleShell)) {
15862e2caf59SThomas Veerman *line = '\0';
15872e2caf59SThomas Veerman }
15882e2caf59SThomas Veerman
15892e2caf59SThomas Veerman /*
15902e2caf59SThomas Veerman * NOW GO FOR THE SOURCES
15912e2caf59SThomas Veerman */
15922e2caf59SThomas Veerman if ((specType == Suffixes) || (specType == ExPath) ||
15932e2caf59SThomas Veerman (specType == Includes) || (specType == Libs) ||
15942e2caf59SThomas Veerman (specType == Null) || (specType == ExObjdir))
15952e2caf59SThomas Veerman {
15962e2caf59SThomas Veerman while (*line) {
15972e2caf59SThomas Veerman /*
15982e2caf59SThomas Veerman * If the target was one that doesn't take files as its sources
15992e2caf59SThomas Veerman * but takes something like suffixes, we take each
16002e2caf59SThomas Veerman * space-separated word on the line as a something and deal
16012e2caf59SThomas Veerman * with it accordingly.
16022e2caf59SThomas Veerman *
16032e2caf59SThomas Veerman * If the target was .SUFFIXES, we take each source as a
16042e2caf59SThomas Veerman * suffix and add it to the list of suffixes maintained by the
16052e2caf59SThomas Veerman * Suff module.
16062e2caf59SThomas Veerman *
16072e2caf59SThomas Veerman * If the target was a .PATH, we add the source as a directory
16082e2caf59SThomas Veerman * to search on the search path.
16092e2caf59SThomas Veerman *
16102e2caf59SThomas Veerman * If it was .INCLUDES, the source is taken to be the suffix of
16112e2caf59SThomas Veerman * files which will be #included and whose search path should
16122e2caf59SThomas Veerman * be present in the .INCLUDES variable.
16132e2caf59SThomas Veerman *
16142e2caf59SThomas Veerman * If it was .LIBS, the source is taken to be the suffix of
16152e2caf59SThomas Veerman * files which are considered libraries and whose search path
16162e2caf59SThomas Veerman * should be present in the .LIBS variable.
16172e2caf59SThomas Veerman *
16182e2caf59SThomas Veerman * If it was .NULL, the source is the suffix to use when a file
16192e2caf59SThomas Veerman * has no valid suffix.
16202e2caf59SThomas Veerman *
16212e2caf59SThomas Veerman * If it was .OBJDIR, the source is a new definition for .OBJDIR,
16222e2caf59SThomas Veerman * and will cause make to do a new chdir to that path.
16232e2caf59SThomas Veerman */
16242e2caf59SThomas Veerman while (*cp && !isspace ((unsigned char)*cp)) {
16252e2caf59SThomas Veerman cp++;
16262e2caf59SThomas Veerman }
16272e2caf59SThomas Veerman savec = *cp;
16282e2caf59SThomas Veerman *cp = '\0';
16292e2caf59SThomas Veerman switch (specType) {
16302e2caf59SThomas Veerman case Suffixes:
16312e2caf59SThomas Veerman Suff_AddSuffix(line, &mainNode);
16322e2caf59SThomas Veerman break;
16332e2caf59SThomas Veerman case ExPath:
16342e2caf59SThomas Veerman Lst_ForEach(paths, ParseAddDir, line);
16352e2caf59SThomas Veerman break;
16362e2caf59SThomas Veerman case Includes:
16372e2caf59SThomas Veerman Suff_AddInclude(line);
16382e2caf59SThomas Veerman break;
16392e2caf59SThomas Veerman case Libs:
16402e2caf59SThomas Veerman Suff_AddLib(line);
16412e2caf59SThomas Veerman break;
16422e2caf59SThomas Veerman case Null:
16432e2caf59SThomas Veerman Suff_SetNull(line);
16442e2caf59SThomas Veerman break;
16452e2caf59SThomas Veerman case ExObjdir:
16462e2caf59SThomas Veerman Main_SetObjdir(line);
16472e2caf59SThomas Veerman break;
16482e2caf59SThomas Veerman default:
16492e2caf59SThomas Veerman break;
16502e2caf59SThomas Veerman }
16512e2caf59SThomas Veerman *cp = savec;
16522e2caf59SThomas Veerman if (savec != '\0') {
16532e2caf59SThomas Veerman cp++;
16542e2caf59SThomas Veerman }
16552e2caf59SThomas Veerman while (*cp && isspace ((unsigned char)*cp)) {
16562e2caf59SThomas Veerman cp++;
16572e2caf59SThomas Veerman }
16582e2caf59SThomas Veerman line = cp;
16592e2caf59SThomas Veerman }
16602e2caf59SThomas Veerman if (paths) {
16612e2caf59SThomas Veerman Lst_Destroy(paths, NULL);
16622e2caf59SThomas Veerman }
16632e2caf59SThomas Veerman if (specType == ExPath)
16642e2caf59SThomas Veerman Dir_SetPATH();
16652e2caf59SThomas Veerman } else {
16662e2caf59SThomas Veerman while (*line) {
16672e2caf59SThomas Veerman /*
16682e2caf59SThomas Veerman * The targets take real sources, so we must beware of archive
16692e2caf59SThomas Veerman * specifications (i.e. things with left parentheses in them)
16702e2caf59SThomas Veerman * and handle them accordingly.
16712e2caf59SThomas Veerman */
16722e2caf59SThomas Veerman for (; *cp && !isspace ((unsigned char)*cp); cp++) {
16732e2caf59SThomas Veerman if ((*cp == LPAREN) && (cp > line) && (cp[-1] != '$')) {
16742e2caf59SThomas Veerman /*
16752e2caf59SThomas Veerman * Only stop for a left parenthesis if it isn't at the
16762e2caf59SThomas Veerman * start of a word (that'll be for variable changes
16772e2caf59SThomas Veerman * later) and isn't preceded by a dollar sign (a dynamic
16782e2caf59SThomas Veerman * source).
16792e2caf59SThomas Veerman */
16802e2caf59SThomas Veerman break;
16812e2caf59SThomas Veerman }
16822e2caf59SThomas Veerman }
16832e2caf59SThomas Veerman
16842e2caf59SThomas Veerman if (*cp == LPAREN) {
16852e2caf59SThomas Veerman sources = Lst_Init(FALSE);
16862e2caf59SThomas Veerman if (Arch_ParseArchive(&line, sources, VAR_CMD) != SUCCESS) {
16872e2caf59SThomas Veerman Parse_Error(PARSE_FATAL,
16882e2caf59SThomas Veerman "Error in source archive spec \"%s\"", line);
16892e2caf59SThomas Veerman goto out;
16902e2caf59SThomas Veerman }
16912e2caf59SThomas Veerman
16922e2caf59SThomas Veerman while (!Lst_IsEmpty (sources)) {
16932e2caf59SThomas Veerman gn = (GNode *)Lst_DeQueue(sources);
16942e2caf59SThomas Veerman ParseDoSrc(tOp, gn->name);
16952e2caf59SThomas Veerman }
16962e2caf59SThomas Veerman Lst_Destroy(sources, NULL);
16972e2caf59SThomas Veerman cp = line;
16982e2caf59SThomas Veerman } else {
16992e2caf59SThomas Veerman if (*cp) {
17002e2caf59SThomas Veerman *cp = '\0';
17012e2caf59SThomas Veerman cp += 1;
17022e2caf59SThomas Veerman }
17032e2caf59SThomas Veerman
17042e2caf59SThomas Veerman ParseDoSrc(tOp, line);
17052e2caf59SThomas Veerman }
17062e2caf59SThomas Veerman while (*cp && isspace ((unsigned char)*cp)) {
17072e2caf59SThomas Veerman cp++;
17082e2caf59SThomas Veerman }
17092e2caf59SThomas Veerman line = cp;
17102e2caf59SThomas Veerman }
17112e2caf59SThomas Veerman }
17122e2caf59SThomas Veerman
17132e2caf59SThomas Veerman if (mainNode == NULL) {
17142e2caf59SThomas Veerman /*
17152e2caf59SThomas Veerman * If we have yet to decide on a main target to make, in the
17162e2caf59SThomas Veerman * absence of any user input, we want the first target on
17172e2caf59SThomas Veerman * the first dependency line that is actually a real target
17182e2caf59SThomas Veerman * (i.e. isn't a .USE or .EXEC rule) to be made.
17192e2caf59SThomas Veerman */
17202e2caf59SThomas Veerman Lst_ForEach(targets, ParseFindMain, NULL);
17212e2caf59SThomas Veerman }
17222e2caf59SThomas Veerman
17232e2caf59SThomas Veerman out:
17242e2caf59SThomas Veerman if (curTargs)
17252e2caf59SThomas Veerman Lst_Destroy(curTargs, NULL);
17262e2caf59SThomas Veerman }
17272e2caf59SThomas Veerman
17282e2caf59SThomas Veerman /*-
17292e2caf59SThomas Veerman *---------------------------------------------------------------------
17302e2caf59SThomas Veerman * Parse_IsVar --
17312e2caf59SThomas Veerman * Return TRUE if the passed line is a variable assignment. A variable
17322e2caf59SThomas Veerman * assignment consists of a single word followed by optional whitespace
17332e2caf59SThomas Veerman * followed by either a += or an = operator.
17342e2caf59SThomas Veerman * This function is used both by the Parse_File function and main when
17352e2caf59SThomas Veerman * parsing the command-line arguments.
17362e2caf59SThomas Veerman *
17372e2caf59SThomas Veerman * Input:
17382e2caf59SThomas Veerman * line the line to check
17392e2caf59SThomas Veerman *
17402e2caf59SThomas Veerman * Results:
17412e2caf59SThomas Veerman * TRUE if it is. FALSE if it ain't
17422e2caf59SThomas Veerman *
17432e2caf59SThomas Veerman * Side Effects:
17442e2caf59SThomas Veerman * none
17452e2caf59SThomas Veerman *---------------------------------------------------------------------
17462e2caf59SThomas Veerman */
17472e2caf59SThomas Veerman Boolean
Parse_IsVar(char * line)17482e2caf59SThomas Veerman Parse_IsVar(char *line)
17492e2caf59SThomas Veerman {
17502e2caf59SThomas Veerman Boolean wasSpace = FALSE; /* set TRUE if found a space */
17512e2caf59SThomas Veerman char ch;
17522e2caf59SThomas Veerman int level = 0;
17532e2caf59SThomas Veerman #define ISEQOPERATOR(c) \
17542e2caf59SThomas Veerman (((c) == '+') || ((c) == ':') || ((c) == '?') || ((c) == '!'))
17552e2caf59SThomas Veerman
17562e2caf59SThomas Veerman /*
17572e2caf59SThomas Veerman * Skip to variable name
17582e2caf59SThomas Veerman */
17592e2caf59SThomas Veerman for (;(*line == ' ') || (*line == '\t'); line++)
17602e2caf59SThomas Veerman continue;
17612e2caf59SThomas Veerman
17622e2caf59SThomas Veerman /* Scan for one of the assignment operators outside a variable expansion */
17632e2caf59SThomas Veerman while ((ch = *line++) != 0) {
17642e2caf59SThomas Veerman if (ch == '(' || ch == '{') {
17652e2caf59SThomas Veerman level++;
17662e2caf59SThomas Veerman continue;
17672e2caf59SThomas Veerman }
17682e2caf59SThomas Veerman if (ch == ')' || ch == '}') {
17692e2caf59SThomas Veerman level--;
17702e2caf59SThomas Veerman continue;
17712e2caf59SThomas Veerman }
17722e2caf59SThomas Veerman if (level != 0)
17732e2caf59SThomas Veerman continue;
17742e2caf59SThomas Veerman while (ch == ' ' || ch == '\t') {
17752e2caf59SThomas Veerman ch = *line++;
17762e2caf59SThomas Veerman wasSpace = TRUE;
17772e2caf59SThomas Veerman }
177884d9c625SLionel Sambuc #ifdef SUNSHCMD
177984d9c625SLionel Sambuc if (ch == ':' && strncmp(line, "sh", 2) == 0) {
178084d9c625SLionel Sambuc line += 2;
178184d9c625SLionel Sambuc continue;
178284d9c625SLionel Sambuc }
178384d9c625SLionel Sambuc #endif
17842e2caf59SThomas Veerman if (ch == '=')
17852e2caf59SThomas Veerman return TRUE;
17862e2caf59SThomas Veerman if (*line == '=' && ISEQOPERATOR(ch))
17872e2caf59SThomas Veerman return TRUE;
17882e2caf59SThomas Veerman if (wasSpace)
17892e2caf59SThomas Veerman return FALSE;
17902e2caf59SThomas Veerman }
17912e2caf59SThomas Veerman
17922e2caf59SThomas Veerman return FALSE;
17932e2caf59SThomas Veerman }
17942e2caf59SThomas Veerman
17952e2caf59SThomas Veerman /*-
17962e2caf59SThomas Veerman *---------------------------------------------------------------------
17972e2caf59SThomas Veerman * Parse_DoVar --
17982e2caf59SThomas Veerman * Take the variable assignment in the passed line and do it in the
17992e2caf59SThomas Veerman * global context.
18002e2caf59SThomas Veerman *
18012e2caf59SThomas Veerman * Note: There is a lexical ambiguity with assignment modifier characters
18022e2caf59SThomas Veerman * in variable names. This routine interprets the character before the =
18032e2caf59SThomas Veerman * as a modifier. Therefore, an assignment like
18042e2caf59SThomas Veerman * C++=/usr/bin/CC
18052e2caf59SThomas Veerman * is interpreted as "C+ +=" instead of "C++ =".
18062e2caf59SThomas Veerman *
18072e2caf59SThomas Veerman * Input:
18082e2caf59SThomas Veerman * line a line guaranteed to be a variable assignment.
18092e2caf59SThomas Veerman * This reduces error checks
18102e2caf59SThomas Veerman * ctxt Context in which to do the assignment
18112e2caf59SThomas Veerman *
18122e2caf59SThomas Veerman * Results:
18132e2caf59SThomas Veerman * none
18142e2caf59SThomas Veerman *
18152e2caf59SThomas Veerman * Side Effects:
18162e2caf59SThomas Veerman * the variable structure of the given variable name is altered in the
18172e2caf59SThomas Veerman * global context.
18182e2caf59SThomas Veerman *---------------------------------------------------------------------
18192e2caf59SThomas Veerman */
18202e2caf59SThomas Veerman void
Parse_DoVar(char * line,GNode * ctxt)18212e2caf59SThomas Veerman Parse_DoVar(char *line, GNode *ctxt)
18222e2caf59SThomas Veerman {
18232e2caf59SThomas Veerman char *cp; /* pointer into line */
18242e2caf59SThomas Veerman enum {
18252e2caf59SThomas Veerman VAR_SUBST, VAR_APPEND, VAR_SHELL, VAR_NORMAL
18262e2caf59SThomas Veerman } type; /* Type of assignment */
18272e2caf59SThomas Veerman char *opc; /* ptr to operator character to
18282e2caf59SThomas Veerman * null-terminate the variable name */
18292e2caf59SThomas Veerman Boolean freeCp = FALSE; /* TRUE if cp needs to be freed,
18302e2caf59SThomas Veerman * i.e. if any variable expansion was
18312e2caf59SThomas Veerman * performed */
18322e2caf59SThomas Veerman int depth;
18332e2caf59SThomas Veerman
18342e2caf59SThomas Veerman /*
18352e2caf59SThomas Veerman * Skip to variable name
18362e2caf59SThomas Veerman */
18372e2caf59SThomas Veerman while ((*line == ' ') || (*line == '\t')) {
18382e2caf59SThomas Veerman line++;
18392e2caf59SThomas Veerman }
18402e2caf59SThomas Veerman
18412e2caf59SThomas Veerman /*
18422e2caf59SThomas Veerman * Skip to operator character, nulling out whitespace as we go
18432e2caf59SThomas Veerman * XXX Rather than counting () and {} we should look for $ and
18442e2caf59SThomas Veerman * then expand the variable.
18452e2caf59SThomas Veerman */
18462e2caf59SThomas Veerman for (depth = 0, cp = line + 1; depth != 0 || *cp != '='; cp++) {
18472e2caf59SThomas Veerman if (*cp == '(' || *cp == '{') {
18482e2caf59SThomas Veerman depth++;
18492e2caf59SThomas Veerman continue;
18502e2caf59SThomas Veerman }
18512e2caf59SThomas Veerman if (*cp == ')' || *cp == '}') {
18522e2caf59SThomas Veerman depth--;
18532e2caf59SThomas Veerman continue;
18542e2caf59SThomas Veerman }
18552e2caf59SThomas Veerman if (depth == 0 && isspace ((unsigned char)*cp)) {
18562e2caf59SThomas Veerman *cp = '\0';
18572e2caf59SThomas Veerman }
18582e2caf59SThomas Veerman }
18592e2caf59SThomas Veerman opc = cp-1; /* operator is the previous character */
18602e2caf59SThomas Veerman *cp++ = '\0'; /* nuke the = */
18612e2caf59SThomas Veerman
18622e2caf59SThomas Veerman /*
18632e2caf59SThomas Veerman * Check operator type
18642e2caf59SThomas Veerman */
18652e2caf59SThomas Veerman switch (*opc) {
18662e2caf59SThomas Veerman case '+':
18672e2caf59SThomas Veerman type = VAR_APPEND;
18682e2caf59SThomas Veerman *opc = '\0';
18692e2caf59SThomas Veerman break;
18702e2caf59SThomas Veerman
18712e2caf59SThomas Veerman case '?':
18722e2caf59SThomas Veerman /*
18732e2caf59SThomas Veerman * If the variable already has a value, we don't do anything.
18742e2caf59SThomas Veerman */
18752e2caf59SThomas Veerman *opc = '\0';
18762e2caf59SThomas Veerman if (Var_Exists(line, ctxt)) {
18772e2caf59SThomas Veerman return;
18782e2caf59SThomas Veerman } else {
18792e2caf59SThomas Veerman type = VAR_NORMAL;
18802e2caf59SThomas Veerman }
18812e2caf59SThomas Veerman break;
18822e2caf59SThomas Veerman
18832e2caf59SThomas Veerman case ':':
18842e2caf59SThomas Veerman type = VAR_SUBST;
18852e2caf59SThomas Veerman *opc = '\0';
18862e2caf59SThomas Veerman break;
18872e2caf59SThomas Veerman
18882e2caf59SThomas Veerman case '!':
18892e2caf59SThomas Veerman type = VAR_SHELL;
18902e2caf59SThomas Veerman *opc = '\0';
18912e2caf59SThomas Veerman break;
18922e2caf59SThomas Veerman
18932e2caf59SThomas Veerman default:
18942e2caf59SThomas Veerman #ifdef SUNSHCMD
18952e2caf59SThomas Veerman while (opc > line && *opc != ':')
18962e2caf59SThomas Veerman opc--;
18972e2caf59SThomas Veerman
18982e2caf59SThomas Veerman if (strncmp(opc, ":sh", 3) == 0) {
18992e2caf59SThomas Veerman type = VAR_SHELL;
19002e2caf59SThomas Veerman *opc = '\0';
19012e2caf59SThomas Veerman break;
19022e2caf59SThomas Veerman }
19032e2caf59SThomas Veerman #endif
19042e2caf59SThomas Veerman type = VAR_NORMAL;
19052e2caf59SThomas Veerman break;
19062e2caf59SThomas Veerman }
19072e2caf59SThomas Veerman
19082e2caf59SThomas Veerman while (isspace ((unsigned char)*cp)) {
19092e2caf59SThomas Veerman cp++;
19102e2caf59SThomas Veerman }
19112e2caf59SThomas Veerman
19122e2caf59SThomas Veerman if (type == VAR_APPEND) {
19132e2caf59SThomas Veerman Var_Append(line, cp, ctxt);
19142e2caf59SThomas Veerman } else if (type == VAR_SUBST) {
19152e2caf59SThomas Veerman /*
19162e2caf59SThomas Veerman * Allow variables in the old value to be undefined, but leave their
19172e2caf59SThomas Veerman * invocation alone -- this is done by forcing oldVars to be false.
19182e2caf59SThomas Veerman * XXX: This can cause recursive variables, but that's not hard to do,
19192e2caf59SThomas Veerman * and this allows someone to do something like
19202e2caf59SThomas Veerman *
19212e2caf59SThomas Veerman * CFLAGS = $(.INCLUDES)
19222e2caf59SThomas Veerman * CFLAGS := -I.. $(CFLAGS)
19232e2caf59SThomas Veerman *
19242e2caf59SThomas Veerman * And not get an error.
19252e2caf59SThomas Veerman */
19262e2caf59SThomas Veerman Boolean oldOldVars = oldVars;
19272e2caf59SThomas Veerman
19282e2caf59SThomas Veerman oldVars = FALSE;
19292e2caf59SThomas Veerman
19302e2caf59SThomas Veerman /*
19312e2caf59SThomas Veerman * make sure that we set the variable the first time to nothing
19322e2caf59SThomas Veerman * so that it gets substituted!
19332e2caf59SThomas Veerman */
19342e2caf59SThomas Veerman if (!Var_Exists(line, ctxt))
19352e2caf59SThomas Veerman Var_Set(line, "", ctxt, 0);
19362e2caf59SThomas Veerman
19372e2caf59SThomas Veerman cp = Var_Subst(NULL, cp, ctxt, FALSE);
19382e2caf59SThomas Veerman oldVars = oldOldVars;
19392e2caf59SThomas Veerman freeCp = TRUE;
19402e2caf59SThomas Veerman
19412e2caf59SThomas Veerman Var_Set(line, cp, ctxt, 0);
19422e2caf59SThomas Veerman } else if (type == VAR_SHELL) {
19432e2caf59SThomas Veerman char *res;
19442e2caf59SThomas Veerman const char *error;
19452e2caf59SThomas Veerman
19462e2caf59SThomas Veerman if (strchr(cp, '$') != NULL) {
19472e2caf59SThomas Veerman /*
19482e2caf59SThomas Veerman * There's a dollar sign in the command, so perform variable
19492e2caf59SThomas Veerman * expansion on the whole thing. The resulting string will need
19502e2caf59SThomas Veerman * freeing when we're done, so set freeCmd to TRUE.
19512e2caf59SThomas Veerman */
19522e2caf59SThomas Veerman cp = Var_Subst(NULL, cp, VAR_CMD, TRUE);
19532e2caf59SThomas Veerman freeCp = TRUE;
19542e2caf59SThomas Veerman }
19552e2caf59SThomas Veerman
19562e2caf59SThomas Veerman res = Cmd_Exec(cp, &error);
19572e2caf59SThomas Veerman Var_Set(line, res, ctxt, 0);
19582e2caf59SThomas Veerman free(res);
19592e2caf59SThomas Veerman
19602e2caf59SThomas Veerman if (error)
19612e2caf59SThomas Veerman Parse_Error(PARSE_WARNING, error, cp);
19622e2caf59SThomas Veerman } else {
19632e2caf59SThomas Veerman /*
19642e2caf59SThomas Veerman * Normal assignment -- just do it.
19652e2caf59SThomas Veerman */
19662e2caf59SThomas Veerman Var_Set(line, cp, ctxt, 0);
19672e2caf59SThomas Veerman }
19682e2caf59SThomas Veerman if (strcmp(line, MAKEOVERRIDES) == 0)
19692e2caf59SThomas Veerman Main_ExportMAKEFLAGS(FALSE); /* re-export MAKEFLAGS */
19702e2caf59SThomas Veerman else if (strcmp(line, ".CURDIR") == 0) {
19712e2caf59SThomas Veerman /*
19722e2caf59SThomas Veerman * Somone is being (too?) clever...
19732e2caf59SThomas Veerman * Let's pretend they know what they are doing and
19742e2caf59SThomas Veerman * re-initialize the 'cur' Path.
19752e2caf59SThomas Veerman */
19762e2caf59SThomas Veerman Dir_InitCur(cp);
19772e2caf59SThomas Veerman Dir_SetPATH();
19782e2caf59SThomas Veerman } else if (strcmp(line, MAKE_JOB_PREFIX) == 0) {
19792e2caf59SThomas Veerman Job_SetPrefix();
19802e2caf59SThomas Veerman } else if (strcmp(line, MAKE_EXPORTED) == 0) {
19812e2caf59SThomas Veerman Var_Export(cp, 0);
19822e2caf59SThomas Veerman }
19832e2caf59SThomas Veerman if (freeCp)
19842e2caf59SThomas Veerman free(cp);
19852e2caf59SThomas Veerman }
19862e2caf59SThomas Veerman
19872e2caf59SThomas Veerman
1988*0a6a1f1dSLionel Sambuc /*
1989*0a6a1f1dSLionel Sambuc * ParseMaybeSubMake --
1990*0a6a1f1dSLionel Sambuc * Scan the command string to see if it a possible submake node
1991*0a6a1f1dSLionel Sambuc * Input:
1992*0a6a1f1dSLionel Sambuc * cmd the command to scan
1993*0a6a1f1dSLionel Sambuc * Results:
1994*0a6a1f1dSLionel Sambuc * TRUE if the command is possibly a submake, FALSE if not.
1995*0a6a1f1dSLionel Sambuc */
1996*0a6a1f1dSLionel Sambuc static Boolean
ParseMaybeSubMake(const char * cmd)1997*0a6a1f1dSLionel Sambuc ParseMaybeSubMake(const char *cmd)
1998*0a6a1f1dSLionel Sambuc {
1999*0a6a1f1dSLionel Sambuc size_t i;
2000*0a6a1f1dSLionel Sambuc static struct {
2001*0a6a1f1dSLionel Sambuc const char *name;
2002*0a6a1f1dSLionel Sambuc size_t len;
2003*0a6a1f1dSLionel Sambuc } vals[] = {
2004*0a6a1f1dSLionel Sambuc #define MKV(A) { A, sizeof(A) - 1 }
2005*0a6a1f1dSLionel Sambuc MKV("${MAKE}"),
2006*0a6a1f1dSLionel Sambuc MKV("${.MAKE}"),
2007*0a6a1f1dSLionel Sambuc MKV("$(MAKE)"),
2008*0a6a1f1dSLionel Sambuc MKV("$(.MAKE)"),
2009*0a6a1f1dSLionel Sambuc MKV("make"),
2010*0a6a1f1dSLionel Sambuc };
2011*0a6a1f1dSLionel Sambuc for (i = 0; i < sizeof(vals)/sizeof(vals[0]); i++) {
2012*0a6a1f1dSLionel Sambuc char *ptr;
2013*0a6a1f1dSLionel Sambuc if ((ptr = strstr(cmd, vals[i].name)) == NULL)
2014*0a6a1f1dSLionel Sambuc continue;
2015*0a6a1f1dSLionel Sambuc if ((ptr == cmd || !isalnum((unsigned char)ptr[-1]))
2016*0a6a1f1dSLionel Sambuc && !isalnum((unsigned char)ptr[vals[i].len]))
2017*0a6a1f1dSLionel Sambuc return TRUE;
2018*0a6a1f1dSLionel Sambuc }
2019*0a6a1f1dSLionel Sambuc return FALSE;
2020*0a6a1f1dSLionel Sambuc }
2021*0a6a1f1dSLionel Sambuc
20222e2caf59SThomas Veerman /*-
20232e2caf59SThomas Veerman * ParseAddCmd --
20242e2caf59SThomas Veerman * Lst_ForEach function to add a command line to all targets
20252e2caf59SThomas Veerman *
20262e2caf59SThomas Veerman * Input:
20272e2caf59SThomas Veerman * gnp the node to which the command is to be added
20282e2caf59SThomas Veerman * cmd the command to add
20292e2caf59SThomas Veerman *
20302e2caf59SThomas Veerman * Results:
20312e2caf59SThomas Veerman * Always 0
20322e2caf59SThomas Veerman *
20332e2caf59SThomas Veerman * Side Effects:
2034*0a6a1f1dSLionel Sambuc * A new element is added to the commands list of the node,
2035*0a6a1f1dSLionel Sambuc * and the node can be marked as a submake node if the command is
2036*0a6a1f1dSLionel Sambuc * determined to be that.
20372e2caf59SThomas Veerman */
20382e2caf59SThomas Veerman static int
ParseAddCmd(void * gnp,void * cmd)20392e2caf59SThomas Veerman ParseAddCmd(void *gnp, void *cmd)
20402e2caf59SThomas Veerman {
20412e2caf59SThomas Veerman GNode *gn = (GNode *)gnp;
20422e2caf59SThomas Veerman
20432e2caf59SThomas Veerman /* Add to last (ie current) cohort for :: targets */
20442e2caf59SThomas Veerman if ((gn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (gn->cohorts))
20452e2caf59SThomas Veerman gn = (GNode *)Lst_Datum(Lst_Last(gn->cohorts));
20462e2caf59SThomas Veerman
20472e2caf59SThomas Veerman /* if target already supplied, ignore commands */
20482e2caf59SThomas Veerman if (!(gn->type & OP_HAS_COMMANDS)) {
20492e2caf59SThomas Veerman (void)Lst_AtEnd(gn->commands, cmd);
2050*0a6a1f1dSLionel Sambuc if (ParseMaybeSubMake(cmd))
2051*0a6a1f1dSLionel Sambuc gn->type |= OP_SUBMAKE;
20522e2caf59SThomas Veerman ParseMark(gn);
20532e2caf59SThomas Veerman } else {
20542e2caf59SThomas Veerman #ifdef notyet
20552e2caf59SThomas Veerman /* XXX: We cannot do this until we fix the tree */
20562e2caf59SThomas Veerman (void)Lst_AtEnd(gn->commands, cmd);
20572e2caf59SThomas Veerman Parse_Error(PARSE_WARNING,
20582e2caf59SThomas Veerman "overriding commands for target \"%s\"; "
20592e2caf59SThomas Veerman "previous commands defined at %s: %d ignored",
20602e2caf59SThomas Veerman gn->name, gn->fname, gn->lineno);
20612e2caf59SThomas Veerman #else
20622e2caf59SThomas Veerman Parse_Error(PARSE_WARNING,
20632e2caf59SThomas Veerman "duplicate script for target \"%s\" ignored",
20642e2caf59SThomas Veerman gn->name);
20652e2caf59SThomas Veerman ParseErrorInternal(gn->fname, gn->lineno, PARSE_WARNING,
20662e2caf59SThomas Veerman "using previous script for \"%s\" defined here",
20672e2caf59SThomas Veerman gn->name);
20682e2caf59SThomas Veerman #endif
20692e2caf59SThomas Veerman }
20702e2caf59SThomas Veerman return(0);
20712e2caf59SThomas Veerman }
20722e2caf59SThomas Veerman
20732e2caf59SThomas Veerman /*-
20742e2caf59SThomas Veerman *-----------------------------------------------------------------------
20752e2caf59SThomas Veerman * ParseHasCommands --
20762e2caf59SThomas Veerman * Callback procedure for Parse_File when destroying the list of
20772e2caf59SThomas Veerman * targets on the last dependency line. Marks a target as already
20782e2caf59SThomas Veerman * having commands if it does, to keep from having shell commands
20792e2caf59SThomas Veerman * on multiple dependency lines.
20802e2caf59SThomas Veerman *
20812e2caf59SThomas Veerman * Input:
20822e2caf59SThomas Veerman * gnp Node to examine
20832e2caf59SThomas Veerman *
20842e2caf59SThomas Veerman * Results:
20852e2caf59SThomas Veerman * None
20862e2caf59SThomas Veerman *
20872e2caf59SThomas Veerman * Side Effects:
20882e2caf59SThomas Veerman * OP_HAS_COMMANDS may be set for the target.
20892e2caf59SThomas Veerman *
20902e2caf59SThomas Veerman *-----------------------------------------------------------------------
20912e2caf59SThomas Veerman */
20922e2caf59SThomas Veerman static void
ParseHasCommands(void * gnp)20932e2caf59SThomas Veerman ParseHasCommands(void *gnp)
20942e2caf59SThomas Veerman {
20952e2caf59SThomas Veerman GNode *gn = (GNode *)gnp;
20962e2caf59SThomas Veerman if (!Lst_IsEmpty(gn->commands)) {
20972e2caf59SThomas Veerman gn->type |= OP_HAS_COMMANDS;
20982e2caf59SThomas Veerman }
20992e2caf59SThomas Veerman }
21002e2caf59SThomas Veerman
21012e2caf59SThomas Veerman /*-
21022e2caf59SThomas Veerman *-----------------------------------------------------------------------
21032e2caf59SThomas Veerman * Parse_AddIncludeDir --
21042e2caf59SThomas Veerman * Add a directory to the path searched for included makefiles
21052e2caf59SThomas Veerman * bracketed by double-quotes. Used by functions in main.c
21062e2caf59SThomas Veerman *
21072e2caf59SThomas Veerman * Input:
21082e2caf59SThomas Veerman * dir The name of the directory to add
21092e2caf59SThomas Veerman *
21102e2caf59SThomas Veerman * Results:
21112e2caf59SThomas Veerman * None.
21122e2caf59SThomas Veerman *
21132e2caf59SThomas Veerman * Side Effects:
21142e2caf59SThomas Veerman * The directory is appended to the list.
21152e2caf59SThomas Veerman *
21162e2caf59SThomas Veerman *-----------------------------------------------------------------------
21172e2caf59SThomas Veerman */
21182e2caf59SThomas Veerman void
Parse_AddIncludeDir(char * dir)21192e2caf59SThomas Veerman Parse_AddIncludeDir(char *dir)
21202e2caf59SThomas Veerman {
21212e2caf59SThomas Veerman (void)Dir_AddDir(parseIncPath, dir);
21222e2caf59SThomas Veerman }
21232e2caf59SThomas Veerman
21242e2caf59SThomas Veerman /*-
21252e2caf59SThomas Veerman *---------------------------------------------------------------------
21262e2caf59SThomas Veerman * ParseDoInclude --
21272e2caf59SThomas Veerman * Push to another file.
21282e2caf59SThomas Veerman *
21292e2caf59SThomas Veerman * The input is the line minus the `.'. A file spec is a string
21302e2caf59SThomas Veerman * enclosed in <> or "". The former is looked for only in sysIncPath.
21312e2caf59SThomas Veerman * The latter in . and the directories specified by -I command line
21322e2caf59SThomas Veerman * options
21332e2caf59SThomas Veerman *
21342e2caf59SThomas Veerman * Results:
21352e2caf59SThomas Veerman * None
21362e2caf59SThomas Veerman *
21372e2caf59SThomas Veerman * Side Effects:
21382e2caf59SThomas Veerman * A structure is added to the includes Lst and readProc, lineno,
21392e2caf59SThomas Veerman * fname and curFILE are altered for the new file
21402e2caf59SThomas Veerman *---------------------------------------------------------------------
21412e2caf59SThomas Veerman */
21422e2caf59SThomas Veerman
21432e2caf59SThomas Veerman static void
Parse_include_file(char * file,Boolean isSystem,int silent)21442e2caf59SThomas Veerman Parse_include_file(char *file, Boolean isSystem, int silent)
21452e2caf59SThomas Veerman {
21462e2caf59SThomas Veerman struct loadedfile *lf;
21472e2caf59SThomas Veerman char *fullname; /* full pathname of file */
21482e2caf59SThomas Veerman char *newName;
21492e2caf59SThomas Veerman char *prefEnd, *incdir;
21502e2caf59SThomas Veerman int fd;
21512e2caf59SThomas Veerman int i;
21522e2caf59SThomas Veerman
21532e2caf59SThomas Veerman /*
21542e2caf59SThomas Veerman * Now we know the file's name and its search path, we attempt to
21552e2caf59SThomas Veerman * find the durn thing. A return of NULL indicates the file don't
21562e2caf59SThomas Veerman * exist.
21572e2caf59SThomas Veerman */
21582e2caf59SThomas Veerman fullname = file[0] == '/' ? bmake_strdup(file) : NULL;
21592e2caf59SThomas Veerman
21602e2caf59SThomas Veerman if (fullname == NULL && !isSystem) {
21612e2caf59SThomas Veerman /*
21622e2caf59SThomas Veerman * Include files contained in double-quotes are first searched for
21632e2caf59SThomas Veerman * relative to the including file's location. We don't want to
21642e2caf59SThomas Veerman * cd there, of course, so we just tack on the old file's
21652e2caf59SThomas Veerman * leading path components and call Dir_FindFile to see if
21662e2caf59SThomas Veerman * we can locate the beast.
21672e2caf59SThomas Veerman */
21682e2caf59SThomas Veerman
21692e2caf59SThomas Veerman incdir = bmake_strdup(curFile->fname);
21702e2caf59SThomas Veerman prefEnd = strrchr(incdir, '/');
21712e2caf59SThomas Veerman if (prefEnd != NULL) {
21722e2caf59SThomas Veerman *prefEnd = '\0';
21732e2caf59SThomas Veerman /* Now do lexical processing of leading "../" on the filename */
21742e2caf59SThomas Veerman for (i = 0; strncmp(file + i, "../", 3) == 0; i += 3) {
21752e2caf59SThomas Veerman prefEnd = strrchr(incdir + 1, '/');
21762e2caf59SThomas Veerman if (prefEnd == NULL || strcmp(prefEnd, "/..") == 0)
21772e2caf59SThomas Veerman break;
21782e2caf59SThomas Veerman *prefEnd = '\0';
21792e2caf59SThomas Veerman }
21802e2caf59SThomas Veerman newName = str_concat(incdir, file + i, STR_ADDSLASH);
21812e2caf59SThomas Veerman fullname = Dir_FindFile(newName, parseIncPath);
21822e2caf59SThomas Veerman if (fullname == NULL)
21832e2caf59SThomas Veerman fullname = Dir_FindFile(newName, dirSearchPath);
21842e2caf59SThomas Veerman free(newName);
21852e2caf59SThomas Veerman }
21862e2caf59SThomas Veerman free(incdir);
21872e2caf59SThomas Veerman
21882e2caf59SThomas Veerman if (fullname == NULL) {
21892e2caf59SThomas Veerman /*
21902e2caf59SThomas Veerman * Makefile wasn't found in same directory as included makefile.
21912e2caf59SThomas Veerman * Search for it first on the -I search path,
21922e2caf59SThomas Veerman * then on the .PATH search path, if not found in a -I directory.
21932e2caf59SThomas Veerman * If we have a suffix specific path we should use that.
21942e2caf59SThomas Veerman */
21952e2caf59SThomas Veerman char *suff;
21962e2caf59SThomas Veerman Lst suffPath = NULL;
21972e2caf59SThomas Veerman
21982e2caf59SThomas Veerman if ((suff = strrchr(file, '.'))) {
21992e2caf59SThomas Veerman suffPath = Suff_GetPath(suff);
22002e2caf59SThomas Veerman if (suffPath != NULL) {
22012e2caf59SThomas Veerman fullname = Dir_FindFile(file, suffPath);
22022e2caf59SThomas Veerman }
22032e2caf59SThomas Veerman }
22042e2caf59SThomas Veerman if (fullname == NULL) {
22052e2caf59SThomas Veerman fullname = Dir_FindFile(file, parseIncPath);
22062e2caf59SThomas Veerman if (fullname == NULL) {
22072e2caf59SThomas Veerman fullname = Dir_FindFile(file, dirSearchPath);
22082e2caf59SThomas Veerman }
22092e2caf59SThomas Veerman }
22102e2caf59SThomas Veerman }
22112e2caf59SThomas Veerman }
22122e2caf59SThomas Veerman
22132e2caf59SThomas Veerman /* Looking for a system file or file still not found */
22142e2caf59SThomas Veerman if (fullname == NULL) {
22152e2caf59SThomas Veerman /*
22162e2caf59SThomas Veerman * Look for it on the system path
22172e2caf59SThomas Veerman */
22182e2caf59SThomas Veerman fullname = Dir_FindFile(file,
22192e2caf59SThomas Veerman Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath);
22202e2caf59SThomas Veerman }
22212e2caf59SThomas Veerman
22222e2caf59SThomas Veerman if (fullname == NULL) {
22232e2caf59SThomas Veerman if (!silent)
22242e2caf59SThomas Veerman Parse_Error(PARSE_FATAL, "Could not find %s", file);
22252e2caf59SThomas Veerman return;
22262e2caf59SThomas Veerman }
22272e2caf59SThomas Veerman
22282e2caf59SThomas Veerman /* Actually open the file... */
22292e2caf59SThomas Veerman fd = open(fullname, O_RDONLY);
22302e2caf59SThomas Veerman if (fd == -1) {
22312e2caf59SThomas Veerman if (!silent)
22322e2caf59SThomas Veerman Parse_Error(PARSE_FATAL, "Cannot open %s", fullname);
22332e2caf59SThomas Veerman free(fullname);
22342e2caf59SThomas Veerman return;
22352e2caf59SThomas Veerman }
22362e2caf59SThomas Veerman
22372e2caf59SThomas Veerman /* load it */
22382e2caf59SThomas Veerman lf = loadfile(fullname, fd);
22392e2caf59SThomas Veerman
2240*0a6a1f1dSLionel Sambuc ParseSetIncludedFile();
22412e2caf59SThomas Veerman /* Start reading from this file next */
22422e2caf59SThomas Veerman Parse_SetInput(fullname, 0, -1, loadedfile_nextbuf, lf);
22432e2caf59SThomas Veerman curFile->lf = lf;
22442e2caf59SThomas Veerman }
22452e2caf59SThomas Veerman
22462e2caf59SThomas Veerman static void
ParseDoInclude(char * line)22472e2caf59SThomas Veerman ParseDoInclude(char *line)
22482e2caf59SThomas Veerman {
22492e2caf59SThomas Veerman char endc; /* the character which ends the file spec */
22502e2caf59SThomas Veerman char *cp; /* current position in file spec */
22512e2caf59SThomas Veerman int silent = (*line != 'i') ? 1 : 0;
22522e2caf59SThomas Veerman char *file = &line[7 + silent];
22532e2caf59SThomas Veerman
22542e2caf59SThomas Veerman /* Skip to delimiter character so we know where to look */
22552e2caf59SThomas Veerman while (*file == ' ' || *file == '\t')
22562e2caf59SThomas Veerman file++;
22572e2caf59SThomas Veerman
22582e2caf59SThomas Veerman if (*file != '"' && *file != '<') {
22592e2caf59SThomas Veerman Parse_Error(PARSE_FATAL,
22602e2caf59SThomas Veerman ".include filename must be delimited by '\"' or '<'");
22612e2caf59SThomas Veerman return;
22622e2caf59SThomas Veerman }
22632e2caf59SThomas Veerman
22642e2caf59SThomas Veerman /*
22652e2caf59SThomas Veerman * Set the search path on which to find the include file based on the
22662e2caf59SThomas Veerman * characters which bracket its name. Angle-brackets imply it's
22672e2caf59SThomas Veerman * a system Makefile while double-quotes imply it's a user makefile
22682e2caf59SThomas Veerman */
22692e2caf59SThomas Veerman if (*file == '<') {
22702e2caf59SThomas Veerman endc = '>';
22712e2caf59SThomas Veerman } else {
22722e2caf59SThomas Veerman endc = '"';
22732e2caf59SThomas Veerman }
22742e2caf59SThomas Veerman
22752e2caf59SThomas Veerman /* Skip to matching delimiter */
22762e2caf59SThomas Veerman for (cp = ++file; *cp && *cp != endc; cp++)
22772e2caf59SThomas Veerman continue;
22782e2caf59SThomas Veerman
22792e2caf59SThomas Veerman if (*cp != endc) {
22802e2caf59SThomas Veerman Parse_Error(PARSE_FATAL,
22812e2caf59SThomas Veerman "Unclosed %cinclude filename. '%c' expected",
22822e2caf59SThomas Veerman '.', endc);
22832e2caf59SThomas Veerman return;
22842e2caf59SThomas Veerman }
22852e2caf59SThomas Veerman *cp = '\0';
22862e2caf59SThomas Veerman
22872e2caf59SThomas Veerman /*
22882e2caf59SThomas Veerman * Substitute for any variables in the file name before trying to
22892e2caf59SThomas Veerman * find the thing.
22902e2caf59SThomas Veerman */
22912e2caf59SThomas Veerman file = Var_Subst(NULL, file, VAR_CMD, FALSE);
22922e2caf59SThomas Veerman
22932e2caf59SThomas Veerman Parse_include_file(file, endc == '>', silent);
22942e2caf59SThomas Veerman free(file);
22952e2caf59SThomas Veerman }
22962e2caf59SThomas Veerman
22972e2caf59SThomas Veerman
22982e2caf59SThomas Veerman /*-
22992e2caf59SThomas Veerman *---------------------------------------------------------------------
2300*0a6a1f1dSLionel Sambuc * ParseSetIncludedFile --
2301*0a6a1f1dSLionel Sambuc * Set the .INCLUDEDFROMFILE variable to the contents of .PARSEFILE
2302*0a6a1f1dSLionel Sambuc * and the .INCLUDEDFROMDIR variable to the contents of .PARSEDIR
2303*0a6a1f1dSLionel Sambuc *
2304*0a6a1f1dSLionel Sambuc * Results:
2305*0a6a1f1dSLionel Sambuc * None
2306*0a6a1f1dSLionel Sambuc *
2307*0a6a1f1dSLionel Sambuc * Side Effects:
2308*0a6a1f1dSLionel Sambuc * The .INCLUDEDFROMFILE variable is overwritten by the contents
2309*0a6a1f1dSLionel Sambuc * of .PARSEFILE and the .INCLUDEDFROMDIR variable is overwriten
2310*0a6a1f1dSLionel Sambuc * by the contents of .PARSEDIR
2311*0a6a1f1dSLionel Sambuc *---------------------------------------------------------------------
2312*0a6a1f1dSLionel Sambuc */
2313*0a6a1f1dSLionel Sambuc static void
ParseSetIncludedFile(void)2314*0a6a1f1dSLionel Sambuc ParseSetIncludedFile(void)
2315*0a6a1f1dSLionel Sambuc {
2316*0a6a1f1dSLionel Sambuc char *pf, *fp = NULL;
2317*0a6a1f1dSLionel Sambuc char *pd, *dp = NULL;
2318*0a6a1f1dSLionel Sambuc
2319*0a6a1f1dSLionel Sambuc pf = Var_Value(".PARSEFILE", VAR_GLOBAL, &fp);
2320*0a6a1f1dSLionel Sambuc Var_Set(".INCLUDEDFROMFILE", pf, VAR_GLOBAL, 0);
2321*0a6a1f1dSLionel Sambuc pd = Var_Value(".PARSEDIR", VAR_GLOBAL, &dp);
2322*0a6a1f1dSLionel Sambuc Var_Set(".INCLUDEDFROMDIR", pd, VAR_GLOBAL, 0);
2323*0a6a1f1dSLionel Sambuc
2324*0a6a1f1dSLionel Sambuc if (DEBUG(PARSE))
2325*0a6a1f1dSLionel Sambuc fprintf(debug_file, "%s: ${.INCLUDEDFROMDIR} = `%s' "
2326*0a6a1f1dSLionel Sambuc "${.INCLUDEDFROMFILE} = `%s'\n", __func__, pd, pf);
2327*0a6a1f1dSLionel Sambuc
2328*0a6a1f1dSLionel Sambuc if (fp)
2329*0a6a1f1dSLionel Sambuc free(fp);
2330*0a6a1f1dSLionel Sambuc if (dp)
2331*0a6a1f1dSLionel Sambuc free(dp);
2332*0a6a1f1dSLionel Sambuc }
2333*0a6a1f1dSLionel Sambuc /*-
2334*0a6a1f1dSLionel Sambuc *---------------------------------------------------------------------
23352e2caf59SThomas Veerman * ParseSetParseFile --
23362e2caf59SThomas Veerman * Set the .PARSEDIR and .PARSEFILE variables to the dirname and
23372e2caf59SThomas Veerman * basename of the given filename
23382e2caf59SThomas Veerman *
23392e2caf59SThomas Veerman * Results:
23402e2caf59SThomas Veerman * None
23412e2caf59SThomas Veerman *
23422e2caf59SThomas Veerman * Side Effects:
23432e2caf59SThomas Veerman * The .PARSEDIR and .PARSEFILE variables are overwritten by the
23442e2caf59SThomas Veerman * dirname and basename of the given filename.
23452e2caf59SThomas Veerman *---------------------------------------------------------------------
23462e2caf59SThomas Veerman */
23472e2caf59SThomas Veerman static void
ParseSetParseFile(const char * filename)23482e2caf59SThomas Veerman ParseSetParseFile(const char *filename)
23492e2caf59SThomas Veerman {
23502e2caf59SThomas Veerman char *slash, *dirname;
23512e2caf59SThomas Veerman const char *pd, *pf;
23522e2caf59SThomas Veerman int len;
23532e2caf59SThomas Veerman
23542e2caf59SThomas Veerman slash = strrchr(filename, '/');
23552e2caf59SThomas Veerman if (slash == NULL) {
23562e2caf59SThomas Veerman Var_Set(".PARSEDIR", pd = curdir, VAR_GLOBAL, 0);
23572e2caf59SThomas Veerman Var_Set(".PARSEFILE", pf = filename, VAR_GLOBAL, 0);
23582e2caf59SThomas Veerman dirname= NULL;
23592e2caf59SThomas Veerman } else {
23602e2caf59SThomas Veerman len = slash - filename;
23612e2caf59SThomas Veerman dirname = bmake_malloc(len + 1);
23622e2caf59SThomas Veerman memcpy(dirname, filename, len);
23632e2caf59SThomas Veerman dirname[len] = '\0';
23642e2caf59SThomas Veerman Var_Set(".PARSEDIR", pd = dirname, VAR_GLOBAL, 0);
23652e2caf59SThomas Veerman Var_Set(".PARSEFILE", pf = slash + 1, VAR_GLOBAL, 0);
23662e2caf59SThomas Veerman }
23672e2caf59SThomas Veerman if (DEBUG(PARSE))
2368*0a6a1f1dSLionel Sambuc fprintf(debug_file, "%s: ${.PARSEDIR} = `%s' ${.PARSEFILE} = `%s'\n",
2369*0a6a1f1dSLionel Sambuc __func__, pd, pf);
23702e2caf59SThomas Veerman free(dirname);
23712e2caf59SThomas Veerman }
23722e2caf59SThomas Veerman
23732e2caf59SThomas Veerman /*
23742e2caf59SThomas Veerman * Track the makefiles we read - so makefiles can
23752e2caf59SThomas Veerman * set dependencies on them.
23762e2caf59SThomas Veerman * Avoid adding anything more than once.
23772e2caf59SThomas Veerman */
23782e2caf59SThomas Veerman
23792e2caf59SThomas Veerman static void
ParseTrackInput(const char * name)23802e2caf59SThomas Veerman ParseTrackInput(const char *name)
23812e2caf59SThomas Veerman {
23822e2caf59SThomas Veerman char *old;
23832e2caf59SThomas Veerman char *fp = NULL;
23842e2caf59SThomas Veerman size_t name_len = strlen(name);
23852e2caf59SThomas Veerman
23862e2caf59SThomas Veerman old = Var_Value(MAKE_MAKEFILES, VAR_GLOBAL, &fp);
23872e2caf59SThomas Veerman if (old) {
23882e2caf59SThomas Veerman /* does it contain name? */
23892e2caf59SThomas Veerman for (; old != NULL; old = strchr(old, ' ')) {
23902e2caf59SThomas Veerman if (*old == ' ')
23912e2caf59SThomas Veerman old++;
23922e2caf59SThomas Veerman if (memcmp(old, name, name_len) == 0
23932e2caf59SThomas Veerman && (old[name_len] == 0 || old[name_len] == ' '))
23942e2caf59SThomas Veerman goto cleanup;
23952e2caf59SThomas Veerman }
23962e2caf59SThomas Veerman }
23972e2caf59SThomas Veerman Var_Append (MAKE_MAKEFILES, name, VAR_GLOBAL);
23982e2caf59SThomas Veerman cleanup:
23992e2caf59SThomas Veerman if (fp) {
24002e2caf59SThomas Veerman free(fp);
24012e2caf59SThomas Veerman }
24022e2caf59SThomas Veerman }
24032e2caf59SThomas Veerman
24042e2caf59SThomas Veerman
24052e2caf59SThomas Veerman /*-
24062e2caf59SThomas Veerman *---------------------------------------------------------------------
24072e2caf59SThomas Veerman * Parse_setInput --
24082e2caf59SThomas Veerman * Start Parsing from the given source
24092e2caf59SThomas Veerman *
24102e2caf59SThomas Veerman * Results:
24112e2caf59SThomas Veerman * None
24122e2caf59SThomas Veerman *
24132e2caf59SThomas Veerman * Side Effects:
24142e2caf59SThomas Veerman * A structure is added to the includes Lst and readProc, lineno,
24152e2caf59SThomas Veerman * fname and curFile are altered for the new file
24162e2caf59SThomas Veerman *---------------------------------------------------------------------
24172e2caf59SThomas Veerman */
24182e2caf59SThomas Veerman void
Parse_SetInput(const char * name,int line,int fd,char * (* nextbuf)(void *,size_t *),void * arg)24192e2caf59SThomas Veerman Parse_SetInput(const char *name, int line, int fd,
24202e2caf59SThomas Veerman char *(*nextbuf)(void *, size_t *), void *arg)
24212e2caf59SThomas Veerman {
24222e2caf59SThomas Veerman char *buf;
24232e2caf59SThomas Veerman size_t len;
24242e2caf59SThomas Veerman
24252e2caf59SThomas Veerman if (name == NULL)
24262e2caf59SThomas Veerman name = curFile->fname;
24272e2caf59SThomas Veerman else
24282e2caf59SThomas Veerman ParseTrackInput(name);
24292e2caf59SThomas Veerman
24302e2caf59SThomas Veerman if (DEBUG(PARSE))
2431*0a6a1f1dSLionel Sambuc fprintf(debug_file, "%s: file %s, line %d, fd %d, nextbuf %p, arg %p\n",
2432*0a6a1f1dSLionel Sambuc __func__, name, line, fd, nextbuf, arg);
24332e2caf59SThomas Veerman
24342e2caf59SThomas Veerman if (fd == -1 && nextbuf == NULL)
24352e2caf59SThomas Veerman /* sanity */
24362e2caf59SThomas Veerman return;
24372e2caf59SThomas Veerman
24382e2caf59SThomas Veerman if (curFile != NULL)
24392e2caf59SThomas Veerman /* Save exiting file info */
24402e2caf59SThomas Veerman Lst_AtFront(includes, curFile);
24412e2caf59SThomas Veerman
24422e2caf59SThomas Veerman /* Allocate and fill in new structure */
24432e2caf59SThomas Veerman curFile = bmake_malloc(sizeof *curFile);
24442e2caf59SThomas Veerman
24452e2caf59SThomas Veerman /*
24462e2caf59SThomas Veerman * Once the previous state has been saved, we can get down to reading
24472e2caf59SThomas Veerman * the new file. We set up the name of the file to be the absolute
24482e2caf59SThomas Veerman * name of the include file so error messages refer to the right
24492e2caf59SThomas Veerman * place.
24502e2caf59SThomas Veerman */
245184d9c625SLionel Sambuc curFile->fname = bmake_strdup(name);
24522e2caf59SThomas Veerman curFile->lineno = line;
24532e2caf59SThomas Veerman curFile->first_lineno = line;
24542e2caf59SThomas Veerman curFile->nextbuf = nextbuf;
24552e2caf59SThomas Veerman curFile->nextbuf_arg = arg;
24562e2caf59SThomas Veerman curFile->lf = NULL;
24572e2caf59SThomas Veerman
24582e2caf59SThomas Veerman assert(nextbuf != NULL);
24592e2caf59SThomas Veerman
24602e2caf59SThomas Veerman /* Get first block of input data */
24612e2caf59SThomas Veerman buf = curFile->nextbuf(curFile->nextbuf_arg, &len);
24622e2caf59SThomas Veerman if (buf == NULL) {
24632e2caf59SThomas Veerman /* Was all a waste of time ... */
246484d9c625SLionel Sambuc if (curFile->fname)
246584d9c625SLionel Sambuc free(curFile->fname);
24662e2caf59SThomas Veerman free(curFile);
24672e2caf59SThomas Veerman return;
24682e2caf59SThomas Veerman }
24692e2caf59SThomas Veerman curFile->P_str = buf;
24702e2caf59SThomas Veerman curFile->P_ptr = buf;
24712e2caf59SThomas Veerman curFile->P_end = buf+len;
24722e2caf59SThomas Veerman
24732e2caf59SThomas Veerman curFile->cond_depth = Cond_save_depth();
24742e2caf59SThomas Veerman ParseSetParseFile(name);
24752e2caf59SThomas Veerman }
24762e2caf59SThomas Veerman
24772e2caf59SThomas Veerman #ifdef SYSVINCLUDE
24782e2caf59SThomas Veerman /*-
24792e2caf59SThomas Veerman *---------------------------------------------------------------------
24802e2caf59SThomas Veerman * ParseTraditionalInclude --
24812e2caf59SThomas Veerman * Push to another file.
24822e2caf59SThomas Veerman *
24832e2caf59SThomas Veerman * The input is the current line. The file name(s) are
24842e2caf59SThomas Veerman * following the "include".
24852e2caf59SThomas Veerman *
24862e2caf59SThomas Veerman * Results:
24872e2caf59SThomas Veerman * None
24882e2caf59SThomas Veerman *
24892e2caf59SThomas Veerman * Side Effects:
24902e2caf59SThomas Veerman * A structure is added to the includes Lst and readProc, lineno,
24912e2caf59SThomas Veerman * fname and curFILE are altered for the new file
24922e2caf59SThomas Veerman *---------------------------------------------------------------------
24932e2caf59SThomas Veerman */
24942e2caf59SThomas Veerman static void
ParseTraditionalInclude(char * line)24952e2caf59SThomas Veerman ParseTraditionalInclude(char *line)
24962e2caf59SThomas Veerman {
24972e2caf59SThomas Veerman char *cp; /* current position in file spec */
24982e2caf59SThomas Veerman int done = 0;
24992e2caf59SThomas Veerman int silent = (line[0] != 'i') ? 1 : 0;
25002e2caf59SThomas Veerman char *file = &line[silent + 7];
25012e2caf59SThomas Veerman char *all_files;
25022e2caf59SThomas Veerman
25032e2caf59SThomas Veerman if (DEBUG(PARSE)) {
2504*0a6a1f1dSLionel Sambuc fprintf(debug_file, "%s: %s\n", __func__, file);
25052e2caf59SThomas Veerman }
25062e2caf59SThomas Veerman
25072e2caf59SThomas Veerman /*
25082e2caf59SThomas Veerman * Skip over whitespace
25092e2caf59SThomas Veerman */
25102e2caf59SThomas Veerman while (isspace((unsigned char)*file))
25112e2caf59SThomas Veerman file++;
25122e2caf59SThomas Veerman
25132e2caf59SThomas Veerman /*
25142e2caf59SThomas Veerman * Substitute for any variables in the file name before trying to
25152e2caf59SThomas Veerman * find the thing.
25162e2caf59SThomas Veerman */
25172e2caf59SThomas Veerman all_files = Var_Subst(NULL, file, VAR_CMD, FALSE);
25182e2caf59SThomas Veerman
25192e2caf59SThomas Veerman if (*file == '\0') {
25202e2caf59SThomas Veerman Parse_Error(PARSE_FATAL,
25212e2caf59SThomas Veerman "Filename missing from \"include\"");
25222e2caf59SThomas Veerman return;
25232e2caf59SThomas Veerman }
25242e2caf59SThomas Veerman
25252e2caf59SThomas Veerman for (file = all_files; !done; file = cp + 1) {
25262e2caf59SThomas Veerman /* Skip to end of line or next whitespace */
25272e2caf59SThomas Veerman for (cp = file; *cp && !isspace((unsigned char) *cp); cp++)
25282e2caf59SThomas Veerman continue;
25292e2caf59SThomas Veerman
25302e2caf59SThomas Veerman if (*cp)
25312e2caf59SThomas Veerman *cp = '\0';
25322e2caf59SThomas Veerman else
25332e2caf59SThomas Veerman done = 1;
25342e2caf59SThomas Veerman
25352e2caf59SThomas Veerman Parse_include_file(file, FALSE, silent);
25362e2caf59SThomas Veerman }
25372e2caf59SThomas Veerman free(all_files);
25382e2caf59SThomas Veerman }
25392e2caf59SThomas Veerman #endif
25402e2caf59SThomas Veerman
25412bc7c627SLionel Sambuc #ifdef GMAKEEXPORT
25422e2caf59SThomas Veerman /*-
25432e2caf59SThomas Veerman *---------------------------------------------------------------------
25442e2caf59SThomas Veerman * ParseGmakeExport --
25452e2caf59SThomas Veerman * Parse export <variable>=<value>
25462e2caf59SThomas Veerman *
25472e2caf59SThomas Veerman * And set the environment with it.
25482e2caf59SThomas Veerman *
25492e2caf59SThomas Veerman * Results:
25502e2caf59SThomas Veerman * None
25512e2caf59SThomas Veerman *
25522e2caf59SThomas Veerman * Side Effects:
25532e2caf59SThomas Veerman * None
25542e2caf59SThomas Veerman *---------------------------------------------------------------------
25552e2caf59SThomas Veerman */
25562e2caf59SThomas Veerman static void
ParseGmakeExport(char * line)25572e2caf59SThomas Veerman ParseGmakeExport(char *line)
25582e2caf59SThomas Veerman {
25592e2caf59SThomas Veerman char *variable = &line[6];
25602e2caf59SThomas Veerman char *value;
25612e2caf59SThomas Veerman
25622e2caf59SThomas Veerman if (DEBUG(PARSE)) {
2563*0a6a1f1dSLionel Sambuc fprintf(debug_file, "%s: %s\n", __func__, variable);
25642e2caf59SThomas Veerman }
25652e2caf59SThomas Veerman
25662e2caf59SThomas Veerman /*
25672e2caf59SThomas Veerman * Skip over whitespace
25682e2caf59SThomas Veerman */
25692e2caf59SThomas Veerman while (isspace((unsigned char)*variable))
25702e2caf59SThomas Veerman variable++;
25712e2caf59SThomas Veerman
25722e2caf59SThomas Veerman for (value = variable; *value && *value != '='; value++)
25732e2caf59SThomas Veerman continue;
25742e2caf59SThomas Veerman
25752e2caf59SThomas Veerman if (*value != '=') {
25762e2caf59SThomas Veerman Parse_Error(PARSE_FATAL,
25772bc7c627SLionel Sambuc "Variable/Value missing from \"export\"");
25782e2caf59SThomas Veerman return;
25792e2caf59SThomas Veerman }
258084d9c625SLionel Sambuc *value++ = '\0'; /* terminate variable */
25812e2caf59SThomas Veerman
25822e2caf59SThomas Veerman /*
25832bc7c627SLionel Sambuc * Expand the value before putting it in the environment.
25842e2caf59SThomas Veerman */
25852e2caf59SThomas Veerman value = Var_Subst(NULL, value, VAR_CMD, FALSE);
25862e2caf59SThomas Veerman setenv(variable, value, 1);
25872e2caf59SThomas Veerman }
25882e2caf59SThomas Veerman #endif
25892e2caf59SThomas Veerman
25902e2caf59SThomas Veerman /*-
25912e2caf59SThomas Veerman *---------------------------------------------------------------------
25922e2caf59SThomas Veerman * ParseEOF --
25932e2caf59SThomas Veerman * Called when EOF is reached in the current file. If we were reading
25942e2caf59SThomas Veerman * an include file, the includes stack is popped and things set up
25952e2caf59SThomas Veerman * to go back to reading the previous file at the previous location.
25962e2caf59SThomas Veerman *
25972e2caf59SThomas Veerman * Results:
25982e2caf59SThomas Veerman * CONTINUE if there's more to do. DONE if not.
25992e2caf59SThomas Veerman *
26002e2caf59SThomas Veerman * Side Effects:
26012e2caf59SThomas Veerman * The old curFILE, is closed. The includes list is shortened.
26022e2caf59SThomas Veerman * lineno, curFILE, and fname are changed if CONTINUE is returned.
26032e2caf59SThomas Veerman *---------------------------------------------------------------------
26042e2caf59SThomas Veerman */
26052e2caf59SThomas Veerman static int
ParseEOF(void)26062e2caf59SThomas Veerman ParseEOF(void)
26072e2caf59SThomas Veerman {
26082e2caf59SThomas Veerman char *ptr;
26092e2caf59SThomas Veerman size_t len;
26102e2caf59SThomas Veerman
26112e2caf59SThomas Veerman assert(curFile->nextbuf != NULL);
26122e2caf59SThomas Veerman
26132e2caf59SThomas Veerman /* get next input buffer, if any */
26142e2caf59SThomas Veerman ptr = curFile->nextbuf(curFile->nextbuf_arg, &len);
26152e2caf59SThomas Veerman curFile->P_ptr = ptr;
26162e2caf59SThomas Veerman curFile->P_str = ptr;
26172e2caf59SThomas Veerman curFile->P_end = ptr + len;
26182e2caf59SThomas Veerman curFile->lineno = curFile->first_lineno;
26192e2caf59SThomas Veerman if (ptr != NULL) {
26202e2caf59SThomas Veerman /* Iterate again */
26212e2caf59SThomas Veerman return CONTINUE;
26222e2caf59SThomas Veerman }
26232e2caf59SThomas Veerman
26242e2caf59SThomas Veerman /* Ensure the makefile (or loop) didn't have mismatched conditionals */
26252e2caf59SThomas Veerman Cond_restore_depth(curFile->cond_depth);
26262e2caf59SThomas Veerman
26272e2caf59SThomas Veerman if (curFile->lf != NULL) {
26282e2caf59SThomas Veerman loadedfile_destroy(curFile->lf);
26292e2caf59SThomas Veerman curFile->lf = NULL;
26302e2caf59SThomas Veerman }
26312e2caf59SThomas Veerman
26322e2caf59SThomas Veerman /* Dispose of curFile info */
26332e2caf59SThomas Veerman /* Leak curFile->fname because all the gnodes have pointers to it */
26342e2caf59SThomas Veerman free(curFile->P_str);
26352e2caf59SThomas Veerman free(curFile);
26362e2caf59SThomas Veerman
26372e2caf59SThomas Veerman curFile = Lst_DeQueue(includes);
26382e2caf59SThomas Veerman
26392e2caf59SThomas Veerman if (curFile == NULL) {
26402e2caf59SThomas Veerman /* We've run out of input */
26412e2caf59SThomas Veerman Var_Delete(".PARSEDIR", VAR_GLOBAL);
26422e2caf59SThomas Veerman Var_Delete(".PARSEFILE", VAR_GLOBAL);
2643*0a6a1f1dSLionel Sambuc Var_Delete(".INCLUDEDFROMDIR", VAR_GLOBAL);
2644*0a6a1f1dSLionel Sambuc Var_Delete(".INCLUDEDFROMFILE", VAR_GLOBAL);
26452e2caf59SThomas Veerman return DONE;
26462e2caf59SThomas Veerman }
26472e2caf59SThomas Veerman
26482e2caf59SThomas Veerman if (DEBUG(PARSE))
26492e2caf59SThomas Veerman fprintf(debug_file, "ParseEOF: returning to file %s, line %d\n",
26502e2caf59SThomas Veerman curFile->fname, curFile->lineno);
26512e2caf59SThomas Veerman
26522e2caf59SThomas Veerman /* Restore the PARSEDIR/PARSEFILE variables */
26532e2caf59SThomas Veerman ParseSetParseFile(curFile->fname);
26542e2caf59SThomas Veerman return (CONTINUE);
26552e2caf59SThomas Veerman }
26562e2caf59SThomas Veerman
26572e2caf59SThomas Veerman #define PARSE_RAW 1
26582e2caf59SThomas Veerman #define PARSE_SKIP 2
26592e2caf59SThomas Veerman
26602e2caf59SThomas Veerman static char *
ParseGetLine(int flags,int * length)26612e2caf59SThomas Veerman ParseGetLine(int flags, int *length)
26622e2caf59SThomas Veerman {
26632e2caf59SThomas Veerman IFile *cf = curFile;
26642e2caf59SThomas Veerman char *ptr;
26652e2caf59SThomas Veerman char ch;
26662e2caf59SThomas Veerman char *line;
26672e2caf59SThomas Veerman char *line_end;
26682e2caf59SThomas Veerman char *escaped;
26692e2caf59SThomas Veerman char *comment;
26702e2caf59SThomas Veerman char *tp;
26712e2caf59SThomas Veerman
26722e2caf59SThomas Veerman /* Loop through blank lines and comment lines */
26732e2caf59SThomas Veerman for (;;) {
26742e2caf59SThomas Veerman cf->lineno++;
26752e2caf59SThomas Veerman line = cf->P_ptr;
26762e2caf59SThomas Veerman ptr = line;
26772e2caf59SThomas Veerman line_end = line;
26782e2caf59SThomas Veerman escaped = NULL;
26792e2caf59SThomas Veerman comment = NULL;
26802e2caf59SThomas Veerman for (;;) {
26812e2caf59SThomas Veerman if (cf->P_end != NULL && ptr == cf->P_end) {
26822e2caf59SThomas Veerman /* end of buffer */
26832e2caf59SThomas Veerman ch = 0;
26842e2caf59SThomas Veerman break;
26852e2caf59SThomas Veerman }
26862e2caf59SThomas Veerman ch = *ptr;
26872e2caf59SThomas Veerman if (ch == 0 || (ch == '\\' && ptr[1] == 0)) {
26882e2caf59SThomas Veerman if (cf->P_end == NULL)
26892e2caf59SThomas Veerman /* End of string (aka for loop) data */
26902e2caf59SThomas Veerman break;
269184d9c625SLionel Sambuc /* see if there is more we can parse */
269284d9c625SLionel Sambuc while (ptr++ < cf->P_end) {
269384d9c625SLionel Sambuc if ((ch = *ptr) == '\n') {
269484d9c625SLionel Sambuc if (ptr > line && ptr[-1] == '\\')
269584d9c625SLionel Sambuc continue;
269684d9c625SLionel Sambuc Parse_Error(PARSE_WARNING,
269784d9c625SLionel Sambuc "Zero byte read from file, skipping rest of line.");
269884d9c625SLionel Sambuc break;
269984d9c625SLionel Sambuc }
270084d9c625SLionel Sambuc }
27012e2caf59SThomas Veerman if (cf->nextbuf != NULL) {
27022e2caf59SThomas Veerman /*
27032e2caf59SThomas Veerman * End of this buffer; return EOF and outer logic
27042e2caf59SThomas Veerman * will get the next one. (eww)
27052e2caf59SThomas Veerman */
27062e2caf59SThomas Veerman break;
27072e2caf59SThomas Veerman }
27082e2caf59SThomas Veerman Parse_Error(PARSE_FATAL, "Zero byte read from file");
27092e2caf59SThomas Veerman return NULL;
27102e2caf59SThomas Veerman }
27112e2caf59SThomas Veerman
27122e2caf59SThomas Veerman if (ch == '\\') {
27132e2caf59SThomas Veerman /* Don't treat next character as special, remember first one */
27142e2caf59SThomas Veerman if (escaped == NULL)
27152e2caf59SThomas Veerman escaped = ptr;
27162e2caf59SThomas Veerman if (ptr[1] == '\n')
27172e2caf59SThomas Veerman cf->lineno++;
27182e2caf59SThomas Veerman ptr += 2;
27192e2caf59SThomas Veerman line_end = ptr;
27202e2caf59SThomas Veerman continue;
27212e2caf59SThomas Veerman }
27222e2caf59SThomas Veerman if (ch == '#' && comment == NULL) {
27232e2caf59SThomas Veerman /* Remember first '#' for comment stripping */
27242e2caf59SThomas Veerman /* Unless previous char was '[', as in modifier :[#] */
27252e2caf59SThomas Veerman if (!(ptr > line && ptr[-1] == '['))
27262e2caf59SThomas Veerman comment = line_end;
27272e2caf59SThomas Veerman }
27282e2caf59SThomas Veerman ptr++;
27292e2caf59SThomas Veerman if (ch == '\n')
27302e2caf59SThomas Veerman break;
27312e2caf59SThomas Veerman if (!isspace((unsigned char)ch))
27322e2caf59SThomas Veerman /* We are not interested in trailing whitespace */
27332e2caf59SThomas Veerman line_end = ptr;
27342e2caf59SThomas Veerman }
27352e2caf59SThomas Veerman
27362e2caf59SThomas Veerman /* Save next 'to be processed' location */
27372e2caf59SThomas Veerman cf->P_ptr = ptr;
27382e2caf59SThomas Veerman
27392e2caf59SThomas Veerman /* Check we have a non-comment, non-blank line */
27402e2caf59SThomas Veerman if (line_end == line || comment == line) {
27412e2caf59SThomas Veerman if (ch == 0)
27422e2caf59SThomas Veerman /* At end of file */
27432e2caf59SThomas Veerman return NULL;
27442e2caf59SThomas Veerman /* Parse another line */
27452e2caf59SThomas Veerman continue;
27462e2caf59SThomas Veerman }
27472e2caf59SThomas Veerman
27482e2caf59SThomas Veerman /* We now have a line of data */
27492e2caf59SThomas Veerman *line_end = 0;
27502e2caf59SThomas Veerman
27512e2caf59SThomas Veerman if (flags & PARSE_RAW) {
27522e2caf59SThomas Veerman /* Leave '\' (etc) in line buffer (eg 'for' lines) */
27532e2caf59SThomas Veerman *length = line_end - line;
27542e2caf59SThomas Veerman return line;
27552e2caf59SThomas Veerman }
27562e2caf59SThomas Veerman
27572e2caf59SThomas Veerman if (flags & PARSE_SKIP) {
27582e2caf59SThomas Veerman /* Completely ignore non-directives */
27592e2caf59SThomas Veerman if (line[0] != '.')
27602e2caf59SThomas Veerman continue;
27612e2caf59SThomas Veerman /* We could do more of the .else/.elif/.endif checks here */
27622e2caf59SThomas Veerman }
27632e2caf59SThomas Veerman break;
27642e2caf59SThomas Veerman }
27652e2caf59SThomas Veerman
27662e2caf59SThomas Veerman /* Brutally ignore anything after a non-escaped '#' in non-commands */
27672e2caf59SThomas Veerman if (comment != NULL && line[0] != '\t') {
27682e2caf59SThomas Veerman line_end = comment;
27692e2caf59SThomas Veerman *line_end = 0;
27702e2caf59SThomas Veerman }
27712e2caf59SThomas Veerman
27722e2caf59SThomas Veerman /* If we didn't see a '\\' then the in-situ data is fine */
27732e2caf59SThomas Veerman if (escaped == NULL) {
27742e2caf59SThomas Veerman *length = line_end - line;
27752e2caf59SThomas Veerman return line;
27762e2caf59SThomas Veerman }
27772e2caf59SThomas Veerman
27782e2caf59SThomas Veerman /* Remove escapes from '\n' and '#' */
27792e2caf59SThomas Veerman tp = ptr = escaped;
27802e2caf59SThomas Veerman escaped = line;
27812e2caf59SThomas Veerman for (; ; *tp++ = ch) {
27822e2caf59SThomas Veerman ch = *ptr++;
27832e2caf59SThomas Veerman if (ch != '\\') {
27842e2caf59SThomas Veerman if (ch == 0)
27852e2caf59SThomas Veerman break;
27862e2caf59SThomas Veerman continue;
27872e2caf59SThomas Veerman }
27882e2caf59SThomas Veerman
27892e2caf59SThomas Veerman ch = *ptr++;
27902e2caf59SThomas Veerman if (ch == 0) {
27912e2caf59SThomas Veerman /* Delete '\\' at end of buffer */
27922e2caf59SThomas Veerman tp--;
27932e2caf59SThomas Veerman break;
27942e2caf59SThomas Veerman }
27952e2caf59SThomas Veerman
27962e2caf59SThomas Veerman if (ch == '#' && line[0] != '\t')
27972e2caf59SThomas Veerman /* Delete '\\' from before '#' on non-command lines */
27982e2caf59SThomas Veerman continue;
27992e2caf59SThomas Veerman
28002e2caf59SThomas Veerman if (ch != '\n') {
28012e2caf59SThomas Veerman /* Leave '\\' in buffer for later */
28022e2caf59SThomas Veerman *tp++ = '\\';
28032e2caf59SThomas Veerman /* Make sure we don't delete an escaped ' ' from the line end */
28042e2caf59SThomas Veerman escaped = tp + 1;
28052e2caf59SThomas Veerman continue;
28062e2caf59SThomas Veerman }
28072e2caf59SThomas Veerman
28082e2caf59SThomas Veerman /* Escaped '\n' replace following whitespace with a single ' ' */
28092e2caf59SThomas Veerman while (ptr[0] == ' ' || ptr[0] == '\t')
28102e2caf59SThomas Veerman ptr++;
28112e2caf59SThomas Veerman ch = ' ';
28122e2caf59SThomas Veerman }
28132e2caf59SThomas Veerman
28142e2caf59SThomas Veerman /* Delete any trailing spaces - eg from empty continuations */
28152e2caf59SThomas Veerman while (tp > escaped && isspace((unsigned char)tp[-1]))
28162e2caf59SThomas Veerman tp--;
28172e2caf59SThomas Veerman
28182e2caf59SThomas Veerman *tp = 0;
28192e2caf59SThomas Veerman *length = tp - line;
28202e2caf59SThomas Veerman return line;
28212e2caf59SThomas Veerman }
28222e2caf59SThomas Veerman
28232e2caf59SThomas Veerman /*-
28242e2caf59SThomas Veerman *---------------------------------------------------------------------
28252e2caf59SThomas Veerman * ParseReadLine --
28262e2caf59SThomas Veerman * Read an entire line from the input file. Called only by Parse_File.
28272e2caf59SThomas Veerman *
28282e2caf59SThomas Veerman * Results:
28292e2caf59SThomas Veerman * A line w/o its newline
28302e2caf59SThomas Veerman *
28312e2caf59SThomas Veerman * Side Effects:
28322e2caf59SThomas Veerman * Only those associated with reading a character
28332e2caf59SThomas Veerman *---------------------------------------------------------------------
28342e2caf59SThomas Veerman */
28352e2caf59SThomas Veerman static char *
ParseReadLine(void)28362e2caf59SThomas Veerman ParseReadLine(void)
28372e2caf59SThomas Veerman {
28382e2caf59SThomas Veerman char *line; /* Result */
28392e2caf59SThomas Veerman int lineLength; /* Length of result */
28402e2caf59SThomas Veerman int lineno; /* Saved line # */
28412e2caf59SThomas Veerman int rval;
28422e2caf59SThomas Veerman
28432e2caf59SThomas Veerman for (;;) {
28442e2caf59SThomas Veerman line = ParseGetLine(0, &lineLength);
28452e2caf59SThomas Veerman if (line == NULL)
28462e2caf59SThomas Veerman return NULL;
28472e2caf59SThomas Veerman
28482e2caf59SThomas Veerman if (line[0] != '.')
28492e2caf59SThomas Veerman return line;
28502e2caf59SThomas Veerman
28512e2caf59SThomas Veerman /*
28522e2caf59SThomas Veerman * The line might be a conditional. Ask the conditional module
28532e2caf59SThomas Veerman * about it and act accordingly
28542e2caf59SThomas Veerman */
28552e2caf59SThomas Veerman switch (Cond_Eval(line)) {
28562e2caf59SThomas Veerman case COND_SKIP:
28572e2caf59SThomas Veerman /* Skip to next conditional that evaluates to COND_PARSE. */
28582e2caf59SThomas Veerman do {
28592e2caf59SThomas Veerman line = ParseGetLine(PARSE_SKIP, &lineLength);
28602e2caf59SThomas Veerman } while (line && Cond_Eval(line) != COND_PARSE);
28612e2caf59SThomas Veerman if (line == NULL)
28622e2caf59SThomas Veerman break;
28632e2caf59SThomas Veerman continue;
28642e2caf59SThomas Veerman case COND_PARSE:
28652e2caf59SThomas Veerman continue;
28662e2caf59SThomas Veerman case COND_INVALID: /* Not a conditional line */
28672e2caf59SThomas Veerman /* Check for .for loops */
28682e2caf59SThomas Veerman rval = For_Eval(line);
28692e2caf59SThomas Veerman if (rval == 0)
28702e2caf59SThomas Veerman /* Not a .for line */
28712e2caf59SThomas Veerman break;
28722e2caf59SThomas Veerman if (rval < 0)
28732e2caf59SThomas Veerman /* Syntax error - error printed, ignore line */
28742e2caf59SThomas Veerman continue;
28752e2caf59SThomas Veerman /* Start of a .for loop */
28762e2caf59SThomas Veerman lineno = curFile->lineno;
28772e2caf59SThomas Veerman /* Accumulate loop lines until matching .endfor */
28782e2caf59SThomas Veerman do {
28792e2caf59SThomas Veerman line = ParseGetLine(PARSE_RAW, &lineLength);
28802e2caf59SThomas Veerman if (line == NULL) {
28812e2caf59SThomas Veerman Parse_Error(PARSE_FATAL,
28822e2caf59SThomas Veerman "Unexpected end of file in for loop.");
28832e2caf59SThomas Veerman break;
28842e2caf59SThomas Veerman }
28852e2caf59SThomas Veerman } while (For_Accum(line));
28862e2caf59SThomas Veerman /* Stash each iteration as a new 'input file' */
28872e2caf59SThomas Veerman For_Run(lineno);
28882e2caf59SThomas Veerman /* Read next line from for-loop buffer */
28892e2caf59SThomas Veerman continue;
28902e2caf59SThomas Veerman }
28912e2caf59SThomas Veerman return (line);
28922e2caf59SThomas Veerman }
28932e2caf59SThomas Veerman }
28942e2caf59SThomas Veerman
28952e2caf59SThomas Veerman /*-
28962e2caf59SThomas Veerman *-----------------------------------------------------------------------
28972e2caf59SThomas Veerman * ParseFinishLine --
28982e2caf59SThomas Veerman * Handle the end of a dependency group.
28992e2caf59SThomas Veerman *
29002e2caf59SThomas Veerman * Results:
29012e2caf59SThomas Veerman * Nothing.
29022e2caf59SThomas Veerman *
29032e2caf59SThomas Veerman * Side Effects:
29042e2caf59SThomas Veerman * inLine set FALSE. 'targets' list destroyed.
29052e2caf59SThomas Veerman *
29062e2caf59SThomas Veerman *-----------------------------------------------------------------------
29072e2caf59SThomas Veerman */
29082e2caf59SThomas Veerman static void
ParseFinishLine(void)29092e2caf59SThomas Veerman ParseFinishLine(void)
29102e2caf59SThomas Veerman {
29112e2caf59SThomas Veerman if (inLine) {
29122e2caf59SThomas Veerman Lst_ForEach(targets, Suff_EndTransform, NULL);
29132e2caf59SThomas Veerman Lst_Destroy(targets, ParseHasCommands);
29142e2caf59SThomas Veerman targets = NULL;
29152e2caf59SThomas Veerman inLine = FALSE;
29162e2caf59SThomas Veerman }
29172e2caf59SThomas Veerman }
29182e2caf59SThomas Veerman
29192e2caf59SThomas Veerman
29202e2caf59SThomas Veerman /*-
29212e2caf59SThomas Veerman *---------------------------------------------------------------------
29222e2caf59SThomas Veerman * Parse_File --
29232e2caf59SThomas Veerman * Parse a file into its component parts, incorporating it into the
29242e2caf59SThomas Veerman * current dependency graph. This is the main function and controls
29252e2caf59SThomas Veerman * almost every other function in this module
29262e2caf59SThomas Veerman *
29272e2caf59SThomas Veerman * Input:
29282e2caf59SThomas Veerman * name the name of the file being read
29292e2caf59SThomas Veerman * fd Open file to makefile to parse
29302e2caf59SThomas Veerman *
29312e2caf59SThomas Veerman * Results:
29322e2caf59SThomas Veerman * None
29332e2caf59SThomas Veerman *
29342e2caf59SThomas Veerman * Side Effects:
29352e2caf59SThomas Veerman * closes fd.
29362e2caf59SThomas Veerman * Loads. Nodes are added to the list of all targets, nodes and links
29372e2caf59SThomas Veerman * are added to the dependency graph. etc. etc. etc.
29382e2caf59SThomas Veerman *---------------------------------------------------------------------
29392e2caf59SThomas Veerman */
29402e2caf59SThomas Veerman void
Parse_File(const char * name,int fd)29412e2caf59SThomas Veerman Parse_File(const char *name, int fd)
29422e2caf59SThomas Veerman {
29432e2caf59SThomas Veerman char *cp; /* pointer into the line */
29442e2caf59SThomas Veerman char *line; /* the line we're working on */
29452e2caf59SThomas Veerman struct loadedfile *lf;
29462e2caf59SThomas Veerman
29472e2caf59SThomas Veerman lf = loadfile(name, fd);
29482e2caf59SThomas Veerman
29492e2caf59SThomas Veerman inLine = FALSE;
29502e2caf59SThomas Veerman fatals = 0;
29512e2caf59SThomas Veerman
29522e2caf59SThomas Veerman if (name == NULL) {
29532e2caf59SThomas Veerman name = "(stdin)";
29542e2caf59SThomas Veerman }
29552e2caf59SThomas Veerman
29562e2caf59SThomas Veerman Parse_SetInput(name, 0, -1, loadedfile_nextbuf, lf);
29572e2caf59SThomas Veerman curFile->lf = lf;
29582e2caf59SThomas Veerman
29592e2caf59SThomas Veerman do {
29602e2caf59SThomas Veerman for (; (line = ParseReadLine()) != NULL; ) {
29612e2caf59SThomas Veerman if (DEBUG(PARSE))
29622e2caf59SThomas Veerman fprintf(debug_file, "ParseReadLine (%d): '%s'\n",
29632e2caf59SThomas Veerman curFile->lineno, line);
29642e2caf59SThomas Veerman if (*line == '.') {
29652e2caf59SThomas Veerman /*
29662e2caf59SThomas Veerman * Lines that begin with the special character may be
29672e2caf59SThomas Veerman * include or undef directives.
29682e2caf59SThomas Veerman * On the other hand they can be suffix rules (.c.o: ...)
29692e2caf59SThomas Veerman * or just dependencies for filenames that start '.'.
29702e2caf59SThomas Veerman */
29712e2caf59SThomas Veerman for (cp = line + 1; isspace((unsigned char)*cp); cp++) {
29722e2caf59SThomas Veerman continue;
29732e2caf59SThomas Veerman }
29742e2caf59SThomas Veerman if (strncmp(cp, "include", 7) == 0 ||
29752e2caf59SThomas Veerman ((cp[0] == 's' || cp[0] == '-') &&
29762e2caf59SThomas Veerman strncmp(&cp[1], "include", 7) == 0)) {
29772e2caf59SThomas Veerman ParseDoInclude(cp);
29782e2caf59SThomas Veerman continue;
29792e2caf59SThomas Veerman }
29802e2caf59SThomas Veerman if (strncmp(cp, "undef", 5) == 0) {
29812e2caf59SThomas Veerman char *cp2;
29822e2caf59SThomas Veerman for (cp += 5; isspace((unsigned char) *cp); cp++)
29832e2caf59SThomas Veerman continue;
29842e2caf59SThomas Veerman for (cp2 = cp; !isspace((unsigned char) *cp2) &&
29852e2caf59SThomas Veerman (*cp2 != '\0'); cp2++)
29862e2caf59SThomas Veerman continue;
29872e2caf59SThomas Veerman *cp2 = '\0';
29882e2caf59SThomas Veerman Var_Delete(cp, VAR_GLOBAL);
29892e2caf59SThomas Veerman continue;
29902e2caf59SThomas Veerman } else if (strncmp(cp, "export", 6) == 0) {
29912e2caf59SThomas Veerman for (cp += 6; isspace((unsigned char) *cp); cp++)
29922e2caf59SThomas Veerman continue;
29932e2caf59SThomas Veerman Var_Export(cp, 1);
29942e2caf59SThomas Veerman continue;
29952e2caf59SThomas Veerman } else if (strncmp(cp, "unexport", 8) == 0) {
29962e2caf59SThomas Veerman Var_UnExport(cp);
29972e2caf59SThomas Veerman continue;
29982e2caf59SThomas Veerman } else if (strncmp(cp, "info", 4) == 0 ||
29992e2caf59SThomas Veerman strncmp(cp, "error", 5) == 0 ||
30002e2caf59SThomas Veerman strncmp(cp, "warning", 7) == 0) {
30012e2caf59SThomas Veerman if (ParseMessage(cp))
30022e2caf59SThomas Veerman continue;
30032e2caf59SThomas Veerman }
30042e2caf59SThomas Veerman }
30052e2caf59SThomas Veerman
30062e2caf59SThomas Veerman if (*line == '\t') {
30072e2caf59SThomas Veerman /*
30082e2caf59SThomas Veerman * If a line starts with a tab, it can only hope to be
30092e2caf59SThomas Veerman * a creation command.
30102e2caf59SThomas Veerman */
30112e2caf59SThomas Veerman cp = line + 1;
30122e2caf59SThomas Veerman shellCommand:
30132e2caf59SThomas Veerman for (; isspace ((unsigned char)*cp); cp++) {
30142e2caf59SThomas Veerman continue;
30152e2caf59SThomas Veerman }
30162e2caf59SThomas Veerman if (*cp) {
30172e2caf59SThomas Veerman if (!inLine)
30182e2caf59SThomas Veerman Parse_Error(PARSE_FATAL,
30192e2caf59SThomas Veerman "Unassociated shell command \"%s\"",
30202e2caf59SThomas Veerman cp);
30212e2caf59SThomas Veerman /*
30222e2caf59SThomas Veerman * So long as it's not a blank line and we're actually
30232e2caf59SThomas Veerman * in a dependency spec, add the command to the list of
30242e2caf59SThomas Veerman * commands of all targets in the dependency spec
30252e2caf59SThomas Veerman */
30262e2caf59SThomas Veerman if (targets) {
30272e2caf59SThomas Veerman cp = bmake_strdup(cp);
30282e2caf59SThomas Veerman Lst_ForEach(targets, ParseAddCmd, cp);
30292e2caf59SThomas Veerman #ifdef CLEANUP
30302e2caf59SThomas Veerman Lst_AtEnd(targCmds, cp);
30312e2caf59SThomas Veerman #endif
30322e2caf59SThomas Veerman }
30332e2caf59SThomas Veerman }
30342e2caf59SThomas Veerman continue;
30352e2caf59SThomas Veerman }
30362e2caf59SThomas Veerman
30372e2caf59SThomas Veerman #ifdef SYSVINCLUDE
30382e2caf59SThomas Veerman if (((strncmp(line, "include", 7) == 0 &&
30392e2caf59SThomas Veerman isspace((unsigned char) line[7])) ||
30402e2caf59SThomas Veerman ((line[0] == 's' || line[0] == '-') &&
30412e2caf59SThomas Veerman strncmp(&line[1], "include", 7) == 0 &&
30422e2caf59SThomas Veerman isspace((unsigned char) line[8]))) &&
30432e2caf59SThomas Veerman strchr(line, ':') == NULL) {
30442e2caf59SThomas Veerman /*
30452e2caf59SThomas Veerman * It's an S3/S5-style "include".
30462e2caf59SThomas Veerman */
30472e2caf59SThomas Veerman ParseTraditionalInclude(line);
30482e2caf59SThomas Veerman continue;
30492e2caf59SThomas Veerman }
30502e2caf59SThomas Veerman #endif
30512e2caf59SThomas Veerman #ifdef GMAKEEXPORT
30522e2caf59SThomas Veerman if (strncmp(line, "export", 6) == 0 &&
30532e2caf59SThomas Veerman isspace((unsigned char) line[6]) &&
30542e2caf59SThomas Veerman strchr(line, ':') == NULL) {
30552e2caf59SThomas Veerman /*
30562bc7c627SLionel Sambuc * It's a Gmake "export".
30572e2caf59SThomas Veerman */
30582e2caf59SThomas Veerman ParseGmakeExport(line);
30592e2caf59SThomas Veerman continue;
30602e2caf59SThomas Veerman }
30612e2caf59SThomas Veerman #endif
30622e2caf59SThomas Veerman if (Parse_IsVar(line)) {
30632e2caf59SThomas Veerman ParseFinishLine();
30642e2caf59SThomas Veerman Parse_DoVar(line, VAR_GLOBAL);
30652e2caf59SThomas Veerman continue;
30662e2caf59SThomas Veerman }
30672e2caf59SThomas Veerman
30682e2caf59SThomas Veerman #ifndef POSIX
30692e2caf59SThomas Veerman /*
30702e2caf59SThomas Veerman * To make life easier on novices, if the line is indented we
30712e2caf59SThomas Veerman * first make sure the line has a dependency operator in it.
30722e2caf59SThomas Veerman * If it doesn't have an operator and we're in a dependency
30732e2caf59SThomas Veerman * line's script, we assume it's actually a shell command
30742e2caf59SThomas Veerman * and add it to the current list of targets.
30752e2caf59SThomas Veerman */
30762e2caf59SThomas Veerman cp = line;
30772e2caf59SThomas Veerman if (isspace((unsigned char) line[0])) {
30782e2caf59SThomas Veerman while ((*cp != '\0') && isspace((unsigned char) *cp))
30792e2caf59SThomas Veerman cp++;
30802e2caf59SThomas Veerman while (*cp && (ParseIsEscaped(line, cp) ||
30812e2caf59SThomas Veerman (*cp != ':') && (*cp != '!'))) {
30822e2caf59SThomas Veerman cp++;
30832e2caf59SThomas Veerman }
30842e2caf59SThomas Veerman if (*cp == '\0') {
30852e2caf59SThomas Veerman if (inLine) {
30862e2caf59SThomas Veerman Parse_Error(PARSE_WARNING,
30872e2caf59SThomas Veerman "Shell command needs a leading tab");
30882e2caf59SThomas Veerman goto shellCommand;
30892e2caf59SThomas Veerman }
30902e2caf59SThomas Veerman }
30912e2caf59SThomas Veerman }
30922e2caf59SThomas Veerman #endif
30932e2caf59SThomas Veerman ParseFinishLine();
30942e2caf59SThomas Veerman
30952e2caf59SThomas Veerman /*
30962e2caf59SThomas Veerman * For some reason - probably to make the parser impossible -
30972e2caf59SThomas Veerman * a ';' can be used to separate commands from dependencies.
30982e2caf59SThomas Veerman * Attempt to avoid ';' inside substitution patterns.
30992e2caf59SThomas Veerman */
31002e2caf59SThomas Veerman {
31012e2caf59SThomas Veerman int level = 0;
31022e2caf59SThomas Veerman
31032e2caf59SThomas Veerman for (cp = line; *cp != 0; cp++) {
31042e2caf59SThomas Veerman if (*cp == '\\' && cp[1] != 0) {
31052e2caf59SThomas Veerman cp++;
31062e2caf59SThomas Veerman continue;
31072e2caf59SThomas Veerman }
31082e2caf59SThomas Veerman if (*cp == '$' &&
31092e2caf59SThomas Veerman (cp[1] == '(' || cp[1] == '{')) {
31102e2caf59SThomas Veerman level++;
31112e2caf59SThomas Veerman continue;
31122e2caf59SThomas Veerman }
31132e2caf59SThomas Veerman if (level > 0) {
31142e2caf59SThomas Veerman if (*cp == ')' || *cp == '}') {
31152e2caf59SThomas Veerman level--;
31162e2caf59SThomas Veerman continue;
31172e2caf59SThomas Veerman }
31182e2caf59SThomas Veerman } else if (*cp == ';') {
31192e2caf59SThomas Veerman break;
31202e2caf59SThomas Veerman }
31212e2caf59SThomas Veerman }
31222e2caf59SThomas Veerman }
31232e2caf59SThomas Veerman if (*cp != 0)
31242e2caf59SThomas Veerman /* Terminate the dependency list at the ';' */
31252e2caf59SThomas Veerman *cp++ = 0;
31262e2caf59SThomas Veerman else
31272e2caf59SThomas Veerman cp = NULL;
31282e2caf59SThomas Veerman
31292e2caf59SThomas Veerman /*
31302e2caf59SThomas Veerman * We now know it's a dependency line so it needs to have all
31312e2caf59SThomas Veerman * variables expanded before being parsed. Tell the variable
31322e2caf59SThomas Veerman * module to complain if some variable is undefined...
31332e2caf59SThomas Veerman */
31342e2caf59SThomas Veerman line = Var_Subst(NULL, line, VAR_CMD, TRUE);
31352e2caf59SThomas Veerman
31362e2caf59SThomas Veerman /*
31372e2caf59SThomas Veerman * Need a non-circular list for the target nodes
31382e2caf59SThomas Veerman */
31392e2caf59SThomas Veerman if (targets)
31402e2caf59SThomas Veerman Lst_Destroy(targets, NULL);
31412e2caf59SThomas Veerman
31422e2caf59SThomas Veerman targets = Lst_Init(FALSE);
31432e2caf59SThomas Veerman inLine = TRUE;
31442e2caf59SThomas Veerman
31452e2caf59SThomas Veerman ParseDoDependency(line);
31462e2caf59SThomas Veerman free(line);
31472e2caf59SThomas Veerman
31482e2caf59SThomas Veerman /* If there were commands after a ';', add them now */
31492e2caf59SThomas Veerman if (cp != NULL) {
31502e2caf59SThomas Veerman goto shellCommand;
31512e2caf59SThomas Veerman }
31522e2caf59SThomas Veerman }
31532e2caf59SThomas Veerman /*
31542e2caf59SThomas Veerman * Reached EOF, but it may be just EOF of an include file...
31552e2caf59SThomas Veerman */
31562e2caf59SThomas Veerman } while (ParseEOF() == CONTINUE);
31572e2caf59SThomas Veerman
31582e2caf59SThomas Veerman if (fatals) {
31592e2caf59SThomas Veerman (void)fflush(stdout);
31602e2caf59SThomas Veerman (void)fprintf(stderr,
31612e2caf59SThomas Veerman "%s: Fatal errors encountered -- cannot continue",
31622e2caf59SThomas Veerman progname);
31632e2caf59SThomas Veerman PrintOnError(NULL, NULL);
31642e2caf59SThomas Veerman exit(1);
31652e2caf59SThomas Veerman }
31662e2caf59SThomas Veerman }
31672e2caf59SThomas Veerman
31682e2caf59SThomas Veerman /*-
31692e2caf59SThomas Veerman *---------------------------------------------------------------------
31702e2caf59SThomas Veerman * Parse_Init --
31712e2caf59SThomas Veerman * initialize the parsing module
31722e2caf59SThomas Veerman *
31732e2caf59SThomas Veerman * Results:
31742e2caf59SThomas Veerman * none
31752e2caf59SThomas Veerman *
31762e2caf59SThomas Veerman * Side Effects:
31772e2caf59SThomas Veerman * the parseIncPath list is initialized...
31782e2caf59SThomas Veerman *---------------------------------------------------------------------
31792e2caf59SThomas Veerman */
31802e2caf59SThomas Veerman void
Parse_Init(void)31812e2caf59SThomas Veerman Parse_Init(void)
31822e2caf59SThomas Veerman {
31832e2caf59SThomas Veerman mainNode = NULL;
31842e2caf59SThomas Veerman parseIncPath = Lst_Init(FALSE);
31852e2caf59SThomas Veerman sysIncPath = Lst_Init(FALSE);
31862e2caf59SThomas Veerman defIncPath = Lst_Init(FALSE);
31872e2caf59SThomas Veerman includes = Lst_Init(FALSE);
31882e2caf59SThomas Veerman #ifdef CLEANUP
31892e2caf59SThomas Veerman targCmds = Lst_Init(FALSE);
31902e2caf59SThomas Veerman #endif
31912e2caf59SThomas Veerman }
31922e2caf59SThomas Veerman
31932e2caf59SThomas Veerman void
Parse_End(void)31942e2caf59SThomas Veerman Parse_End(void)
31952e2caf59SThomas Veerman {
31962e2caf59SThomas Veerman #ifdef CLEANUP
31972e2caf59SThomas Veerman Lst_Destroy(targCmds, (FreeProc *)free);
31982e2caf59SThomas Veerman if (targets)
31992e2caf59SThomas Veerman Lst_Destroy(targets, NULL);
32002e2caf59SThomas Veerman Lst_Destroy(defIncPath, Dir_Destroy);
32012e2caf59SThomas Veerman Lst_Destroy(sysIncPath, Dir_Destroy);
32022e2caf59SThomas Veerman Lst_Destroy(parseIncPath, Dir_Destroy);
32032e2caf59SThomas Veerman Lst_Destroy(includes, NULL); /* Should be empty now */
32042e2caf59SThomas Veerman #endif
32052e2caf59SThomas Veerman }
32062e2caf59SThomas Veerman
32072e2caf59SThomas Veerman
32082e2caf59SThomas Veerman /*-
32092e2caf59SThomas Veerman *-----------------------------------------------------------------------
32102e2caf59SThomas Veerman * Parse_MainName --
32112e2caf59SThomas Veerman * Return a Lst of the main target to create for main()'s sake. If
32122e2caf59SThomas Veerman * no such target exists, we Punt with an obnoxious error message.
32132e2caf59SThomas Veerman *
32142e2caf59SThomas Veerman * Results:
32152e2caf59SThomas Veerman * A Lst of the single node to create.
32162e2caf59SThomas Veerman *
32172e2caf59SThomas Veerman * Side Effects:
32182e2caf59SThomas Veerman * None.
32192e2caf59SThomas Veerman *
32202e2caf59SThomas Veerman *-----------------------------------------------------------------------
32212e2caf59SThomas Veerman */
32222e2caf59SThomas Veerman Lst
Parse_MainName(void)32232e2caf59SThomas Veerman Parse_MainName(void)
32242e2caf59SThomas Veerman {
32252e2caf59SThomas Veerman Lst mainList; /* result list */
32262e2caf59SThomas Veerman
32272e2caf59SThomas Veerman mainList = Lst_Init(FALSE);
32282e2caf59SThomas Veerman
32292e2caf59SThomas Veerman if (mainNode == NULL) {
32302e2caf59SThomas Veerman Punt("no target to make.");
32312e2caf59SThomas Veerman /*NOTREACHED*/
32322e2caf59SThomas Veerman } else if (mainNode->type & OP_DOUBLEDEP) {
32332e2caf59SThomas Veerman (void)Lst_AtEnd(mainList, mainNode);
32342e2caf59SThomas Veerman Lst_Concat(mainList, mainNode->cohorts, LST_CONCNEW);
32352e2caf59SThomas Veerman }
32362e2caf59SThomas Veerman else
32372e2caf59SThomas Veerman (void)Lst_AtEnd(mainList, mainNode);
32382e2caf59SThomas Veerman Var_Append(".TARGETS", mainNode->name, VAR_GLOBAL);
32392e2caf59SThomas Veerman return (mainList);
32402e2caf59SThomas Veerman }
32412e2caf59SThomas Veerman
32422e2caf59SThomas Veerman /*-
32432e2caf59SThomas Veerman *-----------------------------------------------------------------------
32442e2caf59SThomas Veerman * ParseMark --
32452e2caf59SThomas Veerman * Add the filename and lineno to the GNode so that we remember
32462e2caf59SThomas Veerman * where it was first defined.
32472e2caf59SThomas Veerman *
32482e2caf59SThomas Veerman * Side Effects:
32492e2caf59SThomas Veerman * None.
32502e2caf59SThomas Veerman *
32512e2caf59SThomas Veerman *-----------------------------------------------------------------------
32522e2caf59SThomas Veerman */
32532e2caf59SThomas Veerman static void
ParseMark(GNode * gn)32542e2caf59SThomas Veerman ParseMark(GNode *gn)
32552e2caf59SThomas Veerman {
32562e2caf59SThomas Veerman gn->fname = curFile->fname;
32572e2caf59SThomas Veerman gn->lineno = curFile->lineno;
32582e2caf59SThomas Veerman }
3259