[master] b317d95 Introduce VCL_STRANDS, and use it for string compare.

Poul-Henning Kamp phk at FreeBSD.org
Thu Dec 14 10:16:04 UTC 2017


commit b317d959cc797221ece4127896b305d30204f58f
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Thu Dec 14 10:12:15 2017 +0000

    Introduce VCL_STRANDS, and use it for string compare.
    
    VCL_STRANDS is an alternative to VCL_STRING_LIST which uses a
    struct instead of varargs.
    
    This means that multiple VCL_STRANDS can be passed to a function,
    and string-compare really needed that to not waste workspace.
    
    Add <, >, <=, >= string comparisons while here anyway.
    
    The struct and a const char *[N] array are built on the stack and
    they are only valid for the duration of the function call.

diff --git a/bin/varnishd/cache/cache_vrt.c b/bin/varnishd/cache/cache_vrt.c
index 3d0952f..9adc590 100644
--- a/bin/varnishd/cache/cache_vrt.c
+++ b/bin/varnishd/cache/cache_vrt.c
@@ -157,6 +157,64 @@ VRT_GetHdr(VRT_CTX, const struct gethdr_s *hs)
 }
 
 /*--------------------------------------------------------------------
+ * Build STRANDS from what is essentially a STRING_LIST
+ */
+
+VCL_STRANDS
+VRT_BundleStrands(int n, struct strands *s, char const **d, const char *f, ...)
+{
+	va_list ap;
+
+	s->n = n;
+	s->p = d;
+	*d++ = f;
+	va_start(ap, f);
+	while(--n)
+		*d++ = va_arg(ap, const char *);
+	assert(va_arg(ap, const char *) == vrt_magic_string_end);
+	va_end(ap);
+	return (s);
+}
+
+/*--------------------------------------------------------------------
+ * Compare two STRANDS
+ */
+
+int
+VRT_CompareStrands(VCL_STRANDS a, VCL_STRANDS b)
+{
+	const char *pa = NULL, *pb = NULL;
+	int na = 0, nb = 0;
+
+	while (1) {
+		if (pa != NULL && *pa == '\0')
+			pa = NULL;
+		if (pb != NULL && *pb == '\0')
+			pb = NULL;
+		if (pa == NULL && na < a->n)
+			pa = a->p[na++];
+		else if (pb == NULL && nb < b->n)
+			pb = b->p[nb++];
+		else if (pa == NULL && pb == NULL)
+			return (0);
+		else if (pa == NULL)
+			return (-1);
+		else if (pb == NULL)
+			return (1);
+		else if (*pa == '\0')
+			pa = NULL;
+		else if (*pb == '\0')
+			pb = NULL;
+		else if (*pa != *pb)
+			return (*pa - *pb);
+		else {
+			pa++;
+			pb++;
+		}
+	}
+}
+
+/*--------------------------------------------------------------------
  * Collapse a STRING_LIST in the space provided, or return NULL
  */
 
@@ -341,7 +399,7 @@ VRT_r_now(VRT_CTX)
 
 /*--------------------------------------------------------------------*/
 
-char *
+VCL_STRING v_matchproto_()
 VRT_IP_string(VRT_CTX, VCL_IP ip)
 {
 	char *p;
@@ -361,7 +419,7 @@ VRT_IP_string(VRT_CTX, VCL_IP ip)
 	return (p);
 }
 
-char *
+VCL_STRING v_matchproto_()
 VRT_INT_string(VRT_CTX, long num)
 {
 
@@ -369,7 +427,7 @@ VRT_INT_string(VRT_CTX, long num)
 	return (WS_Printf(ctx->ws, "%ld", num));
 }
 
-char *
+VCL_STRING v_matchproto_()
 VRT_REAL_string(VRT_CTX, double num)
 {
 
@@ -377,7 +435,7 @@ VRT_REAL_string(VRT_CTX, double num)
 	return (WS_Printf(ctx->ws, "%.3f", num));
 }
 
-char *
+VCL_STRING v_matchproto_()
 VRT_TIME_string(VRT_CTX, double t)
 {
 	char *p;
@@ -389,7 +447,7 @@ VRT_TIME_string(VRT_CTX, double t)
 	return (p);
 }
 
