=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/make/var.c,v retrieving revision 1.42 retrieving revision 1.43 diff -c -r1.42 -r1.43 *** src/usr.bin/make/var.c 2000/07/17 23:06:32 1.42 --- src/usr.bin/make/var.c 2000/07/17 23:09:06 1.43 *************** *** 1,4 **** ! /* $OpenBSD: var.c,v 1.42 2000/07/17 23:06:32 espie Exp $ */ /* $NetBSD: var.c,v 1.18 1997/03/18 19:24:46 christos Exp $ */ /* --- 1,4 ---- ! /* $OpenBSD: var.c,v 1.43 2000/07/17 23:09:06 espie Exp $ */ /* $NetBSD: var.c,v 1.18 1997/03/18 19:24:46 christos Exp $ */ /* *************** *** 70,76 **** #if 0 static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94"; #else ! static char rcsid[] = "$OpenBSD: var.c,v 1.42 2000/07/17 23:06:32 espie Exp $"; #endif #endif /* not lint */ --- 70,76 ---- #if 0 static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94"; #else ! static char rcsid[] = "$OpenBSD: var.c,v 1.43 2000/07/17 23:09:06 espie Exp $"; #endif #endif /* not lint */ *************** *** 127,132 **** --- 127,133 ---- #include "buf.h" #include "ohash.h" #include "hashconsts.h" + #include "varmodifiers.h" static SymTable *CTXT_GLOBAL, *CTXT_CMD, *CTXT_ENV; *************** *** 188,252 **** char name[1]; /* the variable's name */ } Var; - /* Var*Pattern flags */ - #define VAR_SUB_GLOBAL 0x01 /* Apply substitution globally */ - #define VAR_SUB_ONE 0x02 /* Apply substitution to one word */ - #define VAR_SUB_MATCHED 0x04 /* There was a match */ - #define VAR_MATCH_START 0x08 /* Match at start of word */ - #define VAR_MATCH_END 0x10 /* Match at end of word */ - - typedef struct { - char *lhs; /* String to match */ - size_t leftLen; /* Length of string */ - char *rhs; /* Replacement string (w/ &'s removed) */ - size_t rightLen; /* Length of replacement */ - int flags; - } VarPattern; - - #ifndef MAKE_BOOTSTRAP - typedef struct { - regex_t re; - int nsub; - regmatch_t *matches; - char *replace; - int flags; - } VarREPattern; - #endif - static struct hash_info var_info = { offsetof(Var, name), NULL, hash_alloc, hash_free, element_alloc }; static int quick_lookup __P((const char *, const char **, u_int32_t *)); #define VarValue(v) Buf_Retrieve(&((v)->val)) - static int VarCmp __P((void *, void *)); static Var *varfind __P((const char *, const char *, SymTable *, int, int, u_int32_t)); static Var *VarFind_interval __P((const char *, const char *, SymTable *, int)); #define VarFind(n, ctxt, flags) VarFind_interval(n, NULL, ctxt, flags) static Var *VarAdd __P((const char *, const char *, GSymT *)); static void VarDelete __P((void *)); - static Boolean VarHead __P((const char *, Boolean, Buffer, void *)); - static Boolean VarTail __P((const char *, Boolean, Buffer, void *)); - static Boolean VarSuffix __P((const char *, Boolean, Buffer, void *)); - static Boolean VarRoot __P((const char *, Boolean, Buffer, void *)); - static Boolean VarMatch __P((const char *, Boolean, Buffer, void *)); - #ifdef SYSVVARSUB - static Boolean VarSYSVMatch __P((const char *, Boolean, Buffer, void *)); - #endif - static Boolean VarNoMatch __P((const char *, Boolean, Buffer, void *)); - #ifndef MAKE_BOOTSTRAP - static void VarREError __P((int, regex_t *, const char *)); - static Boolean VarRESubstitute __P((const char *, Boolean, Buffer, void *)); - #endif - static Boolean VarSubstitute __P((const char *, Boolean, Buffer, void *)); - static char *VarGetPattern __P((SymTable *, int, char **, int, int *, size_t *, - VarPattern *)); - static char *VarQuote __P((const char *)); - static char *VarModify __P((const char *, Boolean (*)(const char *, Boolean, Buffer, void *), void *)); - char *VarModifiers_Apply __P((char *, SymTable *, Boolean, - Boolean *, char *, char, size_t *)); static void VarPrintVar __P((void *)); - static Boolean VarUppercase __P((const char *, Boolean, Buffer, void *)); - static Boolean VarLowercase __P((const char *, Boolean, Buffer, void *)); static const char *context_name __P((GSymT *)); static Var *new_var __P((const char *, const char *)); static Var *getvar __P((GSymT *, const char *, const char *, u_int32_t)); --- 189,205 ---- *************** *** 804,1610 **** /*- *----------------------------------------------------------------------- - * VarUppercase -- - * Place the Upper cased word in the given buffer. - * - * Results: - * TRUE if characters were added to the buffer (a space needs to be - * added to the buffer before the next word). - * - * Side Effects: - * The word is added to the buffer. - * - *----------------------------------------------------------------------- - */ - static Boolean - VarUppercase(word, addSpace, buf, dummy) - const char *word; /* Word to Upper Case */ - Boolean addSpace; /* True if need to add a space to the buffer - * before sticking in the head */ - Buffer buf; /* Buffer in which to store it */ - void *dummy; - { - size_t len = strlen(word); - - if (addSpace) - Buf_AddSpace(buf); - while (len--) - Buf_AddChar(buf, toupper(*word++)); - return TRUE; - } - - /*- - *----------------------------------------------------------------------- - * VarLowercase -- - * Place the Lower cased word in the given buffer. - * - * Results: - * TRUE if characters were added to the buffer (a space needs to be - * added to the buffer before the next word). - * - * Side Effects: - * The word is added to the buffer. - * - *----------------------------------------------------------------------- - */ - static Boolean - VarLowercase(word, addSpace, buf, dummy) - const char *word; /* Word to Lower Case */ - Boolean addSpace; /* True if need to add a space to the buffer - * before sticking in the head */ - Buffer buf; /* Buffer in which to store it */ - void *dummy; - { - size_t len = strlen(word); - - if (addSpace) - Buf_AddSpace(buf); - while (len--) - Buf_AddChar(buf, tolower(*word++)); - return TRUE; - } - - /*- - *----------------------------------------------------------------------- - * VarHead -- - * Remove the tail of the given word and place the result in the given - * buffer. - * - * Results: - * TRUE if characters were added to the buffer (a space needs to be - * added to the buffer before the next word). - * - * Side Effects: - * The trimmed word is added to the buffer. - * - *----------------------------------------------------------------------- - */ - static Boolean - VarHead(word, addSpace, buf, dummy) - const char *word; /* Word to trim */ - Boolean addSpace; /* True if need to add a space to the buffer - * before sticking in the head */ - Buffer buf; /* Buffer in which to store it */ - void *dummy; - { - const char *slash; - - slash = strrchr(word, '/'); - if (slash != NULL) { - if (addSpace) - Buf_AddSpace(buf); - Buf_AddInterval(buf, word, slash); - return TRUE; - } else { - /* If no directory part, give . (q.v. the POSIX standard) */ - if (addSpace) - Buf_AddString(buf, " ."); - else - Buf_AddChar(buf, '.'); - } - return(dummy ? TRUE : TRUE); - } - - /*- - *----------------------------------------------------------------------- - * VarTail -- - * Remove the head of the given word and place the result in the given - * buffer. - * - * Results: - * TRUE if characters were added to the buffer (a space needs to be - * added to the buffer before the next word). - * - * Side Effects: - * The trimmed word is added to the buffer. - * - *----------------------------------------------------------------------- - */ - static Boolean - VarTail(word, addSpace, buf, dummy) - const char *word; /* Word to trim */ - Boolean addSpace; /* TRUE if need to stick a space in the - * buffer before adding the tail */ - Buffer buf; /* Buffer in which to store it */ - void *dummy; - { - const char *slash; - - if (addSpace) - Buf_AddSpace(buf); - slash = strrchr(word, '/'); - if (slash != NULL) - Buf_AddString(buf, slash+1); - else - Buf_AddString(buf, word); - return (dummy ? TRUE : TRUE); - } - - /*- - *----------------------------------------------------------------------- - * VarSuffix -- - * Place the suffix of the given word in the given buffer. - * - * Results: - * TRUE if characters were added to the buffer (a space needs to be - * added to the buffer before the next word). - * - * Side Effects: - * The suffix from the word is placed in the buffer. - * - *----------------------------------------------------------------------- - */ - static Boolean - VarSuffix(word, addSpace, buf, dummy) - const char *word; /* Word to trim */ - Boolean addSpace; /* TRUE if need to add a space before placing - * the suffix in the buffer */ - Buffer buf; /* Buffer in which to store it */ - void *dummy; - { - const char *dot; - - dot = strrchr(word, '.'); - if (dot != NULL) { - if (addSpace) - Buf_AddSpace(buf); - Buf_AddString(buf, dot+1); - addSpace = TRUE; - } - return (dummy ? addSpace : addSpace); - } - - /*- - *----------------------------------------------------------------------- - * VarRoot -- - * Remove the suffix of the given word and place the result in the - * buffer. - * - * Results: - * TRUE if characters were added to the buffer (a space needs to be - * added to the buffer before the next word). - * - * Side Effects: - * The trimmed word is added to the buffer. - * - *----------------------------------------------------------------------- - */ - static Boolean - VarRoot(word, addSpace, buf, dummy) - const char *word; /* Word to trim */ - Boolean addSpace; /* TRUE if need to add a space to the buffer - * before placing the root in it */ - Buffer buf; /* Buffer in which to store it */ - void *dummy; - { - const char *dot; - - if (addSpace) - Buf_AddSpace(buf); - - dot = strrchr(word, '.'); - if (dot != NULL) - Buf_AddInterval(buf, word, dot); - else - Buf_AddString(buf, word); - return (dummy ? TRUE : TRUE); - } - - /*- - *----------------------------------------------------------------------- - * VarMatch -- - * Place the word in the buffer if it matches the given pattern. - * Callback function for VarModify to implement the :M modifier. - * - * Results: - * TRUE if a space should be placed in the buffer before the next - * word. - * - * Side Effects: - * The word may be copied to the buffer. - * - *----------------------------------------------------------------------- - */ - static Boolean - VarMatch(word, addSpace, buf, pattern) - const char *word; /* Word to examine */ - Boolean addSpace; /* TRUE if need to add a space to the - * buffer before adding the word, if it - * matches */ - Buffer buf; /* Buffer in which to store it */ - void *pattern; /* Pattern the word must match */ - { - if (Str_Match(word, (char *) pattern)) { - if (addSpace) - Buf_AddSpace(buf); - addSpace = TRUE; - Buf_AddString(buf, word); - } - return addSpace; - } - - #ifdef SYSVVARSUB - /*- - *----------------------------------------------------------------------- - * VarSYSVMatch -- - * Place the word in the buffer if it matches the given pattern. - * Callback function for VarModify to implement the System V % - * modifiers. - * - * Results: - * TRUE if a space should be placed in the buffer before the next - * word. - * - * Side Effects: - * The word may be copied to the buffer. - * - *----------------------------------------------------------------------- - */ - static Boolean - VarSYSVMatch(word, addSpace, buf, patp) - const char *word; /* Word to examine */ - Boolean addSpace; /* TRUE if need to add a space to the - * buffer before adding the word, if it - * matches */ - Buffer buf; /* Buffer in which to store it */ - void *patp; /* Pattern the word must match */ - { - size_t len; - const char *ptr; - VarPattern *pat = (VarPattern *) patp; - - if (*word) { - if (addSpace) - Buf_AddSpace(buf); - - addSpace = TRUE; - - if ((ptr = Str_SYSVMatch(word, pat->lhs, &len)) != NULL) - Str_SYSVSubst(buf, pat->rhs, ptr, len); - else - Buf_AddString(buf, word); - } - return addSpace; - } - #endif - - - /*- - *----------------------------------------------------------------------- - * VarNoMatch -- - * Place the word in the buffer if it doesn't match the given pattern. - * Callback function for VarModify to implement the :N modifier. - * - * Results: - * TRUE if a space should be placed in the buffer before the next - * word. - * - * Side Effects: - * The word may be copied to the buffer. - * - *----------------------------------------------------------------------- - */ - static Boolean - VarNoMatch(word, addSpace, buf, pattern) - const char *word; /* Word to examine */ - Boolean addSpace; /* TRUE if need to add a space to the - * buffer before adding the word, if it - * matches */ - Buffer buf; /* Buffer in which to store it */ - void *pattern; /* Pattern the word must match */ - { - if (!Str_Match(word, (char *) pattern)) { - if (addSpace) - Buf_AddSpace(buf); - addSpace = TRUE; - Buf_AddString(buf, word); - } - return(addSpace); - } - - - /*- - *----------------------------------------------------------------------- - * VarSubstitute -- - * Perform a string-substitution on the given word, placing the - * result in the passed buffer. - * - * Results: - * TRUE if a space is needed before more characters are added. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ - static Boolean - VarSubstitute(word, addSpace, buf, patternp) - const char *word; /* Word to modify */ - Boolean addSpace; /* True if space should be added before - * other characters */ - Buffer buf; /* Buffer for result */ - void *patternp; /* Pattern for substitution */ - { - size_t wordLen; /* Length of word */ - const char *cp; /* General pointer */ - VarPattern *pattern = (VarPattern *) patternp; - - wordLen = strlen(word); - if ((pattern->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) != - (VAR_SUB_ONE|VAR_SUB_MATCHED)) { - /* - * Still substituting -- break it down into simple anchored cases - * and if none of them fits, perform the general substitution case. - */ - if ((pattern->flags & VAR_MATCH_START) && - (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) { - /* - * Anchored at start and beginning of word matches pattern - */ - if ((pattern->flags & VAR_MATCH_END) && - (wordLen == pattern->leftLen)) { - /* - * Also anchored at end and matches to the end (word - * is same length as pattern) add space and rhs only - * if rhs is non-null. - */ - if (pattern->rightLen != 0) { - if (addSpace) - Buf_AddSpace(buf); - addSpace = TRUE; - Buf_AddChars(buf, pattern->rightLen, pattern->rhs); - } - pattern->flags |= VAR_SUB_MATCHED; - } else if (pattern->flags & VAR_MATCH_END) { - /* - * Doesn't match to end -- copy word wholesale - */ - goto nosub; - } else { - /* - * Matches at start but need to copy in trailing characters - */ - if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){ - if (addSpace) - Buf_AddSpace(buf); - addSpace = TRUE; - } - Buf_AddChars(buf, pattern->rightLen, pattern->rhs); - Buf_AddChars(buf, wordLen - pattern->leftLen, - word + pattern->leftLen); - pattern->flags |= VAR_SUB_MATCHED; - } - } else if (pattern->flags & VAR_MATCH_START) { - /* - * Had to match at start of word and didn't -- copy whole word. - */ - goto nosub; - } else if (pattern->flags & VAR_MATCH_END) { - /* - * Anchored at end, Find only place match could occur (leftLen - * characters from the end of the word) and see if it does. Note - * that because the $ will be left at the end of the lhs, we have - * to use strncmp. - */ - cp = word + (wordLen - pattern->leftLen); - if ((cp >= word) && - (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) { - /* - * Match found. If we will place characters in the buffer, - * add a space before hand as indicated by addSpace, then - * stuff in the initial, unmatched part of the word followed - * by the right-hand-side. - */ - if (((cp - word) + pattern->rightLen) != 0) { - if (addSpace) - Buf_AddSpace(buf); - addSpace = TRUE; - } - Buf_AddInterval(buf, word, cp); - Buf_AddChars(buf, pattern->rightLen, pattern->rhs); - pattern->flags |= VAR_SUB_MATCHED; - } else { - /* - * Had to match at end and didn't. Copy entire word. - */ - goto nosub; - } - } else { - /* - * Pattern is unanchored: search for the pattern in the word using - * String_FindSubstring, copying unmatched portions and the - * right-hand-side for each match found, handling non-global - * substitutions correctly, etc. When the loop is done, any - * remaining part of the word (word and wordLen are adjusted - * accordingly through the loop) is copied straight into the - * buffer. - * addSpace is set FALSE as soon as a space is added to the - * buffer. - */ - register Boolean done; - size_t origSize; - - done = FALSE; - origSize = Buf_Size(buf); - while (!done) { - cp = strstr(word, pattern->lhs); - if (cp != (char *)NULL) { - if (addSpace && (((cp - word) + pattern->rightLen) != 0)){ - Buf_AddSpace(buf); - addSpace = FALSE; - } - Buf_AddInterval(buf, word, cp); - Buf_AddChars(buf, pattern->rightLen, pattern->rhs); - wordLen -= (cp - word) + pattern->leftLen; - word = cp + pattern->leftLen; - if (wordLen == 0 || (pattern->flags & VAR_SUB_GLOBAL) == 0){ - done = TRUE; - } - pattern->flags |= VAR_SUB_MATCHED; - } else { - done = TRUE; - } - } - if (wordLen != 0) { - if (addSpace) - Buf_AddSpace(buf); - Buf_AddChars(buf, wordLen, word); - } - /* - * If added characters to the buffer, need to add a space - * before we add any more. If we didn't add any, just return - * the previous value of addSpace. - */ - return (Buf_Size(buf) != origSize || addSpace); - } - return (addSpace); - } - nosub: - if (addSpace) - Buf_AddSpace(buf); - Buf_AddChars(buf, wordLen, word); - return(TRUE); - } - - #ifndef MAKE_BOOTSTRAP - /*- - *----------------------------------------------------------------------- - * VarREError -- - * Print the error caused by a regcomp or regexec call. - * - * Results: - * None. - * - * Side Effects: - * An error gets printed. - * - *----------------------------------------------------------------------- - */ - static void - VarREError(err, pat, str) - int err; - regex_t *pat; - const char *str; - { - char *errbuf; - int errlen; - - errlen = regerror(err, pat, 0, 0); - errbuf = emalloc(errlen); - regerror(err, pat, errbuf, errlen); - Error("%s: %s", str, errbuf); - free(errbuf); - } - - /*- - *----------------------------------------------------------------------- - * VarRESubstitute -- - * Perform a regex substitution on the given word, placing the - * result in the passed buffer. - * - * Results: - * TRUE if a space is needed before more characters are added. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ - static Boolean - VarRESubstitute(word, addSpace, buf, patternp) - const char *word; - Boolean addSpace; - Buffer buf; - void *patternp; - { - VarREPattern *pat; - int xrv; - const char *wp; - char *rp; - int added; - - #define MAYBE_ADD_SPACE() \ - if (addSpace && !added) \ - Buf_AddSpace(buf); \ - added = 1 - - added = 0; - wp = word; - pat = patternp; - - if ((pat->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) == - (VAR_SUB_ONE|VAR_SUB_MATCHED)) - xrv = REG_NOMATCH; - else { - tryagain: - xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, 0); - } - - switch (xrv) { - case 0: - pat->flags |= VAR_SUB_MATCHED; - if (pat->matches[0].rm_so > 0) { - MAYBE_ADD_SPACE(); - Buf_AddChars(buf, pat->matches[0].rm_so, wp); - } - - for (rp = pat->replace; *rp; rp++) { - if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) { - MAYBE_ADD_SPACE(); - Buf_AddChar(buf, rp[1]); - rp++; - } - else if ((*rp == '&') || ((*rp == '\\') && isdigit(rp[1]))) { - int n; - const char *subbuf; - int sublen; - char errstr[3]; - - if (*rp == '&') { - n = 0; - errstr[0] = '&'; - errstr[1] = '\0'; - } else { - n = rp[1] - '0'; - errstr[0] = '\\'; - errstr[1] = rp[1]; - errstr[2] = '\0'; - rp++; - } - - if (n > pat->nsub) { - Error("No subexpression %s", &errstr[0]); - subbuf = ""; - sublen = 0; - } else if ((pat->matches[n].rm_so == -1) && - (pat->matches[n].rm_eo == -1)) { - Error("No match for subexpression %s", &errstr[0]); - subbuf = ""; - sublen = 0; - } else { - subbuf = wp + pat->matches[n].rm_so; - sublen = pat->matches[n].rm_eo - pat->matches[n].rm_so; - } - - if (sublen > 0) { - MAYBE_ADD_SPACE(); - Buf_AddChars(buf, sublen, subbuf); - } - } else { - MAYBE_ADD_SPACE(); - Buf_AddChar(buf, *rp); - } - } - wp += pat->matches[0].rm_eo; - if (pat->flags & VAR_SUB_GLOBAL) - goto tryagain; - if (*wp) { - MAYBE_ADD_SPACE(); - Buf_AddChars(buf, strlen(wp), wp); - } - break; - default: - VarREError(xrv, &pat->re, "Unexpected regex error"); - /* fall through */ - case REG_NOMATCH: - if (*wp) { - MAYBE_ADD_SPACE(); - Buf_AddChars(buf, strlen(wp), wp); - } - break; - } - return(addSpace||added); - } - #endif - - /*- - *----------------------------------------------------------------------- - * VarModify -- - * Modify each of the words of the passed string using the given - * function. Used to implement all modifiers. - * - * Results: - * A string of all the words modified appropriately. - * - *----------------------------------------------------------------------- - */ - static char * - VarModify (str, modProc, datum) - const char *str; /* String whose words should be trimmed */ - /* Function to use to modify them */ - Boolean (*modProc) __P((const char *, Boolean, Buffer, void *)); - void *datum; /* Datum to pass it */ - { - BUFFER buf; /* Buffer for the new string */ - Boolean addSpace; /* TRUE if need to add a space to the - * buffer before adding the trimmed - * word */ - char **av; /* word list */ - char *as; /* word list memory */ - int ac, i; - - Buf_Init(&buf, 0); - addSpace = FALSE; - - av = brk_string(str, &ac, FALSE, &as); - - for (i = 0; i < ac; i++) - addSpace = (*modProc)(av[i], addSpace, &buf, datum); - - free(as); - free(av); - return Buf_Retrieve(&buf); - } - - /*- - *----------------------------------------------------------------------- - * VarGetPattern -- - * Pass through the tstr looking for 1) escaped delimiters, - * '$'s and backslashes (place the escaped character in - * uninterpreted) and 2) unescaped $'s that aren't before - * the delimiter (expand the variable substitution). - * Return the expanded string or NULL if the delimiter was missing - * If pattern is specified, handle escaped ampersands, and replace - * unescaped ampersands with the lhs of the pattern. - * - * Results: - * A string of all the words modified appropriately. - * If length is specified, return the string length of the buffer - * If flags is specified and the last character of the pattern is a - * $ set the VAR_MATCH_END bit of flags. - * - * Side Effects: - * None. - *----------------------------------------------------------------------- - */ - static char * - VarGetPattern(ctxt, err, tstr, delim, flags, length, pattern) - SymTable *ctxt; - int err; - char **tstr; - int delim; - int *flags; - size_t *length; - VarPattern *pattern; - { - char *cp; - BUFFER buf; - size_t junk; - - Buf_Init(&buf, 0); - if (length == NULL) - length = &junk; - - #define IS_A_MATCH(cp, delim) \ - ((cp[0] == '\\') && ((cp[1] == delim) || \ - (cp[1] == '\\') || (cp[1] == '$') || (pattern && (cp[1] == '&')))) - - /* - * Skim through until the matching delimiter is found; - * pick up variable substitutions on the way. Also allow - * backslashes to quote the delimiter, $, and \, but don't - * touch other backslashes. - */ - for (cp = *tstr; *cp && (*cp != delim); cp++) { - if (IS_A_MATCH(cp, delim)) { - Buf_AddChar(&buf, cp[1]); - cp++; - } else if (*cp == '$') { - if (cp[1] == delim) { - if (flags == NULL) - Buf_AddChar(&buf, *cp); - else - /* - * Unescaped $ at end of pattern => anchor - * pattern at end. - */ - *flags |= VAR_MATCH_END; - } - else { - char *cp2; - size_t len; - Boolean freeIt; - - /* - * If unescaped dollar sign not before the - * delimiter, assume it's a variable - * substitution and recurse. - */ - cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt); - Buf_AddString(&buf, cp2); - if (freeIt) - free(cp2); - cp += len - 1; - } - } - else if (pattern && *cp == '&') - Buf_AddChars(&buf, pattern->leftLen, pattern->lhs); - else - Buf_AddChar(&buf, *cp); - } - - if (*cp != delim) { - *tstr = cp; - *length = 0; - return NULL; - } - else { - *tstr = ++cp; - *length = Buf_Size(&buf); - return Buf_Retrieve(&buf); - } - } - - /*- - *----------------------------------------------------------------------- - * VarQuote -- - * Quote shell meta-characters in the string - * - * Results: - * The quoted string - * - *----------------------------------------------------------------------- - */ - static char * - VarQuote(str) - const char *str; - { - - BUFFER buf; - /* This should cover most shells :-( */ - static char meta[] = "\n \t'`\";&<>()|*?{}[]\\$!#^~"; - - Buf_Init(&buf, MAKE_BSIZE); - for (; *str; str++) { - if (strchr(meta, *str) != NULL) - Buf_AddChar(&buf, '\\'); - Buf_AddChar(&buf, *str); - } - return Buf_Retrieve(&buf); - } - - /*- - *----------------------------------------------------------------------- * Var_Parse -- * Given the start of a variable invocation, extract the variable * name and find its value, then modify it according to the --- 757,762 ---- *************** *** 1852,2200 **** return str; } - char * - VarModifiers_Apply(str, ctxt, err, freePtr, start, endc, lengthPtr) - char *str; - SymTable *ctxt; - Boolean err; - Boolean *freePtr; - char *start; - char endc; - size_t *lengthPtr; - { - char *tstr; - char delim; - char *cp; - - tstr = start; - - /* - * Now we need to apply any modifiers the user wants applied. - * These are: - * :M words which match the given . - * is of the standard file - * wildcarding form. - * :S[g] - * Substitute for in the value - * :C[g] - * Substitute for regex in the value - * :H Substitute the head of each word - * :T Substitute the tail of each word - * :E Substitute the extension (minus '.') of - * each word - * :R Substitute the root of each word - * (pathname minus the suffix). - * :lhs=rhs Like :S, but the rhs goes to the end of - * the invocation. - */ - while (*tstr != endc) { - char *newStr; /* New value to return */ - char termc; /* Character which terminated scan */ - - if (DEBUG(VAR)) - printf("Applying :%c to \"%s\"\n", *tstr, str); - switch (*tstr) { - case 'N': - case 'M': - { - for (cp = tstr + 1; - *cp != '\0' && *cp != ':' && *cp != endc; - cp++) { - if (*cp == '\\' && (cp[1] == ':' || cp[1] == endc)){ - cp++; - } - } - termc = *cp; - *cp = '\0'; - if (*tstr == 'M') - newStr = VarModify(str, VarMatch, tstr+1); - else - newStr = VarModify(str, VarNoMatch, tstr+1); - break; - } - case 'S': - { - VarPattern pattern; - - pattern.flags = 0; - delim = tstr[1]; - tstr += 2; - - /* If pattern begins with '^', it is anchored to the - * start of the word -- skip over it and flag pattern. */ - if (*tstr == '^') { - pattern.flags |= VAR_MATCH_START; - tstr++; - } - - cp = tstr; - if ((pattern.lhs = VarGetPattern(ctxt, err, &cp, delim, - &pattern.flags, &pattern.leftLen, NULL)) == NULL) - goto cleanup; - - if ((pattern.rhs = VarGetPattern(ctxt, err, &cp, delim, - NULL, &pattern.rightLen, &pattern)) == NULL) - goto cleanup; - - /* Check for global substitution. If 'g' after the final - * delimiter, substitution is global and is marked that - * way. */ - for (;; cp++) { - switch (*cp) { - case 'g': - pattern.flags |= VAR_SUB_GLOBAL; - continue; - case '1': - pattern.flags |= VAR_SUB_ONE; - continue; - } - break; - } - - termc = *cp; - newStr = VarModify(str, VarSubstitute, &pattern); - - /* Free the two strings. */ - free(pattern.lhs); - free(pattern.rhs); - break; - } - #ifndef MAKE_BOOTSTRAP - case 'C': - { - VarREPattern pattern; - char *re; - int error; - - pattern.flags = 0; - delim = tstr[1]; - tstr += 2; - - cp = tstr; - - if ((re = VarGetPattern(ctxt, err, &cp, delim, NULL, - NULL, NULL)) == NULL) - goto cleanup; - - if ((pattern.replace = VarGetPattern(ctxt, err, &cp, - delim, NULL, NULL, NULL)) == NULL) { - free(re); - goto cleanup; - } - - for (;; cp++) { - switch (*cp) { - case 'g': - pattern.flags |= VAR_SUB_GLOBAL; - continue; - case '1': - pattern.flags |= VAR_SUB_ONE; - continue; - } - break; - } - - termc = *cp; - - error = regcomp(&pattern.re, re, REG_EXTENDED); - free(re); - if (error) { - *lengthPtr = cp - start + 1; - VarREError(error, &pattern.re, "RE substitution error"); - free(pattern.replace); - return var_Error; - } - - pattern.nsub = pattern.re.re_nsub + 1; - if (pattern.nsub < 1) - pattern.nsub = 1; - if (pattern.nsub > 10) - pattern.nsub = 10; - pattern.matches = emalloc(pattern.nsub * - sizeof(regmatch_t)); - newStr = VarModify(str, VarRESubstitute, &pattern); - regfree(&pattern.re); - free(pattern.replace); - free(pattern.matches); - break; - } - #endif - case 'Q': - if (tstr[1] == endc || tstr[1] == ':') { - newStr = VarQuote(str); - cp = tstr + 1; - termc = *cp; - break; - } - /*FALLTHRU*/ - case 'T': - if (tstr[1] == endc || tstr[1] == ':') { - newStr = VarModify(str, VarTail, NULL); - cp = tstr + 1; - termc = *cp; - break; - } - /*FALLTHRU*/ - case 'H': - if (tstr[1] == endc || tstr[1] == ':') { - newStr = VarModify(str, VarHead, NULL); - cp = tstr + 1; - termc = *cp; - break; - } - /*FALLTHRU*/ - case 'E': - if (tstr[1] == endc || tstr[1] == ':') { - newStr = VarModify(str, VarSuffix, NULL); - cp = tstr + 1; - termc = *cp; - break; - } - /*FALLTHRU*/ - case 'R': - if (tstr[1] == endc || tstr[1] == ':') { - newStr = VarModify(str, VarRoot, NULL); - cp = tstr + 1; - termc = *cp; - break; - } - /*FALLTHRU*/ - case 'U': - if (tstr[1] == endc || tstr[1] == ':') { - newStr = VarModify(str, VarUppercase, NULL); - cp = tstr + 1; - termc = *cp; - break; - } - /*FALLTHRU*/ - case 'L': - if (tstr[1] == endc || tstr[1] == ':') { - newStr = VarModify(str, VarLowercase, NULL); - cp = tstr + 1; - termc = *cp; - break; - } - /*FALLTHRU*/ - #ifdef SUNSHCMD - case 's': - if (tstr[1] == 'h' && (tstr[2] == endc || tstr[2] == ':')) { - char *err; - newStr = Cmd_Exec(str, &err); - if (err) - Error(err, str); - cp = tstr + 2; - termc = *cp; - break; - } - /*FALLTHRU*/ - #endif - default: - { - #ifdef SYSVVARSUB - /* This can either be a bogus modifier or a System-V - * substitution command. */ - VarPattern pattern; - Boolean eqFound; - int cnt; /* Used to count brace pairs when - * variable in in parens or braces */ - char startc; - - if (endc == ')') - startc = '('; - else - startc = '{'; - - pattern.flags = 0; - eqFound = FALSE; - /* First we make a pass through the string trying - * to verify it is a SYSV-make-style translation: - * it must be: =) */ - cp = tstr; - cnt = 1; - while (*cp != '\0' && cnt) { - if (*cp == '=') { - eqFound = TRUE; - /* continue looking for endc */ - } - else if (*cp == endc) - cnt--; - else if (*cp == startc) - cnt++; - if (cnt) - cp++; - } - if (*cp == endc && eqFound) { - - /* Now we break this sucker into the lhs and - * rhs. We must null terminate them of course. */ - for (cp = tstr; *cp != '='; cp++) - continue; - pattern.lhs = tstr; - pattern.leftLen = cp - tstr; - *cp++ = '\0'; - - pattern.rhs = cp; - cnt = 1; - while (cnt) { - if (*cp == endc) - cnt--; - else if (*cp == startc) - cnt++; - if (cnt) - cp++; - } - pattern.rightLen = cp - pattern.rhs; - *cp = '\0'; - - /* SYSV modifications happen through the whole - * string. Note the pattern is anchored at the end. */ - newStr = VarModify(str, VarSYSVMatch, &pattern); - - /* Restore the nulled characters */ - pattern.lhs[pattern.leftLen] = '='; - pattern.rhs[pattern.rightLen] = endc; - termc = endc; - } else - #endif - { - Error ("Unknown modifier '%c'\n", *tstr); - for (cp = tstr+1; - *cp != ':' && *cp != endc && *cp != '\0';) - cp++; - termc = *cp; - newStr = var_Error; - } - } - } - if (DEBUG(VAR)) - printf("Result is \"%s\"\n", newStr); - - if (*freePtr) - free(str); - str = newStr; - if (str != var_Error) - *freePtr = TRUE; - else - *freePtr = FALSE; - if (termc == '\0') - Error("Unclosed variable specification"); - else if (termc == ':') - *cp++ = termc; - else - *cp = termc; - tstr = cp; - } - *lengthPtr += tstr - start+1; - return str; - - cleanup: - *lengthPtr += cp - start +1; - if (*freePtr) - free(str); - Error("Unclosed substitution for (%c missing)", delim); - return var_Error; - } - /*- *----------------------------------------------------------------------- * Var_Subst -- --- 1004,1009 ---- *************** *** 2365,2413 **** if (doFree) free(val); } - } - - /*- - *----------------------------------------------------------------------- - * Var_GetTail -- - * Return the tail from each of a list of words. Used to set the - * System V local variables. - * - * Results: - * The resulting string. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ - char * - Var_GetTail(file) - char *file; /* Filename to modify */ - { - return VarModify(file, VarTail, NULL); - } - - /*- - *----------------------------------------------------------------------- - * Var_GetHead -- - * Find the leading components of a (list of) filename(s). - * XXX: VarHead does not replace foo by ., as (sun) System V make - * does. - * - * Results: - * The leading components. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ - char * - Var_GetHead(file) - char *file; /* Filename to manipulate */ - { - return VarModify(file, VarHead, NULL); } /*- --- 1174,1179 ----