[BACK]Return to var.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / make

Diff for /src/usr.bin/make/var.c between version 1.43 and 1.44

version 1.43, 2000/07/17 23:09:06 version 1.44, 2000/07/17 23:26:50
Line 769 
Line 769 
  *      2...?).   *      2...?).
  *      A Boolean in *freePtr telling whether the returned string should   *      A Boolean in *freePtr telling whether the returned string should
  *      be freed by the caller.   *      be freed by the caller.
  *  
  * Side Effects:  
  *      None.  
  *  
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 char *  char *
 Var_Parse(str, ctxt, err, lengthPtr, freePtr)  Var_Parse(str, ctxt, err, lengthPtr, freePtr)
     char          *str;         /* The string to parse */      char        *str;           /* The string to parse */
     SymTable      *ctxt;        /* The context for the variable */      SymTable    *ctxt;          /* The context for the variable */
     Boolean         err;        /* TRUE if undefined variables are an error */      Boolean     err;            /* TRUE if undefined variables are an error */
     size_t          *lengthPtr; /* OUT: The length of the specification */      size_t      *lengthPtr;     /* OUT: The length of the specification */
     Boolean         *freePtr;   /* OUT: TRUE if caller should free result */      Boolean     *freePtr;       /* OUT: TRUE if caller should free result */
 {  {
     char            *tstr;      /* Pointer into str */      char        *tstr;          /* Pointer into str */
     Var             *v;         /* Variable in invocation */      Var         *v;             /* Variable in invocation */
     Boolean         haveModifier;/* TRUE if have modifiers for the variable */      char        endc;           /* Ending character when variable in parens
     char            endc;       /* Ending character when variable in parens  
                                  * or braces */                                   * or braces */
     char            *start;      char        *start;
     Boolean         dynamic;    /* TRUE if the variable is local and we're      char        *val;           /* Variable value  */
                                  * expanding it in a non-local context. This      u_int32_t   k;
                                  * is done to support dynamic sources. The      int         idx;
                                  * result is just the invocation, unaltered */  
   
     *freePtr = FALSE;      *freePtr = FALSE;
     dynamic = FALSE;      start = str++;
     start = str;  
   
     if (str[1] != '(' && str[1] != '{') {      val = NULL;
         /*  
          * If it's not bounded by braces of some sort, life is much simpler.  
          * We just need to check for the first character and return the  
          * value if it exists.  
          */  
         v = VarFind_interval(str+1, str+2, ctxt, FIND_ENV | FIND_MINE);  
         if (v == NULL) {  
             *lengthPtr = 2;  
   
             if (ctxt == CTXT_CMD || ctxt == CTXT_GLOBAL || ctxt == NULL) {      if (*str != '(' && *str != '{') {
                 /*          tstr = str + 1;
                  * If substituting a local variable in a non-local context,          *lengthPtr = 2;
                  * assume it's for dynamic source stuff. We have to handle          endc = '\0';
                  * this specially and return the longhand for the variable  
                  * with the dollar sign escaped so it makes it back to the  
                  * caller. Only four of the local variables are treated  
                  * specially as they are the only four that will be set  
                  * when dynamic sources are expanded.  
                  */  
                 switch (str[1]) {  
                     case '@':  
                         return "$(.TARGET)";  
                     case '%':  
                         return "$(.ARCHIVE)";  
                     case '*':  
                         return "$(.PREFIX)";  
                     case '!':  
                         return "$(.MEMBER)";  
                 }  
             }  
             /* Error.  */  
             return err ? var_Error : varNoError;  
         } else {  
             haveModifier = FALSE;  
             tstr = &str[1];  
             endc = str[1];  
         }  
     } else {      } else {
         endc = str[1] == '(' ? ')' : '}';          endc = *str == '(' ? ')' : '}';
           str++;
   
         /* Skip to the end character or a colon, whichever comes first.  */          /* Find eventual modifiers in the variable */
         for (tstr = str + 2; *tstr != '\0' && *tstr != endc && *tstr != ':';)          for (tstr = str; *tstr != ':'; tstr++)
              tstr++;              if (*tstr == '\0' || *tstr == endc) {
         if (*tstr == ':')                  endc = '\0';
             haveModifier = TRUE;                  break;
         else if (*tstr != '\0')  
             haveModifier = FALSE;  
         else {  
             /*  
              * If we never did find the end character, return NULL  
              * right now, setting the length to be the distance to  
              * the end of the string, since that's what make does.  
              */  
             *lengthPtr = tstr - str;  
             return var_Error;  
         }  
   
         v = VarFind_interval(str + 2, tstr, ctxt, FIND_ENV | FIND_MINE);  
         if (v == NULL && ctxt != CTXT_CMD && ctxt != CTXT_GLOBAL &&  
             ctxt != NULL &&  
             (tstr-str) == 4 && (str[3] == 'F' || str[3] == 'D'))  
         {  
             /*  
              * Check for bogus D and F forms of local variables since we're  
              * in a local context and the name is the right length.  
              */  
             switch (str[2]) {  
                 case '@':  
                 case '%':  
                 case '*':  
                 case '!':  
                 case '>':  
                 case '<':  
                 {  
                     char    *val;  
   
                     /* Well, it's local -- go look for it.  */  
                     v = VarFind_interval(str+2, str+3, ctxt, 0);  
   
                     if (v != NULL) {  
                         /* No need for nested expansion or anything, as we're  
                          * the only one who sets these things and we sure don't  
                          * but nested invocations in them...  */  
                         val = VarValue(v);  
   
                         if (str[3] == 'D')  
                             val = Var_GetHead(val);  
                         else  
                             val = Var_GetTail(val);  
                         /* Resulting string is dynamically allocated, so  
                          * tell caller to free it.  */  
                         *freePtr = TRUE;  
                         *lengthPtr = tstr-start+1;  
                         *tstr = endc;  
                         return val;  
                     }  
                     break;  
                 }  
             }              }
         }          *lengthPtr = tstr+1 - start;
       }
   
         if (v == NULL) {      idx = quick_lookup(str, &tstr, &k);
             if ((tstr-str == 3 ||      v = varfind(str, tstr, ctxt, FIND_ENV | FIND_MINE, idx, k);
                  (tstr-str == 4 && (str[3] == 'F' ||      if (v == NULL) {
                                          str[3] == 'D'))) &&          /* Find out about D and F forms of local variables. */
                 (ctxt == CTXT_CMD || ctxt == CTXT_GLOBAL || ctxt == NULL))          if (idx == -1 && tstr == str+2 && (str[1] == 'D' || str[1] == 'F')) {
             {              switch (*str) {
                 /* If substituting a local variable in a non-local context,              case '@':
                  * assume it's for dynamic source stuff. We have to handle                  idx = TARGET_INDEX;
                  * this specially and return the longhand for the variable                  break;
                  * with the dollar sign escaped so it makes it back to the              case '!':
                  * caller. Only four of the local variables are treated                  idx = ARCHIVE_INDEX;
                  * specially as they are the only four that will be set                  break;
                  * when dynamic sources are expanded.  */              case '*':
                 switch (str[2]) {                  idx = PREFIX_INDEX;
                     case '@':                  break;
                     case '%':              case '%':
                     case '*':                  idx = MEMBER_INDEX;
                     case '!':                  break;
                         dynamic = TRUE;              default:
                         break;                  break;
                 }  
             } else if (tstr-str > 4 && str[2] == '.' &&  
                        isupper((unsigned char) str[3]) &&  
                        (ctxt == CTXT_CMD || ctxt == CTXT_GLOBAL || ctxt == NULL))  
             {  
                 int     len;  
   
                 len = (tstr-str) - 3;  
                 if ((strncmp(str+2, ".TARGET", len) == 0) ||  
                     (strncmp(str+2, ".ARCHIVE", len) == 0) ||  
                     (strncmp(str+2, ".PREFIX", len) == 0) ||  
                     (strncmp(str+2, ".MEMBER", len) == 0)) {  
                     dynamic = TRUE;  
                 }  
             }              }
               /* This is a DF form, check if we can expand it now.  */
             if (!haveModifier) {              if (idx != -1 && ctxt != NULL && ctxt != CTXT_GLOBAL) {
                 /* No modifiers -- have specification length so we can return                  v = varfind(str, str+1, ctxt, 0, idx, 0);
                  * now.  */                  /* No need for nested expansion or anything, as we're
                 *lengthPtr = tstr - start + 1;                   * the only one who sets these things and we sure don't
                 *tstr = endc;                   * do nested invocations in them...  */
                 if (dynamic) {                  if (v != NULL) {
                     char *n;                      val = VarValue(v);
                     n = emalloc(*lengthPtr + 1);                      if (str[1] == 'D')
                     strncpy(n, start, *lengthPtr);                          val = Var_GetHead(val);
                     n[*lengthPtr] = '\0';                      else
                           val = Var_GetTail(val);
                     *freePtr = TRUE;                      *freePtr = TRUE;
                     return n;                  }
                 } else  
                     return err ? var_Error : varNoError;  
             } else {  
                 /* Still need to get to the end of the variable specification,  
                  * so kludge up a Var structure for the modifications */  
                 v = new_var(str+1, NULL);       /* junk has name, for error reports */  
                 v->flags = VAR_JUNK;  
             }              }
         }          }
     }      } else {
           if (v->flags & VAR_IN_USE)
               Fatal("Variable %s is recursive.", v->name);
               /*NOTREACHED*/
           else
               v->flags |= VAR_IN_USE;
           /* Before doing any modification, we have to make sure the value
            * has been fully expanded. If it looks like recursion might be
            * necessary (there's a dollar sign somewhere in the variable's value)
            * we just call Var_Subst to do any other substitutions that are
            * necessary. Note that the value returned by Var_Subst will have
            * been dynamically-allocated, so it will need freeing when we
            * return.  */
           val = VarValue(v);
           if (strchr(val, '$') != NULL) {
               val = Var_Subst(val, ctxt, err);
               *freePtr = TRUE;
           }
   
     if (v->flags & VAR_IN_USE)          v->flags &= ~VAR_IN_USE;
         Fatal("Variable %s is recursive.", v->name);  
         /*NOTREACHED*/  
     else  
         v->flags |= VAR_IN_USE;  
     /* Before doing any modification, we have to make sure the value  
      * has been fully expanded. If it looks like recursion might be  
      * necessary (there's a dollar sign somewhere in the variable's value)  
      * we just call Var_Subst to do any other substitutions that are  
      * necessary. Note that the value returned by Var_Subst will have  
      * been dynamically-allocated, so it will need freeing when we  
      * return.  */  
     str = VarValue(v);  
     if (strchr(str, '$') != NULL) {  
         str = Var_Subst(str, ctxt, err);  
         *freePtr = TRUE;  
     }      }
       if (endc != '\0')
     v->flags &= ~VAR_IN_USE;          val = VarModifiers_Apply(val, ctxt, err, freePtr, tstr+1, endc,
   
     *lengthPtr = tstr - start + 1;  
     if (str != NULL && haveModifier)  
         str = VarModifiers_Apply(str, ctxt, err, freePtr, tstr+1, endc,  
             lengthPtr);              lengthPtr);
       if (val == NULL) {
     if (v->flags & VAR_JUNK) {          /* Dynamic source that can't be expanded for now: copy the var
         /* Perform any free'ing needed and set *freePtr to FALSE so the caller           * specification instead.  */
          * doesn't try to free a static pointer.  */          if (idx != -1 && (ctxt == NULL || ctxt == CTXT_GLOBAL)) {
         if (*freePtr)  
             free(str);  
         *freePtr = FALSE;  
         Buf_Destroy(&(v->val));  
         free(v);  
         if (dynamic) {  
             str = emalloc(*lengthPtr + 1);  
             strncpy(str, start, *lengthPtr);  
             str[*lengthPtr] = '\0';  
             *freePtr = TRUE;              *freePtr = TRUE;
         } else {              val = interval_dup(start, start+ *lengthPtr);
             str = err ? var_Error : varNoError;          } else
         }              val = err ? var_Error : varNoError;
     }      }
     return str;  
       return val;
 }  }
   
 /*-  /*-

Legend:
Removed from v.1.43  
changed lines
  Added in v.1.44