[master] 12cd341e3 varnishtest: Allow macros to be backed by functions
Dridi Boukelmoune
dridi.boukelmoune at gmail.com
Mon Jul 5 15:48:05 UTC 2021
commit 12cd341e3cd8d588af0811106b3ba8e91b5c6b17
Author: Dridi Boukelmoune <dridi.boukelmoune at gmail.com>
Date: Thu Jun 17 15:49:45 2021 +0200
varnishtest: Allow macros to be backed by functions
Instead of having a mere value, these would be able to compute a macro
expansion. We parse the contents inside the ${...} delimiters as a VAV,
but there can't be (yet?) nested curly {braces}, even quoted.
The first argument inside the delimiters is the macro name, and other
VAV arguments are treated as arguments to the macro's function.
For example ${foo,bar,baz} would call the a macro "foo"'s function with
arguments "bar" and "baz". Simple macros don't take arguments and work
as usual.
diff --git a/bin/varnishtest/vtc.c b/bin/varnishtest/vtc.c
index 7a9eb6144..2eb2e5d43 100644
--- a/bin/varnishtest/vtc.c
+++ b/bin/varnishtest/vtc.c
@@ -80,6 +80,7 @@ struct macro {
VTAILQ_ENTRY(macro) list;
char *name;
char *val;
+ macro_f *func;
};
static VTAILQ_HEAD(,macro) macro_list = VTAILQ_HEAD_INITIALIZER(macro_list);
@@ -99,7 +100,7 @@ static const struct cmds top_cmds[] = {
/**********************************************************************/
static struct macro *
-macro_def_int(const char *name, const char *fmt, va_list ap)
+macro_def_int(const char *name, macro_f *func, const char *fmt, va_list ap)
{
struct macro *m;
char buf[512];
@@ -115,9 +116,15 @@ macro_def_int(const char *name, const char *fmt, va_list ap)
VTAILQ_INSERT_TAIL(¯o_list, m, list);
}
AN(m);
- vbprintf(buf, fmt, ap);
- REPLACE(m->val, buf);
- AN(m->val);
+ if (func != NULL) {
+ AZ(fmt);
+ m->func = func;
+ } else {
+ AN(fmt);
+ vbprintf(buf, fmt, ap);
+ REPLACE(m->val, buf);
+ AN(m->val);
+ }
return (m);
}
@@ -128,12 +135,12 @@ macro_def_int(const char *name, const char *fmt, va_list ap)
*/
void
-extmacro_def(const char *name, const char *fmt, ...)
+extmacro_def(const char *name, macro_f *func, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
- (void)macro_def_int(name, fmt, ap);
+ (void)macro_def_int(name, func, fmt, ap);
va_end(ap);
}
@@ -149,8 +156,13 @@ init_macro(void)
struct macro *m;
/* Dump the extmacros for completeness */
- VTAILQ_FOREACH(m, ¯o_list, list)
- vtc_log(vltop, 4, "extmacro def %s=%s", m->name, m->val);
+ VTAILQ_FOREACH(m, ¯o_list, list) {
+ if (m->val != NULL)
+ vtc_log(vltop, 4,
+ "extmacro def %s=%s", m->name, m->val);
+ else
+ vtc_log(vltop, 4, "extmacro def %s(...)", m->name);
+ }
AZ(pthread_mutex_init(¯o_mtx, NULL));
}
@@ -172,7 +184,7 @@ macro_def(struct vtclog *vl, const char *instance, const char *name,
AZ(pthread_mutex_lock(¯o_mtx));
va_start(ap, fmt);
- m = macro_def_int(name, fmt, ap);
+ m = macro_def_int(name, NULL, fmt, ap);
va_end(ap);
vtc_log(vl, 4, "macro def %s=%s", name, m->val);
AZ(pthread_mutex_unlock(¯o_mtx));
@@ -208,35 +220,61 @@ void
macro_cat(struct vtclog *vl, struct vsb *vsb, const char *b, const char *e)
{
struct macro *m;
- int l;
- char *retval = NULL;
+ char **argv, *retval = NULL;
+ const char *err = NULL;
+ int argc;
AN(b);
if (e == NULL)
e = strchr(b, '\0');
AN(e);
- l = e - b;
- if (l == 4 && !memcmp(b, "date", l)) {
+ argv = VAV_ParseTxt(b, e, &argc, ARGV_COMMA);
+ AN(argv);
+
+ if (*argv != NULL)
+ vtc_fatal(vl, "Macro ${%.*s} parsing failed: %s",
+ (int)(e - b), b, *argv);
+
+ assert(argc >= 2);
+
+ if (!strcmp(argv[1], "date")) {
double t = VTIM_real();
retval = malloc(VTIM_FORMAT_SIZE);
AN(retval);
VTIM_format(t, retval);
VSB_cat(vsb, retval);
free(retval);
+ VAV_Free(argv);
return;
}
AZ(pthread_mutex_lock(¯o_mtx));
VTAILQ_FOREACH(m, ¯o_list, list) {
CHECK_OBJ_NOTNULL(m, MACRO_MAGIC);
- if (!strncmp(b, m->name, l) && m->name[l] == '\0')
+ if (!strcmp(argv[1], m->name))
break;
}
- if (m != NULL)
- REPLACE(retval, m->val);
+ if (m != NULL) {
+ if (m->func != NULL) {
+ AZ(m->val);
+ retval = m->func(argc, argv, &err);
+ if (err == NULL)
+ AN(retval);
+ } else {
+ AN(m->val);
+ if (argc == 2)
+ REPLACE(retval, m->val);
+ else
+ err = "macro does not take arguments";
+ }
+ }
AZ(pthread_mutex_unlock(¯o_mtx));
+ if (err != NULL)
+ vtc_fatal(vl, "Macro ${%.*s} failed: %s",
+ (int)(e - b), b, err);
+
if (retval == NULL) {
if (!ign_unknown_macro)
vtc_fatal(vl, "Macro ${%.*s} not found",
@@ -247,6 +285,7 @@ macro_cat(struct vtclog *vl, struct vsb *vsb, const char *b, const char *e)
VSB_cat(vsb, retval);
free(retval);
+ VAV_Free(argv);
}
struct vsb *
diff --git a/bin/varnishtest/vtc.h b/bin/varnishtest/vtc.h
index 6e6978018..55d28b351 100644
--- a/bin/varnishtest/vtc.h
+++ b/bin/varnishtest/vtc.h
@@ -139,8 +139,9 @@ struct vsb *macro_expand(struct vtclog *vl, const char *text);
struct vsb *macro_expandf(struct vtclog *vl, const char *, ...)
v_printflike_(2, 3);
-void extmacro_def(const char *name, const char *fmt, ...)
- v_printflike_(2, 3);
+typedef char* macro_f(int, char *const *, const char **);
+void extmacro_def(const char *name, macro_f *func, const char *fmt, ...)
+ v_printflike_(3, 4);
struct http;
void cmd_stream(CMD_ARGS);
diff --git a/bin/varnishtest/vtc_main.c b/bin/varnishtest/vtc_main.c
index 309bd876e..141dac1e5 100644
--- a/bin/varnishtest/vtc_main.c
+++ b/bin/varnishtest/vtc_main.c
@@ -167,7 +167,7 @@ parse_D_opt(char *arg)
if (!q)
return (0);
*q++ = '\0';
- extmacro_def(p, "%s", q);
+ extmacro_def(p, NULL, "%s", q);
return (1);
}
@@ -544,7 +544,7 @@ i_mode(void)
}
AN(topbuild);
- extmacro_def("topbuild", "%s", topbuild);
+ extmacro_def("topbuild", NULL, "%s", topbuild);
/*
* Build $PATH which can find all programs in the build tree
@@ -605,7 +605,7 @@ ip_magic(void)
}
assert(bad_backend_fd >= 0);
VTCP_myname(bad_backend_fd, abuf, sizeof abuf, pbuf, sizeof(pbuf));
- extmacro_def("localhost", "%s", abuf);
+ extmacro_def("localhost", NULL, "%s", abuf);
s = strdup(abuf);
AN(s);
@@ -620,9 +620,9 @@ ip_magic(void)
/* Expose a backend that is forever down. */
if (VSA_Get_Proto(sa) == AF_INET)
- extmacro_def("bad_backend", "%s:%s", abuf, pbuf);
+ extmacro_def("bad_backend", NULL, "%s:%s", abuf, pbuf);
else
- extmacro_def("bad_backend", "[%s]:%s", abuf, pbuf);
+ extmacro_def("bad_backend", NULL, "[%s]:%s", abuf, pbuf);
/* our default bind/listen address */
if (VSA_Get_Proto(sa) == AF_INET)
@@ -631,7 +631,7 @@ ip_magic(void)
bprintf(abuf, "[%s]:0", s);
free(s);
- extmacro_def("listen_addr", "%s", abuf);
+ extmacro_def("listen_addr", NULL, "%s", abuf);
default_listen_addr = strdup(abuf);
AN(default_listen_addr);
free(sa);
@@ -644,7 +644,7 @@ ip_magic(void)
* check your /proc/sys/net/ipv4/ip_nonlocal_bind setting.
*/
- extmacro_def("bad_ip", "%s", "192.0.2.255");
+ extmacro_def("bad_ip", NULL, "%s", "192.0.2.255");
}
/**********************************************************************
@@ -725,7 +725,7 @@ main(int argc, char * const *argv)
tmppath = strdup("/tmp");
cwd = getcwd(buf, sizeof buf);
- extmacro_def("pwd", "%s", cwd);
+ extmacro_def("pwd", NULL, "%s", cwd);
vmod_path = NULL;
More information about the varnish-commit
mailing list