[master] dccd281 Add an "ENUM" type as a possible argument to VMOD functions.

Poul-Henning Kamp phk at varnish-cache.org
Mon Jan 31 22:50:42 CET 2011


commit dccd2814066fc9c228b3e44887062c3d6c54ee2b
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Mon Jan 31 21:49:03 2011 +0000

    Add an "ENUM" type as a possible argument to VMOD functions.
    
    VCC expects an ID, and complains if it is not on the list of
    valid values.  The value is passed as a "const char *"
    
    More and better error messages from vmod.py

diff --git a/bin/varnishtest/tests/m00000.vtc b/bin/varnishtest/tests/m00000.vtc
index 7ad2054..7874836 100644
--- a/bin/varnishtest/tests/m00000.vtc
+++ b/bin/varnishtest/tests/m00000.vtc
@@ -13,6 +13,7 @@ varnish v1 -vcl+backend {
 	sub vcl_deliver {
 		set resp.http.foo = std.toupper(resp.http.foo);
 		set resp.http.bar = std.tolower(resp.http.bar);
+		set resp.http.who = std.author(phk);
 		std.log("VCL initiated log");
 		std.syslog(8 + 7, "Somebody runs varnishtest");
 	}
@@ -26,3 +27,10 @@ client c1 {
 	expect resp.http.foo == "BAR"
 	expect resp.http.bar == "foo"
 } -run
+
+varnish v1 -badvcl {
+	import std from "${topbuild}/lib/libvmod_std/.libs/libvmod_std.so.1" ;
+	sub vcl_deliver {
+		set resp.http.who = std.author(jfk);
+	}
+}
diff --git a/lib/libvcl/vcc_expr.c b/lib/libvcl/vcc_expr.c
index ff3fb48..1a5b074 100644
--- a/lib/libvcl/vcc_expr.c
+++ b/lib/libvcl/vcc_expr.c
@@ -550,6 +550,32 @@ vcc_Eval_Func(struct vcc *tl, struct expr **e, const struct symbol *sym)
 			Fh(tl, 0, "struct vmod_priv %s;\n", buf);
 			e1 = vcc_mk_expr(VOID, "&%s", buf);
 			p += strlen(p) + 1;
+		} else if (fmt == ENUM) {
+			ExpectErr(tl, ID);
+			ERRCHK(tl);
+			r = p;
+			do {
+				if (vcc_IdIs(tl->t, p))
+					break;
+				p += strlen(p) + 1;
+			} while (*p != '\0');
+			if (*p == '\0') {
+				vsb_printf(tl->sb, "Wrong enum value.");
+				vsb_printf(tl->sb, "  Expected one of:\n");
+				do {
+					vsb_printf(tl->sb, "\t%s\n", r);
+					r += strlen(r) + 1;
+				} while (*r != '\0');
+				vcc_ErrWhere(tl, tl->t);
+				return;
+			}
+			e1 = vcc_mk_expr(VOID, "\"%.*s\"", PF(tl->t));
+			while (*p != '\0')
+				p += strlen(p) + 1;
+			p++;
+			SkipToken(tl, ID);
+			if (*p != '\0')
+				SkipToken(tl, ',');
 		} else {
 			vcc_expr0(tl, &e1, fmt);
 			ERRCHK(tl);
diff --git a/lib/libvcl/vcc_types.h b/lib/libvcl/vcc_types.h
index 94399e7..aeaec90 100644
--- a/lib/libvcl/vcc_types.h
+++ b/lib/libvcl/vcc_types.h
@@ -41,4 +41,5 @@ VCC_TYPE(IP)
 VCC_TYPE(HEADER)
 VCC_TYPE(BYTES)
 VCC_TYPE(REAL)
+VCC_TYPE(ENUM)
 /*lint -restore */
diff --git a/lib/libvmod_std/vmod.py b/lib/libvmod_std/vmod.py
index f751e82..7d751cb 100755
--- a/lib/libvmod_std/vmod.py
+++ b/lib/libvmod_std/vmod.py
@@ -53,6 +53,7 @@ ctypes = {
 	'STRING_LIST':	"const char *, ...",
 	'BOOL':		"unsigned",
 	'BACKEND':	"struct director *",
+	'ENUM':		"const char *",
 	'TIME':		"double",
 	'REAL':		"double",
 	'DURATION':	"double",
@@ -73,7 +74,7 @@ tdl = ""
 plist = ""
 slist = ""
 
-def do_func(fname, rval, args):
+def do_func(fname, rval, args, vargs):
 	global pstruct
 	global pinit
 	global plist
@@ -81,27 +82,33 @@ def do_func(fname, rval, args):
 	global tdl
 	#print(fname, rval, args)
 
-	proto = ctypes[rval] + " vmod_" + fname + "(struct sess *"
-	sproto = ctypes[rval] + " td_" + modname + "_" + fname + "(struct sess *"
-	s=", "
+	# C argument list
+	cargs = "(struct sess *"
 	for i in args:
-		proto += s + ctypes[i]
-		sproto += s + ctypes[i]
-	proto += ")"
-	sproto += ")"
+		cargs += ", " + i
+	cargs += ")"
 
+	# Prototypes for vmod implementation and interface typedef
+	proto = ctypes[rval] + " vmod_" + fname + cargs
+	sproto = ctypes[rval] + " td_" + modname + "_" + fname + cargs
+
+	# append to lists of prototypes
 	plist += proto + ";\n"
 	tdl += "typedef " + sproto + ";\n"
 
+	# Append to struct members
 	pstruct += "\ttd_" + modname + "_" + fname + "\t*" + fname + ";\n"
+
+	# Append to struct initializer
 	pinit += "\tvmod_" + fname + ",\n"
 
+	# Compose the vmod spec-string
 	s = modname + '.' + fname + "\\0"
 	s += "Vmod_Func_" + modname + "." + fname + "\\0"
-	s += rval
-	for i in args:
-		s += '\\0' + i
-	slist += '\t"' + s + '\\0",\n'
+	s += rval + '\\0'
+	for i in vargs:
+		s +=  i + '\\0'
+	slist += '\t"' + s + '",\n'
 
 #######################################################################
 
@@ -115,6 +122,30 @@ def partition(string, separator):
 
 #######################################################################
 
+def is_c_name(s):
+	return None != re.match("^[a-z][a-z0-9_]*$", s)
+
+#######################################################################
+
+def parse_enum(tq):
+	assert tq[0] == '{'
+	assert tq[-1] == '}'
+	f = tq[1:-1].split(',')
+	s="ENUM\\0"
+	b=dict()
+	for i in f:
+		i = i.strip()
+		if not is_c_name(i):
+			raise Exception("Enum value '%s' is illegal" % i)
+		if i in b:
+			raise Exception("Duplicate Enum value '%s'" % i)
+		b[i] = True
+		s = s + i.strip() + '\\0'
+	s = s + '\\0'
+	return s
+
+#######################################################################
+
 f = open(specfile, "r")
 
 def nextline():
@@ -127,9 +158,6 @@ def nextline():
 		if l0 != "":
 			return l0
 
-def is_c_name(s):
-	return None != re.match("^[a-z][a-z0-9_]*$", s)
-
 while True:
 	l0 = nextline()
 	if l0 == "":
@@ -184,6 +212,7 @@ while True:
 	l = l[:-1]
 
 	args = list()
+	vargs = list()
 
 	for i in re.finditer("([A-Z_]+)\s*({[^}]+})?(,|$)", l):
 		at = i.group(1)
@@ -191,9 +220,22 @@ while True:
 		if at not in ctypes:
 			raise Exception(
 			    "Argument type '%s' not a valid type" % at)
-		args.append(at)
 
-	do_func(fname, rt_type, args)
+		args.append(ctypes[at])
+
+		if at == "ENUM":
+			if tq == None:
+				raise Exception(
+				    "Argument type '%s' needs qualifier {...}" % at)
+			at=parse_enum(tq)
+
+		elif tq != None:
+			raise Exception(
+			    "Argument type '%s' cannot be qualified with {...}" % at)
+		
+		vargs.append(at)
+
+	do_func(fname, rt_type, args, vargs)
 
 #######################################################################
 def dumps(s):
diff --git a/lib/libvmod_std/vmod.vcc b/lib/libvmod_std/vmod.vcc
index ffb99b0..b2923dc 100644
--- a/lib/libvmod_std/vmod.vcc
+++ b/lib/libvmod_std/vmod.vcc
@@ -34,3 +34,9 @@ Function REAL random(REAL, REAL)
 Function VOID log(STRING_LIST)
 Function VOID syslog(INT, STRING_LIST)
 Function STRING fileread(PRIV_CALL, STRING)
+Function STRING author(ENUM {
+	phk,
+	des,
+	kristian,
+	mithrandir
+})
diff --git a/lib/libvmod_std/vmod_std.c b/lib/libvmod_std/vmod_std.c
index c6a51ea..2807af1 100644
--- a/lib/libvmod_std/vmod_std.c
+++ b/lib/libvmod_std/vmod_std.c
@@ -161,3 +161,18 @@ vmod_syslog(struct sess *sp, int fac, const char *fmt, ...)
 	if (p != NULL)
 		syslog(fac, "%s", buf);
 }
+
+const char * __match_proto__()
+vmod_author(struct sess *sp, const char *id)
+{
+	(void)sp;
+	if (!strcmp(id, "phk"))
+		return ("Poul-Henning");
+	if (!strcmp(id, "des"))
+		return ("Dag-Erling");
+	if (!strcmp(id, "kristian"))
+		return ("Kristian");
+	if (!strcmp(id, "mithrandir"))
+		return ("Tollef");
+	WRONG("Illegal VMOD enum");
+}



More information about the varnish-commit mailing list