Commit 5f831033 authored by Dridi Boukelmoune's avatar Dridi Boukelmoune

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.

Conflicts:
	bin/varnishtest/vtc.c
	bin/varnishtest/vtc_main.c
parent 8700e538
......@@ -75,6 +75,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);
......@@ -82,10 +83,10 @@ static VTAILQ_HEAD(,macro) macro_list = VTAILQ_HEAD_INITIALIZER(macro_list);
/**********************************************************************/
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[256];
struct vsb *vsb;
VTAILQ_FOREACH(m, &macro_list, list)
if (!strcmp(name, m->name))
......@@ -98,9 +99,18 @@ macro_def_int(const char *name, const char *fmt, va_list ap)
VTAILQ_INSERT_TAIL(&macro_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 {
vsb = VSB_new_auto();
AN(vsb);
VSB_vprintf(vsb, fmt, ap);
AZ(VSB_finish(vsb));
REPLACE(m->val, VSB_data(vsb));
AN(m->val);
VSB_destroy(&vsb);
}
return (m);
}
......@@ -111,12 +121,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);
}
......@@ -132,8 +142,13 @@ init_macro(void)
struct macro *m;
/* Dump the extmacros for completeness */
VTAILQ_FOREACH(m, &macro_list, list)
vtc_log(vltop, 4, "extmacro def %s=%s", m->name, m->val);
VTAILQ_FOREACH(m, &macro_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(&macro_mtx, NULL));
}
......@@ -155,7 +170,7 @@ macro_def(struct vtclog *vl, const char *instance, const char *name,
AZ(pthread_mutex_lock(&macro_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(&macro_mtx));
......@@ -191,35 +206,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(64);
AN(retval);
VTIM_format(t, retval);
VSB_cat(vsb, retval);
free(retval);
VAV_Free(argv);
return;
}
AZ(pthread_mutex_lock(&macro_mtx));
VTAILQ_FOREACH(m, &macro_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(&macro_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",
......@@ -230,6 +271,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 *
......
......@@ -121,8 +121,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);
......
......@@ -161,7 +161,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);
}
......@@ -504,7 +504,8 @@ 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
*/
......@@ -571,7 +572,7 @@ ip_magic(void)
fd = VTCP_bind(sa, NULL);
assert(fd >= 0);
VTCP_myname(fd, abuf, sizeof abuf, pbuf, sizeof(pbuf));
extmacro_def("localhost", "%s", abuf);
extmacro_def("localhost", NULL, "%s", abuf);
#if defined (__APPLE__)
/*
......@@ -583,7 +584,7 @@ ip_magic(void)
#endif
/* Expose a backend that is forever down. */
extmacro_def("bad_backend", "%s %s", abuf, pbuf);
extmacro_def("bad_backend", NULL, "%s %s", abuf, pbuf);
/*
* We need an IP number which will not repond, ever, and that is a
......@@ -593,7 +594,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");
}
/**********************************************************************
......@@ -673,7 +674,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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment