home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / make / var.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-18  |  51.5 KB  |  1,880 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[] = "@(#)var.c    5.7 (Berkeley) 6/1/90";
  41. #endif /* not lint */
  42.  
  43. /*-
  44.  * var.c --
  45.  *    Variable-handling functions
  46.  *
  47.  * Interface:
  48.  *    Var_Set              Set the value of a variable in the given
  49.  *                      context. The variable is created if it doesn't
  50.  *                      yet exist. The value and variable name need not
  51.  *                      be preserved.
  52.  *
  53.  *    Var_Append        Append more characters to an existing variable
  54.  *                      in the given context. The variable needn't
  55.  *                      exist already -- it will be created if it doesn't.
  56.  *                      A space is placed between the old value and the
  57.  *                      new one.
  58.  *
  59.  *    Var_Exists        See if a variable exists.
  60.  *
  61.  *    Var_Value         Return the value of a variable in a context or
  62.  *                      NULL if the variable is undefined.
  63.  *
  64.  *    Var_Subst         Substitute for all variables in a string using
  65.  *                      the given context as the top-most one. If the
  66.  *                      third argument is non-zero, Parse_Error is
  67.  *                      called if any variables are undefined.
  68.  *
  69.  *    Var_Parse         Parse a variable expansion from a string and
  70.  *                      return the result and the number of characters
  71.  *                      consumed.
  72.  *
  73.  *    Var_Delete        Delete a variable in a context.
  74.  *
  75.  *    Var_Init          Initialize this module.
  76.  *
  77.  * Debugging:
  78.  *    Var_Dump          Print out all variables defined in the given
  79.  *                      context.
  80.  *
  81.  * XXX: There's a lot of duplication in these functions.
  82.  */
  83.  
  84. #include    <ctype.h>
  85. #include    "make.h"
  86. #include    "buf.h"
  87. extern char *getenv();
  88.  
  89. /*
  90.  * This is a harmless return value for Var_Parse that can be used by Var_Subst
  91.  * to determine if there was an error in parsing -- easier than returning
  92.  * a flag, as things outside this module don't give a hoot.
  93.  */
  94. char     var_Error[] = "";
  95.  
  96. /*
  97.  * Similar to var_Error, but returned when the 'err' flag for Var_Parse is
  98.  * set false. Why not just use a constant? Well, gcc likes to condense
  99.  * identical string instances...
  100.  */
  101. char    varNoError[] = "";
  102.  
  103. /*
  104.  * Internally, variables are contained in four different contexts.
  105.  *    1) the environment. They may not be changed. If an environment
  106.  *        variable is appended-to, the result is placed in the global
  107.  *        context.
  108.  *    2) the global context. Variables set in the Makefile are located in
  109.  *        the global context. It is the penultimate context searched when
  110.  *        substituting.
  111.  *    3) the command-line context. All variables set on the command line
  112.  *       are placed in this context. They are UNALTERABLE once placed here.
  113.  *    4) the local context. Each target has associated with it a context
  114.  *       list. On this list are located the structures describing such
  115.  *       local variables as $(@) and $(*)
  116.  * The four contexts are searched in the reverse order from which they are
  117.  * listed.
  118.  */
  119. GNode          *VAR_GLOBAL;   /* variables from the makefile */
  120. GNode          *VAR_CMD;      /* variables defined on the command-line */
  121.  
  122. #define FIND_CMD    0x1   /* look in VAR_CMD when searching */
  123. #define FIND_GLOBAL    0x2   /* look in VAR_GLOBAL as well */
  124. #define FIND_ENV      0x4   /* look in the environment also */
  125.  
  126. typedef struct Var {
  127.     char          *name;    /* the variable's name */
  128.     Buffer      val;            /* its value */
  129.     int              flags;        /* miscellaneous status flags */
  130. #define VAR_IN_USE    1           /* Variable's value currently being used.
  131.                      * Used to avoid recursion */
  132. #define VAR_FROM_ENV    2           /* Variable comes from the environment */
  133. #define VAR_JUNK      4           /* Variable is a junk variable that
  134.                      * should be destroyed when done with
  135.                      * it. Used by Var_Parse for undefined,
  136.                      * modified variables */
  137. }  Var;
  138.  
  139. /*-
  140.  *-----------------------------------------------------------------------
  141.  * VarCmp  --
  142.  *    See if the given variable matches the named one. Called from
  143.  *    Lst_Find when searching for a variable of a given name.
  144.  *
  145.  * Results:
  146.  *    0 if they match. non-zero otherwise.
  147.  *
  148.  * Side Effects:
  149.  *    none
  150.  *-----------------------------------------------------------------------
  151.  */
  152. static int
  153. VarCmp (v, name)
  154.     Var            *v;        /* VAR structure to compare */
  155.     char           *name;    /* name to look for */
  156. {
  157.     return (strcmp (name, v->name));
  158. }
  159.  
  160. /*-
  161.  *-----------------------------------------------------------------------
  162.  * VarFind --
  163.  *    Find the given variable in the given context and any other contexts
  164.  *    indicated.
  165.  *
  166.  * Results:
  167.  *    A pointer to the structure describing the desired variable or
  168.  *    NIL if the variable does not exist.
  169.  *
  170.  * Side Effects:
  171.  *    None
  172.  *-----------------------------------------------------------------------
  173.  */
  174. static Var *
  175. VarFind (name, ctxt, flags)
  176.     char               *name;    /* name to find */
  177.     GNode              *ctxt;    /* context in which to find it */
  178.     int                 flags;    /* FIND_GLOBAL set means to look in the
  179.                  * VAR_GLOBAL context as well.
  180.                  * FIND_CMD set means to look in the VAR_CMD
  181.                  * context also.
  182.                  * FIND_ENV set means to look in the
  183.                  * environment */
  184. {
  185.     LstNode             var;
  186.     Var              *v;
  187.  
  188.     /*
  189.      * If the variable name begins with a '.', it could very well be one of
  190.      * the local ones.  We check the name against all the local variables
  191.      * and substitute the short version in for 'name' if it matches one of
  192.      * them.
  193.      */
  194.     if (*name == '.' && isupper(name[1]))
  195.         switch (name[1]) {
  196.         case 'A':
  197.             if (!strcmp(name, ".ALLSRC"))
  198.                 name = ALLSRC;
  199.             if (!strcmp(name, ".ARCHIVE"))
  200.                 name = ARCHIVE;
  201.             break;
  202.         case 'I':
  203.             if (!strcmp(name, ".IMPSRC"))
  204.                 name = IMPSRC;
  205.             break;
  206.         case 'M':
  207.             if (!strcmp(name, ".MEMBER"))
  208.                 name = MEMBER;
  209.             break;
  210.         case 'O':
  211.             if (!strcmp(name, ".OODATE"))
  212.                 name = OODATE;
  213.             break;
  214.         case 'P':
  215.             if (!strcmp(name, ".PREFIX"))
  216.                 name = PREFIX;
  217.             break;
  218.         case 'T':
  219.             if (!strcmp(name, ".TARGET"))
  220.                 name = TARGET;
  221.             break;
  222.         }
  223.     /*
  224.      * First look for the variable in the given context. If it's not there,
  225.      * look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order,
  226.      * depending on the FIND_* flags in 'flags'
  227.      */
  228.     var = Lst_Find (ctxt->context, (ClientData)name, VarCmp);
  229.  
  230.     if ((var == NILLNODE) && (flags & FIND_CMD) && (ctxt != VAR_CMD)) {
  231.     var = Lst_Find (VAR_CMD->context, (ClientData)name, VarCmp);
  232.     }
  233.     if (!checkEnvFirst && (var == NILLNODE) && (flags & FIND_GLOBAL) &&
  234.     (ctxt != VAR_GLOBAL))
  235.     {
  236.     var = Lst_Find (VAR_GLOBAL->context, (ClientData)name, VarCmp);
  237.     }
  238.     if ((var == NILLNODE) && (flags & FIND_ENV)) {
  239.     char *env;
  240.  
  241.     if ((env = getenv (name)) != NULL) {
  242.         /*
  243.          * If the variable is found in the environment, we only duplicate
  244.          * its value (since eVarVal was allocated on the stack). The name
  245.          * doesn't need duplication since it's always in the environment
  246.          */
  247.         int          len;
  248.         
  249.         v = (Var *) emalloc(sizeof(Var));
  250.         v->name = name;
  251.  
  252.         len = strlen(env);
  253.         
  254.         v->val = Buf_Init(len);
  255.         Buf_AddBytes(v->val, len, (Byte *)env);
  256.         
  257.         v->flags = VAR_FROM_ENV;
  258.         return (v);
  259.     } else if (checkEnvFirst && (flags & FIND_GLOBAL) &&
  260.            (ctxt != VAR_GLOBAL))
  261.     {
  262.         var = Lst_Find (VAR_GLOBAL->context, (ClientData)name, VarCmp);
  263.         if (var == NILLNODE) {
  264.         return ((Var *) NIL);
  265.         } else {
  266.         return ((Var *)Lst_Datum(var));
  267.         }
  268.     } else {
  269.         return((Var *)NIL);
  270.     }
  271.     } else if (var == NILLNODE) {
  272.     return ((Var *) NIL);
  273.     } else {
  274.     return ((Var *) Lst_Datum (var));
  275.     }
  276. }
  277.  
  278. /*-
  279.  *-----------------------------------------------------------------------
  280.  * VarAdd  --
  281.  *    Add a new variable of name name and value val to the given context
  282.  *
  283.  * Results:
  284.  *    None
  285.  *
  286.  * Side Effects:
  287.  *    The new variable is placed at the front of the given context
  288.  *    The name and val arguments are duplicated so they may
  289.  *    safely be freed.
  290.  *-----------------------------------------------------------------------
  291.  */
  292. static
  293. VarAdd (name, val, ctxt)
  294.     char           *name;    /* name of variable to add */
  295.     char           *val;    /* value to set it to */
  296.     GNode          *ctxt;    /* context in which to set it */
  297. {
  298.     register Var   *v;
  299.     int              len;
  300.  
  301.     v = (Var *) emalloc (sizeof (Var));
  302.  
  303.     v->name = strdup (name);
  304.  
  305.     len = strlen(val);
  306.     v->val = Buf_Init(len+1);
  307.     Buf_AddBytes(v->val, len, (Byte *)val);
  308.  
  309.     v->flags = 0;
  310.  
  311.     (void) Lst_AtFront (ctxt->context, (ClientData)v);
  312.     if (DEBUG(VAR)) {
  313.     printf("%s:%s = %s\n", ctxt->name, name, val);
  314.     }
  315. }
  316.  
  317. /*-
  318.  *-----------------------------------------------------------------------
  319.  * Var_Delete --
  320.  *    Remove a variable from a context.
  321.  *
  322.  * Results:
  323.  *    None.
  324.  *
  325.  * Side Effects:
  326.  *    The Var structure is removed and freed.
  327.  *
  328.  *-----------------------------------------------------------------------
  329.  */
  330. void
  331. Var_Delete(name, ctxt)
  332.     char          *name;
  333.     GNode      *ctxt;
  334. {
  335.     LstNode       ln;
  336.  
  337.     if (DEBUG(VAR)) {
  338.     printf("%s:delete %s\n", ctxt->name, name);
  339.     }
  340.     ln = Lst_Find(ctxt->context, (ClientData)name, VarCmp);
  341.     if (ln != NILLNODE) {
  342.     register Var       *v;
  343.  
  344.     v = (Var *)Lst_Datum(ln);
  345.     Lst_Remove(ctxt->context, ln);
  346.     Buf_Destroy(v->val, TRUE);
  347.     free(v->name);
  348.     free((char *)v);
  349.     }
  350. }
  351.  
  352. /*-
  353.  *-----------------------------------------------------------------------
  354.  * Var_Set --
  355.  *    Set the variable name to the value val in the given context.
  356.  *
  357.  * Results:
  358.  *    None.
  359.  *
  360.  * Side Effects:
  361.  *    If the variable doesn't yet exist, a new record is created for it.
  362.  *    Else the old value is freed and the new one stuck in its place
  363.  *
  364.  * Notes:
  365.  *    The variable is searched for only in its context before being
  366.  *    created in that context. I.e. if the context is VAR_GLOBAL,
  367.  *    only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only
  368.  *    VAR_CMD->context is searched. This is done to avoid the literally
  369.  *    thousands of unnecessary strcmp's that used to be done to
  370.  *    set, say, $(@) or $(<).
  371.  *-----------------------------------------------------------------------
  372.  */
  373. void
  374. Var_Set (name, val, ctxt)
  375.     char           *name;    /* name of variable to set */
  376.     char           *val;    /* value to give to the variable */
  377.     GNode          *ctxt;    /* context in which to set it */
  378. {
  379.     register Var   *v;
  380.  
  381.     /*
  382.      * We only look for a variable in the given context since anything set
  383.      * here will override anything in a lower context, so there's not much
  384.      * point in searching them all just to save a bit of memory...
  385.      */
  386.     v = VarFind (name, ctxt, 0);
  387.     if (v == (Var *) NIL) {
  388.     VarAdd (name, val, ctxt);
  389.     } else {
  390.     Buf_Discard(v->val, Buf_Size(v->val));
  391.     Buf_AddBytes(v->val, strlen(val), (Byte *)val);
  392.  
  393.     if (DEBUG(VAR)) {
  394.         printf("%s:%s = %s\n", ctxt->name, name, val);
  395.     }
  396.     }
  397.     /*
  398.      * Any variables given on the command line are automatically exported
  399.      * to the environment (as per POSIX standard)
  400.      */
  401.     if (ctxt == VAR_CMD) {
  402.     setenv(name, val);
  403.     }
  404. }
  405.  
  406. /*-
  407.  *-----------------------------------------------------------------------
  408.  * Var_Append --
  409.  *    The variable of the given name has the given value appended to it in
  410.  *    the given context.
  411.  *
  412.  * Results:
  413.  *    None
  414.  *
  415.  * Side Effects:
  416.  *    If the variable doesn't exist, it is created. Else the strings
  417.  *    are concatenated (with a space in between).
  418.  *
  419.  * Notes:
  420.  *    Only if the variable is being sought in the global context is the
  421.  *    environment searched.
  422.  *    XXX: Knows its calling circumstances in that if called with ctxt
  423.  *    an actual target, it will only search that context since only
  424.  *    a local variable could be being appended to. This is actually
  425.  *    a big win and must be tolerated.
  426.  *-----------------------------------------------------------------------
  427.  */
  428. void
  429. Var_Append (name, val, ctxt)
  430.     char           *name;    /* Name of variable to modify */
  431.     char           *val;    /* String to append to it */
  432.     GNode          *ctxt;    /* Context in which this should occur */
  433. {
  434.     register Var   *v;
  435.     register char  *cp;
  436.  
  437.     v = VarFind (name, ctxt, (ctxt == VAR_GLOBAL) ? FIND_ENV : 0);
  438.  
  439.     if (v == (Var *) NIL) {
  440.     VarAdd (name, val, ctxt);
  441.     } else {
  442.     Buf_AddByte(v->val, (Byte)' ');
  443.     Buf_AddBytes(v->val, strlen(val), (Byte *)val);
  444.  
  445.     if (DEBUG(VAR)) {
  446.         printf("%s:%s = %s\n", ctxt->name, name,
  447.            Buf_GetAll(v->val, (int *)NULL));
  448.     }
  449.  
  450.     if (v->flags & VAR_FROM_ENV) {
  451.         /*
  452.          * If the original variable came from the environment, we
  453.          * have to install it in the global context (we could place
  454.          * it in the environment, but then we should provide a way to
  455.          * export other variables...)
  456.          */
  457.         v->flags &= ~VAR_FROM_ENV;
  458.         Lst_AtFront(ctxt->context, (ClientData)v);
  459.     }
  460.     }
  461. }
  462.  
  463. /*-
  464.  *-----------------------------------------------------------------------
  465.  * Var_Exists --
  466.  *    See if the given variable exists.
  467.  *
  468.  * Results:
  469.  *    TRUE if it does, FALSE if it doesn't
  470.  *
  471.  * Side Effects:
  472.  *    None.
  473.  *
  474.  *-----------------------------------------------------------------------
  475.  */
  476. Boolean
  477. Var_Exists(name, ctxt)
  478.     char      *name;        /* Variable to find */
  479.     GNode      *ctxt;        /* Context in which to start search */
  480. {
  481.     Var              *v;
  482.  
  483.     v = VarFind(name, ctxt, FIND_CMD|FIND_GLOBAL|FIND_ENV);
  484.  
  485.     if (v == (Var *)NIL) {
  486.     return(FALSE);
  487.     } else if (v->flags & VAR_FROM_ENV) {
  488.     Buf_Destroy(v->val, TRUE);
  489.     free((char *)v);
  490.     }
  491.     return(TRUE);
  492. }
  493.  
  494. /*-
  495.  *-----------------------------------------------------------------------
  496.  * Var_Value --
  497.  *    Return the value of the named variable in the given context
  498.  *
  499.  * Results:
  500.  *    The value if the variable exists, NULL if it doesn't
  501.  *
  502.  * Side Effects:
  503.  *    None
  504.  *-----------------------------------------------------------------------
  505.  */
  506. char *
  507. Var_Value (name, ctxt)
  508.     char           *name;    /* name to find */
  509.     GNode          *ctxt;    /* context in which to search for it */
  510. {
  511.     Var            *v;
  512.  
  513.     v = VarFind (name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
  514.     if (v != (Var *) NIL) {
  515.     return ((char *)Buf_GetAll(v->val, (int *)NULL));
  516.     } else {
  517.     return ((char *) NULL);
  518.     }
  519. }
  520.  
  521. /*-
  522.  *-----------------------------------------------------------------------
  523.  * VarHead --
  524.  *    Remove the tail of the given word and place the result in the given
  525.  *    buffer.
  526.  *
  527.  * Results:
  528.  *    TRUE if characters were added to the buffer (a space needs to be
  529.  *    added to the buffer before the next word).
  530.  *
  531.  * Side Effects:
  532.  *    The trimmed word is added to the buffer.
  533.  *
  534.  *-----------------------------------------------------------------------
  535.  */
  536. static Boolean
  537. VarHead (word, addSpace, buf)
  538.     char          *word;        /* Word to trim */
  539.     Boolean       addSpace;     /* True if need to add a space to the buffer
  540.                  * before sticking in the head */
  541.     Buffer        buf;            /* Buffer in which to store it */
  542. {
  543.     register char *slash;
  544.  
  545.     slash = rindex (word, '/');
  546.     if (slash != (char *)NULL) {
  547.     if (addSpace) {
  548.         Buf_AddByte (buf, (Byte)' ');
  549.     }
  550.     *slash = '\0';
  551.     Buf_AddBytes (buf, strlen (word), (Byte *)word);
  552.     *slash = '/';
  553.     return (TRUE);
  554.     } else {
  555.     /*
  556.      * If no directory part, give . (q.v. the POSIX standard)
  557.      */
  558.     if (addSpace) {
  559.         Buf_AddBytes(buf, 2, (Byte *)" .");
  560.     } else {
  561.         Buf_AddByte(buf, (Byte)'.');
  562.     }
  563.     return(TRUE);
  564.     }
  565. }
  566.  
  567. /*-
  568.  *-----------------------------------------------------------------------
  569.  * VarTail --
  570.  *    Remove the head of the given word and place the result in the given
  571.  *    buffer.
  572.  *
  573.  * Results:
  574.  *    TRUE if characters were added to the buffer (a space needs to be
  575.  *    added to the buffer before the next word).
  576.  *
  577.  * Side Effects:
  578.  *    The trimmed word is added to the buffer.
  579.  *
  580.  *-----------------------------------------------------------------------
  581.  */
  582. static Boolean
  583. VarTail (word, addSpace, buf)
  584.     char          *word;        /* Word to trim */
  585.     Boolean       addSpace;     /* TRUE if need to stick a space in the
  586.                  * buffer before adding the tail */
  587.     Buffer        buf;            /* Buffer in which to store it */
  588. {
  589.     register char *slash;
  590.  
  591.     if (addSpace) {
  592.     Buf_AddByte (buf, (Byte)' ');
  593.     }
  594.  
  595.     slash = rindex (word, '/');
  596.     if (slash != (char *)NULL) {
  597.     *slash++ = '\0';
  598.     Buf_AddBytes (buf, strlen(slash), (Byte *)slash);
  599.     slash[-1] = '/';
  600.     } else {
  601.     Buf_AddBytes (buf, strlen(word), (Byte *)word);
  602.     }
  603.     return (TRUE);
  604. }
  605.  
  606. /*-
  607.  *-----------------------------------------------------------------------
  608.  * VarSuffix --
  609.  *    Place the suffix of the given word in the given buffer.
  610.  *
  611.  * Results:
  612.  *    TRUE if characters were added to the buffer (a space needs to be
  613.  *    added to the buffer before the next word).
  614.  *
  615.  * Side Effects:
  616.  *    The suffix from the word is placed in the buffer.
  617.  *
  618.  *-----------------------------------------------------------------------
  619.  */
  620. static Boolean
  621. VarSuffix (word, addSpace, buf)
  622.     char          *word;        /* Word to trim */
  623.     Boolean       addSpace;     /* TRUE if need to add a space before placing
  624.                  * the suffix in the buffer */
  625.     Buffer        buf;            /* Buffer in which to store it */
  626. {
  627.     register char *dot;
  628.  
  629.     dot = rindex (word, '.');
  630.     if (dot != (char *)NULL) {
  631.     if (addSpace) {
  632.         Buf_AddByte (buf, (Byte)' ');
  633.     }
  634.     *dot++ = '\0';
  635.     Buf_AddBytes (buf, strlen (dot), (Byte *)dot);
  636.     dot[-1] = '.';
  637.     return (TRUE);
  638.     } else {
  639.     return (addSpace);
  640.     }
  641. }
  642.  
  643. /*-
  644.  *-----------------------------------------------------------------------
  645.  * VarRoot --
  646.  *    Remove the suffix of the given word and place the result in the
  647.  *    buffer.
  648.  *
  649.  * Results:
  650.  *    TRUE if characters were added to the buffer (a space needs to be
  651.  *    added to the buffer before the next word).
  652.  *
  653.  * Side Effects:
  654.  *    The trimmed word is added to the buffer.
  655.  *
  656.  *-----------------------------------------------------------------------
  657.  */
  658. static Boolean
  659. VarRoot (word, addSpace, buf)
  660.     char          *word;        /* Word to trim */
  661.     Boolean       addSpace;     /* TRUE if need to add a space to the buffer
  662.                  * before placing the root in it */
  663.     Buffer        buf;            /* Buffer in which to store it */
  664. {
  665.     register char *dot;
  666.  
  667.     if (addSpace) {
  668.     Buf_AddByte (buf, (Byte)' ');
  669.     }
  670.  
  671.     dot = rindex (word, '.');
  672.     if (dot != (char *)NULL) {
  673.     *dot = '\0';
  674.     Buf_AddBytes (buf, strlen (word), (Byte *)word);
  675.     *dot = '.';
  676.     } else {
  677.     Buf_AddBytes (buf, strlen(word), (Byte *)word);
  678.     }
  679.     return (TRUE);
  680. }
  681.  
  682. /*-
  683.  *-----------------------------------------------------------------------
  684.  * VarMatch --
  685.  *    Place the word in the buffer if it matches the given pattern.
  686.  *    Callback function for VarModify to implement the :M modifier.
  687.  *    
  688.  * Results:
  689.  *    TRUE if a space should be placed in the buffer before the next
  690.  *    word.
  691.  *
  692.  * Side Effects:
  693.  *    The word may be copied to the buffer.
  694.  *
  695.  *-----------------------------------------------------------------------
  696.  */
  697. static Boolean
  698. VarMatch (word, addSpace, buf, pattern)
  699.     char          *word;        /* Word to examine */
  700.     Boolean       addSpace;     /* TRUE if need to add a space to the
  701.                  * buffer before adding the word, if it
  702.                  * matches */
  703.     Buffer        buf;            /* Buffer in which to store it */
  704.     char          *pattern;     /* Pattern the word must match */
  705. {
  706.     if (Str_Match(word, pattern)) {
  707.     if (addSpace) {
  708.         Buf_AddByte(buf, (Byte)' ');
  709.     }
  710.     addSpace = TRUE;
  711.     Buf_AddBytes(buf, strlen(word), (Byte *)word);
  712.     }
  713.     return(addSpace);
  714. }
  715.  
  716. /*-
  717.  *-----------------------------------------------------------------------
  718.  * VarNoMatch --
  719.  *    Place the word in the buffer if it doesn't match the given pattern.
  720.  *    Callback function for VarModify to implement the :N modifier.
  721.  *    
  722.  * Results:
  723.  *    TRUE if a space should be placed in the buffer before the next
  724.  *    word.
  725.  *
  726.  * Side Effects:
  727.  *    The word may be copied to the buffer.
  728.  *
  729.  *-----------------------------------------------------------------------
  730.  */
  731. static Boolean
  732. VarNoMatch (word, addSpace, buf, pattern)
  733.     char          *word;        /* Word to examine */
  734.     Boolean       addSpace;     /* TRUE if need to add a space to the
  735.                  * buffer before adding the word, if it
  736.                  * matches */
  737.     Buffer        buf;            /* Buffer in which to store it */
  738.     char          *pattern;     /* Pattern the word must match */
  739. {
  740.     if (!Str_Match(word, pattern)) {
  741.     if (addSpace) {
  742.         Buf_AddByte(buf, (Byte)' ');
  743.     }
  744.     addSpace = TRUE;
  745.     Buf_AddBytes(buf, strlen(word), (Byte *)word);
  746.     }
  747.     return(addSpace);
  748. }
  749.  
  750. typedef struct {
  751.     char          *lhs;        /* String to match */
  752.     int              leftLen;  /* Length of string */
  753.     char          *rhs;        /* Replacement string (w/ &'s removed) */
  754.     int              rightLen; /* Length of replacement */
  755.     int              flags;
  756. #define VAR_SUB_GLOBAL    1   /* Apply substitution globally */
  757. #define VAR_MATCH_START    2   /* Match at start of word */
  758. #define VAR_MATCH_END    4   /* Match at end of word */
  759. #define VAR_NO_SUB    8   /* Substitution is non-global and already done */
  760. } VarPattern;
  761.  
  762. /*-
  763.  *-----------------------------------------------------------------------
  764.  * VarSubstitute --
  765.  *    Perform a string-substitution on the given word, placing the
  766.  *    result in the passed buffer.
  767.  *
  768.  * Results:
  769.  *    TRUE if a space is needed before more characters are added.
  770.  *
  771.  * Side Effects:
  772.  *    None.
  773.  *
  774.  *-----------------------------------------------------------------------
  775.  */
  776. static Boolean
  777. VarSubstitute (word, addSpace, buf, pattern)
  778.     char              *word;        /* Word to modify */
  779.     Boolean           addSpace;   /* True if space should be added before
  780.                      * other characters */
  781.     Buffer            buf;        /* Buffer for result */
  782.     register VarPattern    *pattern;   /* Pattern for substitution */
  783. {
  784.     register int      wordLen;    /* Length of word */
  785.     register char     *cp;        /* General pointer */
  786.  
  787.     wordLen = strlen(word);
  788.     if ((pattern->flags & VAR_NO_SUB) == 0) {
  789.     /*
  790.      * Still substituting -- break it down into simple anchored cases
  791.      * and if none of them fits, perform the general substitution case.
  792.      */
  793.     if ((pattern->flags & VAR_MATCH_START) &&
  794.         (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) {
  795.         /*
  796.          * Anchored at start and beginning of word matches pattern
  797.          */
  798.         if ((pattern->flags & VAR_MATCH_END) &&
  799.             (wordLen == pattern->leftLen)) {
  800.             /*
  801.              * Also anchored at end and matches to the end (word
  802.              * is same length as pattern) add space and rhs only
  803.              * if rhs is non-null.
  804.              */
  805.             if (pattern->rightLen != 0) {
  806.                 if (addSpace) {
  807.                 Buf_AddByte(buf, (Byte)' ');
  808.                 }
  809.                 addSpace = TRUE;
  810.                 Buf_AddBytes(buf, pattern->rightLen,
  811.                      (Byte *)pattern->rhs);
  812.             }
  813.         } else if (pattern->flags & VAR_MATCH_END) {
  814.             /*
  815.              * Doesn't match to end -- copy word wholesale
  816.              */
  817.             goto nosub;
  818.         } else {
  819.             /*
  820.              * Matches at start but need to copy in trailing characters
  821.              */
  822.             if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){
  823.             if (addSpace) {
  824.                 Buf_AddByte(buf, (Byte)' ');
  825.             }
  826.             addSpace = TRUE;
  827.             }
  828.             Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
  829.             Buf_AddBytes(buf, wordLen - pattern->leftLen,
  830.                  (Byte *)(word + pattern->leftLen));
  831.         }
  832.     } else if (pattern->flags & VAR_MATCH_START) {
  833.         /*
  834.          * Had to match at start of word and didn't -- copy whole word.
  835.          */
  836.         goto nosub;
  837.     } else if (pattern->flags & VAR_MATCH_END) {
  838.         /*
  839.          * Anchored at end, Find only place match could occur (leftLen
  840.          * characters from the end of the word) and see if it does. Note
  841.          * that because the $ will be left at the end of the lhs, we have
  842.          * to use strncmp.
  843.          */
  844.         cp = word + (wordLen - pattern->leftLen);
  845.         if ((cp >= word) &&
  846.         (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) {
  847.         /*
  848.          * Match found. If we will place characters in the buffer,
  849.          * add a space before hand as indicated by addSpace, then
  850.          * stuff in the initial, unmatched part of the word followed
  851.          * by the right-hand-side.
  852.          */
  853.         if (((cp - word) + pattern->rightLen) != 0) {
  854.             if (addSpace) {
  855.             Buf_AddByte(buf, (Byte)' ');
  856.             }
  857.             addSpace = TRUE;
  858.         }
  859.         Buf_AddBytes(buf, cp - word, (Byte *)word);
  860.         Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
  861.         } else {
  862.         /*
  863.          * Had to match at end and didn't. Copy entire word.
  864.          */
  865.         goto nosub;
  866.         }
  867.     } else {
  868.         /*
  869.          * Pattern is unanchored: search for the pattern in the word using
  870.          * String_FindSubstring, copying unmatched portions and the
  871.          * right-hand-side for each match found, handling non-global
  872.          * subsititutions correctly, etc. When the loop is done, any
  873.          * remaining part of the word (word and wordLen are adjusted
  874.          * accordingly through the loop) is copied straight into the
  875.          * buffer.
  876.          * addSpace is set FALSE as soon as a space is added to the
  877.          * buffer.
  878.          */
  879.         register Boolean done;
  880.         int origSize;
  881.  
  882.         done = FALSE;
  883.         origSize = Buf_Size(buf);
  884.         while (!done) {
  885.         cp = Str_FindSubstring(word, pattern->lhs);
  886.         if (cp != (char *)NULL) {
  887.             if (addSpace && (((cp - word) + pattern->rightLen) != 0)){
  888.             Buf_AddByte(buf, (Byte)' ');
  889.             addSpace = FALSE;
  890.             }
  891.             Buf_AddBytes(buf, cp-word, (Byte *)word);
  892.             Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
  893.             wordLen -= (cp - word) + pattern->leftLen;
  894.             word = cp + pattern->leftLen;
  895.             if (wordLen == 0) {
  896.             done = TRUE;
  897.             }
  898.             if ((pattern->flags & VAR_SUB_GLOBAL) == 0) {
  899.             done = TRUE;
  900.             pattern->flags |= VAR_NO_SUB;
  901.             }
  902.         } else {
  903.             done = TRUE;
  904.         }
  905.         }
  906.         if (wordLen != 0) {
  907.         if (addSpace) {
  908.             Buf_AddByte(buf, (Byte)' ');
  909.         }
  910.         Buf_AddBytes(buf, wordLen, (Byte *)word);
  911.         }
  912.         /*
  913.          * If added characters to the buffer, need to add a space
  914.          * before we add any more. If we didn't add any, just return
  915.          * the previous value of addSpace.
  916.          */
  917.         return ((Buf_Size(buf) != origSize) || addSpace);
  918.     }
  919.     /*
  920.      * Common code for anchored substitutions: if performed a substitution
  921.      * and it's not supposed to be global, mark the pattern as requiring
  922.      * no more substitutions. addSpace was set TRUE if characters were
  923.      * added to the buffer.
  924.      */
  925.     if ((pattern->flags & VAR_SUB_GLOBAL) == 0) {
  926.         pattern->flags |= VAR_NO_SUB;
  927.     }
  928.     return (addSpace);
  929.     }
  930.  nosub:
  931.     if (addSpace) {
  932.     Buf_AddByte(buf, (Byte)' ');
  933.     }
  934.     Buf_AddBytes(buf, wordLen, (Byte *)word);
  935.     return(TRUE);
  936. }
  937.  
  938. /*-
  939.  *-----------------------------------------------------------------------
  940.  * VarModify --
  941.  *    Modify each of the words of the passed string using the given
  942.  *    function. Used to implement all modifiers.
  943.  *
  944.  * Results:
  945.  *    A string of all the words modified appropriately.
  946.  *
  947.  * Side Effects:
  948.  *    None.
  949.  *
  950.  *-----------------------------------------------------------------------
  951.  */
  952. static char *
  953. VarModify (str, modProc, datum)
  954.     char          *str;                /* String whose words should be trimmed */
  955.     Boolean          (*modProc)();     /* Function to use to modify them */
  956.     ClientData      datum;            /* Datum to pass it */
  957. {
  958.     Buffer        buf;                /* Buffer for the new string */
  959.     register char *cp;                /* Pointer to end of current word */
  960.     char          endc;                /* Character that ended the word */
  961.     Boolean       addSpace;         /* TRUE if need to add a space to the
  962.                      * buffer before adding the trimmed
  963.                      * word */
  964.     
  965.     buf = Buf_Init (0);
  966.     cp = str;
  967.     addSpace = FALSE;
  968.     
  969.     while (1) {
  970.     /*
  971.      * Skip to next word and place cp at its end.
  972.      */
  973.     while (isspace (*str)) {
  974.         str++;
  975.     }
  976.     for (cp = str; *cp != '\0' && !isspace (*cp); cp++) {
  977.         /* void */ ;
  978.     }
  979.     if (cp == str) {
  980.         /*
  981.          * If we didn't go anywhere, we must be done!
  982.          */
  983.         Buf_AddByte (buf, '\0');
  984.         str = (char *)Buf_GetAll (buf, (int *)NULL);
  985.         Buf_Destroy (buf, FALSE);
  986.         return (str);
  987.     }
  988.     /*
  989.      * Nuke terminating character, but save it in endc b/c if str was
  990.      * some variable's value, it would not be good to screw it
  991.      * over...
  992.      */
  993.     endc = *cp;
  994.     *cp = '\0';
  995.  
  996.     addSpace = (* modProc) (str, addSpace, buf, datum);
  997.  
  998.     if (endc) {
  999.         *cp++ = endc;
  1000.     }
  1001.     str = cp;
  1002.     }
  1003. }
  1004.  
  1005. /*-
  1006.  *-----------------------------------------------------------------------
  1007.  * Var_Parse --
  1008.  *    Given the start of a variable invocation, extract the variable
  1009.  *    name and find its value, then modify it according to the
  1010.  *    specification.
  1011.  *
  1012.  * Results:
  1013.  *    The (possibly-modified) value of the variable or var_Error if the
  1014.  *    specification is invalid. The length of the specification is
  1015.  *    placed in *lengthPtr (for invalid specifications, this is just
  1016.  *    2...?).
  1017.  *    A Boolean in *freePtr telling whether the returned string should
  1018.  *    be freed by the caller.
  1019.  *
  1020.  * Side Effects:
  1021.  *    None.
  1022.  *
  1023.  *-----------------------------------------------------------------------
  1024.  */
  1025. char *
  1026. Var_Parse (str, ctxt, err, lengthPtr, freePtr)
  1027.     char          *str;            /* The string to parse */
  1028.     GNode         *ctxt;        /* The context for the variable */
  1029.     Boolean         err;        /* TRUE if undefined variables are an error */
  1030.     int                *lengthPtr;    /* OUT: The length of the specification */
  1031.     Boolean         *freePtr;     /* OUT: TRUE if caller should free result */
  1032. {
  1033.     register char   *tstr;        /* Pointer into str */
  1034.     Var                *v;            /* Variable in invocation */
  1035.     register char   *cp;        /* Secondary pointer into str (place marker
  1036.                  * for tstr) */
  1037.     Boolean         haveModifier;/* TRUE if have modifiers for the variable */
  1038.     register char   endc;        /* Ending character when variable in parens
  1039.                  * or braces */
  1040.     char            *start;
  1041.     Boolean         dynamic;    /* TRUE if the variable is local and we're
  1042.                  * expanding it in a non-local context. This
  1043.                  * is done to support dynamic sources. The
  1044.                  * result is just the invocation, unaltered */
  1045.     
  1046.     *freePtr = FALSE;
  1047.     dynamic = FALSE;
  1048.     start = str;
  1049.     
  1050.     if (str[1] != '(' && str[1] != '{') {
  1051.     /*
  1052.      * If it's not bounded by braces of some sort, life is much simpler.
  1053.      * We just need to check for the first character and return the
  1054.      * value if it exists.
  1055.      */
  1056.     char      name[2];
  1057.  
  1058.     name[0] = str[1];
  1059.     name[1] = '\0';
  1060.  
  1061.     v = VarFind (name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
  1062.     if (v == (Var *)NIL) {
  1063.         *lengthPtr = 2;
  1064.         
  1065.         if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) {
  1066.         /*
  1067.          * If substituting a local variable in a non-local context,
  1068.          * assume it's for dynamic source stuff. We have to handle
  1069.          * this specially and return the longhand for the variable
  1070.          * with the dollar sign escaped so it makes it back to the
  1071.          * caller. Only four of the local variables are treated
  1072.          * specially as they are the only four that will be set
  1073.          * when dynamic sources are expanded.
  1074.          */
  1075.         switch (str[1]) {
  1076.             case '@':
  1077.             return("$(.TARGET)");
  1078.             case '%':
  1079.             return("$(.ARCHIVE)");
  1080.             case '*':
  1081.             return("$(.PREFIX)");
  1082.             case '!':
  1083.             return("$(.MEMBER)");
  1084.         }
  1085.         }
  1086.         /*
  1087.          * Error
  1088.          */
  1089.         return (err ? var_Error : varNoError);
  1090.     } else {
  1091.         haveModifier = FALSE;
  1092.         tstr = &str[1];
  1093.         endc = str[1];
  1094.     }
  1095.     } else {
  1096.     endc = str[1] == '(' ? ')' : '}';
  1097.  
  1098.     /*
  1099.      * Skip to the end character or a colon, whichever comes first.
  1100.      */
  1101.     for (tstr = str + 2;
  1102.          *tstr != '\0' && *tstr != endc && *tstr != ':';
  1103.          tstr++)
  1104.     {
  1105.         continue;
  1106.     }
  1107.     if (*tstr == ':') {
  1108.         haveModifier = TRUE;
  1109.     } else if (*tstr != '\0') {
  1110.         haveModifier = FALSE;
  1111.     } else {
  1112.         /*
  1113.          * If we never did find the end character, return NULL
  1114.          * right now, setting the length to be the distance to
  1115.          * the end of the string, since that's what make does.
  1116.          */
  1117.         *lengthPtr = tstr - str;
  1118.         return (var_Error);
  1119.     }
  1120.     *tstr = '\0';
  1121.      
  1122.     v = VarFind (str + 2, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
  1123.     if ((v == (Var *)NIL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) &&
  1124.         ((tstr-str) == 4) && (str[3] == 'F' || str[3] == 'D'))
  1125.     {
  1126.         /*
  1127.          * Check for bogus D and F forms of local variables since we're
  1128.          * in a local context and the name is the right length.
  1129.          */
  1130.         switch(str[2]) {
  1131.         case '@':
  1132.         case '%':
  1133.         case '*':
  1134.         case '!':
  1135.         case '>':
  1136.         case '<':
  1137.         {
  1138.             char    vname[2];
  1139.             char    *val;
  1140.  
  1141.             /*
  1142.              * Well, it's local -- go look for it.
  1143.              */
  1144.             vname[0] = str[2];
  1145.             vname[1] = '\0';
  1146.             v = VarFind(vname, ctxt, 0);
  1147.             
  1148.             if (v != (Var *)NIL) {
  1149.             /*
  1150.              * No need for nested expansion or anything, as we're
  1151.              * the only one who sets these things and we sure don't
  1152.              * but nested invocations in them...
  1153.              */
  1154.             val = (char *)Buf_GetAll(v->val, (int *)NULL);
  1155.             
  1156.             if (str[3] == 'D') {
  1157.                 val = VarModify(val, VarHead, (ClientData)0);
  1158.             } else {
  1159.                 val = VarModify(val, VarTail, (ClientData)0);
  1160.             }
  1161.             /*
  1162.              * Resulting string is dynamically allocated, so
  1163.              * tell caller to free it.
  1164.              */
  1165.             *freePtr = TRUE;
  1166.             *lengthPtr = tstr-start+1;
  1167.             *tstr = endc;
  1168.             return(val);
  1169.             }
  1170.             break;
  1171.         }
  1172.         }
  1173.     }
  1174.                 
  1175.     if (v == (Var *)NIL) {
  1176.         if ((((tstr-str) == 3) ||
  1177.          ((((tstr-str) == 4) && (str[3] == 'F' ||
  1178.                      str[3] == 'D')))) &&
  1179.         ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))
  1180.         {
  1181.         /*
  1182.          * If substituting a local variable in a non-local context,
  1183.          * assume it's for dynamic source stuff. We have to handle
  1184.          * this specially and return the longhand for the variable
  1185.          * with the dollar sign escaped so it makes it back to the
  1186.          * caller. Only four of the local variables are treated
  1187.          * specially as they are the only four that will be set
  1188.          * when dynamic sources are expanded.
  1189.          */
  1190.         switch (str[2]) {
  1191.             case '@':
  1192.             case '%':
  1193.             case '*':
  1194.             case '!':
  1195.             dynamic = TRUE;
  1196.             break;
  1197.         }
  1198.         } else if (((tstr-str) > 4) && (str[2] == '.') &&
  1199.                isupper(str[3]) &&
  1200.                ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))
  1201.         {
  1202.         int    len;
  1203.         
  1204.         len = (tstr-str) - 3;
  1205.         if ((strncmp(str+2, ".TARGET", len) == 0) ||
  1206.             (strncmp(str+2, ".ARCHIVE", len) == 0) ||
  1207.             (strncmp(str+2, ".PREFIX", len) == 0) ||
  1208.             (strncmp(str+2, ".MEMBER", len) == 0))
  1209.         {
  1210.             dynamic = TRUE;
  1211.         }
  1212.         }
  1213.         
  1214.         if (!haveModifier) {
  1215.         /*
  1216.          * No modifiers -- have specification length so we can return
  1217.          * now.
  1218.          */
  1219.         *lengthPtr = tstr - start + 1;
  1220.         *tstr = endc;
  1221.         if (dynamic) {
  1222.             str = emalloc(*lengthPtr + 1);
  1223.             strncpy(str, start, *lengthPtr);
  1224.             str[*lengthPtr] = '\0';
  1225.             *freePtr = TRUE;
  1226.             return(str);
  1227.         } else {
  1228.             return (err ? var_Error : varNoError);
  1229.         }
  1230.         } else {
  1231.         /*
  1232.          * Still need to get to the end of the variable specification,
  1233.          * so kludge up a Var structure for the modifications
  1234.          */
  1235.         v = (Var *) emalloc(sizeof(Var));
  1236.         v->name = &str[1];
  1237.         v->val = Buf_Init(1);
  1238.         v->flags = VAR_JUNK;
  1239.         }
  1240.     }
  1241.     }
  1242.  
  1243.     if (v->flags & VAR_IN_USE) {
  1244.     Fatal("Variable %s is recursive.", v->name);
  1245.     /*NOTREACHED*/
  1246.     } else {
  1247.     v->flags |= VAR_IN_USE;
  1248.     }
  1249.     /*
  1250.      * Before doing any modification, we have to make sure the value
  1251.      * has been fully expanded. If it looks like recursion might be
  1252.      * necessary (there's a dollar sign somewhere in the variable's value)
  1253.      * we just call Var_Subst to do any other substitutions that are
  1254.      * necessary. Note that the value returned by Var_Subst will have
  1255.      * been dynamically-allocated, so it will need freeing when we
  1256.      * return.
  1257.      */
  1258.     str = (char *)Buf_GetAll(v->val, (int *)NULL);
  1259.     if (index (str, '$') != (char *)NULL) {
  1260.     str = Var_Subst(str, ctxt, err);
  1261.     *freePtr = TRUE;
  1262.     }
  1263.     
  1264.     v->flags &= ~VAR_IN_USE;
  1265.     
  1266.     /*
  1267.      * Now we need to apply any modifiers the user wants applied.
  1268.      * These are:
  1269.      *        :M<pattern>    words which match the given <pattern>.
  1270.      *                    <pattern> is of the standard file
  1271.      *                    wildcarding form.
  1272.      *        :S<d><pat1><d><pat2><d>[g]
  1273.      *                    Substitute <pat2> for <pat1> in the value
  1274.      *        :H            Substitute the head of each word
  1275.      *        :T            Substitute the tail of each word
  1276.      *        :E            Substitute the extension (minus '.') of
  1277.      *                    each word
  1278.      *        :R            Substitute the root of each word
  1279.      *                    (pathname minus the suffix).
  1280.      *              :lhs=rhs      Like :S, but the rhs goes to the end of
  1281.      *                            the invocation.
  1282.      */
  1283.     if ((str != (char *)NULL) && haveModifier) {
  1284.     /*
  1285.      * Skip initial colon while putting it back.
  1286.      */
  1287.     *tstr++ = ':';
  1288.     while (*tstr != endc) {
  1289.         char    *newStr;    /* New value to return */
  1290.         char    termc;        /* Character which terminated scan */
  1291.         
  1292.         if (DEBUG(VAR)) {
  1293.         printf("Applying :%c to \"%s\"\n", *tstr, str);
  1294.         }
  1295.         switch (*tstr) {
  1296.         case 'N':
  1297.         case 'M':
  1298.         {
  1299.             char    *pattern;
  1300.             char    *cp2;
  1301.             Boolean copy;
  1302.  
  1303.             copy = FALSE;
  1304.             for (cp = tstr + 1;
  1305.              *cp != '\0' && *cp != ':' && *cp != endc;
  1306.              cp++)
  1307.             {
  1308.             if (*cp == '\\' && (cp[1] == ':' || cp[1] == endc)){
  1309.                 copy = TRUE;
  1310.                 cp++;
  1311.             }
  1312.             }
  1313.             termc = *cp;
  1314.             *cp = '\0';
  1315.             if (copy) {
  1316.             /*
  1317.              * Need to compress the \:'s out of the pattern, so
  1318.              * allocate enough room to hold the uncompressed
  1319.              * pattern (note that cp started at tstr+1, so
  1320.              * cp - tstr takes the null byte into account) and
  1321.              * compress the pattern into the space.
  1322.              */
  1323.             pattern = emalloc(cp - tstr);
  1324.             for (cp2 = pattern, cp = tstr + 1;
  1325.                  *cp != '\0';
  1326.                  cp++, cp2++)
  1327.             {
  1328.                 if ((*cp == '\\') &&
  1329.                 (cp[1] == ':' || cp[1] == endc)) {
  1330.                     cp++;
  1331.                 }
  1332.                 *cp2 = *cp;
  1333.             }
  1334.             *cp2 = '\0';
  1335.             } else {
  1336.             pattern = &tstr[1];
  1337.             }
  1338.             if (*tstr == 'M' || *tstr == 'm') {
  1339.             newStr = VarModify(str, VarMatch, (ClientData)pattern);
  1340.             } else {
  1341.             newStr = VarModify(str, VarNoMatch,
  1342.                        (ClientData)pattern);
  1343.             }
  1344.             if (copy) {
  1345.             free(pattern);
  1346.             }
  1347.             break;
  1348.         }
  1349.         case 'S':
  1350.         {
  1351.             VarPattern         pattern;
  1352.             register char   delim;
  1353.             Buffer          buf;        /* Buffer for patterns */
  1354.             register char   *cp2;
  1355.             int                lefts;
  1356.  
  1357.             pattern.flags = 0;
  1358.             delim = tstr[1];
  1359.             tstr += 2;
  1360.             /*
  1361.              * If pattern begins with '^', it is anchored to the
  1362.              * start of the word -- skip over it and flag pattern.
  1363.              */
  1364.             if (*tstr == '^') {
  1365.             pattern.flags |= VAR_MATCH_START;
  1366.             tstr += 1;
  1367.             }
  1368.  
  1369.             buf = Buf_Init(0);
  1370.             
  1371.             /*
  1372.              * Pass through the lhs looking for 1) escaped delimiters,
  1373.              * '$'s and backslashes (place the escaped character in
  1374.              * uninterpreted) and 2) unescaped $'s that aren't before
  1375.              * the delimiter (expand the variable substitution).
  1376.              * The result is left in the Buffer buf.
  1377.              */
  1378.             for (cp = tstr; *cp != '\0' && *cp != delim; cp++) {
  1379.             if ((*cp == '\\') &&
  1380.                 ((cp[1] == delim) ||
  1381.                  (cp[1] == '$') ||
  1382.                  (cp[1] == '\\')))
  1383.             {
  1384.                 Buf_AddByte(buf, (Byte)cp[1]);
  1385.                 cp++;
  1386.             } else if (*cp == '$') {
  1387.                 if (cp[1] != delim) {
  1388.                 /*
  1389.                  * If unescaped dollar sign not before the
  1390.                  * delimiter, assume it's a variable
  1391.                  * substitution and recurse.
  1392.                  */
  1393.                 char        *cp2;
  1394.                 int        len;
  1395.                 Boolean        freeIt;
  1396.                 
  1397.                 cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt);
  1398.                 Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
  1399.                 if (freeIt) {
  1400.                     free(cp2);
  1401.                 }
  1402.                 cp += len - 1;
  1403.                 } else {
  1404.                 /*
  1405.                  * Unescaped $ at end of pattern => anchor
  1406.                  * pattern at end.
  1407.                  */
  1408.                 pattern.flags |= VAR_MATCH_END;
  1409.                 }
  1410.             } else {
  1411.                 Buf_AddByte(buf, (Byte)*cp);
  1412.             }
  1413.             }
  1414.  
  1415.             Buf_AddByte(buf, (Byte)'\0');
  1416.             
  1417.             /*
  1418.              * If lhs didn't end with the delimiter, complain and
  1419.              * return NULL
  1420.              */
  1421.             if (*cp != delim) {
  1422.             *lengthPtr = cp - start + 1;
  1423.             if (*freePtr) {
  1424.                 free(str);
  1425.             }
  1426.             Buf_Destroy(buf, TRUE);
  1427.             Error("Unclosed substitution for %s (%c missing)",
  1428.                   v->name, delim);
  1429.             return (var_Error);
  1430.             }
  1431.  
  1432.             /*
  1433.              * Fetch pattern and destroy buffer, but preserve the data
  1434.              * in it, since that's our lhs. Note that Buf_GetAll
  1435.              * will return the actual number of bytes, which includes
  1436.              * the null byte, so we have to decrement the length by
  1437.              * one.
  1438.              */
  1439.             pattern.lhs = (char *)Buf_GetAll(buf, &pattern.leftLen);
  1440.             pattern.leftLen--;
  1441.             Buf_Destroy(buf, FALSE);
  1442.  
  1443.             /*
  1444.              * Now comes the replacement string. Three things need to
  1445.              * be done here: 1) need to compress escaped delimiters and
  1446.              * ampersands and 2) need to replace unescaped ampersands
  1447.              * with the l.h.s. (since this isn't regexp, we can do
  1448.              * it right here) and 3) expand any variable substitutions.
  1449.              */
  1450.             buf = Buf_Init(0);
  1451.             
  1452.             tstr = cp + 1;
  1453.             for (cp = tstr; *cp != '\0' && *cp != delim; cp++) {
  1454.             if ((*cp == '\\') &&
  1455.                 ((cp[1] == delim) ||
  1456.                  (cp[1] == '&') ||
  1457.                  (cp[1] == '\\') ||
  1458.                  (cp[1] == '$')))
  1459.             {
  1460.                 Buf_AddByte(buf, (Byte)cp[1]);
  1461.                 cp++;
  1462.             } else if ((*cp == '$') && (cp[1] != delim)) {
  1463.                 char    *cp2;
  1464.                 int        len;
  1465.                 Boolean freeIt;
  1466.  
  1467.                 cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt);
  1468.                 Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
  1469.                 cp += len - 1;
  1470.                 if (freeIt) {
  1471.                 free(cp2);
  1472.                 }
  1473.             } else if (*cp == '&') {
  1474.                 Buf_AddBytes(buf, pattern.leftLen,
  1475.                      (Byte *)pattern.lhs);
  1476.             } else {
  1477.                 Buf_AddByte(buf, (Byte)*cp);
  1478.             }
  1479.             }
  1480.  
  1481.             Buf_AddByte(buf, (Byte)'\0');
  1482.             
  1483.             /*
  1484.              * If didn't end in delimiter character, complain
  1485.              */
  1486.             if (*cp != delim) {
  1487.             *lengthPtr = cp - start + 1;
  1488.             if (*freePtr) {
  1489.                 free(str);
  1490.             }
  1491.             Buf_Destroy(buf, TRUE);
  1492.             Error("Unclosed substitution for %s (%c missing)",
  1493.                   v->name, delim);
  1494.             return (var_Error);
  1495.             }
  1496.  
  1497.             pattern.rhs = (char *)Buf_GetAll(buf, &pattern.rightLen);
  1498.             pattern.rightLen--;
  1499.             Buf_Destroy(buf, FALSE);
  1500.  
  1501.             /*
  1502.              * Check for global substitution. If 'g' after the final
  1503.              * delimiter, substitution is global and is marked that
  1504.              * way.
  1505.              */
  1506.             cp++;
  1507.             if (*cp == 'g') {
  1508.             pattern.flags |= VAR_SUB_GLOBAL;
  1509.             cp++;
  1510.             }
  1511.  
  1512.             termc = *cp;
  1513.             newStr = VarModify(str, VarSubstitute,
  1514.                        (ClientData)&pattern);
  1515.             /*
  1516.              * Free the two strings.
  1517.              */
  1518.             free(pattern.lhs);
  1519.             free(pattern.rhs);
  1520.             break;
  1521.         }
  1522.         case 'T':
  1523.             if (tstr[1] == endc || tstr[1] == ':') {
  1524.             newStr = VarModify (str, VarTail, (ClientData)0);
  1525.             cp = tstr + 1;
  1526.             termc = *cp;
  1527.             break;
  1528.             }
  1529.             /*FALLTHRU*/
  1530.         case 'H':
  1531.             if (tstr[1] == endc || tstr[1] == ':') {
  1532.             newStr = VarModify (str, VarHead, (ClientData)0);
  1533.             cp = tstr + 1;
  1534.             termc = *cp;
  1535.             break;
  1536.             }
  1537.             /*FALLTHRU*/
  1538.         case 'E':
  1539.             if (tstr[1] == endc || tstr[1] == ':') {
  1540.             newStr = VarModify (str, VarSuffix, (ClientData)0);
  1541.             cp = tstr + 1;
  1542.             termc = *cp;
  1543.             break;
  1544.             }
  1545.             /*FALLTHRU*/
  1546.         case 'R':
  1547.             if (tstr[1] == endc || tstr[1] == ':') {
  1548.             newStr = VarModify (str, VarRoot, (ClientData)0);
  1549.             cp = tstr + 1;
  1550.             termc = *cp;
  1551.             break;
  1552.             }
  1553.             /*FALLTHRU*/
  1554.         default: {
  1555.             /*
  1556.              * This can either be a bogus modifier or a System-V
  1557.              * substitution command.
  1558.              */
  1559.             VarPattern      pattern;
  1560.             Boolean         eqFound;
  1561.             
  1562.             pattern.flags = 0;
  1563.             eqFound = FALSE;
  1564.             /*
  1565.              * First we make a pass through the string trying
  1566.              * to verify it is a SYSV-make-style translation:
  1567.              * it must be: <string1>=<string2>)
  1568.              */
  1569.             for (cp = tstr; *cp != '\0' && *cp != endc; cp++) {
  1570.             if (*cp == '=') {
  1571.                 eqFound = TRUE;
  1572.                 /* continue looking for endc */
  1573.             }
  1574.             }
  1575.             if (*cp == endc && eqFound) {
  1576.             
  1577.             /*
  1578.              * Now we break this sucker into the lhs and
  1579.              * rhs. We must null terminate them of course.
  1580.              */
  1581.             for (cp = tstr; *cp != '='; cp++) {
  1582.                 ;
  1583.             }
  1584.             pattern.lhs = tstr;
  1585.             pattern.leftLen = cp - tstr;
  1586.             *cp++ = '\0';
  1587.             
  1588.             pattern.rhs = cp;
  1589.             while (*cp != endc) {
  1590.                 cp++;
  1591.             }
  1592.             pattern.rightLen = cp - pattern.rhs;
  1593.             *cp = '\0';
  1594.             
  1595.             /*
  1596.              * SYSV modifications happen through the whole
  1597.              * string. Note the pattern is anchored at the end.
  1598.              */
  1599.             pattern.flags |= VAR_SUB_GLOBAL|VAR_MATCH_END;
  1600.  
  1601.             newStr = VarModify(str, VarSubstitute,
  1602.                        (ClientData)&pattern);
  1603.  
  1604.             /*
  1605.              * Restore the nulled characters
  1606.              */
  1607.             pattern.lhs[pattern.leftLen] = '=';
  1608.             pattern.rhs[pattern.rightLen] = endc;
  1609.             termc = endc;
  1610.             } else {
  1611.             Error ("Unknown modifier '%c'\n", *tstr);
  1612.             for (cp = tstr+1;
  1613.                  *cp != ':' && *cp != endc && *cp != '\0';
  1614.                  cp++) {
  1615.                  ;
  1616.             }
  1617.             termc = *cp;
  1618.             newStr = var_Error;
  1619.             }
  1620.         }
  1621.         }
  1622.         if (DEBUG(VAR)) {
  1623.         printf("Result is \"%s\"\n", newStr);
  1624.         }
  1625.         
  1626.         if (*freePtr) {
  1627.         free (str);
  1628.         }
  1629.         str = newStr;
  1630.         if (str != var_Error) {
  1631.         *freePtr = TRUE;
  1632.         } else {
  1633.         *freePtr = FALSE;
  1634.         }
  1635.         if (termc == '\0') {
  1636.         Error("Unclosed variable specification for %s", v->name);
  1637.         } else if (termc == ':') {
  1638.         *cp++ = termc;
  1639.         } else {
  1640.         *cp = termc;
  1641.         }
  1642.         tstr = cp;
  1643.     }
  1644.     *lengthPtr = tstr - start + 1;
  1645.     } else {
  1646.     *lengthPtr = tstr - start + 1;
  1647.     *tstr = endc;
  1648.     }
  1649.     
  1650.     if (v->flags & VAR_FROM_ENV) {
  1651.     Boolean      destroy = FALSE;
  1652.     
  1653.     if (str != (char *)Buf_GetAll(v->val, (int *)NULL)) {
  1654.         destroy = TRUE;
  1655.     } else {
  1656.         /*
  1657.          * Returning the value unmodified, so tell the caller to free
  1658.          * the thing.
  1659.          */
  1660.         *freePtr = TRUE;
  1661.     }
  1662.     Buf_Destroy(v->val, destroy);
  1663.     free((Address)v);
  1664.     } else if (v->flags & VAR_JUNK) {
  1665.     /*
  1666.      * Perform any free'ing needed and set *freePtr to FALSE so the caller
  1667.      * doesn't try to free a static pointer.
  1668.      */
  1669.     if (*freePtr) {
  1670.         free(str);
  1671.     }
  1672.     *freePtr = FALSE;
  1673.     free((Address)v);
  1674.     if (dynamic) {
  1675.         str = emalloc(*lengthPtr + 1);
  1676.         strncpy(str, start, *lengthPtr);
  1677.         str[*lengthPtr] = '\0';
  1678.         *freePtr = TRUE;
  1679.     } else {
  1680.         str = var_Error;
  1681.     }
  1682.     }
  1683.     return (str);
  1684. }
  1685.  
  1686. /*-
  1687.  *-----------------------------------------------------------------------
  1688.  * Var_Subst  --
  1689.  *    Substitute for all variables in the given string in the given context
  1690.  *    If undefErr is TRUE, Parse_Error will be called when an undefined
  1691.  *    variable is encountered.
  1692.  *
  1693.  * Results:
  1694.  *    The resulting string.
  1695.  *
  1696.  * Side Effects:
  1697.  *    None. The old string must be freed by the caller
  1698.  *-----------------------------------------------------------------------
  1699.  */
  1700. char *
  1701. Var_Subst (str, ctxt, undefErr)
  1702.     register char *str;                /* the string in which to substitute */
  1703.     GNode         *ctxt;        /* the context wherein to find variables */
  1704.     Boolean       undefErr;         /* TRUE if undefineds are an error */
  1705. {
  1706.     Buffer        buf;                /* Buffer for forming things */
  1707.     char          *val;            /* Value to substitute for a variable */
  1708.     int              length;           /* Length of the variable invocation */
  1709.     Boolean       doFree;           /* Set true if val should be freed */
  1710.     static Boolean errorReported;   /* Set true if an error has already
  1711.                      * been reported to prevent a plethora
  1712.                      * of messages when recursing */
  1713.  
  1714.     buf = Buf_Init (BSIZE);
  1715.     errorReported = FALSE;
  1716.  
  1717.     while (*str) {
  1718.     if ((*str == '$') && (str[1] == '$')) {
  1719.         /*
  1720.          * A dollar sign may be escaped either with another dollar sign.
  1721.          * In such a case, we skip over the escape character and store the
  1722.          * dollar sign into the buffer directly.
  1723.          */
  1724.         str++;
  1725.         Buf_AddByte(buf, (Byte)*str);
  1726.         str++;
  1727.     } else if (*str != '$') {
  1728.         /*
  1729.          * Skip as many characters as possible -- either to the end of
  1730.          * the string or to the next dollar sign (variable invocation).
  1731.          */
  1732.         char  *cp;
  1733.  
  1734.         for (cp = str++; *str != '$' && *str != '\0'; str++) {
  1735.         ;
  1736.         }
  1737.         Buf_AddBytes(buf, str - cp, (Byte *)cp);
  1738.     } else {
  1739.         val = Var_Parse (str, ctxt, undefErr, &length, &doFree);
  1740.  
  1741.         /*
  1742.          * When we come down here, val should either point to the
  1743.          * value of this variable, suitably modified, or be NULL.
  1744.          * Length should be the total length of the potential
  1745.          * variable invocation (from $ to end character...)
  1746.          */
  1747.         if (val == var_Error || val == varNoError) {
  1748.         /*
  1749.          * If performing old-time variable substitution, skip over
  1750.          * the variable and continue with the substitution. Otherwise,
  1751.          * store the dollar sign and advance str so we continue with
  1752.          * the string...
  1753.          */
  1754.         if (oldVars) {
  1755.             str += length;
  1756.         } else if (undefErr) {
  1757.             /*
  1758.              * If variable is undefined, complain and skip the
  1759.              * variable. The complaint will stop us from doing anything
  1760.              * when the file is parsed.
  1761.              */
  1762.             if (!errorReported) {
  1763.             Parse_Error (PARSE_FATAL,
  1764.                      "Undefined variable \"%.*s\"",length,str);
  1765.             }
  1766.             str += length;
  1767.             errorReported = TRUE;
  1768.         } else {
  1769.             Buf_AddByte (buf, (Byte)*str);
  1770.             str += 1;
  1771.         }
  1772.         } else {
  1773.         /*
  1774.          * We've now got a variable structure to store in. But first,
  1775.          * advance the string pointer.
  1776.          */
  1777.         str += length;
  1778.         
  1779.         /*
  1780.          * Copy all the characters from the variable value straight
  1781.          * into the new string.
  1782.          */
  1783.         Buf_AddBytes (buf, strlen (val), (Byte *)val);
  1784.         if (doFree) {
  1785.             free ((Address)val);
  1786.         }
  1787.         }
  1788.     }
  1789.     }
  1790.     
  1791.     Buf_AddByte (buf, '\0');
  1792.     str = (char *)Buf_GetAll (buf, (int *)NULL);
  1793.     Buf_Destroy (buf, FALSE);
  1794.     return (str);
  1795. }
  1796.  
  1797. /*-
  1798.  *-----------------------------------------------------------------------
  1799.  * Var_GetTail --
  1800.  *    Return the tail from each of a list of words. Used to set the
  1801.  *    System V local variables.
  1802.  *
  1803.  * Results:
  1804.  *    The resulting string.
  1805.  *
  1806.  * Side Effects:
  1807.  *    None.
  1808.  *
  1809.  *-----------------------------------------------------------------------
  1810.  */
  1811. char *
  1812. Var_GetTail(file)
  1813.     char        *file;        /* Filename to modify */
  1814. {
  1815.     return(VarModify(file, VarTail, (ClientData)0));
  1816. }
  1817.  
  1818. /*-
  1819.  *-----------------------------------------------------------------------
  1820.  * Var_GetHead --
  1821.  *    Find the leading components of a (list of) filename(s).
  1822.  *    XXX: VarHead does not replace foo by ., as (sun) System V make
  1823.  *    does.
  1824.  *
  1825.  * Results:
  1826.  *    The leading components.
  1827.  *
  1828.  * Side Effects:
  1829.  *    None.
  1830.  *
  1831.  *-----------------------------------------------------------------------
  1832.  */
  1833. char *
  1834. Var_GetHead(file)
  1835.     char        *file;        /* Filename to manipulate */
  1836. {
  1837.     return(VarModify(file, VarHead, (ClientData)0));
  1838. }
  1839.  
  1840. /*-
  1841.  *-----------------------------------------------------------------------
  1842.  * Var_Init --
  1843.  *    Initialize the module
  1844.  *
  1845.  * Results:
  1846.  *    None
  1847.  *
  1848.  * Side Effects:
  1849.  *    The VAR_CMD and VAR_GLOBAL contexts are created 
  1850.  *-----------------------------------------------------------------------
  1851.  */
  1852. void
  1853. Var_Init ()
  1854. {
  1855.     VAR_GLOBAL = Targ_NewGN ("Global");
  1856.     VAR_CMD = Targ_NewGN ("Command");
  1857.  
  1858. }
  1859.  
  1860. /****************** PRINT DEBUGGING INFO *****************/
  1861. static
  1862. VarPrintVar (v)
  1863.     Var            *v;
  1864. {
  1865.     printf ("%-16s = %s\n", v->name, Buf_GetAll(v->val, (int *)NULL));
  1866.     return (0);
  1867. }
  1868.  
  1869. /*-
  1870.  *-----------------------------------------------------------------------
  1871.  * Var_Dump --
  1872.  *    print all variables in a context
  1873.  *-----------------------------------------------------------------------
  1874.  */
  1875. Var_Dump (ctxt)
  1876.     GNode          *ctxt;
  1877. {
  1878.     Lst_ForEach (ctxt->context, VarPrintVar);
  1879. }
  1880.