-const char * v_matchproto_()
+VCL_STRING v_matchproto_()
 VRT_BACKEND_string(VCL_BACKEND d)
 {
 	if (d == NULL)
@@ -398,7 +456,7 @@ VRT_BACKEND_string(VCL_BACKEND d)
 	return (d->vcl_name);
 }
 
-const char *
+VCL_STRING v_matchproto_()
 VRT_BOOL_string(unsigned val)
 {
 
diff --git a/bin/varnishtest/tests/a00015.vtc b/bin/varnishtest/tests/a00015.vtc
index 03caf19..843637f 100644
--- a/bin/varnishtest/tests/a00015.vtc
+++ b/bin/varnishtest/tests/a00015.vtc
@@ -12,7 +12,7 @@ server s1 {
 	txresp -hdr "Content-Type: text/plain" -body response
 } -start
 
-varnish v1 -vcl+backend {} -start
+varnish v1 -vcl+backend {} -start -cliok "param.set debug +syncvsl"
 
 client c1 {
 	txreq -req POST -hdr "Content-Type: text/plain" -body request
diff --git a/bin/varnishtest/tests/v00002.vtc b/bin/varnishtest/tests/v00002.vtc
new file mode 100644
index 0000000..48d914e
--- /dev/null
+++ b/bin/varnishtest/tests/v00002.vtc
@@ -0,0 +1,174 @@
+varnishtest "Test VCL STRINGS/STRANDS comparisons"
+
+server s1 {
+	rxreq
+	txresp
+} -start
+
+varnish v1 -vcl+backend {
+	sub vcl_deliver {
+		set resp.http.test = req.http.test;
+
+		set resp.http.eq =
+		    req.http.foo == req.http.bar;
+
+		set resp.http.neq =
+		    req.http.foo != req.http.bar;
+
+		set resp.http.lt =
+		    req.http.foo < req.http.bar;
+
+		set resp.http.le =
+		    req.http.foo <= req.http.bar;
+
+		set resp.http.gt =
+		    req.http.foo > req.http.bar;
+
+		set resp.http.ge =
+		    req.http.foo >= req.http.bar;
+	}
+} -start
+
+client c1 {
+	txreq -hdr "foo: 1" -hdr "bar: 1" -hdr "test: 1"
+	rxresp
+	expect resp.http.eq == true
+	expect resp.http.neq == false
+	expect resp.http.lt == false
+	expect resp.http.le == true
+	expect resp.http.gt == false
+	expect resp.http.ge == true
+
+	txreq -hdr "foo: 1" -hdr "bar: 2" -hdr "test: 2"
+	rxresp
+	expect resp.http.eq == false
+	expect resp.http.neq == true
+	expect resp.http.lt == true
+	expect resp.http.le == true
+	expect resp.http.gt == false
+	expect resp.http.ge == false
+
+	txreq -hdr "foo: 2" -hdr "bar: 1" -hdr "test: 3"
+	rxresp
+	expect resp.http.eq == false
+	expect resp.http.neq == true
+	expect resp.http.lt == false
+	expect resp.http.le == false
+	expect resp.http.gt == true
+	expect resp.http.ge == true
+
+	txreq -hdr "foo: 1" -hdr "bar: 11" -hdr "test: 4"
+	rxresp
+	expect resp.http.eq == false
+	expect resp.http.neq == true
+	expect resp.http.lt == true
+	expect resp.http.le == true
+	expect resp.http.gt == false
+	expect resp.http.ge == false
+
+	txreq -hdr "foo: 11" -hdr "bar: 1" -hdr "test: 5"
+	rxresp
+	expect resp.http.eq == false
+	expect resp.http.neq == true
+	expect resp.http.lt == false
+	expect resp.http.le == false
+	expect resp.http.gt == true
+	expect resp.http.ge == true
+
+	txreq -hdr "foo:" -hdr "bar:" -hdr "test: 6"
+	rxresp
+	expect resp.http.eq == true
+	expect resp.http.neq == false
+	expect resp.http.lt == false
+	expect resp.http.le == true
+	expect resp.http.gt == false
+	expect resp.http.ge == true
+
+	txreq -hdr "foo:" -hdr "bar: 1" -hdr "test: 7"
+	rxresp
+	expect resp.http.eq == false
+	expect resp.http.neq == true
+	expect resp.http.lt == true
+	expect resp.http.le == true
+	expect resp.http.gt == false
+	expect resp.http.ge == false
+
+} -run
+
+varnish v1 -vsl_catchup -vcl+backend {
+	sub vcl_deliver {
+		set resp.http.test = req.http.test;
+
+		set resp.http.eq =
+		    req.http.foo + " " == req.http.bar + " ";
+
+		set resp.http.neq =
+		    req.http.foo + " " != req.http.bar + " ";
+
+		set resp.http.lt =
+		    req.http.foo + " " < req.http.bar + " ";
+
+		set resp.http.le =
+		    req.http.foo + " " <= req.http.bar + " ";
+
+		set resp.http.gt =
+		    req.http.foo + " " > req.http.bar + " ";
+
+		set resp.http.ge =
+		    req.http.foo + " " >= req.http.bar + " ";
+	}
+}
+
+client c1 -run
+
+varnish v1 -vsl_catchup -vcl+backend {
+	sub vcl_deliver {
+		set resp.http.test = req.http.test;
+
+		set resp.http.eq =
+		    req.http.foo == req.http.bar + req.http.not;
+
+		set resp.http.neq =
+		    req.http.foo != req.http.bar + req.http.not;
+
+		set resp.http.lt =
+		    req.http.foo < req.http.bar + req.http.not;
+
+		set resp.http.le =
+		    req.http.foo <= req.http.bar + req.http.not;
+
+		set resp.http.gt =
+		    req.http.foo > req.http.bar + req.http.not;
+
+		set resp.http.ge =
+		    req.http.foo >= req.http.bar + req.http.not;
+	}
+}
+
+client c1 -run
+
+varnish v1 -vsl_catchup -vcl+backend {
+	sub vcl_deliver {
+		set resp.http.test = req.http.test;
+
+		set resp.http.eq =
+		    req.http.not + req.http.foo == req.http.bar + req.http.not;
+
+		set resp.http.neq =
+		    req.http.not + req.http.foo != req.http.bar + req.http.not;
+
+		set resp.http.lt =
+		    req.http.not + req.http.foo < req.http.bar + req.http.not;
+
+		set resp.http.le =
+		    req.http.not + req.http.foo <= req.http.bar + req.http.not;
+
+		set resp.http.gt =
+		    req.http.not + req.http.foo > req.http.bar + req.http.not;
+
+		set resp.http.ge =
+		    req.http.not + req.http.foo >= req.http.bar + req.http.not;
+	}
+}
+
+client c1 -run
diff --git a/include/vrt.h b/include/vrt.h
index 0a78bd1..12e0375 100644
--- a/include/vrt.h
+++ b/include/vrt.h
@@ -61,6 +61,7 @@
  *	VRT_r_beresp_storage_hint() removed - under discussion #2509
  *	VRT_l_beresp_storage_hint() removed - under discussion #2509
  *	VRT_blob() added
+ *	VCL_STRANDS added
  * 6.1 (2017-09-15 aka 5.2)
  *	http_CollectHdrSep added
  *	VRT_purge modified (may fail a transaction, signature changed)
@@ -114,6 +115,11 @@ struct vsb;
 struct vsl_log;
 struct ws;
 
+struct strands {
+	int		n;
+	const char	**p;
+};
+
 /***********************************************************************
  * This is the central definition of the mapping from VCL types to
  * C-types.  The python scripts read these from here.
@@ -136,6 +142,7 @@ typedef const struct suckaddr *			VCL_IP;
 typedef const struct vrt_backend_probe *	VCL_PROBE;
 typedef double					VCL_REAL;
 typedef const struct stevedore *		VCL_STEVEDORE;
+typedef const struct strands *			VCL_STRANDS;
 typedef const char *				VCL_STRING;
 typedef double					VCL_TIME;
 typedef struct vcl *				VCL_VCL;
@@ -421,14 +428,19 @@ VCL_STEVEDORE VRT_stevedore(const char *nm);
 
 /* Convert things to string */
 
-char *VRT_IP_string(VRT_CTX, VCL_IP);
-char *VRT_INT_string(VRT_CTX, VCL_INT);
-char *VRT_REAL_string(VRT_CTX, VCL_REAL);
-char *VRT_TIME_string(VRT_CTX, VCL_TIME);
-const char *VRT_BOOL_string(VCL_BOOL);
-const char *VRT_BACKEND_string(VCL_BACKEND);
-const char *VRT_STEVEDORE_string(VCL_STEVEDORE);
-const char *VRT_CollectString(VRT_CTX, const char *p, ...);
+VCL_STRANDS VRT_BundleStrands(int, struct strands *, char const **,
+    const char *f, ...);
+int VRT_CompareStrands(VCL_STRANDS a, VCL_STRANDS b);
+
+VCL_STRING VRT_BACKEND_string(VCL_BACKEND);
+VCL_STRING VRT_BOOL_string(VCL_BOOL);
+VCL_STRING VRT_CollectString(VRT_CTX, const char *p, ...);
+VCL_STRING VRT_INT_string(VRT_CTX, VCL_INT);
+VCL_STRING VRT_IP_string(VRT_CTX, VCL_IP);
+VCL_STRING VRT_REAL_string(VRT_CTX, VCL_REAL);
+VCL_STRING VRT_STEVEDORE_string(VCL_STEVEDORE);
+VCL_STRING VRT_STRANDS_string(VCL_STRANDS);
+VCL_STRING VRT_TIME_string(VRT_CTX, VCL_TIME);
 
 #ifdef va_start	// XXX: hackish
 void *VRT_VSC_Alloc(const char *, size_t, size_t, const unsigned char *, size_t,
diff --git a/lib/libvcc/vcc_expr.c b/lib/libvcc/vcc_expr.c
index 7ad4bb0..742ca21 100644
--- a/lib/libvcc/vcc_expr.c
+++ b/lib/libvcc/vcc_expr.c
@@ -129,6 +129,8 @@ vcc_delete_expr(struct expr *e)
  *	\v1  insert subexpression 1
  *	\v2  insert subexpression 2
  *	\vS  insert subexpression 1(STRINGS) as STRING
+ *	\vT  insert subexpression 1(STRINGS) as STRANDS
+ *	\vt  insert subexpression 1(STRINGS) as STRANDS
  *	\v+  increase indentation
  *	\v-  decrease indentation
  *	anything else is literal
@@ -140,10 +142,10 @@ vcc_delete_expr(struct expr *e)
  */
 
 static struct expr *
-vcc_expr_edit(vcc_type_t fmt, const char *p, struct expr *e1,
+vcc_expr_edit(struct vcc *tl, vcc_type_t fmt, const char *p, struct expr *e1,
     struct expr *e2)
 {
-	struct expr *e;
+	struct expr *e, *e3;
 	int nl = 1;
 
 	AN(e1);
@@ -161,15 +163,33 @@ vcc_expr_edit(vcc_type_t fmt, const char *p, struct expr *e1,
 		case '+': VSB_cat(e->vsb, "\v+"); break;
 		case '-': VSB_cat(e->vsb, "\v-"); break;
 		case 'S':
+		case 's':
+			e3 = (*p == 'S' ? e1 : e2);
+			AN(e3);
 			assert(e1->fmt == STRINGS);
-			if (e1->nstr > 1)
+			if (e3->nstr > 1)
 				VSB_cat(e->vsb,
 				    "\nVRT_CollectString(ctx,\v+\n");
-			VSB_cat(e->vsb, VSB_data(e1->vsb));
-			if (e1->nstr > 1)
+			VSB_cat(e->vsb, VSB_data(e3->vsb));
+			if (e3->nstr > 1)
 				VSB_cat(e->vsb,
 				    ",\nvrt_magic_string_end)\v-\n");
 			break;
+		case 'T':
+		case 't':
+			e3 = (*p == 'T' ? e1 : e2);
+			AN(e3);
+			VSB_printf(tl->curproc->prologue,
+			    "  struct strands strs_%u_a;\n"
+			    "  const char * strs_%u_s[%d];\n",
+			    tl->unique, tl->unique, e3->nstr);
+			VSB_printf(e->vsb,
+			    "\v+\nVRT_BundleStrands(%d, &strs_%u_a, strs_%u_s,"
+			    "\v+\n%s,\nvrt_magic_string_end)\v-\v-",
+			    e3->nstr, tl->unique, tl->unique,
+			VSB_data(e3->vsb));
+			tl->unique++;
+			break;
 		case '1':
 			VSB_cat(e->vsb, VSB_data(e1->vsb));
 			break;
@@ -208,7 +228,7 @@ vcc_expr_fmt(struct vsb *d, int ind, const struct expr *e1)
 	while (*p != '\0') {
 		if (*p == '\n') {
 			VSB_putc(d, '\n');
-			if (++p == '\0')
+			if (*++p == '\0')
 				break;
 			for (i = 0; i < ind; i++)
 				VSB_cat(d, " ");
@@ -241,7 +261,7 @@ vcc_expr_tostring(struct vcc *tl, struct expr **e, vcc_type_t fmt)
 	p = (*e)->fmt->tostring;
 	if (p != NULL) {
 		AN(*p);
-		*e = vcc_expr_edit(fmt, p, *e, NULL);
+		*e = vcc_expr_edit(tl, fmt, p, *e, NULL);
 		(*e)->constant = constant;
 		(*e)->nstr = 1;
 	} else {
@@ -279,11 +299,11 @@ vcc_Eval_Regsub(struct vcc *tl, struct expr **e, const struct symbol *sym,
 	ExpectErr(tl, CSTR);
 	p = vcc_regexp(tl);
 	bprintf(buf, "VRT_regsub(ctx, %d,\v+\n\v1,\n%s", all, p);
-	*e = vcc_expr_edit(STRING, buf, e2, NULL);
+	*e = vcc_expr_edit(tl, STRING, buf, e2, NULL);
 	SkipToken(tl, ',');
 	vcc_expr0(tl, &e2, STRING);
 	ERRCHK(tl);
-	*e = vcc_expr_edit(STRINGS, "\v1,\n\v2)\v-", *e, e2);
+	*e = vcc_expr_edit(tl, STRINGS, "\v1,\n\v2)\v-", *e, e2);
 	(*e)->nstr = 1;
 	SkipToken(tl, ')');
 }
@@ -545,7 +565,7 @@ vcc_func(struct vcc *tl, struct expr **e, const char *spec,
 		if (fa->result == NULL && fa->val != NULL)
 			fa->result = vcc_mk_expr(fa->type, "%s", fa->val);
 		if (fa->result != NULL)
-			e1 = vcc_expr_edit(e1->fmt, "\v1,\n\v2",
+			e1 = vcc_expr_edit(tl, e1->fmt, "\v1,\n\v2",
 			    e1, fa->result);
 		else {
 			VSB_printf(tl->sb, "Argument '%s' missing\n",
@@ -554,7 +574,7 @@ vcc_func(struct vcc *tl, struct expr **e, const char *spec,
 		}
 		free(fa);
 	}
-	*e = vcc_expr_edit(e1->fmt, "\v1\n)\v-", e1, NULL);
+	*e = vcc_expr_edit(tl, e1->fmt, "\v1\n)\v-", e1, NULL);
 	SkipToken(tl, ')');
 }
 
@@ -625,7 +645,7 @@ vcc_expr4(struct vcc *tl, struct expr **e, vcc_type_t fmt)
 		if (e2->fmt == STRINGS)
 			*e = e2;
 		else
-			*e = vcc_expr_edit(e2->fmt, "(\v1)", e2, NULL);
+			*e = vcc_expr_edit(tl, e2->fmt, "(\v1)", e2, NULL);
 		return;
 	}
 	switch (tl->t->tok) {
@@ -780,9 +800,9 @@ vcc_expr_mul(struct vcc *tl, struct expr **e, vcc_type_t fmt)
 			return;
 		}
 		if (tk->tok == '*')
-			*e = vcc_expr_edit((*e)->fmt, "(\v1*\v2)", *e, e2);
+			*e = vcc_expr_edit(tl, (*e)->fmt, "(\v1*\v2)", *e, e2);
 		else
-			*e = vcc_expr_edit((*e)->fmt, "(\v1/\v2)", *e, e2);
+			*e = vcc_expr_edit(tl, (*e)->fmt, "(\v1/\v2)", *e, e2);
 	}
 }
 
@@ -847,9 +867,9 @@ vcc_expr_add(struct vcc *tl, struct expr **e, vcc_type_t fmt)
 				break;
 
 		if (ap->op == '+') {
-			*e = vcc_expr_edit(ap->fmt, "(\v1 + \v2)", *e, e2);
+			*e = vcc_expr_edit(tl, ap->fmt, "(\v1 + \v2)", *e, e2);
 		} else if (ap->op == '-') {
-			*e = vcc_expr_edit(ap->fmt, "(\v1 - \v2)", *e, e2);
+			*e = vcc_expr_edit(tl, ap->fmt, "(\v1 - \v2)", *e, e2);
 		} else if (tk->tok == '+' &&
 		    ((*e)->fmt == STRINGS || fmt == STRINGS)) {
 			if ((*e)->fmt != STRINGS)
@@ -857,14 +877,14 @@ vcc_expr_add(struct vcc *tl, struct expr **e, vcc_type_t fmt)
 			if (e2->fmt != STRINGS)
 				vcc_expr_tostring(tl, &e2, STRINGS);
 			if (vcc_islit(*e) && vcc_isconst(e2)) {
-				*e = vcc_expr_edit(STRINGS,
+				*e = vcc_expr_edit(tl, STRINGS,
 				    "\v1\n\v2", *e, e2);
 				(*e)->constant = EXPR_CONST;
 				if (vcc_islit(e2))
 					(*e)->constant |= EXPR_STR_CONST;
 			} else {
 				n = (*e)->nstr + e2->nstr;
-				*e = vcc_expr_edit(STRINGS,
+				*e = vcc_expr_edit(tl, STRINGS,
 				    "\v1,\n\v2", *e, e2);
 				(*e)->constant = EXPR_VAR;
 				(*e)->nstr = n;
@@ -919,7 +939,7 @@ cmp_simple(struct vcc *tl, struct expr **e, const struct cmps *cp)
 		    vcc_utype((*e)->fmt), PF(tk), vcc_utype(e2->fmt));
 		vcc_ErrWhere(tl, tk);
 	} else
-		*e = vcc_expr_edit(BOOL, cp->emit, *e, e2);
+		*e = vcc_expr_edit(tl, BOOL, cp->emit, *e, e2);
 }
 
 static void v_matchproto_(cmp_f)
@@ -928,13 +948,13 @@ cmp_regexp(struct vcc *tl, struct expr **e, const struct cmps *cp)
 	char buf[128];
 	const char *re;
 
-	*e = vcc_expr_edit(STRING, "\vS", *e, NULL);
+	*e = vcc_expr_edit(tl, STRING, "\vS", *e, NULL);
 	vcc_NextToken(tl);
 	ExpectErr(tl, CSTR);
 	re = vcc_regexp(tl);
 	ERRCHK(tl);
 	bprintf(buf, "%sVRT_re_match(ctx, \v1, %s)", cp->emit, re);
-	*e = vcc_expr_edit(BOOL, buf, *e, NULL);
+	*e = vcc_expr_edit(tl, BOOL, buf, *e, NULL);
 }
 
 static void v_matchproto_(cmp_f)
@@ -949,7 +969,7 @@ cmp_acl(struct vcc *tl, struct expr **e, const struct cmps *cp)
 	vcc_NextToken(tl);
 	VCC_GlobalSymbol(sym, ACL, ACL_SYMBOL_PREFIX);
 	bprintf(buf, "%sVRT_acl_match(ctx, %s, \v1)", cp->emit, sym->rname);
-	*e = vcc_expr_edit(BOOL, buf, *e, NULL);
+	*e = vcc_expr_edit(tl, BOOL, buf, *e, NULL);
 }
 
 static void v_matchproto_(cmp_f)
@@ -957,6 +977,7 @@ cmp_string(struct vcc *tl, struct expr **e, const struct cmps *cp)
 {
 	struct expr *e2;
 	struct token *tk;
+	char buf[128];
 
 	tk = tl->t;
 	vcc_NextToken(tl);
@@ -967,10 +988,12 @@ cmp_string(struct vcc *tl, struct expr **e, const struct cmps *cp)
 		    "Comparison of different types: %s '%.*s' %s\n",
 		    vcc_utype((*e)->fmt), PF(tk), vcc_utype(e2->fmt));
 		vcc_ErrWhere(tl, tk);
+	} else if ((*e)->nstr == 1 && e2->nstr == 1) {
+		bprintf(buf, "(%s VRT_strcmp(\v1, \v2))", cp->emit);
+		*e = vcc_expr_edit(tl, BOOL, buf, *e, e2);
 	} else {
-		*e = vcc_expr_edit(STRING, "\vS", *e, NULL);
-		e2 = vcc_expr_edit(STRING, "\vS", e2, NULL);
-		*e = vcc_expr_edit(BOOL, cp->emit, *e, e2);
+		bprintf(buf, "(%s VRT_CompareStrands(\vT, \vt))", cp->emit);
+		*e = vcc_expr_edit(tl, BOOL, buf, *e, e2);
 	}
 }
 
@@ -1004,8 +1027,12 @@ static const struct cmps vcc_cmps[] = {
 	{IP,		'~',		cmp_acl, "" },
 	{IP,		T_NOMATCH,	cmp_acl, "!" },
 
-	{STRINGS,	T_EQ,		cmp_string, "!VRT_strcmp(\v1, \v2)" },
-	{STRINGS,	T_NEQ,		cmp_string, "VRT_strcmp(\v1, \v2)" },
+	{STRINGS,	T_EQ,		cmp_string, "0 =="},
+	{STRINGS,	T_NEQ,		cmp_string, "0 !="},
+	{STRINGS,	'<',		cmp_string, "0 > "},
+	{STRINGS,	'>',		cmp_string, "0 < "},
+	{STRINGS,	T_LEQ,		cmp_string, "0 >="},
+	{STRINGS,	T_GEQ,		cmp_string, "0 <="},
 
 	{STRINGS,	'~',		cmp_regexp, "" },
 	{STRINGS,	T_NOMATCH,	cmp_regexp, "!" },
@@ -1057,11 +1084,11 @@ vcc_expr_cmp(struct vcc *tl, struct expr **e, vcc_type_t fmt)
 	if (fmt != BOOL)
 		return;
 	if ((*e)->fmt == BACKEND || (*e)->fmt == INT)
-		*e = vcc_expr_edit(BOOL, "(\v1 != 0)", *e, NULL);
+		*e = vcc_expr_edit(tl, BOOL, "(\v1 != 0)", *e, NULL);
 	else if ((*e)->fmt == DURATION)
-		*e = vcc_expr_edit(BOOL, "(\v1 > 0)", *e, NULL);
+		*e = vcc_expr_edit(tl, BOOL, "(\v1 > 0)", *e, NULL);
 	else if ((*e)->fmt == STRINGS)
-		*e = vcc_expr_edit(BOOL, "(\vS != 0)", *e, NULL);
+		*e = vcc_expr_edit(tl, BOOL, "(\vS != 0)", *e, NULL);
 	else
 		INCOMPL();
 }
@@ -1093,7 +1120,7 @@ vcc_expr_not(struct vcc *tl, struct expr **e, vcc_type_t fmt)
 		VSB_printf(tl->sb, "%s.\n", vcc_utype(e2->fmt));
 		vcc_ErrWhere2(tl, tk, tl->t);
 	} else {
-		*e = vcc_expr_edit(BOOL, "!(\v1)", e2, NULL);
+		*e = vcc_expr_edit(tl, BOOL, "!(\v1)", e2, NULL);
 	}
 }
 
@@ -1114,7 +1141,7 @@ vcc_expr_cand(struct vcc *tl, struct expr **e, vcc_type_t fmt)
 	ERRCHK(tl);
 	if ((*e)->fmt != BOOL || tl->t->tok != T_CAND)
 		return;
-	*e = vcc_expr_edit(BOOL, "(\v+\n\v1", *e, NULL);
+	*e = vcc_expr_edit(tl, BOOL, "(\v+\n\v1", *e, NULL);
 	while (tl->t->tok == T_CAND) {
 		vcc_NextToken(tl);
 		tk = tl->t;
@@ -1127,9 +1154,9 @@ vcc_expr_cand(struct vcc *tl, struct expr **e, vcc_type_t fmt)
 			vcc_ErrWhere2(tl, tk, tl->t);
 			return;
 		}
-		*e = vcc_expr_edit(BOOL, "\v1\v-\n&&\v+\n\v2", *e, e2);
+		*e = vcc_expr_edit(tl, BOOL, "\v1\v-\n&&\v+\n\v2", *e, e2);
 	}
-	*e = vcc_expr_edit(BOOL, "\v1\v-\n)", *e, NULL);
+	*e = vcc_expr_edit(tl, BOOL, "\v1\v-\n)", *e, NULL);
 }
 
 /*--------------------------------------------------------------------
@@ -1149,7 +1176,7 @@ vcc_expr_cor(struct vcc *tl, struct expr **e, vcc_type_t fmt)
 	ERRCHK(tl);
 	if ((*e)->fmt != BOOL || tl->t->tok != T_COR)
 		return;
-	*e = vcc_expr_edit(BOOL, "(\v+\n\v1", *e, NULL);
+	*e = vcc_expr_edit(tl, BOOL, "(\v+\n\v1", *e, NULL);
 	while (tl->t->tok == T_COR) {
 		vcc_NextToken(tl);
 		tk = tl->t;
@@ -1162,9 +1189,9 @@ vcc_expr_cor(struct vcc *tl, struct expr **e, vcc_type_t fmt)
 			vcc_ErrWhere2(tl, tk, tl->t);
 			return;
 		}
-		*e = vcc_expr_edit(BOOL, "\v1\v-\n||\v+\n\v2", *e, e2);
+		*e = vcc_expr_edit(tl, BOOL, "\v1\v-\n||\v+\n\v2", *e, e2);
 	}
-	*e = vcc_expr_edit(BOOL, "\v1\v-\n)", *e, NULL);
+	*e = vcc_expr_edit(tl, BOOL, "\v1\v-\n)", *e, NULL);
 }
 
 /*--------------------------------------------------------------------
@@ -1191,12 +1218,15 @@ vcc_expr0(struct vcc *tl, struct expr **e, vcc_type_t fmt)
 	if ((*e)->fmt == STRINGS && fmt == STRING_LIST)
 		(*e)->fmt = STRING_LIST;
 	else if ((*e)->fmt == STRINGS && fmt == STRING)
-		*e = vcc_expr_edit(STRING, "\vS", *e, NULL);
-	else if ((*e)->fmt != STRINGS && (fmt == STRING || fmt == STRING_LIST))
+		*e = vcc_expr_edit(tl, STRING, "\vS", *e, NULL);
+	else if ((*e)->fmt == STRINGS && fmt == STRANDS) {
+		*e = vcc_expr_edit(tl, STRANDS, "\vT", (*e), NULL);
+	} else if ((*e)->fmt != STRINGS &&
+	    (fmt == STRING || fmt == STRING_LIST))
 		vcc_expr_tostring(tl, e, fmt);
 
 	if ((*e)->fmt == STRING_LIST)
-		*e = vcc_expr_edit(STRING_LIST,
+		*e = vcc_expr_edit(tl, STRING_LIST,
 		    "\v+\n\v1,\nvrt_magic_string_end\v-", *e, NULL);
 
 	if (fmt != (*e)->fmt)  {
diff --git a/lib/libvcc/vcc_types.c b/lib/libvcc/vcc_types.c
index cb446c8..dbeaacb 100644
--- a/lib/libvcc/vcc_types.c
+++ b/lib/libvcc/vcc_types.c
@@ -131,7 +131,11 @@ const struct type STEVEDORE[1] = {{
 const struct type STRING[1] = {{
 	.magic =		TYPE_MAGIC,
 	.name =			"STRING",
-	.tostring =		"",
+}};
+
+const struct type STRANDS[1] = {{
+	.magic =		TYPE_MAGIC,
+	.name =			"STRANDS",
 }};
 
 const struct type STRINGS[1] = {{


More information about the varnish-commit mailing list