diff options
author | jmallett <jmallett@FreeBSD.org> | 2002-10-28 23:33:57 +0000 |
---|---|---|
committer | jmallett <jmallett@FreeBSD.org> | 2002-10-28 23:33:57 +0000 |
commit | 1d4b44fe4a5179218b67807b2f8a72b1ea5e30da (patch) | |
tree | e236724d2a28f3e60d37eeb142b7049cd93427bb /usr.bin | |
parent | 46972a1cd987b2dea0a141dde525fdc000ab59d2 (diff) | |
download | FreeBSD-src-1d4b44fe4a5179218b67807b2f8a72b1ea5e30da.zip FreeBSD-src-1d4b44fe4a5179218b67807b2f8a72b1ea5e30da.tar.gz |
Split var.c into var.c and var_modify.c and move all the modification funcs
to var_modify.c, for readability. constify some low hanging fruit (string
manipulation functions) and the upper layers appropriately. No longer use
the private strstr(3) implementation, while changing string code.
Tested by: lots of successful make buildworld.
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/make/Makefile | 2 | ||||
-rw-r--r-- | usr.bin/make/job.c | 4 | ||||
-rw-r--r-- | usr.bin/make/nonints.h | 7 | ||||
-rw-r--r-- | usr.bin/make/str.c | 55 | ||||
-rw-r--r-- | usr.bin/make/var.c | 652 | ||||
-rw-r--r-- | usr.bin/make/var.h | 97 | ||||
-rw-r--r-- | usr.bin/make/var_modify.c | 583 |
7 files changed, 731 insertions, 669 deletions
diff --git a/usr.bin/make/Makefile b/usr.bin/make/Makefile index 6c135c3..1163282 100644 --- a/usr.bin/make/Makefile +++ b/usr.bin/make/Makefile @@ -5,7 +5,7 @@ PROG= make CFLAGS+=-I${.CURDIR} SRCS= arch.c buf.c compat.c cond.c dir.c for.c hash.c job.c main.c \ - make.c parse.c str.c suff.c targ.c util.c var.c + make.c parse.c str.c suff.c targ.c util.c var.c var_modify.c SRCS+= lstAppend.c lstAtEnd.c lstAtFront.c lstClose.c lstConcat.c \ lstDatum.c lstDeQueue.c lstDestroy.c lstDupl.c lstEnQueue.c \ lstFind.c lstFindFrom.c lstFirst.c lstForEach.c lstForEachFrom.c \ diff --git a/usr.bin/make/job.c b/usr.bin/make/job.c index b25edd8..e7d0450 100644 --- a/usr.bin/make/job.c +++ b/usr.bin/make/job.c @@ -1877,7 +1877,7 @@ JobOutput(Job *job, char *cp, char *endp, int msg) char *ecp; if (commandShell->noPrint) { - ecp = Str_FindSubstring(cp, commandShell->noPrint); + ecp = strstr(cp, commandShell->noPrint); while (ecp != NULL) { if (cp != ecp) { *ecp = '\0'; @@ -1905,7 +1905,7 @@ JobOutput(Job *job, char *cp, char *endp, int msg) while (*cp == ' ' || *cp == '\t' || *cp == '\n') { cp++; } - ecp = Str_FindSubstring(cp, commandShell->noPrint); + ecp = strstr(cp, commandShell->noPrint); } else { return cp; } diff --git a/usr.bin/make/nonints.h b/usr.bin/make/nonints.h index a9720c5..d7047e4 100644 --- a/usr.bin/make/nonints.h +++ b/usr.bin/make/nonints.h @@ -94,10 +94,9 @@ void str_init(void); void str_end(void); char *str_concat(char *, char *, int); char **brk_string(char *, int *, Boolean); -char *Str_FindSubstring(char *, char *); -int Str_Match(char *, char *); -char *Str_SYSVMatch(char *, char *, int *len); -void Str_SYSVSubst(Buffer, char *, char *, int); +int Str_Match(const char *, const char *); +const char *Str_SYSVMatch(const char *, const char *, int *); +void Str_SYSVSubst(Buffer, const char *, const char *, int); /* suff.c */ void Suff_ClearSuffixes(void); diff --git a/usr.bin/make/str.c b/usr.bin/make/str.c index 56cb71f..a6fdb63 100644 --- a/usr.bin/make/str.c +++ b/usr.bin/make/str.c @@ -253,44 +253,6 @@ done: argv[argc] = (char *)NULL; } /* - * Str_FindSubstring -- See if a string contains a particular substring. - * - * Results: If string contains substring, the return value is the location of - * the first matching instance of substring in string. If string doesn't - * contain substring, the return value is NULL. Matching is done on an exact - * character-for-character basis with no wildcards or special characters. - * - * Side effects: None. - * - * XXX should be strstr(3). - */ -char * -Str_FindSubstring(char *string, char *substring) -{ - char *a, *b; - - /* - * First scan quickly through the two strings looking for a single- - * character match. When it's found, then compare the rest of the - * substring. - */ - - for (b = substring; *string != 0; string += 1) { - if (*string != *b) - continue; - a = string; - for (;;) { - if (*b == 0) - return(string); - if (*a++ != *b++) - break; - } - b = substring; - } - return((char *) NULL); -} - -/* * Str_Match -- * * See if a particular string matches a particular pattern. @@ -302,7 +264,7 @@ Str_FindSubstring(char *string, char *substring) * Side effects: None. */ int -Str_Match(char *string, char *pattern) +Str_Match(const char *string, const char *pattern) { char c2; @@ -404,12 +366,13 @@ thisCharOK: ++pattern; * *----------------------------------------------------------------------- */ -char * -Str_SYSVMatch(char *word, char *pattern, int *len) +const char * +Str_SYSVMatch(const char *word, const char *pattern, int *len) { - char *p = pattern; - char *w = word; - char *m; + const char *m, *p, *w; + + p = pattern; + w = word; if (*w == '\0') { /* Zero-length word cannot be matched against */ @@ -468,9 +431,9 @@ Str_SYSVMatch(char *word, char *pattern, int *len) *----------------------------------------------------------------------- */ void -Str_SYSVSubst(Buffer buf, char *pat, char *src, int len) +Str_SYSVSubst(Buffer buf, const char *pat, const char *src, int len) { - char *m; + const char *m; if ((m = strchr(pat, '%')) != NULL) { /* Copy the prefix */ diff --git a/usr.bin/make/var.c b/usr.bin/make/var.c index a1462bc..6d3093a 100644 --- a/usr.bin/make/var.c +++ b/usr.bin/make/var.c @@ -89,6 +89,7 @@ __FBSDID("$FreeBSD$"); #include <stdlib.h> #include "make.h" #include "buf.h" +#include "var.h" /* * This is a harmless return value for Var_Parse that can be used by Var_Subst @@ -129,64 +130,16 @@ static Lst allVars; /* List of all variables */ #define FIND_GLOBAL 0x2 /* look in VAR_GLOBAL as well */ #define FIND_ENV 0x4 /* look in the environment also */ -typedef struct Var { - char *name; /* the variable's name */ - Buffer val; /* its value */ - int flags; /* miscellaneous status flags */ -#define VAR_IN_USE 1 /* Variable's value currently being used. - * Used to avoid recursion */ -#define VAR_FROM_ENV 2 /* Variable comes from the environment */ -#define VAR_JUNK 4 /* Variable is a junk variable that - * should be destroyed when done with - * it. Used by Var_Parse for undefined, - * modified variables */ -} 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 */ -#define VAR_NOSUBST 0x20 /* don't expand vars in VarGetPattern */ - -typedef struct { - char *lhs; /* String to match */ - int leftLen; /* Length of string */ - char *rhs; /* Replacement string (w/ &'s removed) */ - int rightLen; /* Length of replacement */ - int flags; -} VarPattern; - -typedef struct { - regex_t re; - int nsub; - regmatch_t *matches; - char *replace; - int flags; -} VarREPattern; - static int VarCmp(void *, void *); static void VarPossiblyExpand(char **, GNode *); static Var *VarFind(char *, GNode *, int); static void VarAdd(char *, char *, GNode *); static void VarDelete(void *); -static Boolean VarHead(char *, Boolean, Buffer, void *); -static Boolean VarTail(char *, Boolean, Buffer, void *); -static Boolean VarSuffix(char *, Boolean, Buffer, void *); -static Boolean VarRoot(char *, Boolean, Buffer, void *); -static Boolean VarMatch(char *, Boolean, Buffer, void *); -#ifdef SYSVVARSUB -static Boolean VarSYSVMatch(char *, Boolean, Buffer, void *); -#endif -static Boolean VarNoMatch(char *, Boolean, Buffer, void *); -static void VarREError(int, regex_t *, const char *); -static Boolean VarRESubstitute(char *, Boolean, Buffer, void *); -static Boolean VarSubstitute(char *, Boolean, Buffer, void *); static char *VarGetPattern(GNode *, int, char **, int, int *, int *, VarPattern *); -static char *VarQuote(char *); -static char *VarModify(char *, Boolean (*)(char *, Boolean, Buffer, void *), +static char *VarQuote(const char *); +static char *VarModify(char *, + Boolean (*)(const char *, Boolean, Buffer, void *), void *); static int VarPrintVar(void *, void *); @@ -616,567 +569,6 @@ Var_Value (char *name, GNode *ctxt, char **frp) /*- *----------------------------------------------------------------------- - * 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 (char *word, Boolean addSpace, Buffer buf, void *dummy __unused) -{ - char *slash; - - slash = strrchr (word, '/'); - if (slash != (char *)NULL) { - if (addSpace) { - Buf_AddByte (buf, (Byte)' '); - } - *slash = '\0'; - Buf_AddBytes (buf, strlen (word), (Byte *)word); - *slash = '/'; - return (TRUE); - } else { - /* - * If no directory part, give . (q.v. the POSIX standard) - */ - if (addSpace) { - Buf_AddBytes(buf, 2, (Byte *)" ."); - } else { - Buf_AddByte(buf, (Byte)'.'); - } - } - return (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 (char *word, Boolean addSpace, Buffer buf, void *dummy __unused) -{ - char *slash; - - if (addSpace) { - Buf_AddByte (buf, (Byte)' '); - } - - slash = strrchr (word, '/'); - if (slash != (char *)NULL) { - *slash++ = '\0'; - Buf_AddBytes (buf, strlen(slash), (Byte *)slash); - slash[-1] = '/'; - } else { - Buf_AddBytes (buf, strlen(word), (Byte *)word); - } - return (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 (char *word, Boolean addSpace, Buffer buf, void *dummy __unused) -{ - char *dot; - - dot = strrchr (word, '.'); - if (dot != (char *)NULL) { - if (addSpace) { - Buf_AddByte (buf, (Byte)' '); - } - *dot++ = '\0'; - Buf_AddBytes (buf, strlen (dot), (Byte *)dot); - dot[-1] = '.'; - addSpace = TRUE; - } - return (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 (char *word, Boolean addSpace, Buffer buf, void *dummy __unused) -{ - char *dot; - - if (addSpace) { - Buf_AddByte (buf, (Byte)' '); - } - - dot = strrchr (word, '.'); - if (dot != (char *)NULL) { - *dot = '\0'; - Buf_AddBytes (buf, strlen (word), (Byte *)word); - *dot = '.'; - } else { - Buf_AddBytes (buf, strlen(word), (Byte *)word); - } - return (TRUE); -} - -/*- - *----------------------------------------------------------------------- - * VarMatch -- - * Place the word in the buffer if it matches the given pattern. - * Callback function for VarModify to implement the :M modifier. - * A space will be added if requested. A pattern is supplied - * which the word must match. - * - * 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 (char *word, Boolean addSpace, Buffer buf, void *pattern) -{ - if (Str_Match(word, (char *) pattern)) { - if (addSpace) { - Buf_AddByte(buf, (Byte)' '); - } - addSpace = TRUE; - Buf_AddBytes(buf, strlen(word), (Byte *)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. A space is added if requested. - * - * 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 (char *word, Boolean addSpace, Buffer buf, void *patp) -{ - int len; - char *ptr; - VarPattern *pat = (VarPattern *) patp; - - if (addSpace) - Buf_AddByte(buf, (Byte)' '); - - addSpace = TRUE; - - if ((ptr = Str_SYSVMatch(word, pat->lhs, &len)) != NULL) - Str_SYSVSubst(buf, pat->rhs, ptr, len); - else - Buf_AddBytes(buf, strlen(word), (Byte *) 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. A - * space is added if requested. - * - * 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 (char *word, Boolean addSpace, Buffer buf, void *pattern) -{ - if (!Str_Match(word, (char *) pattern)) { - if (addSpace) { - Buf_AddByte(buf, (Byte)' '); - } - addSpace = TRUE; - Buf_AddBytes(buf, strlen(word), (Byte *)word); - } - return(addSpace); -} - - -/*- - *----------------------------------------------------------------------- - * VarSubstitute -- - * Perform a string-substitution on the given word, placing the - * result in the passed buffer. A space is added if requested. - * - * Results: - * TRUE if a space is needed before more characters are added. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -static Boolean -VarSubstitute (char *word, Boolean addSpace, Buffer buf, void *patternp) -{ - int wordLen; /* Length of word */ - char *cp; /* General pointer */ - VarPattern *pattern = (VarPattern *) patternp; - - wordLen = strlen(word); - if (1) { /* substitute in each word of the variable */ - /* - * Break substitution 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_AddByte(buf, (Byte)' '); - } - addSpace = TRUE; - Buf_AddBytes(buf, pattern->rightLen, - (Byte *)pattern->rhs); - } - } 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_AddByte(buf, (Byte)' '); - } - addSpace = TRUE; - } - Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs); - Buf_AddBytes(buf, wordLen - pattern->leftLen, - (Byte *)(word + pattern->leftLen)); - } - } 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_AddByte(buf, (Byte)' '); - } - addSpace = TRUE; - } - Buf_AddBytes(buf, cp - word, (Byte *)word); - Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs); - } 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. - */ - Boolean done; - int origSize; - - done = FALSE; - origSize = Buf_Size(buf); - while (!done) { - cp = Str_FindSubstring(word, pattern->lhs); - if (cp != (char *)NULL) { - if (addSpace && (((cp - word) + pattern->rightLen) != 0)){ - Buf_AddByte(buf, (Byte)' '); - addSpace = FALSE; - } - Buf_AddBytes(buf, cp-word, (Byte *)word); - Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs); - wordLen -= (cp - word) + pattern->leftLen; - word = cp + pattern->leftLen; - if (wordLen == 0 || (pattern->flags & VAR_SUB_GLOBAL) == 0){ - done = TRUE; - } - } else { - done = TRUE; - } - } - if (wordLen != 0) { - if (addSpace) { - Buf_AddByte(buf, (Byte)' '); - } - Buf_AddBytes(buf, wordLen, (Byte *)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); - } - /* - * Common code for anchored substitutions: - * addSpace was set TRUE if characters were added to the buffer. - */ - return (addSpace); - } - nosub: - if (addSpace) { - Buf_AddByte(buf, (Byte)' '); - } - Buf_AddBytes(buf, wordLen, (Byte *)word); - return(TRUE); -} - -/*- - *----------------------------------------------------------------------- - * VarREError -- - * Print the error caused by a regcomp or regexec call. - * - * Results: - * None. - * - * Side Effects: - * An error gets printed. - * - *----------------------------------------------------------------------- - */ -static void -VarREError(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. A space is added if requested. - * - * Results: - * TRUE if a space is needed before more characters are added. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -static Boolean -VarRESubstitute(char *word, Boolean addSpace, Buffer buf, void *patternp) -{ - VarREPattern *pat; - int xrv; - char *wp; - char *rp; - int added; - int flags = 0; - -#define MAYBE_ADD_SPACE() \ - if (addSpace && !added) \ - Buf_AddByte(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, flags); - } - - switch (xrv) { - case 0: - pat->flags |= VAR_SUB_MATCHED; - if (pat->matches[0].rm_so > 0) { - MAYBE_ADD_SPACE(); - Buf_AddBytes(buf, pat->matches[0].rm_so, wp); - } - - for (rp = pat->replace; *rp; rp++) { - if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) { - MAYBE_ADD_SPACE(); - Buf_AddByte(buf,rp[1]); - rp++; - } - else if ((*rp == '&') || - ((*rp == '\\') && isdigit((unsigned char)rp[1]))) { - int n; - 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_AddBytes(buf, sublen, subbuf); - } - } else { - MAYBE_ADD_SPACE(); - Buf_AddByte(buf, *rp); - } - } - wp += pat->matches[0].rm_eo; - if (pat->flags & VAR_SUB_GLOBAL) { - flags |= REG_NOTBOL; - if (pat->matches[0].rm_so == 0 && pat->matches[0].rm_eo == 0) { - MAYBE_ADD_SPACE(); - Buf_AddByte(buf, *wp); - wp++; - - } - if (*wp) - goto tryagain; - } - if (*wp) { - MAYBE_ADD_SPACE(); - Buf_AddBytes(buf, strlen(wp), wp); - } - break; - default: - VarREError(xrv, &pat->re, "Unexpected regex error"); - /* fall through */ - case REG_NOMATCH: - if (*wp) { - MAYBE_ADD_SPACE(); - Buf_AddBytes(buf,strlen(wp),wp); - } - break; - } - return(addSpace||added); -} - - -/*- - *----------------------------------------------------------------------- * VarModify -- * Modify each of the words of the passed string using the given * function. Used to implement all modifiers. @@ -1190,7 +582,7 @@ VarRESubstitute(char *word, Boolean addSpace, Buffer buf, void *patternp) *----------------------------------------------------------------------- */ static char * -VarModify (char *str, Boolean (*modProc)(char *, Boolean, Buffer, void *), +VarModify (char *str, Boolean (*modProc)(const char *, Boolean, Buffer, void *), void *datum) { Buffer buf; /* Buffer for the new string */ @@ -1351,12 +743,13 @@ VarGetPattern(GNode *ctxt, int err, char **tstr, int delim, int *flags, *----------------------------------------------------------------------- */ static char * -VarQuote(char *str) +VarQuote(const char *str) { Buffer buf; /* This should cover most shells :-( */ static char meta[] = "\n \t'`\";&<>()|*?{}[]\\$!#^~"; + char *ret; buf = Buf_Init (MAKE_BSIZE); for (; *str; str++) { @@ -1365,11 +758,38 @@ VarQuote(char *str) Buf_AddByte(buf, (Byte)*str); } Buf_AddByte(buf, (Byte) '\0'); - str = (char *)Buf_GetAll (buf, (int *)NULL); + ret = Buf_GetAll (buf, NULL); Buf_Destroy (buf, FALSE); - return str; + return ret; +} + +/*- + *----------------------------------------------------------------------- + * VarREError -- + * Print the error caused by a regcomp or regexec call. + * + * Results: + * None. + * + * Side Effects: + * An error gets printed. + * + *----------------------------------------------------------------------- + */ +void +VarREError(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); } + /*- *----------------------------------------------------------------------- * Var_Parse -- diff --git a/usr.bin/make/var.h b/usr.bin/make/var.h new file mode 100644 index 0000000..7a94f06 --- /dev/null +++ b/usr.bin/make/var.h @@ -0,0 +1,97 @@ +/*- + * Copyright (c) 2002 Juli Mallett. + * Copyright (c) 1988, 1989, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1989 by Berkeley Softworks + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Adam de Boor. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +typedef struct Var { + char *name; /* the variable's name */ + Buffer val; /* its value */ + int flags; /* miscellaneous status flags */ +#define VAR_IN_USE 1 /* Variable's value currently being used. + * Used to avoid recursion */ +#define VAR_FROM_ENV 2 /* Variable comes from the environment */ +#define VAR_JUNK 4 /* Variable is a junk variable that + * should be destroyed when done with + * it. Used by Var_Parse for undefined, + * modified variables */ +} 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 */ +#define VAR_NOSUBST 0x20 /* don't expand vars in VarGetPattern */ + +typedef struct { + char *lhs; /* String to match */ + int leftLen; /* Length of string */ + char *rhs; /* Replacement string (w/ &'s removed) */ + int rightLen; /* Length of replacement */ + int flags; +} VarPattern; + +typedef struct { + regex_t re; + int nsub; + regmatch_t *matches; + char *replace; + int flags; +} VarREPattern; + +/* + * var.c + */ +void VarREError(int, regex_t *, const char *); + +/* + * var_modify.c + */ +Boolean VarHead(const char *, Boolean, Buffer, void *); +Boolean VarTail(const char *, Boolean, Buffer, void *); +Boolean VarSuffix(const char *, Boolean, Buffer, void *); +Boolean VarRoot(const char *, Boolean, Buffer, void *); +Boolean VarMatch(const char *, Boolean, Buffer, void *); +#ifdef SYSVVARSUB +Boolean VarSYSVMatch(const char *, Boolean, Buffer, void *); +#endif +Boolean VarNoMatch(const char *, Boolean, Buffer, void *); +Boolean VarRESubstitute(const char *, Boolean, Buffer, void *); +Boolean VarSubstitute(const char *, Boolean, Buffer, void *); diff --git a/usr.bin/make/var_modify.c b/usr.bin/make/var_modify.c new file mode 100644 index 0000000..ef4257c --- /dev/null +++ b/usr.bin/make/var_modify.c @@ -0,0 +1,583 @@ +/* + * Copyright (c) 2002 Juli Mallett. + * Copyright (c) 1988, 1989, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1989 by Berkeley Softworks + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Adam de Boor. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)var.c 8.3 (Berkeley) 3/19/94 + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <ctype.h> +#include <sys/types.h> +#include <regex.h> +#include <stdlib.h> +#include "make.h" +#include "buf.h" +#include "var.h" + +/*- + *----------------------------------------------------------------------- + * 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. + * + *----------------------------------------------------------------------- + */ +Boolean +VarHead (const char *word, Boolean addSpace, Buffer buf, void *dummy __unused) +{ + char *slash; + char *buffer; + + buffer = estrdup(word); + slash = strrchr (buffer, '/'); + if (slash != NULL) { + if (addSpace) { + Buf_AddByte (buf, (Byte)' '); + } + *slash = '\0'; + Buf_AddBytes (buf, strlen (word), (Byte *)word); + free(buffer); + return (TRUE); + } else { + /* + * If no directory part, give . (q.v. the POSIX standard) + */ + if (addSpace) { + Buf_AddBytes(buf, 2, (Byte *)" ."); + } else { + Buf_AddByte(buf, (Byte)'.'); + } + } + free(buffer); + return (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. + * + *----------------------------------------------------------------------- + */ +Boolean +VarTail (const char *word, Boolean addSpace, Buffer buf, void *dummy __unused) +{ + const char *slash; + + if (addSpace) { + Buf_AddByte (buf, (Byte)' '); + } + + slash = strrchr (word, '/'); + if (slash++ != NULL) { + Buf_AddBytes (buf, strlen(slash), (Byte *)slash); + } else { + Buf_AddBytes (buf, strlen(word), (Byte *)word); + } + return (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. + * + *----------------------------------------------------------------------- + */ +Boolean +VarSuffix (const char *word, Boolean addSpace, Buffer buf, void *dummy __unused) +{ + const char *dot; + + dot = strrchr (word, '.'); + if (dot++ != (char *)NULL) { + if (addSpace) { + Buf_AddByte (buf, (Byte)' '); + } + Buf_AddBytes (buf, strlen (dot), (Byte *)dot); + addSpace = TRUE; + } + return (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. + * + *----------------------------------------------------------------------- + */ +Boolean +VarRoot (const char *word, Boolean addSpace, Buffer buf, void *dummy __unused) +{ + char *buffer; + char *dot; + + if (addSpace) { + Buf_AddByte (buf, (Byte)' '); + } + + buffer = estrdup(word); + dot = strrchr (buffer, '.'); + if (dot != NULL) { + *dot = '\0'; + } + Buf_AddBytes (buf, strlen(buffer), (Byte *)buffer); + free(buffer); + return (TRUE); +} + +/*- + *----------------------------------------------------------------------- + * VarMatch -- + * Place the word in the buffer if it matches the given pattern. + * Callback function for VarModify to implement the :M modifier. + * A space will be added if requested. A pattern is supplied + * which the word must match. + * + * 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. + * + *----------------------------------------------------------------------- + */ +Boolean +VarMatch (const char *word, Boolean addSpace, Buffer buf, void *pattern) +{ + if (Str_Match(word, pattern)) { + if (addSpace) { + Buf_AddByte(buf, (Byte)' '); + } + addSpace = TRUE; + Buf_AddBytes(buf, strlen(word), 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. A space is added if requested. + * + * 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. + * + *----------------------------------------------------------------------- + */ +Boolean +VarSYSVMatch (const char *word, Boolean addSpace, Buffer buf, void *patp) +{ + int len; + const char *ptr; + VarPattern *pat = (VarPattern *) patp; + + if (addSpace) + Buf_AddByte(buf, (Byte)' '); + + addSpace = TRUE; + + if ((ptr = Str_SYSVMatch(word, pat->lhs, &len)) != NULL) + Str_SYSVSubst(buf, pat->rhs, ptr, len); + else + Buf_AddBytes(buf, strlen(word), (Byte *) 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. A + * space is added if requested. + * + * 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. + * + *----------------------------------------------------------------------- + */ +Boolean +VarNoMatch (const char *word, Boolean addSpace, Buffer buf, void *pattern) +{ + if (!Str_Match(word, pattern)) { + if (addSpace) { + Buf_AddByte(buf, (Byte)' '); + } + addSpace = TRUE; + Buf_AddBytes(buf, strlen(word), (Byte *)word); + } + return(addSpace); +} + + +/*- + *----------------------------------------------------------------------- + * VarSubstitute -- + * Perform a string-substitution on the given word, placing the + * result in the passed buffer. A space is added if requested. + * + * Results: + * TRUE if a space is needed before more characters are added. + * + * Side Effects: + * None. + * + *----------------------------------------------------------------------- + */ +Boolean +VarSubstitute (const char *word, Boolean addSpace, Buffer buf, void *patternp) +{ + int wordLen; /* Length of word */ + const char *cp; /* General pointer */ + VarPattern *pattern = (VarPattern *) patternp; + + wordLen = strlen(word); + if (1) { /* substitute in each word of the variable */ + /* + * Break substitution 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_AddByte(buf, (Byte)' '); + } + addSpace = TRUE; + Buf_AddBytes(buf, pattern->rightLen, + (Byte *)pattern->rhs); + } + } 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_AddByte(buf, (Byte)' '); + } + addSpace = TRUE; + } + Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs); + Buf_AddBytes(buf, wordLen - pattern->leftLen, + (Byte *)(word + pattern->leftLen)); + } + } 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_AddByte(buf, (Byte)' '); + } + addSpace = TRUE; + } + Buf_AddBytes(buf, cp - word, (Byte *)word); + Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs); + } 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 + * strstr(3), 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. + */ + Boolean done; + int 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_AddByte(buf, (Byte)' '); + addSpace = FALSE; + } + Buf_AddBytes(buf, cp-word, (Byte *)word); + Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs); + wordLen -= (cp - word) + pattern->leftLen; + word = cp + pattern->leftLen; + if (wordLen == 0 || (pattern->flags & VAR_SUB_GLOBAL) == 0){ + done = TRUE; + } + } else { + done = TRUE; + } + } + if (wordLen != 0) { + if (addSpace) { + Buf_AddByte(buf, (Byte)' '); + } + Buf_AddBytes(buf, wordLen, (Byte *)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); + } + /* + * Common code for anchored substitutions: + * addSpace was set TRUE if characters were added to the buffer. + */ + return (addSpace); + } + nosub: + if (addSpace) { + Buf_AddByte(buf, (Byte)' '); + } + Buf_AddBytes(buf, wordLen, (Byte *)word); + return(TRUE); +} + +/*- + *----------------------------------------------------------------------- + * VarRESubstitute -- + * Perform a regex substitution on the given word, placing the + * result in the passed buffer. A space is added if requested. + * + * Results: + * TRUE if a space is needed before more characters are added. + * + * Side Effects: + * None. + * + *----------------------------------------------------------------------- + */ +Boolean +VarRESubstitute(const char *word, Boolean addSpace, Buffer buf, void *patternp) +{ + VarREPattern *pat; + int xrv; + const char *wp; + char *rp; + int added; + int flags = 0; + +#define MAYBE_ADD_SPACE() \ + if (addSpace && !added) \ + Buf_AddByte(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, flags); + } + + switch (xrv) { + case 0: + pat->flags |= VAR_SUB_MATCHED; + if (pat->matches[0].rm_so > 0) { + MAYBE_ADD_SPACE(); + Buf_AddBytes(buf, pat->matches[0].rm_so, wp); + } + + for (rp = pat->replace; *rp; rp++) { + if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) { + MAYBE_ADD_SPACE(); + Buf_AddByte(buf,rp[1]); + rp++; + } + else if ((*rp == '&') || + ((*rp == '\\') && isdigit((unsigned char)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_AddBytes(buf, sublen, subbuf); + } + } else { + MAYBE_ADD_SPACE(); + Buf_AddByte(buf, *rp); + } + } + wp += pat->matches[0].rm_eo; + if (pat->flags & VAR_SUB_GLOBAL) { + flags |= REG_NOTBOL; + if (pat->matches[0].rm_so == 0 && pat->matches[0].rm_eo == 0) { + MAYBE_ADD_SPACE(); + Buf_AddByte(buf, *wp); + wp++; + + } + if (*wp) + goto tryagain; + } + if (*wp) { + MAYBE_ADD_SPACE(); + Buf_AddBytes(buf, strlen(wp), wp); + } + break; + default: + VarREError(xrv, &pat->re, "Unexpected regex error"); + /* fall through */ + case REG_NOMATCH: + if (*wp) { + MAYBE_ADD_SPACE(); + Buf_AddBytes(buf,strlen(wp),wp); + } + break; + } + return(addSpace||added); +} |