home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 May / W2KPRK.iso / apps / posix / source / MAKE / PARSE.C < prev    next >
C/C++ Source or Header  |  1999-11-17  |  64KB  |  2,257 lines

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