Module Name: src
Committed By: rillig
Date: Fri Jul 3 22:10:42 UTC 2020
Modified Files:
src/usr.bin/make: var.c
src/usr.bin/make/unit-tests: modmisc.exp modmisc.mk
Log Message:
make(1): clean up documentation, small refactorings for variables
- document the callback for VarModify
- clearly mark the callbacks
- shorten the documentation for some callback functions
- fix the documentation of VarSYSVMatch
- remove unnecessary null check from VarLoopExpand
- add test for applying modifiers to empty strings
To generate a diff of this commit:
cvs rdiff -u -r1.243 -r1.244 src/usr.bin/make/var.c
cvs rdiff -u -r1.7 -r1.8 src/usr.bin/make/unit-tests/modmisc.exp
cvs rdiff -u -r1.6 -r1.7 src/usr.bin/make/unit-tests/modmisc.mk
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/usr.bin/make/var.c
diff -u src/usr.bin/make/var.c:1.243 src/usr.bin/make/var.c:1.244
--- src/usr.bin/make/var.c:1.243 Fri Jul 3 18:41:50 2020
+++ src/usr.bin/make/var.c Fri Jul 3 22:10:42 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: var.c,v 1.243 2020/07/03 18:41:50 rillig Exp $ */
+/* $NetBSD: var.c,v 1.244 2020/07/03 22:10:42 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -69,14 +69,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: var.c,v 1.243 2020/07/03 18:41:50 rillig Exp $";
+static char rcsid[] = "$NetBSD: var.c,v 1.244 2020/07/03 22:10:42 rillig Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94";
#else
-__RCSID("$NetBSD: var.c,v 1.243 2020/07/03 18:41:50 rillig Exp $");
+__RCSID("$NetBSD: var.c,v 1.244 2020/07/03 22:10:42 rillig Exp $");
#endif
#endif /* not lint */
#endif
@@ -1168,7 +1168,22 @@ Var_Value(const char *name, GNode *ctxt,
return p;
}
-/* Add the dirname of the given word to the buffer. */
+
+/* This callback for VarModify gets a single word from an expression and
+ * typically adds a modification of this word to the buffer. It may also do
+ * nothing or add several words.
+ *
+ * If addSpaces is TRUE, it must add a space before adding anything else to
+ * the buffer.
+ *
+ * It returns the addSpace value for the next call of this callback. Typical
+ * return values are the current addSpaces or TRUE. */
+typedef Boolean (*VarModifyCallback)(GNode *ctxt, Var_Parse_State *vpstate,
+ char *word, Boolean addSpace, Buffer *buf, void *data);
+
+
+/* Callback function for VarModify to implement the :H modifier.
+ * Add the dirname of the given word to the buffer. */
static Boolean
VarHead(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
char *word, Boolean addSpace, Buffer *buf,
@@ -1186,7 +1201,8 @@ VarHead(GNode *ctx MAKE_ATTR_UNUSED, Var
return TRUE;
}
-/* Add the basename of the given word to the buffer. */
+/* Callback function for VarModify to implement the :T modifier.
+ * Add the basename of the given word to the buffer. */
static Boolean
VarTail(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
char *word, Boolean addSpace, Buffer *buf,
@@ -1198,11 +1214,11 @@ VarTail(GNode *ctx MAKE_ATTR_UNUSED, Var
if (addSpace && vpstate->varSpace)
Buf_AddByte(buf, vpstate->varSpace);
Buf_AddBytes(buf, strlen(base), base);
-
return TRUE;
}
-/* Add the filename suffix of the given word to the buffer, if it exists. */
+/* Callback function for VarModify to implement the :E modifier.
+ * Add the filename suffix of the given word to the buffer, if it exists. */
static Boolean
VarSuffix(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
char *word, Boolean addSpace, Buffer *buf,
@@ -1218,7 +1234,8 @@ VarSuffix(GNode *ctx MAKE_ATTR_UNUSED, V
return TRUE;
}
-/* Add the filename basename of the given word to the buffer. */
+/* Callback function for VarModify to implement the :R modifier.
+ * Add the filename basename of the given word to the buffer. */
static Boolean
VarRoot(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
char *word, Boolean addSpace, Buffer *buf,
@@ -1233,167 +1250,78 @@ VarRoot(GNode *ctx MAKE_ATTR_UNUSED, Var
return TRUE;
}
-/*-
- *-----------------------------------------------------------------------
- * VarMatch --
- * Place the word in the buffer if it matches the given pattern.
- * Callback function for VarModify to implement the :M modifier.
- *
- * Input:
- * word Word to examine
- * addSpace TRUE if need to add a space to the buffer
- * before adding the word, if it matches
- * buf Buffer in which to store it
- * pattern Pattern 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.
- *
- *-----------------------------------------------------------------------
- */
+/* Callback function for VarModify to implement the :M modifier.
+ * Place the word in the buffer if it matches the given pattern. */
static Boolean
VarMatch(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
char *word, Boolean addSpace, Buffer *buf,
- void *pattern)
+ void *data)
{
+ const char *pattern = data;
if (DEBUG(VAR))
- fprintf(debug_file, "VarMatch [%s] [%s]\n", word, (char *)pattern);
- if (Str_Match(word, (char *)pattern)) {
- if (addSpace && vpstate->varSpace) {
- Buf_AddByte(buf, vpstate->varSpace);
- }
- addSpace = TRUE;
- Buf_AddBytes(buf, strlen(word), word);
- }
- return addSpace;
+ fprintf(debug_file, "VarMatch [%s] [%s]\n", word, pattern);
+ if (!Str_Match(word, pattern))
+ return addSpace;
+ if (addSpace && vpstate->varSpace)
+ Buf_AddByte(buf, vpstate->varSpace);
+ Buf_AddBytes(buf, strlen(word), word);
+ return TRUE;
}
#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.
- *
- * Input:
- * word Word to examine
- * addSpace TRUE if need to add a space to the buffer
- * before adding the word, if it matches
- * buf Buffer in which to store it
- * patp Pattern 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.
- *
- *-----------------------------------------------------------------------
- */
+/* Callback function for VarModify to implement the :%.from=%.to modifier. */
static Boolean
VarSYSVMatch(GNode *ctx, Var_Parse_State *vpstate,
char *word, Boolean addSpace, Buffer *buf,
- void *patp)
+ void *data)
{
size_t len;
char *ptr;
Boolean hasPercent;
- VarPattern *pat = (VarPattern *)patp;
- char *varexp;
+ VarPattern *pat = data;
if (addSpace && vpstate->varSpace)
Buf_AddByte(buf, vpstate->varSpace);
- addSpace = TRUE;
-
if ((ptr = Str_SYSVMatch(word, pat->lhs, &len, &hasPercent)) != NULL) {
- varexp = Var_Subst(NULL, pat->rhs, ctx, VARF_WANTRES);
+ char *varexp = Var_Subst(NULL, pat->rhs, ctx, VARF_WANTRES);
Str_SYSVSubst(buf, varexp, ptr, len, hasPercent);
free(varexp);
} else {
Buf_AddBytes(buf, strlen(word), word);
}
- return addSpace;
+ return TRUE;
}
#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.
- *
- * Input:
- * word Word to examine
- * addSpace TRUE if need to add a space to the buffer
- * before adding the word, if it matches
- * buf Buffer in which to store it
- * pattern Pattern 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.
- *
- *-----------------------------------------------------------------------
- */
+/* Callback function for VarModify to implement the :N modifier.
+ * Place the word in the buffer if it doesn't match the given pattern. */
static Boolean
VarNoMatch(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
char *word, Boolean addSpace, Buffer *buf,
- void *pattern)
+ void *data)
{
- if (!Str_Match(word, (char *)pattern)) {
- if (addSpace && vpstate->varSpace) {
- Buf_AddByte(buf, vpstate->varSpace);
- }
- addSpace = TRUE;
- Buf_AddBytes(buf, strlen(word), word);
- }
- return addSpace;
+ const char *pattern = data;
+ if (Str_Match(word, pattern))
+ return addSpace;
+ if (addSpace && vpstate->varSpace)
+ Buf_AddByte(buf, vpstate->varSpace);
+ Buf_AddBytes(buf, strlen(word), word);
+ return TRUE;
}
-
-/*-
- *-----------------------------------------------------------------------
- * VarSubstitute --
- * Perform a string-substitution on the given word, placing the
- * result in the passed buffer.
- *
- * Input:
- * word Word to modify
- * addSpace True if space should be added before
- * other characters
- * buf Buffer for result
- * patternp Pattern for substitution
- *
- * Results:
- * TRUE if a space is needed before more characters are added.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
+/* Callback function for VarModify to implement the :S,from,to, modifier.
+ * Perform a string substitution on the given word. */
static Boolean
VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
char *word, Boolean addSpace, Buffer *buf,
- void *patternp)
+ void *data)
{
- int wordLen; /* Length of word */
- char *cp; /* General pointer */
- VarPattern *pattern = (VarPattern *)patternp;
+ int wordLen = strlen(word);
+ char *cp; /* General pointer */
+ VarPattern *pattern = data;
- wordLen = strlen(word);
if ((pattern->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) !=
(VAR_SUB_ONE|VAR_SUB_MATCHED)) {
/*
@@ -1565,32 +1493,19 @@ VarREError(int reerr, regex_t *pat, cons
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.
- *
- *-----------------------------------------------------------------------
- */
+/* Callback function for VarModify to implement the :C/from/to/ modifier.
+ * Perform a regex substitution on the given word. */
static Boolean
VarRESubstitute(GNode *ctx MAKE_ATTR_UNUSED,
Var_Parse_State *vpstate MAKE_ATTR_UNUSED,
char *word, Boolean addSpace, Buffer *buf,
- void *patternp)
+ void *data)
{
- VarREPattern *pat;
+ VarREPattern *pat = data;
int xrv;
- char *wp;
+ char *wp = word;
char *rp;
- int added;
+ int added = 0;
int flags = 0;
#define MAYBE_ADD_SPACE() \
@@ -1598,10 +1513,6 @@ VarRESubstitute(GNode *ctx MAKE_ATTR_UNU
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;
@@ -1697,40 +1608,20 @@ VarRESubstitute(GNode *ctx MAKE_ATTR_UNU
#endif
-
-/*-
- *-----------------------------------------------------------------------
- * VarLoopExpand --
- * Implements the :@<temp>@<string>@ modifier of ODE make.
- * We set the temp variable named in pattern.lhs to word and expand
- * pattern.rhs storing the result in the passed buffer.
- *
- * Input:
- * word Word to modify
- * addSpace True if space should be added before
- * other characters
- * buf Buffer for result
- * pattern Datafor substitution
- *
- * Results:
- * TRUE if a space is needed before more characters are added.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
+/* Callback function for VarModify to implement the :@var@...@ modifier of
+ * ODE make. We set the temp variable named in pattern.lhs to word and
+ * expand pattern.rhs. */
static Boolean
VarLoopExpand(GNode *ctx MAKE_ATTR_UNUSED,
Var_Parse_State *vpstate MAKE_ATTR_UNUSED,
char *word, Boolean addSpace, Buffer *buf,
- void *loopp)
+ void *data)
{
- VarLoop_t *loop = (VarLoop_t *)loopp;
+ VarLoop_t *loop = data;
char *s;
int slen;
- if (word && *word) {
+ if (*word) {
Var_Set_with_flags(loop->tvar, word, loop->ctxt, VAR_NO_EXPORT);
s = Var_Subst(NULL, loop->str, loop->ctxt, loop->flags);
if (s != NULL && *s != '\0') {
@@ -1834,7 +1725,8 @@ VarSelectWords(GNode *ctx MAKE_ATTR_UNUS
}
-/* Replace each word with the result of realpath() if successful. */
+/* Callback function for VarModify to implement the :tA modifier.
+ * Replace each word with the result of realpath() if successful. */
static Boolean
VarRealpath(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
char *word, Boolean addSpace, Buffer *buf,
@@ -1856,14 +1748,12 @@ VarRealpath(GNode *ctx MAKE_ATTR_UNUSED,
/*-
*-----------------------------------------------------------------------
- * VarModify --
- * Modify each of the words of the passed string using the given
- * function. Used to implement all modifiers.
+ * Modify each of the words of the passed string using the given function.
*
* Input:
* str String whose words should be trimmed
* modProc Function to use to modify them
- * datum Datum to pass it
+ * data Custom data for the modProc
*
* Results:
* A string of all the words modified appropriately.
@@ -1875,10 +1765,7 @@ VarRealpath(GNode *ctx MAKE_ATTR_UNUSED,
*/
static char *
VarModify(GNode *ctx, Var_Parse_State *vpstate,
- const char *str,
- Boolean (*modProc)(GNode *, Var_Parse_State *, char *,
- Boolean, Buffer *, void *),
- void *datum)
+ const char *str, VarModifyCallback modProc, void *datum)
{
Buffer buf; /* Buffer for the new string */
Boolean addSpace; /* TRUE if need to add a space to the
Index: src/usr.bin/make/unit-tests/modmisc.exp
diff -u src/usr.bin/make/unit-tests/modmisc.exp:1.7 src/usr.bin/make/unit-tests/modmisc.exp:1.8
--- src/usr.bin/make/unit-tests/modmisc.exp:1.7 Fri Jul 3 19:21:11 2020
+++ src/usr.bin/make/unit-tests/modmisc.exp Fri Jul 3 22:10:42 2020
@@ -11,4 +11,10 @@ dirname of 'a/b/c def a.b.c a.b/c a a.a
basename of 'a/b/c def a.b.c a.b/c a a.a .gitignore a a.a' is 'c def a.b.c c a a.a .gitignore a a.a'
suffix of 'a/b/c def a.b.c a.b/c a a.a .gitignore a a.a' is 'c b/c a gitignore a'
root of 'a/b/c def a.b.c a.b/c a a.a .gitignore a a.a' is 'a/b/c def a.b a a a a a'
+S:
+C:
+@:
+S:empty
+C:empty
+@:
exit status 0
Index: src/usr.bin/make/unit-tests/modmisc.mk
diff -u src/usr.bin/make/unit-tests/modmisc.mk:1.6 src/usr.bin/make/unit-tests/modmisc.mk:1.7
--- src/usr.bin/make/unit-tests/modmisc.mk:1.6 Fri Jul 3 18:41:50 2020
+++ src/usr.bin/make/unit-tests/modmisc.mk Fri Jul 3 22:10:42 2020
@@ -1,4 +1,4 @@
-# $Id: modmisc.mk,v 1.6 2020/07/03 18:41:50 rillig Exp $
+# $Id: modmisc.mk,v 1.7 2020/07/03 22:10:42 rillig Exp $
#
# miscellaneous modifier tests
@@ -15,7 +15,7 @@ MOD_HOMES=S,/home/,/homes/,
MOD_OPT=@d@$${exists($$d):?$$d:$${d:S,/usr,/opt,}}@
MOD_SEP=S,:, ,g
-all: modvar modvarloop modsysv mod-HTE
+all: modvar modvarloop modsysv mod-HTE emptyvar undefvar
modsysv:
@echo "The answer is ${libfoo.a:L:libfoo.a=42}"
@@ -43,3 +43,18 @@ mod-HTE:
@echo "basename of '"${PATHNAMES:Q}"' is '"${PATHNAMES:T:Q}"'"
@echo "suffix of '"${PATHNAMES:Q}"' is '"${PATHNAMES:E:Q}"'"
@echo "root of '"${PATHNAMES:Q}"' is '"${PATHNAMES:R:Q}"'"
+
+# When a modifier is applied to the "" variable, the result is discarded.
+emptyvar:
+ @echo S:${:S,^$,empty,}
+ @echo C:${:C,^$,empty,}
+ @echo @:${:@var@${var}@}
+
+# The :U modifier turns even the "" variable into something that has a value.
+# The resulting variable is empty, but is still considered to contain a
+# single empty word. This word can be accessed by the :S and :C modifiers,
+# but not by the :@ modifier since it explicitly skips empty words.
+undefvar:
+ @echo S:${:U:S,^$,empty,}
+ @echo C:${:U:C,^$,empty,}
+ @echo @:${:U:@var@empty@}