[master] c4a12be Long overdue rename of libvcl to libvcc.
Poul-Henning Kamp
phk at varnish-cache.org
Tue Sep 17 13:14:43 CEST 2013
commit c4a12be0d42232e32be44cdf85a0545d85d2df59
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date: Tue Sep 17 11:14:04 2013 +0000
Long overdue rename of libvcl to libvcc.
diff --git a/bin/varnishd/Makefile.am b/bin/varnishd/Makefile.am
index da3480f..680deb1 100644
--- a/bin/varnishd/Makefile.am
+++ b/bin/varnishd/Makefile.am
@@ -118,7 +118,7 @@ varnishd_LDFLAGS = -export-dynamic
varnishd_LDADD = \
$(top_builddir)/lib/libvarnish/libvarnish.la \
$(top_builddir)/lib/libvarnishcompat/libvarnishcompat.la \
- $(top_builddir)/lib/libvcl/libvcl.la \
+ $(top_builddir)/lib/libvcc/libvcc.la \
$(top_builddir)/lib/libvgz/libvgz.la \
@JEMALLOC_LDADD@ \
@PCRE_LIBS@ \
diff --git a/bin/varnishd/cache/cache_backend_cfg.c b/bin/varnishd/cache/cache_backend_cfg.c
index c217845..1fdf795 100644
--- a/bin/varnishd/cache/cache_backend_cfg.c
+++ b/bin/varnishd/cache/cache_backend_cfg.c
@@ -147,7 +147,7 @@ VBE_DropRefConn(struct backend *b)
}
/*--------------------------------------------------------------------
- * See lib/libvcl/vcc_backend.c::emit_sockaddr()
+ * See lib/libvcc/vcc_backend.c::emit_sockaddr()
*/
static void
diff --git a/bin/varnishd/flint.sh b/bin/varnishd/flint.sh
index 0694b78..b616a29 100755
--- a/bin/varnishd/flint.sh
+++ b/bin/varnishd/flint.sh
@@ -23,7 +23,7 @@ flexelint \
mgt/*.c \
../../lib/libvarnish/*.c \
../../lib/libvarnishcompat/execinfo.c \
- ../../lib/libvcl/*.c \
+ ../../lib/libvcc/*.c \
../../lib/libvmod_std/*.c \
../../lib/libvmod_debug/*.c \
../../lib/libvmod_directors/*.c \
diff --git a/bin/varnishd/mgt/mgt_vcc.c b/bin/varnishd/mgt/mgt_vcc.c
index 28ac476..6701436 100644
--- a/bin/varnishd/mgt/mgt_vcc.c
+++ b/bin/varnishd/mgt/mgt_vcc.c
@@ -42,7 +42,7 @@
#include "common/params.h"
#include "mgt/mgt.h"
-#include "libvcl.h"
+#include "libvcc.h"
#include "vcl.h"
#include "vcli.h"
#include "vcli_priv.h"
diff --git a/configure.ac b/configure.ac
index 0bd07b6..0e73cf3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -580,7 +580,7 @@ AC_CONFIG_FILES([
lib/libvarnishapi/Makefile
lib/libvarnishtools/Makefile
lib/libvarnishcompat/Makefile
- lib/libvcl/Makefile
+ lib/libvcc/Makefile
lib/libvgz/Makefile
lib/libvmod_debug/Makefile
lib/libvmod_std/Makefile
diff --git a/include/Makefile.am b/include/Makefile.am
index 605a71e..5b75aca 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -42,7 +42,7 @@ nobase_noinst_HEADERS = \
compat/execinfo.h \
compat/srandomdev.h \
flopen.h \
- libvcl.h \
+ libvcc.h \
persistent.h \
vcli_common.h \
vcli_priv.h \
@@ -84,9 +84,9 @@ nobase_pkgdatainclude_HEADERS = \
vsb.h \
vsha256.h
-tbl/vrt_stv_var.h tbl/vcl_returns.h tbl/vcc_types.h vcl.h vrt_obj.h: $(top_srcdir)/lib/libvcl/generate.py $(top_srcdir)/include/vrt.h
+tbl/vrt_stv_var.h tbl/vcl_returns.h tbl/vcc_types.h vcl.h vrt_obj.h: $(top_srcdir)/lib/libvcc/generate.py $(top_srcdir)/include/vrt.h
mkdir -p tbl
- @PYTHON@ $(top_srcdir)/lib/libvcl/generate.py $(top_srcdir) $(top_builddir)
+ @PYTHON@ $(top_srcdir)/lib/libvcc/generate.py $(top_srcdir) $(top_builddir)
BUILT_SOURCES = vcs_version.h vmod_abi.h
MAINTAINERCLEANFILES = vcs_version.h
diff --git a/include/libvcc.h b/include/libvcc.h
new file mode 100644
index 0000000..5c50c34
--- /dev/null
+++ b/include/libvcc.h
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2009 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+struct vcc;
+
+struct vcc *VCC_New(void);
+void VCC_Default_VCL(struct vcc *, const char *str);
+void VCC_VCL_dir(struct vcc *, const char *str);
+void VCC_VMOD_dir(struct vcc *, const char *str);
+void VCC_Err_Unref(struct vcc *tl, unsigned u);
+void VCC_Allow_InlineC(struct vcc *tl, unsigned u);
+void VCC_Unsafe_Path(struct vcc *tl, unsigned u);
+
+char *VCC_Compile(const struct vcc *, struct vsb *sb, const char *b);
diff --git a/include/libvcl.h b/include/libvcl.h
deleted file mode 100644
index 5c50c34..0000000
--- a/include/libvcl.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2009 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
-
-struct vcc;
-
-struct vcc *VCC_New(void);
-void VCC_Default_VCL(struct vcc *, const char *str);
-void VCC_VCL_dir(struct vcc *, const char *str);
-void VCC_VMOD_dir(struct vcc *, const char *str);
-void VCC_Err_Unref(struct vcc *tl, unsigned u);
-void VCC_Allow_InlineC(struct vcc *tl, unsigned u);
-void VCC_Unsafe_Path(struct vcc *tl, unsigned u);
-
-char *VCC_Compile(const struct vcc *, struct vsb *sb, const char *b);
diff --git a/include/vrt.h b/include/vrt.h
index 203bba1..e203168 100644
--- a/include/vrt.h
+++ b/include/vrt.h
@@ -28,7 +28,7 @@
*
* Runtime support for compiled VCL programs.
*
- * XXX: When this file is changed, lib/libvcl/generate.py *MUST* be rerun.
+ * XXX: When this file is changed, lib/libvcc/generate.py *MUST* be rerun.
*/
struct req;
diff --git a/lib/Makefile.am b/lib/Makefile.am
index eb67436..c0c0e60 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -5,7 +5,7 @@ SUBDIRS = \
libvarnish \
libvarnishapi \
libvarnishtools \
- libvcl \
+ libvcc \
libvgz \
libvmod_debug \
libvmod_std \
@@ -16,7 +16,7 @@ DIST_SUBDIRS = \
libvarnish \
libvarnishapi \
libvarnishtools \
- libvcl \
+ libvcc \
libvgz \
libvmod_debug \
libvmod_std \
diff --git a/lib/libvcc/Makefile.am b/lib/libvcc/Makefile.am
new file mode 100644
index 0000000..b030dc4
--- /dev/null
+++ b/lib/libvcc/Makefile.am
@@ -0,0 +1,44 @@
+#
+
+AM_LDFLAGS = $(AM_LT_LDFLAGS)
+
+AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include
+
+pkglib_LTLIBRARIES = libvcc.la
+
+libvcc_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
+
+libvcc_la_SOURCES = \
+ vcc_compile.h \
+ vcc_token_defs.h \
+ \
+ vcc_acl.c \
+ vcc_action.c \
+ vcc_backend.c \
+ vcc_backend_util.c \
+ vcc_compile.c \
+ vcc_expr.c \
+ vcc_parse.c \
+ vcc_fixed_token.c \
+ vcc_obj.c \
+ vcc_storage.c \
+ vcc_utils.c \
+ vcc_symb.c \
+ vcc_token.c \
+ vcc_var.c \
+ vcc_vmod.c \
+ vcc_xref.c
+
+EXTRA_DIST = \
+ generate.py
+
+dist_pkgdata_SCRIPTS = \
+ vmodtool.py
+
+vcc_obj.c vcc_fixed_token.c vcc_token_defs.h: \
+ $(srcdir)/generate.py $(top_srcdir)/include/vrt.h
+ @PYTHON@ $(srcdir)/generate.py $(srcdir) $(top_builddir)
+
+CLEANFILES = $(builddir)/vcc_token_defs.h \
+ $(builddir)/vcc_fixed_token.c \
+ $(builddir)/vcc_obj.c
diff --git a/lib/libvcc/flint.lnt b/lib/libvcc/flint.lnt
new file mode 100644
index 0000000..60b3850
--- /dev/null
+++ b/lib/libvcc/flint.lnt
@@ -0,0 +1,46 @@
+-passes=3
+
+// Review all below this line
+
+-printf_code( H, void *, unsigned)
+-printf_code( ju, long long unsigned)
+-printf_code( jx, long long unsigned)
+
++libh ../../config.h
+-header(../../config.h)
+-sem(lbv_assert, r_no)
+-sem(strchr, 1p, type(1), 2n == 0 ? (@p < 1p) : (@p < 1p || @p == 0 ))
+-sem(vcc_new_source, custodial(1))
+
+-emacro((???),va_arg) // the va_arg() macro can yield 415, 416, 661, 662
+ // 796 and 797 (out-of-bounds errors).
+
+
+-emacro(413, offsetof) // likely null pointer
+
+// -ffc // No automatic custody
+
+-esym(534, vsb_printf) // Ignoring return value of function
+-esym(534, vsb_cat) // Ignoring return value of function
+-esym(534, vsb_bcat) // Ignoring return value of function
+-esym(534, vsb_vprintf) // Ignoring return value of function
+-esym(534, memset) // Ignoring return value of function
+-e788 // enum constant 'HND_Unclass' not used within defaulted switch
+-e716 // while(1) ...
+-e786 // String concatenation within initializer
+-e732 // Loss of sign (arg. no. 2) (int to unsigned int)
+
+
+-e763 // Redundant declaration for symbol '...' previously declared
+
+
+-e737 // Loss of sign in promotion from int to unsigned int
+-e534 // Ignoring return value of function
+-e506 // Constant value boolean
+-e774 // Boolean within 'if' always evaluates to False
+-e713 // Loss of precision (assignment) (unsigned long long to long long)
+-e574 // Signed-unsigned mix with relational
+-e539 // Did not expect positive indentation
+-e734 // Loss of precision (assignment) (31 bits to 8 bits)
+-e747 // Significant prototype coercion (arg. no. 2) long
+-e712 // Loss of precision (assignment) (long long to
diff --git a/lib/libvcc/flint.sh b/lib/libvcc/flint.sh
new file mode 100755
index 0000000..3bb465a
--- /dev/null
+++ b/lib/libvcc/flint.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+flexelint \
+ -I/usr/include \
+ -I. \
+ -I../.. \
+ -I../../include \
+ -I../../contrib/libevent \
+ flint.lnt \
+ *.c
diff --git a/lib/libvcc/generate.py b/lib/libvcc/generate.py
new file mode 100755
index 0000000..3f20b08
--- /dev/null
+++ b/lib/libvcc/generate.py
@@ -0,0 +1,952 @@
+#!/usr/local/bin/python3.1
+#-
+# Copyright (c) 2006 Verdens Gang AS
+# Copyright (c) 2006-2013 Varnish Software AS
+# All rights reserved.
+#
+# Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# Generate various .c and .h files for the VCL compiler and the interfaces
+# for it.
+
+#######################################################################
+# These are our tokens
+
+# We could drop all words such as "include", "if" etc, and use the
+# ID type instead, but declaring them tokens makes them reserved words
+# which hopefully makes for better error messages.
+# XXX: does it actually do that ?
+
+import sys
+
+srcroot = "../.."
+buildroot = "../.."
+if len(sys.argv) == 3:
+ srcroot = sys.argv[1]
+ buildroot = sys.argv[2]
+
+tokens = {
+ "T_INC": "++",
+ "T_DEC": "--",
+ "T_CAND": "&&",
+ "T_COR": "||",
+ "T_LEQ": "<=",
+ "T_EQ": "==",
+ "T_NEQ": "!=",
+ "T_GEQ": ">=",
+ "T_SHR": ">>",
+ "T_SHL": "<<",
+ "T_INCR": "+=",
+ "T_DECR": "-=",
+ "T_MUL": "*=",
+ "T_DIV": "/=",
+ "T_NOMATCH": "!~",
+
+ # Single char tokens, for convenience on one line
+ None: "{}()*+-/%><=;!&.|~,",
+
+ # These have handwritten recognizers
+ "ID": None,
+ "CNUM": None,
+ "CSTR": None,
+ "EOI": None,
+ "CSRC": None,
+}
+
+#######################################################################
+# Our methods and actions
+
+returns =(
+ ('recv', "C", ('error', 'pass', 'pipe', 'hash', 'purge',)),
+ ('pipe', "C", ('error', 'pipe',)),
+ ('pass', "C", ('error', 'restart', 'fetch',)),
+ ('hash', "C", ('lookup',)),
+ ('purge', "C", ('error', 'fetch',)),
+ ('miss', "C", ('error', 'restart', 'pass', 'fetch',)),
+ ('hit', "C", ('error', 'restart', 'pass', 'fetch', 'deliver',)),
+ ('backend_fetch', "B", ('fetch', 'abandon')),
+ ('backend_response', "B", ('deliver', 'retry', 'abandon')),
+ ('deliver', "C", ('restart', 'deliver',)),
+ ('error', "C", ('restart', 'deliver',)),
+ ('init', "", ('ok',)),
+ ('fini', "", ('ok',)),
+)
+
+#######################################################################
+# Variables available in sessions
+#
+# 'all' means all methods
+# 'client' means all methods tagged "C"
+# 'backend' means all methods tagged "B"
+# 'both' means all methods tagged "B" or "C"
+
+sp_variables = [
+ ('client.ip',
+ 'IP',
+ ( 'both',),
+ ( ),
+ ),
+ ('client.identity',
+ 'STRING',
+ ( 'both',),
+ ( 'both',),
+ ),
+ ('server.ip',
+ 'IP',
+ ( 'client',),
+ ( ),
+ ),
+ ('server.hostname',
+ 'STRING',
+ ( 'client',),
+ ( ),
+ ),
+ ('server.identity',
+ 'STRING',
+ ( 'client',),
+ ( ),
+ ),
+ ('server.port',
+ 'INT',
+ ( 'client',),
+ ( ),
+ ),
+ ('req.method',
+ 'STRING',
+ ( 'client',),
+ ( 'client',),
+ ),
+ ('req.request',
+ 'STRING',
+ ( 'client',),
+ ( 'client',),
+ ),
+ ('req.url',
+ 'STRING',
+ ( 'client',),
+ ( 'client',),
+ ),
+ ('req.proto',
+ 'STRING',
+ ( 'client',),
+ ( 'client',),
+ ),
+ ('req.http.',
+ 'HEADER',
+ ( 'client',),
+ ( 'client',),
+ ),
+ ('req.restarts',
+ 'INT',
+ ( 'client',),
+ ( ),
+ ),
+ ('req.esi_level',
+ 'INT',
+ ( 'client',),
+ ( ),
+ ),
+ ('req.ttl',
+ 'DURATION',
+ ( 'client',),
+ ( 'client',),
+ ),
+ ('req.grace',
+ 'DURATION',
+ ( 'client',),
+ ( 'client',),
+ ),
+ ('req.keep',
+ 'DURATION',
+ ( 'client',),
+ ( 'client',),
+ ),
+ ('req.xid',
+ 'STRING',
+ ( 'client',),
+ ( ),
+ ),
+ ('req.esi',
+ 'BOOL',
+ ( 'recv', 'backend_response', 'deliver', 'error',),
+ ( 'recv', 'backend_response', 'deliver', 'error',),
+ ),
+ ('req.can_gzip',
+ 'BOOL',
+ ( 'client',),
+ ( ),
+ ),
+ ('req.backend',
+ 'BACKEND',
+ ( 'client',),
+ ( 'client',),
+ ),
+ ('req.backend.healthy',
+ 'BOOL',
+ ( 'client',),
+ ( ),
+ ),
+ ('req.hash_ignore_busy',
+ 'BOOL',
+ ( 'recv',),
+ ( 'recv',),
+ ),
+ ('req.hash_always_miss',
+ 'BOOL',
+ ( 'recv',),
+ ( 'recv',),
+ ),
+ ('bereq.retries',
+ 'INT',
+ ( 'backend',),
+ ( ),
+ ),
+ ('bereq.backend',
+ 'BACKEND',
+ ( 'pipe', 'backend', ),
+ ( 'pipe', 'backend', ),
+ ),
+ ('bereq.backend.healthy',
+ 'BOOL',
+ ( 'pipe', 'backend', ),
+ ( ),
+ ),
+ ('bereq.method',
+ 'STRING',
+ ( 'pipe', 'backend', ),
+ ( 'pipe', 'backend', ),
+ ),
+ ('bereq.request',
+ 'STRING',
+ ( 'pipe', 'backend', ),
+ ( 'pipe', 'backend', ),
+ ),
+ ('bereq.url',
+ 'STRING',
+ ( 'pipe', 'backend', ),
+ ( 'pipe', 'backend', ),
+ ),
+ ('bereq.proto',
+ 'STRING',
+ ( 'pipe', 'backend', ),
+ ( 'pipe', 'backend', ),
+ ),
+ ('bereq.http.',
+ 'HEADER',
+ ( 'pipe', 'backend', ),
+ ( 'pipe', 'backend', ),
+ ),
+ ('bereq.uncacheable',
+ 'BOOL',
+ ( 'backend', ),
+ ( 'backend', ),
+ ),
+ ('bereq.connect_timeout',
+ 'DURATION',
+ ( 'pipe', 'backend', ),
+ ( 'pipe', 'backend', ),
+ ),
+ ('bereq.first_byte_timeout',
+ 'DURATION',
+ ( 'pipe', 'backend', ),
+ ( 'pipe', 'backend', ),
+ ),
+ ('bereq.between_bytes_timeout',
+ 'DURATION',
+ ( 'pipe', 'backend', ),
+ ( 'pipe', 'backend', ),
+ ),
+ ('beresp.proto',
+ 'STRING',
+ ( 'backend_response',),
+ ( 'backend_response',),
+ ),
+ ('beresp.status',
+ 'INT',
+ ( 'backend_response',),
+ ( 'backend_response',),
+ ),
+ ('beresp.response',
+ 'STRING',
+ ( 'backend_response',),
+ ( 'backend_response',),
+ ),
+ ('beresp.http.',
+ 'HEADER',
+ ( 'backend_response',),
+ ( 'backend_response',),
+ ),
+ ('beresp.do_esi',
+ 'BOOL',
+ ( 'backend_response',),
+ ( 'backend_response',),
+ ),
+ ('beresp.do_stream',
+ 'BOOL',
+ ( 'backend_response',),
+ ( 'backend_response',),
+ ),
+ ('beresp.do_gzip',
+ 'BOOL',
+ ( 'backend_response',),
+ ( 'backend_response',),
+ ),
+ ('beresp.do_gunzip',
+ 'BOOL',
+ ( 'backend_response',),
+ ( 'backend_response',),
+ ),
+ ('beresp.uncacheable',
+ 'BOOL',
+ ( 'backend_response',),
+ ( 'backend_response',),
+ ),
+ ('beresp.ttl',
+ 'DURATION',
+ ( 'backend_response',),
+ ( 'backend_response',),
+ ),
+ ('beresp.grace',
+ 'DURATION',
+ ( 'backend_response',),
+ ( 'backend_response',),
+ ),
+ ('beresp.keep',
+ 'DURATION',
+ ( 'backend_response',),
+ ( 'backend_response',),
+ ),
+ ('beresp.backend.name',
+ 'STRING',
+ ( 'backend_response',),
+ ( ),
+ ),
+ ('beresp.backend.ip',
+ 'IP',
+ ( 'backend_response',),
+ ( ),
+ ),
+ ('beresp.backend.port',
+ 'INT',
+ ( 'backend_response',),
+ ( ),
+ ),
+ ('beresp.storage',
+ 'STRING',
+ ( 'backend_response',),
+ ( 'backend_response',),
+ ),
+ ('obj.proto',
+ 'STRING',
+ ( 'hit', 'error',),
+ ( 'hit', 'error',),
+ ),
+ ('obj.status',
+ 'INT',
+ ( 'error',),
+ ( 'error',),
+ ),
+ ('obj.response',
+ 'STRING',
+ ( 'error',),
+ ( 'error',),
+ ),
+ ('obj.hits',
+ 'INT',
+ ( 'hit', 'deliver',),
+ ( 'hit', 'deliver',),
+ ),
+ ('obj.http.',
+ 'HEADER',
+ ( 'hit', 'error',),
+ ( 'error',), # XXX ?
+ ),
+ ('obj.ttl',
+ 'DURATION',
+ ( 'hit', 'error',),
+ ( 'hit', 'error',),
+ ),
+ ('obj.grace',
+ 'DURATION',
+ ( 'hit', 'error',),
+ ( 'hit', 'error',),
+ ),
+ ('obj.keep',
+ 'DURATION',
+ ( 'hit', 'error',),
+ ( 'hit', 'error',),
+ ),
+ ('obj.last_use',
+ 'TIME',
+ ( 'hit', 'deliver',),
+ ( 'hit', 'deliver',),
+ ),
+ ('obj.uncacheable',
+ 'BOOL',
+ ( 'hit', 'deliver', 'error',),
+ ( ),
+ ),
+ ('resp.proto',
+ 'STRING',
+ ( 'deliver',),
+ ( 'deliver',),
+ ),
+ ('resp.status',
+ 'INT',
+ ( 'deliver',),
+ ( 'deliver',),
+ ),
+ ('resp.response',
+ 'STRING',
+ ( 'deliver',),
+ ( 'deliver',),
+ ),
+ ('resp.http.',
+ 'HEADER',
+ ( 'deliver',),
+ ( 'deliver',),
+ ),
+ ('now',
+ 'TIME',
+ ( 'all',),
+ ( ),
+ ),
+]
+
+stv_variables = (
+ ('free_space', 'BYTES', "0."),
+ ('used_space', 'BYTES', "0."),
+ ('happy', 'BOOL', "0"),
+)
+
+#######################################################################
+# VCL to C type conversion
+
+vcltypes = {
+ 'STRING_LIST': "void*",
+}
+
+fi = open(srcroot + "/include/vrt.h")
+
+for i in fi:
+ j = i.split();
+ if len(j) < 3:
+ continue
+ if j[0] != "typedef":
+ continue
+ if j[-1][-1] != ";":
+ continue
+ if j[-1][:4] != "VCL_":
+ continue
+ d = " ".join(j[1:-1])
+ vcltypes[j[-1][4:-1]] = d
+fi.close()
+
+#######################################################################
+# Nothing is easily configurable below this line.
+#######################################################################
+
+import sys
+import copy
+
+#######################################################################
+# Emit a function to recognize tokens in a string
+
+def emit_vcl_fixed_token(fo, tokens):
+
+ recog = list()
+ emit = dict()
+ for i in tokens:
+ j = tokens[i]
+ if (j != None):
+ recog.append(j)
+ emit[j] = i
+
+ recog.sort()
+ rrecog = copy.copy(recog)
+ rrecog.sort(key = lambda x: -len(x))
+
+ fo.write("""
+#define M1()\tdo {*q = p + 1; return (p[0]); } while (0)
+#define M2(c,t)\tdo {if (p[1] == (c)) { *q = p + 2; return (t); }} while (0)
+
+unsigned
+vcl_fixed_token(const char *p, const char **q)
+{
+
+\tswitch (p[0]) {
+""")
+ last_initial = None
+ for i in recog:
+ if (i[0] == last_initial):
+ continue
+ last_initial = i[0]
+ fo.write("\tcase '%s':\n" % last_initial)
+ need_ret = True
+ for j in rrecog:
+ if (j[0] != last_initial):
+ continue
+ if len(j) == 2:
+ fo.write("\t\tM2('%s', %s);\n" %
+ (j[1], emit[j]))
+ elif len(j) == 1:
+ fo.write("\t\tM1();\n")
+ need_ret = False
+ else:
+ fo.write("\t\tif (")
+ k = 1
+ l = len(j)
+ while (k < l):
+ fo.write("p[%d] == '%s'" % (k, j[k]))
+ fo.write(" &&")
+ if (k % 3) == 0:
+ fo.write("\n\t\t ")
+ else:
+ fo.write(" ")
+ k += 1
+ fo.write("!isvar(p[%d])) {\n" % l)
+ fo.write("\t\t\t*q = p + %d;\n" % l)
+ fo.write("\t\t\treturn (%s);\n" % emit[j])
+ fo.write("\t\t}\n")
+ if need_ret:
+ fo.write("\t\treturn (0);\n")
+ fo.write("\tdefault:\n\t\treturn (0);\n\t}\n}\n")
+
+#######################################################################
+# Emit the vcl_tnames (token->string) conversion array
+
+def emit_vcl_tnames(fo, tokens):
+ fo.write("\nconst char * const vcl_tnames[256] = {\n")
+ l = list(tokens.keys())
+ l.sort()
+ for i in l:
+ j = tokens[i]
+ if j == None:
+ j = i
+ if i[0] == "'":
+ j = i
+ fo.write("\t[%s] = \"%s\",\n" % (i, j))
+ fo.write("};\n")
+
+#######################################################################
+# Read a C-source file and spit out code that outputs it with VSB_cat()
+
+def emit_file(fo, fn):
+ fi = open(fn)
+ fc = fi.read()
+ fi.close()
+
+ w = 66 # Width of lines, after white space prefix
+ maxlen = 10240 # Max length of string literal
+
+ x = 0
+ l = 0
+ fo.write("\n\t/* %s */\n\n" % fn)
+ for c in fc:
+ if l == 0:
+ fo.write("\tVSB_cat(sb, \"")
+ l += 12
+ x += 12
+ if x == 0:
+ fo.write("\t \"")
+ d = c
+ if c == '\n':
+ d = "\\n"
+ elif c == '\t':
+ d = "\\t"
+ elif c == '"':
+ d = "\\\""
+ elif c == '\\':
+ d = "\\\\"
+
+ if c == '\n' and x > w - 20:
+ fo.write(d + "\"\n")
+ x = 0
+ continue
+ if c.isspace() and x > w - 10:
+ fo.write(d + "\"\n")
+ x = 0
+ continue
+
+ fo.write(d)
+ x += len(d)
+ l += len(d)
+ if l > maxlen:
+ fo.write("\");\n")
+ l = 0;
+ x = 0
+ if x > w - 3:
+ fo.write("\"\n")
+ x = 0
+ if x != 0:
+ fo.write("\"")
+ if l != 0:
+ fo.write("\t);\n")
+
+#######################################################################
+
+def polish_tokens(tokens):
+ # Expand single char tokens
+ st = tokens[None]
+ del tokens[None]
+
+ for i in st:
+ tokens["'" + i + "'"] = i
+#######################################################################
+
+def file_header(fo):
+ fo.write("""/*
+ * NB: This file is machine generated, DO NOT EDIT!
+ *
+ * Edit and run generate.py instead
+ */
+""")
+
+#######################################################################
+
+polish_tokens(tokens)
+
+fo = open(buildroot + "/lib/libvcc/vcc_token_defs.h", "w")
+
+file_header(fo)
+
+j = 128
+l = list(tokens.keys())
+l.sort()
+for i in l:
+ if i[0] == "'":
+ continue
+ fo.write("#define\t%s %d\n" % (i, j))
+ j += 1
+ assert j < 256
+
+fo.close()
+
+#######################################################################
+
+rets = dict()
+vcls = list()
+vcls_client = list()
+vcls_backend = list()
+for i in returns:
+ vcls.append(i[0])
+ for j in i[1]:
+ if j == "B":
+ vcls_backend.append(i[0])
+ elif j == "C":
+ vcls_client.append(i[0])
+ for j in i[2]:
+ rets[j] = True
+
+#######################################################################
+
+fo = open(buildroot + "/include/tbl/vcl_returns.h", "w")
+
+file_header(fo)
+
+fo.write("\n/*lint -save -e525 -e539 */\n")
+
+fo.write("\n#ifdef VCL_RET_MAC\n")
+l = list(rets.keys())
+l.sort()
+for i in l:
+ fo.write("VCL_RET_MAC(%s, %s" % (i.lower(), i.upper()))
+ s=", "
+ for j in returns:
+ if i in j[2]:
+ fo.write("%sVCL_MET_%s" % (s, j[0].upper()))
+ s = " | "
+ fo.write(")\n")
+fo.write("#endif\n")
+
+fo.write("\n#ifdef VCL_MET_MAC\n")
+for i in returns:
+ fo.write("VCL_MET_MAC(%s,%s,\n" % (i[0].lower(), i[0].upper()))
+ p = " ("
+ for j in i[2]:
+ fo.write(" %s(1U << VCL_RET_%s)\n" % (p, j.upper()))
+ p = "| "
+ fo.write("))\n")
+fo.write("#endif\n")
+fo.write("\n/*lint -restore */\n")
+fo.close()
+
+#######################################################################
+
+fo = open(buildroot + "/include/vcl.h", "w")
+
+file_header(fo)
+
+fo.write("""
+struct vrt_ctx;
+struct req;
+struct busyobj;
+struct ws;
+struct cli;
+struct worker;
+
+typedef int vcl_init_f(struct cli *);
+typedef void vcl_fini_f(struct cli *);
+typedef int vcl_func_f(const struct vrt_ctx *ctx);
+""")
+
+
+fo.write("\n/* VCL Methods */\n")
+n = 0
+for i in returns:
+ fo.write("#define VCL_MET_%s\t\t(1U << %d)\n" % (i[0].upper(), n))
+ n += 1
+
+fo.write("\n#define VCL_MET_MAX\t\t%d\n" % n)
+fo.write("\n#define VCL_MET_MASK\t\t0x%x\n" % ((1 << n) - 1))
+
+
+fo.write("\n/* VCL Returns */\n")
+n = 0
+l = list(rets.keys())
+l.sort()
+for i in l:
+ fo.write("#define VCL_RET_%s\t\t%d\n" % (i.upper(), n))
+ n += 1
+
+fo.write("\n#define VCL_RET_MAX\t\t%d\n" % n)
+
+
+fo.write("""
+struct VCL_conf {
+ unsigned magic;
+#define VCL_CONF_MAGIC 0x7406c509 /* from /dev/random */
+
+ struct director **director;
+ unsigned ndirector;
+ struct vrt_ref *ref;
+ unsigned nref;
+ unsigned busy;
+ unsigned discard;
+
+ unsigned nsrc;
+ const char **srcname;
+ const char **srcbody;
+
+ vcl_init_f *init_vcl;
+ vcl_fini_f *fini_vcl;
+""")
+
+for i in returns:
+ fo.write("\tvcl_func_f\t*" + i[0] + "_func;\n")
+
+fo.write("""
+};
+""")
+
+fo.close()
+
+#######################################################################
+
+def restrict(fo, spec):
+ d = dict()
+ for j in spec:
+ if j == 'all':
+ for i in vcls:
+ d[i] = True
+ elif j == 'backend':
+ for i in vcls_backend:
+ d[i] = True
+ elif j == 'client':
+ for i in vcls_client:
+ d[i] = True
+ elif j == 'both':
+ for i in vcls_client:
+ d[i] = True
+ for i in vcls_backend:
+ d[i] = True
+ else:
+ assert j in vcls
+ d[j] = True
+ p = ""
+ n = 0
+ l = list(d.keys())
+ l.sort()
+ w = 0
+ fo.write("\t\t")
+ for j in l:
+ x = p + "VCL_MET_" + j.upper()
+ if w + len(x) > 60:
+ fo.write("\n\t\t")
+ w = 0
+ fo.write(x)
+ w += len(x)
+ p = " | "
+ if len(d) == 0:
+ fo.write("0")
+ fo.write(",\n")
+
+#######################################################################
+
+fh = open(buildroot + "/include/vrt_obj.h", "w")
+file_header(fh)
+
+fo = open(buildroot + "/lib/libvcc/vcc_obj.c", "w")
+file_header(fo)
+
+fo.write("""
+#include "config.h"
+
+#include <stdio.h>
+
+#include "vcc_compile.h"
+
+const struct var vcc_vars[] = {
+""")
+
+sp_variables.sort()
+for i in sp_variables:
+ typ = i[1]
+ cnam = i[0].replace(".", "_")
+ ctyp = vcltypes[typ]
+
+ fo.write("\t{ \"%s\", %s, %d,\n" % (i[0], typ, len(i[0])))
+
+ if len(i[2]) == 0:
+ fo.write('\t NULL,\t/* No reads allowed */\n')
+ elif typ == "HEADER":
+ fo.write('\t "HDR_')
+ fo.write(i[0].split(".")[0].upper())
+ fo.write('",\n')
+ else:
+ fo.write('\t "VRT_r_%s(ctx)",\n' % cnam)
+ fh.write(ctyp + " VRT_r_%s(const struct vrt_ctx *);\n" % cnam )
+ restrict(fo, i[2])
+
+ if len(i[3]) == 0:
+ fo.write('\t NULL,\t/* No writes allowed */\n')
+ elif typ == "HEADER":
+ fo.write('\t "HDR_')
+ fo.write(i[0].split(".")[0].upper())
+ fo.write('",\n')
+ else:
+ fo.write('\t "VRT_l_%s(ctx, ",\n' % cnam)
+ fh.write("void VRT_l_%s(const struct vrt_ctx *, " % cnam)
+ if typ != "STRING":
+ fh.write(ctyp + ");\n")
+ else:
+ fh.write(ctyp + ", ...);\n")
+ restrict(fo, i[3])
+
+ fo.write("\t},\n")
+
+fo.write("\t{ NULL }\n};\n")
+
+for i in stv_variables:
+ fh.write(vcltypes[i[1]] + " VRT_Stv_" + i[0] + "(const char *);\n")
+
+fo.close()
+fh.close()
+
+#######################################################################
+
+fo = open(buildroot + "/lib/libvcc/vcc_fixed_token.c", "w")
+
+file_header(fo)
+fo.write("""
+
+#include "config.h"
+
+#include <ctype.h>
+#include <stdio.h>
+
+#include "vcc_compile.h"
+""")
+
+emit_vcl_fixed_token(fo, tokens)
+emit_vcl_tnames(fo, tokens)
+
+fo.write("""
+void
+vcl_output_lang_h(struct vsb *sb)
+{
+""")
+
+emit_file(fo, buildroot + "/include/vcl.h")
+emit_file(fo, srcroot + "/include/vrt.h")
+emit_file(fo, buildroot + "/include/vrt_obj.h")
+
+fo.write("""
+}
+""")
+
+fo.close()
+
+#######################################################################
+ft = open(buildroot + "/include/tbl/vcc_types.h", "w")
+file_header(ft)
+
+ft.write("/*lint -save -e525 -e539 */\n")
+
+i = list(vcltypes.keys())
+i.sort()
+for j in i:
+ ft.write("VCC_TYPE(" + j + ")\n")
+ft.write("/*lint -restore */\n")
+ft.close()
+
+#######################################################################
+
+fo = open(buildroot + "/include/tbl/vrt_stv_var.h", "w")
+
+file_header(fo)
+
+fo.write("""
+#ifndef VRTSTVTYPE
+#define VRTSTVTYPE(ct)
+#define VRTSTVTYPEX
+#endif
+#ifndef VRTSTVVAR
+#define VRTSTVVAR(nm, vtype, ctype, dval)
+#define VRTSTVVARX
+#endif
+""")
+
+x=dict()
+for i in stv_variables:
+ ct = vcltypes[i[1]]
+ if not ct in x:
+ fo.write("VRTSTVTYPE(" + ct + ")\n")
+ x[ct] = 1
+ fo.write("VRTSTVVAR(" + i[0] + ",\t" + i[1] + ",\t")
+ fo.write(ct + ",\t" + i[2] + ")")
+ fo.write("\n")
+
+fo.write("""
+#ifdef VRTSTVTYPEX
+#undef VRTSTVTYPEX
+#undef VRTSTVTYPE
+#endif
+#ifdef VRTSTVVARX
+#undef VRTSTVVARX
+#undef VRTSTVVAR
+#endif
+""")
+
+fo.close
diff --git a/lib/libvcc/vcc_acl.c b/lib/libvcc/vcc_acl.c
new file mode 100644
index 0000000..fa8a7d7
--- /dev/null
+++ b/lib/libvcc/vcc_acl.c
@@ -0,0 +1,502 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2010 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <netdb.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "vcc_compile.h"
+
+#include "vrt.h"
+
+struct acl_e {
+ VTAILQ_ENTRY(acl_e) list;
+ unsigned char data[VRT_ACL_MAXADDR + 1];
+ unsigned mask;
+ unsigned not;
+ unsigned para;
+ struct token *t_addr;
+ struct token *t_mask;
+};
+
+/* Compare two acl rules for ordering */
+
+#define CMP(a, b) \
+ do { \
+ if ((a) < (b)) \
+ return (-1); \
+ else if ((b) < (a)) \
+ return (1); \
+ } while (0)
+
+static int
+vcl_acl_cmp(struct acl_e *ae1, struct acl_e *ae2)
+{
+ unsigned char *p1, *p2;
+ unsigned m;
+
+ p1 = ae1->data;
+ p2 = ae2->data;
+ m = ae1->mask;
+ if (ae2->mask < m)
+ m = ae2->mask;
+ for (; m >= 8; m -= 8) {
+ CMP(*p1, *p2);
+ p1++;
+ p2++;
+ }
+ if (m) {
+ m = 0xff00 >> m;
+ m &= 0xff;
+ CMP(*p1 & m, *p2 & m);
+ }
+ /* Long mask is less than short mask */
+ CMP(ae2->mask, ae1->mask);
+
+ return (0);
+}
+
+
+static void
+vcc_acl_add_entry(struct vcc *tl, const struct acl_e *ae, int l,
+ const unsigned char *u, int fam)
+{
+ struct acl_e *ae2, *aen;
+ int i;
+
+ if (fam == PF_INET && ae->mask > 32) {
+ VSB_printf(tl->sb,
+ "Too wide mask (%u) for IPv4 address\n", ae->mask);
+ if (ae->t_mask != NULL)
+ vcc_ErrWhere(tl, ae->t_mask);
+ else
+ vcc_ErrWhere(tl, ae->t_addr);
+ return;
+ }
+ if (fam == PF_INET6 && ae->mask > 128) {
+ VSB_printf(tl->sb,
+ "Too wide mask (%u) for IPv6 address\n", ae->mask);
+ vcc_ErrWhere(tl, ae->t_mask);
+ return;
+ }
+
+ /* Make a copy from the template */
+ aen = TlAlloc(tl, sizeof *ae2);
+ AN(aen);
+ *aen = *ae;
+
+ /* We treat family as part of address, it saves code */
+ assert(fam <= 0xff);
+ aen->data[0] = fam & 0xff;
+ aen->mask += 8;
+
+ memcpy(aen->data + 1, u, l);
+
+ VTAILQ_FOREACH(ae2, &tl->acl, list) {
+ i = vcl_acl_cmp(aen, ae2);
+ if (i == 0) {
+ /*
+ * If the two rules agree, silently ignore it
+ * XXX: is that counter intuitive ?
+ */
+ if (aen->not == ae2->not)
+ return;
+ VSB_printf(tl->sb, "Conflicting ACL entries:\n");
+ vcc_ErrWhere(tl, ae2->t_addr);
+ VSB_printf(tl->sb, "vs:\n");
+ vcc_ErrWhere(tl, aen->t_addr);
+ return;
+ }
+ /*
+ * We could eliminate pointless rules here, for instance in:
+ * "10.1.0.1";
+ * "10.1";
+ * The first rule is clearly pointless, as the second one
+ * covers it.
+ *
+ * We do not do this however, because the shmlog may
+ * be used to gather statistics.
+ */
+ if (i < 0) {
+ VTAILQ_INSERT_BEFORE(ae2, aen, list);
+ return;
+ }
+ }
+ VTAILQ_INSERT_TAIL(&tl->acl, aen, list);
+}
+
+static void
+vcc_acl_try_getaddrinfo(struct vcc *tl, struct acl_e *ae)
+{
+ struct addrinfo *res0, *res, hint;
+ struct sockaddr_in *sin4;
+ struct sockaddr_in6 *sin6;
+ unsigned char *u, i4, i6;
+ int error;
+
+ memset(&hint, 0, sizeof hint);
+ hint.ai_family = PF_UNSPEC;
+ hint.ai_socktype = SOCK_STREAM;
+ error = getaddrinfo(ae->t_addr->dec, "0", &hint, &res0);
+ if (error) {
+ if (ae->para) {
+ VSB_printf(tl->sb,
+ "Warning: %s ignored\n -- %s\n",
+ ae->t_addr->dec, gai_strerror(error));
+ Fh(tl, 1, "/* Ignored ACL entry: %s%s",
+ ae->para ? "\"(\" " : "", ae->not ? "\"!\" " : "");
+ EncToken(tl->fh, ae->t_addr);
+ if (ae->t_mask)
+ Fh(tl, 0, "/%u", ae->mask);
+ Fh(tl, 0, "%s\n", ae->para ? " \")\"" : "");
+ Fh(tl, 1, " * getaddrinfo: %s */\n",
+ gai_strerror(error));
+ } else {
+ VSB_printf(tl->sb,
+ "DNS lookup(%s): %s\n",
+ ae->t_addr->dec, gai_strerror(error));
+ vcc_ErrWhere(tl, ae->t_addr);
+ }
+ return;
+ }
+
+ i4 = i6 = 0;
+ for(res = res0; res != NULL; res = res->ai_next) {
+ switch(res->ai_family) {
+ case PF_INET:
+ assert(PF_INET < 256);
+ sin4 = (void*)res->ai_addr;
+ assert(sizeof(sin4->sin_addr) == 4);
+ u = (void*)&sin4->sin_addr;
+ if (ae->t_mask == NULL)
+ ae->mask = 32;
+ i4++;
+ vcc_acl_add_entry(tl, ae, 4, u, res->ai_family);
+ break;
+ case PF_INET6:
+ assert(PF_INET6 < 256);
+ sin6 = (void*)res->ai_addr;
+ assert(sizeof(sin6->sin6_addr) == 16);
+ u = (void*)&sin6->sin6_addr;
+ if (ae->t_mask == NULL)
+ ae->mask = 128;
+ i6++;
+ vcc_acl_add_entry(tl, ae, 16, u, res->ai_family);
+ break;
+ default:
+ VSB_printf(tl->sb,
+ "Ignoring unknown protocol family (%d) for %.*s\n",
+ res->ai_family, PF(ae->t_addr));
+ continue;
+ }
+ ERRCHK(tl);
+ }
+ freeaddrinfo(res0);
+
+ if (ae->t_mask != NULL && i4 > 0 && i6 > 0) {
+ VSB_printf(tl->sb,
+ "Mask (%u) specified, but string resolves to"
+ " both IPv4 and IPv6 addresses.\n", ae->mask);
+ vcc_ErrWhere(tl, ae->t_mask);
+ return;
+ }
+}
+
+/*--------------------------------------------------------------------
+ * Ancient stupidity on the part of X/Open and other standards orgs
+ * dictate that "192.168" be translated to 192.0.0.168. Ever since
+ * CIDR happened, "192.168/16" notation has been used, but appearantly
+ * no API supports parsing this, so roll our own.
+ */
+
+static int
+vcc_acl_try_netnotation(struct vcc *tl, struct acl_e *ae)
+{
+ unsigned char b[4];
+ int i, j, k;
+ unsigned u;
+ const char *p;
+
+ memset(b, 0, sizeof b);
+ p = ae->t_addr->dec;
+ for (i = 0; i < 4; i++) {
+ j = sscanf(p, "%u%n", &u, &k);
+ if (j != 1)
+ return (0);
+ if (u & ~0xff)
+ return (0);
+ b[i] = (unsigned char)u;
+ if (p[k] == '\0')
+ break;
+ if (p[k] != '.')
+ return (0);
+ p += k + 1;
+ }
+ if (ae->t_mask == NULL)
+ ae->mask = 8 + 8 * i;
+ vcc_acl_add_entry(tl, ae, 4, b, AF_INET);
+ return (1);
+}
+
+static void
+vcc_acl_entry(struct vcc *tl)
+{
+ struct acl_e *ae;
+
+ ae = TlAlloc(tl, sizeof *ae);
+ AN(ae);
+
+ if (tl->t->tok == '!') {
+ ae->not = 1;
+ vcc_NextToken(tl);
+ }
+
+ if (tl->t->tok == '(') {
+ ae->para = 1;
+ vcc_NextToken(tl);
+ }
+
+ if (!ae->not && tl->t->tok == '!') {
+ ae->not = 1;
+ vcc_NextToken(tl);
+ }
+
+ ExpectErr(tl, CSTR);
+ ae->t_addr = tl->t;
+ vcc_NextToken(tl);
+
+ if (tl->t->tok == '/') {
+ vcc_NextToken(tl);
+ ae->t_mask = tl->t;
+ ExpectErr(tl, CNUM);
+ ae->mask = vcc_UintVal(tl);
+ }
+
+ if (ae->para)
+ SkipToken(tl, ')');
+
+ if (!vcc_acl_try_netnotation(tl, ae)) {
+ ERRCHK(tl);
+ vcc_acl_try_getaddrinfo(tl, ae);
+ }
+ ERRCHK(tl);
+}
+
+/*********************************************************************
+ * Emit a function to match the ACL we have collected
+ */
+
+/*
+ * XXX: this is semi-silly. We try really hard to not depend in the
+ * XXX: systems include files while compiling VCL, but we need to know
+ * XXX: the size of the sa_familiy member.
+ * XXX: FlexeLint complains about these antics, so isolate it in a
+ * XXX: separate function.
+ */
+
+/*lint -save -e506 -e774 -e550 */
+static void
+c_is_a_silly_language(const struct vcc *tl)
+{
+ struct sockaddr sa;
+
+ assert(sizeof (unsigned char) == 1);
+ assert(sizeof (unsigned short) == 2);
+ assert(sizeof (unsigned int) == 4);
+ if (sizeof sa.sa_family == 1)
+ Fh(tl, 0, "\tunsigned char fam;\n");
+ else if (sizeof sa.sa_family == 2)
+ Fh(tl, 0, "\tunsigned short fam;\n");
+ else if (sizeof sa.sa_family == 4)
+ Fh(tl, 0, "\tunsigned int fam;\n");
+ else
+ assert(0 == __LINE__);
+}
+/*lint -restore */
+
+static void
+vcc_acl_emit(const struct vcc *tl, const char *acln, int anon)
+{
+ struct acl_e *ae;
+ int depth, l, m, i;
+ unsigned at[VRT_ACL_MAXADDR + 1];
+ const char *oc;
+
+ Fh(tl, 0, "\nstatic int\n");
+ Fh(tl, 0, "match_acl_%s_%s(const struct vrt_ctx *ctx, const void *p)\n",
+ anon ? "anon" : "named", acln);
+ Fh(tl, 0, "{\n");
+ Fh(tl, 0, "\tconst unsigned char *a;\n");
+ c_is_a_silly_language(tl);
+
+ Fh(tl, 0, "\n");
+ Fh(tl, 0, "\ta = p;\n");
+ Fh(tl, 0, "\tVRT_memmove(&fam, a + %zd, sizeof fam);\n",
+ offsetof(struct sockaddr, sa_family));
+ Fh(tl, 0, "\tif (fam == %d)\n", PF_INET);
+ Fh(tl, 0, "\t\ta += %zd;\n", offsetof(struct sockaddr_in, sin_addr));
+ Fh(tl, 0, "\telse if (fam == %d)\n", PF_INET6);
+ Fh(tl, 0, "\t\ta += %zd;\n", offsetof(struct sockaddr_in6, sin6_addr));
+ Fh(tl, 0, "\telse {\n");
+ Fh(tl, 0, "\t\tVRT_acl_log(ctx, \"NO_FAM %s\");\n", acln);
+ Fh(tl, 0, "\t\treturn(0);\n");
+ Fh(tl, 0, "\t}\n\n");
+ depth = -1;
+ oc = 0;
+ at[0] = 256;
+ VTAILQ_FOREACH(ae, &tl->acl, list) {
+
+ /* Find how much common prefix we have */
+ for (l = 0; l <= depth && l * 8 < ae->mask - 7; l++) {
+ assert(l >= 0);
+ if (ae->data[l] != at[l])
+ break;
+ }
+
+ /* Back down, if necessary */
+ oc = "";
+ while (l <= depth) {
+ Fh(tl, 0, "\t%*s}\n", -depth, "");
+ depth--;
+ }
+
+ m = ae->mask;
+ m -= l * 8;
+ assert(m >= 0);
+
+ /* Do whole byte compares */
+ for (i = l; m >= 8; m -= 8, i++) {
+ if (i == 0)
+ Fh(tl, 0, "\t%*s%sif (fam == %d) {\n",
+ -i, "", oc, ae->data[i]);
+ else
+ Fh(tl, 0, "\t%*s%sif (a[%d] == %d) {\n",
+ -i, "", oc, i - 1, ae->data[i]);
+ at[i] = ae->data[i];
+ depth = i;
+ oc = "";
+ }
+
+ if (m > 0) {
+ /* Do fractional byte compares */
+ Fh(tl, 0, "\t%*s%sif ((a[%d] & 0x%x) == %d) {\n",
+ -i, "", oc, i - 1, (0xff00 >> m) & 0xff,
+ ae->data[i] & ((0xff00 >> m) & 0xff));
+ at[i] = 256;
+ depth = i;
+ oc = "";
+ }
+
+ i = (ae->mask + 7) / 8;
+
+ if (!anon) {
+ Fh(tl, 0, "\t%*sVRT_acl_log(ctx, \"%sMATCH %s \" ",
+ -i, "", ae->not ? "NEG_" : "", acln);
+ EncToken(tl->fh, ae->t_addr);
+ if (ae->t_mask != NULL)
+ Fh(tl, 0, " \"/%.*s\" ", PF(ae->t_mask));
+ Fh(tl, 0, ");\n");
+ }
+
+ Fh(tl, 0, "\t%*sreturn (%d);\n", -i, "", ae->not ? 0 : 1);
+ }
+
+ /* Unwind */
+ for (; 0 <= depth; depth--)
+ Fh(tl, 0, "\t%*.*s}\n", depth, depth, "");
+
+ /* Deny by default */
+ if (!anon)
+ Fh(tl, 0, "\tVRT_acl_log(ctx, \"NO_MATCH %s\");\n", acln);
+ Fh(tl, 0, "\treturn (0);\n}\n");
+}
+
+void
+vcc_Acl_Hack(struct vcc *tl, char *b)
+{
+ char acln[32];
+ unsigned tcond;
+
+ VTAILQ_INIT(&tl->acl);
+ tcond = tl->t->tok;
+ vcc_NextToken(tl);
+ bprintf(acln, "%u", tl->unique++);
+ vcc_acl_entry(tl);
+ vcc_acl_emit(tl, acln, 1);
+ sprintf(b, "%smatch_acl_anon_%s(ctx, \v1)",
+ (tcond == T_NEQ ? "!" : ""), acln);
+}
+
+void
+vcc_Acl(struct vcc *tl)
+{
+ struct token *an;
+ int i;
+ char acln[1024];
+
+ vcc_NextToken(tl);
+ VTAILQ_INIT(&tl->acl);
+
+ ExpectErr(tl, ID);
+ if (!vcc_isCid(tl->t)) {
+ VSB_printf(tl->sb,
+ "Names of VCL acl's cannot contain '-'\n");
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+ an = tl->t;
+ vcc_NextToken(tl);
+
+ i = vcc_AddDef(tl, an, SYM_ACL);
+ if (i > 1) {
+ VSB_printf(tl->sb, "ACL %.*s redefined\n", PF(an));
+ vcc_ErrWhere(tl, an);
+ return;
+ }
+ bprintf(acln, "%.*s", PF(an));
+
+ SkipToken(tl, '{');
+
+ while (tl->t->tok != '}') {
+ vcc_acl_entry(tl);
+ ERRCHK(tl);
+ SkipToken(tl, ';');
+ }
+ SkipToken(tl, '}');
+
+ vcc_acl_emit(tl, acln, 0);
+}
diff --git a/lib/libvcc/vcc_action.c b/lib/libvcc/vcc_action.c
new file mode 100644
index 0000000..4e441d2
--- /dev/null
+++ b/lib/libvcc/vcc_action.c
@@ -0,0 +1,445 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2013 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file parses the real action of the VCL code, the procedure
+ * statements which do the actual work.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "vcc_compile.h"
+
+/*--------------------------------------------------------------------*/
+
+static void
+parse_call(struct vcc *tl)
+{
+
+ vcc_NextToken(tl);
+ ExpectErr(tl, ID);
+ vcc_AddCall(tl, tl->t);
+ vcc_AddRef(tl, tl->t, SYM_SUB);
+ Fb(tl, 1, "if (VGC_function_%.*s(ctx))\n", PF(tl->t));
+ Fb(tl, 1, "\treturn (1);\n");
+ vcc_NextToken(tl);
+ return;
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+parse_error(struct vcc *tl)
+{
+
+ VSB_printf(tl->sb,
+ "Syntax has changed, use:\n"
+ "\treturn(error(999));\n"
+ "or\n"
+ "\treturn(error(999, \"Response text\"));\n");
+ vcc_ErrWhere(tl, tl->t);
+ return;
+}
+
+/*--------------------------------------------------------------------*/
+
+static const struct arith {
+ enum var_type type;
+ unsigned oper;
+ enum var_type want;
+} arith[] = {
+ { INT, T_INCR, INT },
+ { INT, T_DECR, INT },
+ { INT, T_MUL, INT },
+ { INT, T_DIV, INT },
+ { INT, '=', INT },
+ { INT, 0, INT },
+ { TIME, T_INCR, DURATION },
+ { TIME, T_DECR, DURATION },
+ { TIME, T_MUL, REAL },
+ { TIME, T_DIV, REAL },
+ { TIME, '=', TIME },
+ { TIME, 0, TIME },
+ { DURATION, T_INCR, DURATION },
+ { DURATION, T_DECR, DURATION },
+ { DURATION, T_MUL, REAL },
+ { DURATION, T_DIV, REAL },
+ { DURATION, '=', DURATION },
+ { DURATION, 0, DURATION },
+ { VOID, '=', VOID }
+};
+
+static void
+parse_set(struct vcc *tl)
+{
+ const struct var *vp;
+ const struct arith *ap;
+ enum var_type fmt;
+
+ vcc_NextToken(tl);
+ ExpectErr(tl, ID);
+ vp = vcc_FindVar(tl, tl->t, 1, "cannot be set");
+ ERRCHK(tl);
+ assert(vp != NULL);
+ Fb(tl, 1, "%s\n", vp->lname);
+ tl->indent += INDENT;
+ vcc_NextToken(tl);
+ fmt = vp->fmt;
+ for (ap = arith; ap->type != VOID; ap++) {
+ if (ap->type != fmt)
+ continue;
+ if (ap->oper != tl->t->tok)
+ continue;
+ if (ap->oper != '=')
+ Fb(tl, 1, "%s %c ", vp->rname, *tl->t->b);
+ vcc_NextToken(tl);
+ fmt = ap->want;
+ break;
+ }
+ if (ap->type == VOID)
+ SkipToken(tl, ap->oper);
+ if (fmt == HEADER) {
+ vcc_Expr(tl, STRING_LIST);
+ } else if (fmt == STRING) {
+ vcc_Expr(tl, STRING_LIST);
+ } else {
+ vcc_Expr(tl, fmt);
+ }
+ tl->indent -= INDENT;
+ Fb(tl, 1, ");\n");
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+parse_unset(struct vcc *tl)
+{
+ const struct var *vp;
+
+ /* XXX: Wrong, should use VCC_Expr(HEADER) */
+ vcc_NextToken(tl);
+ ExpectErr(tl, ID);
+ vp = vcc_FindVar(tl, tl->t, 1, "cannot be unset");
+ ERRCHK(tl);
+ assert(vp != NULL);
+ if (vp->fmt != HEADER) {
+ VSB_printf(tl->sb,
+ "Only http header variables can be unset.\n");
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+ ERRCHK(tl);
+ Fb(tl, 1, "%svrt_magic_string_unset);\n", vp->lname);
+ vcc_NextToken(tl);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+parse_new(struct vcc *tl)
+{
+ struct symbol *sy1, *sy2, *sy3;
+ const char *p, *s_obj, *s_init, *s_struct, *s_fini;
+ char buf1[128];
+ char buf2[128];
+
+ vcc_NextToken(tl);
+ ExpectErr(tl, ID);
+ if (!vcc_isCid(tl->t)) {
+ VSB_printf(tl->sb,
+ "Names of VCL objects cannot contain '-'\n");
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+ sy1 = VCC_FindSymbol(tl, tl->t, SYM_NONE);
+ XXXAZ(sy1);
+
+ sy1 = VCC_AddSymbolTok(tl, tl->t, SYM_NONE); // XXX: NONE ?
+ XXXAN(sy1);
+ vcc_NextToken(tl);
+
+ ExpectErr(tl, '=');
+ vcc_NextToken(tl);
+
+ ExpectErr(tl, ID);
+ sy2 = VCC_FindSymbol(tl, tl->t, SYM_OBJECT);
+ XXXAN(sy2);
+
+ /*lint -save -e448 */
+ /* Split the first three args */
+ p = sy2->args;
+ s_obj = p;
+ p += strlen(p) + 1;
+ s_init = p;
+ while (p[0] != '\0' || p[1] != '\0')
+ p++;
+ p += 2;
+ s_struct = p;
+ p += strlen(p) + 1;
+ s_fini = p + strlen(p) + 1;
+ while (p[0] != '\0' || p[1] != '\0')
+ p++;
+ p += 2;
+
+ Fh(tl, 0, "static %s *%s;\n\n", s_struct, sy1->name);
+
+ vcc_NextToken(tl);
+
+ bprintf(buf1, ", &%s, \"%s\"", sy1->name, sy1->name);
+ vcc_Eval_Func(tl, s_init, buf1, "ASDF", s_init + strlen(s_init) + 1);
+ Fd(tl, 0, "\t%s(&%s);\n", s_fini, sy1->name);
+ ExpectErr(tl, ';');
+
+ bprintf(buf1, ", %s", sy1->name);
+ /* Split the methods from the args */
+ while (*p != '\0') {
+ p += strlen(s_obj);
+ bprintf(buf2, "%s%s", sy1->name, p);
+ sy3 = VCC_AddSymbolStr(tl, buf2, SYM_FUNC);
+ AN(sy3);
+ sy3->eval = vcc_Eval_SymFunc;
+ p += strlen(p) + 1;
+ sy3->cfunc = p;
+ p += strlen(p) + 1;
+
+ /* Functions which return VOID are procedures */
+ if (!memcmp(p, "VOID\0", 5))
+ sy3->kind = SYM_PROC;
+
+ sy3->args = p;
+ sy3->extra = TlDup(tl, buf1);
+ while (p[0] != '\0' || p[1] != '\0') {
+ if (!memcmp(p, "ENUM\0", 5)) {
+ /* XXX: Special case for ENUM that has
+ it's own \0\0 end marker. Not exactly
+ elegant, we should consider
+ alternatives here. Maybe runlength
+ encode the entire block? */
+ p += strlen(p) + 1;
+ while (p[0] != '\0' || p[1] != '\0')
+ p++;
+ }
+ p++;
+ }
+ p += 2;
+ }
+ /*lint -restore */
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+parse_ban(struct vcc *tl)
+{
+
+ vcc_NextToken(tl);
+
+ ExpectErr(tl, '(');
+ vcc_NextToken(tl);
+
+ Fb(tl, 1, "VRT_ban_string(\n");
+ tl->indent += INDENT;
+ vcc_Expr(tl, STRING);
+ tl->indent -= INDENT;
+ ERRCHK(tl);
+ Fb(tl, 1, ");\n");
+
+ ExpectErr(tl, ')');
+ vcc_NextToken(tl);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+parse_hash_data(struct vcc *tl)
+{
+ vcc_NextToken(tl);
+ SkipToken(tl, '(');
+
+ Fb(tl, 1, "VRT_hashdata(ctx, ");
+ vcc_Expr(tl, STRING_LIST);
+ ERRCHK(tl);
+ Fb(tl, 0, ");\n");
+ SkipToken(tl, ')');
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+parse_return(struct vcc *tl)
+{
+ int retval = 0;
+
+ vcc_NextToken(tl);
+ ExpectErr(tl, '(');
+ vcc_NextToken(tl);
+ ExpectErr(tl, ID);
+
+ /* 'error' gets special handling, to allow optional status/response */
+ if (vcc_IdIs(tl->t, "error")) {
+ vcc_NextToken(tl);
+ if (tl->t->tok == ')') {
+ VSB_printf(tl->sb,
+ "Syntax has changed, use:\n"
+ "\treturn(error(999));\n"
+ "or\n"
+ "\treturn(error(999, \"Response text\"));\n");
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+ ExpectErr(tl, '(');
+ vcc_NextToken(tl);
+ Fb(tl, 1, "VRT_error(ctx,\n");
+ tl->indent += INDENT;
+ vcc_Expr(tl, INT);
+ ERRCHK(tl);
+ Fb(tl, 1, ",\n");
+ if (tl->t->tok == ',') {
+ vcc_NextToken(tl);
+ vcc_Expr(tl, STRING);
+ ERRCHK(tl);
+ } else {
+ Fb(tl, 1, "(const char*)0\n");
+ }
+ tl->indent -= INDENT;
+ ExpectErr(tl, ')');
+ vcc_NextToken(tl);
+ Fb(tl, 1, ");\n");
+ Fb(tl, 1, "VRT_handling(ctx, VCL_RET_ERROR);\n");
+ Fb(tl, 1, "return (1);\n");
+ vcc_ProcAction(tl->curproc, VCL_RET_ERROR, tl->t);
+ ExpectErr(tl, ')');
+ vcc_NextToken(tl);
+ return;
+ }
+
+#define VCL_RET_MAC(l, U, B) \
+ do { \
+ if (vcc_IdIs(tl->t, #l)) { \
+ Fb(tl, 1, "VRT_handling(ctx, VCL_RET_" #U ");\n"); \
+ Fb(tl, 1, "return (1);\n"); \
+ vcc_ProcAction(tl->curproc, VCL_RET_##U, tl->t);\
+ retval = 1; \
+ } \
+ } while (0);
+#include "tbl/vcl_returns.h"
+#undef VCL_RET_MAC
+ if (!retval) {
+ VSB_printf(tl->sb, "Expected return action name.\n");
+ vcc_ErrWhere(tl, tl->t);
+ ERRCHK(tl);
+ }
+ vcc_NextToken(tl);
+ ExpectErr(tl, ')');
+ vcc_NextToken(tl);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+parse_rollback(struct vcc *tl)
+{
+
+ vcc_NextToken(tl);
+ Fb(tl, 1, "VRT_Rollback(ctx);\n");
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+parse_purge(struct vcc *tl)
+{
+
+ vcc_NextToken(tl);
+ Fb(tl, 1, "VRT_purge(ctx, 0, 0);\n");
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+parse_synthetic(struct vcc *tl)
+{
+ vcc_NextToken(tl);
+
+ Fb(tl, 1, "VRT_synth_page(ctx, 0, ");
+ vcc_Expr(tl, STRING_LIST);
+ ERRCHK(tl);
+ Fb(tl, 0, ");\n");
+}
+
+/*--------------------------------------------------------------------*/
+
+typedef void action_f(struct vcc *tl);
+
+static struct action_table {
+ const char *name;
+ action_f *func;
+ unsigned bitmask;
+} action_table[] = {
+ /* Keep list sorted from here */
+ { "ban", parse_ban },
+ { "call", parse_call },
+ { "error", parse_error },
+ { "hash_data", parse_hash_data, VCL_MET_HASH },
+ { "new", parse_new, VCL_MET_INIT},
+ { "purge", parse_purge, VCL_MET_MISS | VCL_MET_HIT },
+ { "remove", parse_unset }, /* backward compatibility */
+ { "return", parse_return },
+ { "rollback", parse_rollback },
+ { "set", parse_set },
+ { "synthetic", parse_synthetic, VCL_MET_ERROR },
+ { "unset", parse_unset },
+ { NULL, NULL }
+};
+
+int
+vcc_ParseAction(struct vcc *tl)
+{
+ struct token *at;
+ struct action_table *atp;
+ const struct symbol *sym;
+
+ at = tl->t;
+ assert(at->tok == ID);
+ for(atp = action_table; atp->name != NULL; atp++) {
+ if (vcc_IdIs(at, atp->name)) {
+ if (atp->bitmask != 0)
+ vcc_AddUses(tl, at, atp->bitmask,
+ "not a valid action");
+ atp->func(tl);
+ return (1);
+ }
+ }
+ sym = VCC_FindSymbol(tl, tl->t, SYM_NONE);
+ if (sym != NULL && sym->kind == SYM_PROC) {
+ vcc_Expr_Call(tl, sym);
+ return (1);
+ }
+ return (0);
+}
diff --git a/lib/libvcc/vcc_backend.c b/lib/libvcc/vcc_backend.c
new file mode 100644
index 0000000..b548d94
--- /dev/null
+++ b/lib/libvcc/vcc_backend.c
@@ -0,0 +1,484 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2013 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "vcc_compile.h"
+
+#include "vss.h"
+
+/*--------------------------------------------------------------------
+ * Struct sockaddr is not really designed to be a compile time
+ * initialized data structure, so we encode it as a byte-string
+ * and put it in an official sockaddr when we load the VCL.
+ */
+
+static void
+Emit_Sockaddr(struct vcc *tl, const struct token *t_host, const char *port)
+{
+ const char *ipv4, *ipv4a, *ipv6, *ipv6a, *pa;
+ const char *err;
+ char *hop, *pop;
+
+ AN(t_host->dec);
+
+ err = VSS_parse(t_host->dec, &hop, &pop);
+ if (err != NULL) {
+ VSB_printf(tl->sb,
+ "Backend host '%.*s': %s\n", PF(t_host), err);
+ vcc_ErrWhere(tl, t_host);
+ return;
+ }
+ Resolve_Sockaddr(tl,
+ hop != NULL ? hop : t_host->dec,
+ pop != NULL ? pop : port,
+ &ipv4, &ipv4a, &ipv6, &ipv6a, &pa, 2, t_host, "Backend host");
+ ERRCHK(tl);
+ if (ipv4 != NULL) {
+ Fb(tl, 0, "\t.ipv4_sockaddr = %s,\n", ipv4);
+ Fb(tl, 0, "\t.ipv4_addr = \"%s\",\n", ipv4a);
+ }
+ if (ipv6 != NULL) {
+ Fb(tl, 0, "\t.ipv6_sockaddr = %s,\n", ipv6);
+ Fb(tl, 0, "\t.ipv6_addr = \"%s\",\n", ipv6a);
+ }
+ Fb(tl, 0, "\t.port = \"%s\",\n", pa);
+}
+
+/*--------------------------------------------------------------------
+ * Parse a backend probe specification
+ */
+
+static void
+vcc_ProbeRedef(struct vcc *tl, struct token **t_did,
+ struct token *t_field)
+{
+ /* .url and .request are mutually exclusive */
+
+ if (*t_did != NULL) {
+ VSB_printf(tl->sb, "Probe request redefinition at:\n");
+ vcc_ErrWhere(tl, t_field);
+ VSB_printf(tl->sb, "Previous definition:\n");
+ vcc_ErrWhere(tl, *t_did);
+ return;
+ }
+ *t_did = t_field;
+}
+
+static void
+vcc_ParseProbeSpec(struct vcc *tl)
+{
+ struct fld_spec *fs;
+ struct token *t_field;
+ struct token *t_did = NULL, *t_window = NULL, *t_threshold = NULL;
+ struct token *t_initial = NULL;
+ unsigned window, threshold, initial, status;
+ double t;
+
+ fs = vcc_FldSpec(tl,
+ "?url",
+ "?request",
+ "?expected_response",
+ "?timeout",
+ "?interval",
+ "?window",
+ "?threshold",
+ "?initial",
+ NULL);
+
+ SkipToken(tl, '{');
+
+ window = 0;
+ threshold = 0;
+ initial = 0;
+ status = 0;
+ Fh(tl, 0, "static const struct vrt_backend_probe vgc_probe__%d = {\n",
+ tl->nprobe++);
+ while (tl->t->tok != '}') {
+
+ vcc_IsField(tl, &t_field, fs);
+ ERRCHK(tl);
+ if (vcc_IdIs(t_field, "url")) {
+ vcc_ProbeRedef(tl, &t_did, t_field);
+ ERRCHK(tl);
+ ExpectErr(tl, CSTR);
+ Fh(tl, 0, "\t.url = ");
+ EncToken(tl->fh, tl->t);
+ Fh(tl, 0, ",\n");
+ vcc_NextToken(tl);
+ } else if (vcc_IdIs(t_field, "request")) {
+ vcc_ProbeRedef(tl, &t_did, t_field);
+ ERRCHK(tl);
+ ExpectErr(tl, CSTR);
+ Fh(tl, 0, "\t.request =\n");
+ while (tl->t->tok == CSTR) {
+ Fh(tl, 0, "\t\t");
+ EncToken(tl->fh, tl->t);
+ Fh(tl, 0, " \"\\r\\n\"\n");
+ vcc_NextToken(tl);
+ }
+ Fh(tl, 0, "\t\t\"\\r\\n\",\n");
+ } else if (vcc_IdIs(t_field, "timeout")) {
+ Fh(tl, 0, "\t.timeout = ");
+ vcc_Duration(tl, &t);
+ ERRCHK(tl);
+ Fh(tl, 0, "%g,\n", t);
+ } else if (vcc_IdIs(t_field, "interval")) {
+ Fh(tl, 0, "\t.interval = ");
+ vcc_Duration(tl, &t);
+ ERRCHK(tl);
+ Fh(tl, 0, "%g,\n", t);
+ } else if (vcc_IdIs(t_field, "window")) {
+ t_window = tl->t;
+ window = vcc_UintVal(tl);
+ ERRCHK(tl);
+ } else if (vcc_IdIs(t_field, "initial")) {
+ t_initial = tl->t;
+ initial = vcc_UintVal(tl);
+ ERRCHK(tl);
+ } else if (vcc_IdIs(t_field, "expected_response")) {
+ status = vcc_UintVal(tl);
+ if (status < 100 || status > 999) {
+ VSB_printf(tl->sb,
+ "Must specify .expected_response with "
+ "exactly three digits "
+ "(100 <= x <= 999)\n");
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+ ERRCHK(tl);
+ } else if (vcc_IdIs(t_field, "threshold")) {
+ t_threshold = tl->t;
+ threshold = vcc_UintVal(tl);
+ ERRCHK(tl);
+ } else {
+ vcc_ErrToken(tl, t_field);
+ vcc_ErrWhere(tl, t_field);
+ ErrInternal(tl);
+ return;
+ }
+
+ SkipToken(tl, ';');
+ }
+
+ if (t_threshold != NULL || t_window != NULL) {
+ if (t_threshold == NULL && t_window != NULL) {
+ VSB_printf(tl->sb,
+ "Must specify .threshold with .window\n");
+ vcc_ErrWhere(tl, t_window);
+ return;
+ } else if (t_threshold != NULL && t_window == NULL) {
+ if (threshold > 64) {
+ VSB_printf(tl->sb,
+ "Threshold must be 64 or less.\n");
+ vcc_ErrWhere(tl, t_threshold);
+ return;
+ }
+ window = threshold + 1;
+ } else if (window > 64) {
+ AN(t_window);
+ VSB_printf(tl->sb, "Window must be 64 or less.\n");
+ vcc_ErrWhere(tl, t_window);
+ return;
+ }
+ if (threshold > window ) {
+ VSB_printf(tl->sb,
+ "Threshold can not be greater than window.\n");
+ AN(t_threshold);
+ vcc_ErrWhere(tl, t_threshold);
+ AN(t_window);
+ vcc_ErrWhere(tl, t_window);
+ }
+ Fh(tl, 0, "\t.window = %u,\n", window);
+ Fh(tl, 0, "\t.threshold = %u,\n", threshold);
+ }
+ if (t_initial != NULL)
+ Fh(tl, 0, "\t.initial = %u,\n", initial);
+ else
+ Fh(tl, 0, "\t.initial = ~0U,\n");
+ if (status > 0)
+ Fh(tl, 0, "\t.exp_status = %u,\n", status);
+ Fh(tl, 0, "};\n");
+ SkipToken(tl, '}');
+}
+
+/*--------------------------------------------------------------------
+ * Parse and emit a probe definition
+ */
+
+void
+vcc_ParseProbe(struct vcc *tl)
+{
+ struct token *t_probe;
+ int i;
+
+ vcc_NextToken(tl); /* ID: probe */
+
+ vcc_ExpectCid(tl); /* ID: name */
+ ERRCHK(tl);
+ t_probe = tl->t;
+ vcc_NextToken(tl);
+ i = vcc_AddDef(tl, t_probe, SYM_PROBE);
+ if (i > 1) {
+ VSB_printf(tl->sb, "Probe %.*s redefined\n", PF(t_probe));
+ vcc_ErrWhere(tl, t_probe);
+ }
+
+ Fh(tl, 0, "\n#define vgc_probe_%.*s\tvgc_probe__%d\n",
+ PF(t_probe), tl->nprobe);
+ vcc_ParseProbeSpec(tl);
+}
+
+/*--------------------------------------------------------------------
+ * Parse and emit a backend host definition
+ *
+ * The struct vrt_backend is emitted to Fh().
+ */
+
+static void
+vcc_ParseHostDef(struct vcc *tl, const struct token *t_be)
+{
+ struct token *t_field;
+ struct token *t_host = NULL;
+ struct token *t_port = NULL;
+ struct token *t_hosthdr = NULL;
+ struct fld_spec *fs;
+ struct vsb *vsb;
+ unsigned u;
+ double t;
+ char vgcname[MAX_BACKEND_NAME + 8];
+
+ sprintf(vgcname, "_%.*s", PF(t_be));
+
+ Fh(tl, 1, "\n#define VGC_backend_%s %d\n", vgcname, tl->ndirector);
+
+ fs = vcc_FldSpec(tl,
+ "!host",
+ "?port",
+ "?host_header",
+ "?connect_timeout",
+ "?first_byte_timeout",
+ "?between_bytes_timeout",
+ "?probe",
+ "?max_connections",
+ NULL);
+
+ SkipToken(tl, '{');
+
+ vsb = VSB_new_auto();
+ AN(vsb);
+ tl->fb = vsb;
+
+ Fb(tl, 0, "\nstatic const struct vrt_backend vgc_dir_priv_%s = {\n",
+ vgcname);
+
+ Fb(tl, 0, "\t.vcl_name = \"%.*s", PF(t_be));
+ Fb(tl, 0, "\",\n");
+
+ /* Check for old syntax */
+ if (tl->t->tok == ID && vcc_IdIs(tl->t, "set")) {
+ VSB_printf(tl->sb,
+ "NB: Backend Syntax has changed:\n"
+ "Remove \"set\" and \"backend\" in front"
+ " of backend fields.\n" );
+ vcc_ErrToken(tl, tl->t);
+ VSB_printf(tl->sb, " at ");
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+
+ while (tl->t->tok != '}') {
+
+ vcc_IsField(tl, &t_field, fs);
+ ERRCHK(tl);
+ if (vcc_IdIs(t_field, "host")) {
+ ExpectErr(tl, CSTR);
+ assert(tl->t->dec != NULL);
+ t_host = tl->t;
+ vcc_NextToken(tl);
+ SkipToken(tl, ';');
+ } else if (vcc_IdIs(t_field, "port")) {
+ ExpectErr(tl, CSTR);
+ assert(tl->t->dec != NULL);
+ t_port = tl->t;
+ vcc_NextToken(tl);
+ SkipToken(tl, ';');
+ } else if (vcc_IdIs(t_field, "host_header")) {
+ ExpectErr(tl, CSTR);
+ assert(tl->t->dec != NULL);
+ t_hosthdr = tl->t;
+ vcc_NextToken(tl);
+ SkipToken(tl, ';');
+ } else if (vcc_IdIs(t_field, "connect_timeout")) {
+ Fb(tl, 0, "\t.connect_timeout = ");
+ vcc_Duration(tl, &t);
+ ERRCHK(tl);
+ Fb(tl, 0, "%g,\n", t);
+ SkipToken(tl, ';');
+ } else if (vcc_IdIs(t_field, "first_byte_timeout")) {
+ Fb(tl, 0, "\t.first_byte_timeout = ");
+ vcc_Duration(tl, &t);
+ ERRCHK(tl);
+ Fb(tl, 0, "%g,\n", t);
+ SkipToken(tl, ';');
+ } else if (vcc_IdIs(t_field, "between_bytes_timeout")) {
+ Fb(tl, 0, "\t.between_bytes_timeout = ");
+ vcc_Duration(tl, &t);
+ ERRCHK(tl);
+ Fb(tl, 0, "%g,\n", t);
+ SkipToken(tl, ';');
+ } else if (vcc_IdIs(t_field, "max_connections")) {
+ u = vcc_UintVal(tl);
+ ERRCHK(tl);
+ SkipToken(tl, ';');
+ Fb(tl, 0, "\t.max_connections = %u,\n", u);
+ } else if (vcc_IdIs(t_field, "probe") && tl->t->tok == '{') {
+ Fb(tl, 0, "\t.probe = &vgc_probe__%d,\n", tl->nprobe);
+ vcc_ParseProbeSpec(tl);
+ ERRCHK(tl);
+ } else if (vcc_IdIs(t_field, "probe") && tl->t->tok == ID) {
+ Fb(tl, 0, "\t.probe = &vgc_probe_%.*s,\n", PF(tl->t));
+ vcc_AddRef(tl, tl->t, SYM_PROBE);
+ vcc_NextToken(tl);
+ SkipToken(tl, ';');
+ } else if (vcc_IdIs(t_field, "probe")) {
+ VSB_printf(tl->sb,
+ "Expected '{' or name of probe, got ");
+ vcc_ErrToken(tl, tl->t);
+ VSB_printf(tl->sb, " at\n");
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ } else {
+ ErrInternal(tl);
+ return;
+ }
+
+ }
+
+ vcc_FieldsOk(tl, fs);
+ ERRCHK(tl);
+
+ /* Check that the hostname makes sense */
+ assert(t_host != NULL);
+ if (t_port != NULL)
+ Emit_Sockaddr(tl, t_host, t_port->dec);
+ else
+ Emit_Sockaddr(tl, t_host, "80");
+ ERRCHK(tl);
+
+ ExpectErr(tl, '}');
+
+ /* We have parsed it all, emit the ident string */
+
+ /* Emit the hosthdr field, fall back to .host if not specified */
+ Fb(tl, 0, "\t.hosthdr = ");
+ if (t_hosthdr != NULL)
+ EncToken(tl->fb, t_hosthdr);
+ else
+ EncToken(tl->fb, t_host);
+ Fb(tl, 0, ",\n");
+
+ /* Close the struct */
+ Fb(tl, 0, "};\n");
+
+ vcc_NextToken(tl);
+
+ tl->fb = NULL;
+ AZ(VSB_finish(vsb));
+ Fh(tl, 0, "%s", VSB_data(vsb));
+ VSB_delete(vsb);
+
+ Fi(tl, 0, "\tVRT_init_dir(cli, VCL_conf.director,\n"
+ "\t VGC_backend_%s, &vgc_dir_priv_%s);\n", vgcname, vgcname);
+ Ff(tl, 0, "\tVRT_fini_dir(cli, VGCDIR(%s));\n", vgcname);
+ tl->ndirector++;
+}
+
+/*--------------------------------------------------------------------
+ * Parse directors and backends
+ */
+
+void
+vcc_ParseBackend(struct vcc *tl)
+{
+ struct token *t_first, *t_be;
+ int isfirst;
+ struct symbol *sym;
+
+ t_first = tl->t;
+ vcc_NextToken(tl); /* ID: backend */
+
+ vcc_ExpectCid(tl); /* ID: name */
+ ERRCHK(tl);
+
+ if (tl->t->e - tl->t->b > MAX_BACKEND_NAME) {
+ VSB_printf(tl->sb,
+ "Name of %.*s too long (max %d, is %zu):\n",
+ PF(t_first), MAX_BACKEND_NAME,
+ (size_t)(tl->t->e - tl->t->b));
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+
+ t_be = tl->t;
+ vcc_NextToken(tl);
+
+ isfirst = tl->ndirector;
+
+ sym = VCC_GetSymbolTok(tl, t_be, SYM_BACKEND);
+ AN(sym);
+ if (sym->ndef > 0) {
+ VSB_printf(tl->sb, "Backend %.*s redefined\n", PF(t_be));
+ vcc_ErrWhere(tl, t_be);
+ return;
+ }
+ sym->fmt = BACKEND;
+ sym->eval = vcc_Eval_Backend;
+ sym->ndef++;
+ ERRCHK(tl);
+
+ vcc_ParseHostDef(tl, t_be);
+ ERRCHK(tl);
+
+ if (tl->err) {
+ VSB_printf(tl->sb,
+ "\nIn %.*s specification starting at:\n", PF(t_first));
+ vcc_ErrWhere(tl, t_first);
+ return;
+ }
+
+ if (isfirst == 1 || vcc_IdIs(t_be, "default")) {
+ tl->defaultdir = tl->ndirector - 1;
+ tl->t_defaultdir = t_be;
+ }
+}
diff --git a/lib/libvcc/vcc_backend_util.c b/lib/libvcc/vcc_backend_util.c
new file mode 100644
index 0000000..de361a5
--- /dev/null
+++ b/lib/libvcc/vcc_backend_util.c
@@ -0,0 +1,134 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2011 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "vcc_compile.h"
+
+/*--------------------------------------------------------------------
+ * Helper functions to complain about duplicate and missing fields
+ *
+ * XXX: idea: add groups to check for exclusivity, such that
+ * XXX: ("!foo", "?bar", "!{", "this", "that", "}", NULL)
+ * XXX: means exactly one of "this" or "that", and
+ * XXX: ("!foo", "?bar", "?{", "this", "that", "}", NULL)
+ * XXX: means at most one of "this" or "that".
+ */
+
+struct fld_spec {
+ const char *name;
+ struct token *found;
+};
+
+static void
+vcc_ResetFldSpec(struct fld_spec *f)
+{
+
+ for (; f->name != NULL; f++)
+ f->found = NULL;
+}
+
+struct fld_spec *
+vcc_FldSpec(struct vcc *tl, const char *first, ...)
+{
+ struct fld_spec f[100], *r;
+ int n = 0;
+ va_list ap;
+ const char *p;
+
+ f[n++].name = first;
+ va_start(ap, first);
+ while (1) {
+ p = va_arg(ap, const char *);
+ if (p == NULL)
+ break;
+ f[n++].name = p;
+ assert(n < 100);
+ }
+ va_end(ap);
+ f[n++].name = NULL;
+
+ vcc_ResetFldSpec(f);
+
+ r = TlAlloc(tl, sizeof *r * n);
+ memcpy(r, f, n * sizeof *r);
+ return (r);
+}
+
+void
+vcc_IsField(struct vcc *tl, struct token **t, struct fld_spec *fs)
+{
+ struct token *t_field;
+
+ SkipToken(tl, '.');
+ ExpectErr(tl, ID);
+ t_field = tl->t;
+ *t = t_field;
+ vcc_NextToken(tl);
+ SkipToken(tl, '=');
+
+ for (; fs->name != NULL; fs++) {
+ if (!vcc_IdIs(t_field, fs->name + 1))
+ continue;
+ if (fs->found == NULL) {
+ fs->found = t_field;
+ return;
+ }
+ VSB_printf(tl->sb, "Field ");
+ vcc_ErrToken(tl, t_field);
+ VSB_printf(tl->sb, " redefined at:\n");
+ vcc_ErrWhere(tl, t_field);
+ VSB_printf(tl->sb, "\nFirst defined at:\n");
+ vcc_ErrWhere(tl, fs->found);
+ return;
+ }
+ VSB_printf(tl->sb, "Unknown field: ");
+ vcc_ErrToken(tl, t_field);
+ VSB_printf(tl->sb, " at\n");
+ vcc_ErrWhere(tl, t_field);
+ return;
+}
+
+void
+vcc_FieldsOk(struct vcc *tl, const struct fld_spec *fs)
+{
+
+ for (; fs->name != NULL; fs++) {
+ if (*fs->name == '!' && fs->found == NULL) {
+ VSB_printf(tl->sb,
+ "Mandatory field '%s' missing.\n", fs->name + 1);
+ tl->err = 1;
+ }
+ }
+}
diff --git a/lib/libvcc/vcc_compile.c b/lib/libvcc/vcc_compile.c
new file mode 100644
index 0000000..1b3ee4e
--- /dev/null
+++ b/lib/libvcc/vcc_compile.c
@@ -0,0 +1,823 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2013 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * XXX:
+ * Better error messages, throughout.
+ * >It also accured to me that we could link the errors to the error
+ * >documentation.
+ * >
+ * >Unreferenced function 'request_policy', first mention is
+ * > Line 8 Pos 4
+ * > sub request_policy {
+ * > ----##############--
+ * >Read more about this type of error:
+ * >http://varnish/doc/error.html#Unreferenced%20function
+ * >
+ * >
+ * > Unknown variable 'obj.bandwidth'
+ * > At: Line 88 Pos 12
+ * > if (obj.bandwidth < 1 kb/h) {
+ * > ------------#############------------
+ * >Read more about this type of error:
+ * >http://varnish/doc/error.html#Unknown%20variable
+ *
+ */
+
+#include "config.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "vcc_compile.h"
+
+#include "libvcc.h"
+#include "vfil.h"
+
+struct method method_tab[] = {
+#define VCL_MET_MAC(l,U,m) { "vcl_"#l, m, VCL_MET_##U },
+#include "tbl/vcl_returns.h"
+#undef VCL_MET_MAC
+ { NULL, 0U, 0}
+};
+
+/*--------------------------------------------------------------------*/
+
+static void
+TlDoFree(struct vcc *tl, void *p)
+{
+ struct membit *mb;
+
+ mb = calloc(sizeof *mb, 1);
+ assert(mb != NULL);
+ mb->ptr = p;
+ VTAILQ_INSERT_TAIL(&tl->membits, mb, list);
+}
+
+
+void *
+TlAlloc(struct vcc *tl, unsigned len)
+{
+ void *p;
+
+ p = calloc(len, 1);
+ assert(p != NULL);
+ TlDoFree(tl, p);
+ return (p);
+}
+
+char *
+TlDup(struct vcc *tl, const char *s)
+{
+ char *p;
+
+ p = TlAlloc(tl, strlen(s) + 1);
+ AN(p);
+ strcpy(p, s);
+ return (p);
+}
+
+char *
+TlDupTok(struct vcc *tl, const struct token *tok)
+{
+ char *p;
+ int i;
+
+ i = tok->e - tok->b;
+ p = TlAlloc(tl, i + 1);
+ AN(p);
+ memcpy(p, tok->b, i);
+ p[i] = '\0';
+ return (p);
+}
+
+/*--------------------------------------------------------------------*/
+
+int
+IsMethod(const struct token *t)
+{
+ struct method *m;
+
+ assert(t->tok == ID);
+ for(m = method_tab; m->name != NULL; m++) {
+ if (vcc_IdIs(t, m->name))
+ return (m - method_tab);
+ }
+ if ((t->b[0] == 'v'|| t->b[0] == 'V') &&
+ (t->b[1] == 'c'|| t->b[1] == 'C') &&
+ (t->b[2] == 'l'|| t->b[2] == 'L'))
+ return (-2);
+ return (-1);
+}
+
+/*--------------------------------------------------------------------
+ * Printf output to the vsbs, possibly indented
+ */
+
+void
+Fh(const struct vcc *tl, int indent, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (indent)
+ VSB_printf(tl->fh, "%*.*s", tl->hindent, tl->hindent, "");
+ va_start(ap, fmt);
+ VSB_vprintf(tl->fh, fmt, ap);
+ va_end(ap);
+}
+
+void
+Fb(const struct vcc *tl, int indent, const char *fmt, ...)
+{
+ va_list ap;
+
+ assert(tl->fb != NULL);
+ if (indent)
+ VSB_printf(tl->fb, "%*.*s", tl->indent, tl->indent, "");
+ va_start(ap, fmt);
+ VSB_vprintf(tl->fb, fmt, ap);
+ va_end(ap);
+}
+
+void
+Fc(const struct vcc *tl, int indent, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (indent)
+ VSB_printf(tl->fc, "%*.*s", tl->indent, tl->indent, "");
+ va_start(ap, fmt);
+ VSB_vprintf(tl->fc, fmt, ap);
+ va_end(ap);
+}
+
+void
+Fi(const struct vcc *tl, int indent, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (indent)
+ VSB_printf(tl->fi, "%*.*s", tl->iindent, tl->iindent, "");
+ va_start(ap, fmt);
+ VSB_vprintf(tl->fi, fmt, ap);
+ va_end(ap);
+}
+
+void
+Fd(const struct vcc *tl, int indent, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (indent)
+ VSB_printf(tl->fd, "%*.*s", tl->findent, tl->findent, "");
+ va_start(ap, fmt);
+ VSB_vprintf(tl->fd, fmt, ap);
+ va_end(ap);
+}
+
+
+void
+Ff(const struct vcc *tl, int indent, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (indent)
+ VSB_printf(tl->ff, "%*.*s", tl->findent, tl->findent, "");
+ va_start(ap, fmt);
+ VSB_vprintf(tl->ff, fmt, ap);
+ va_end(ap);
+}
+
+/*--------------------------------------------------------------------*/
+
+void
+EncString(struct vsb *sb, const char *b, const char *e, int mode)
+{
+
+ if (e == NULL)
+ e = strchr(b, '\0');
+
+ VSB_cat(sb, "\"");
+ for (; b < e; b++) {
+ switch (*b) {
+ case '\\':
+ case '"':
+ VSB_printf(sb, "\\%c", *b);
+ break;
+ case '\n':
+ VSB_printf(sb, "\\n");
+ if (mode)
+ VSB_printf(sb, "\"\n\t\"");
+ break;
+ case '\t': VSB_printf(sb, "\\t"); break;
+ case '\r': VSB_printf(sb, "\\r"); break;
+ case ' ': VSB_printf(sb, " "); break;
+ default:
+ if (isgraph(*b))
+ VSB_printf(sb, "%c", *b);
+ else
+ VSB_printf(sb, "\\%03o", (uint8_t)*b);
+ break;
+ }
+ }
+ VSB_cat(sb, "\"");
+}
+
+void
+EncToken(struct vsb *sb, const struct token *t)
+{
+
+ assert(t->tok == CSTR);
+ EncString(sb, t->dec, NULL, 1);
+}
+
+/*--------------------------------------------------------------------
+ * Output the location/profiling table. For each counted token, we
+ * record source+line+charpos for the first character in the token.
+ */
+
+static void
+LocTable(const struct vcc *tl)
+{
+ struct token *t;
+ unsigned lin, pos;
+ struct source *sp;
+ const char *p;
+
+ Fh(tl, 0, "\n#define VGC_NREFS %u\n", tl->cnt + 1);
+ Fc(tl, 0, "\nstatic struct vrt_ref VGC_ref[VGC_NREFS] = {\n");
+ lin = 1;
+ pos = 0;
+ sp = 0;
+ p = NULL;
+ VTAILQ_FOREACH(t, &tl->tokens, list) {
+ if (t->cnt == 0)
+ continue;
+ assert(t->src != NULL);
+ if (t->src != sp) {
+ lin = 1;
+ pos = 0;
+ sp = t->src;
+ p = sp->b;
+ }
+ assert(sp != NULL);
+ assert(p != NULL);
+ for (;p < t->b; p++) {
+ if (*p == '\n') {
+ lin++;
+ pos = 0;
+ } else if (*p == '\t') {
+ pos &= ~7;
+ pos += 8;
+ } else
+ pos++;
+
+ }
+ Fc(tl, 0, " [%3u] = { %d, %8tu, %4u, %3u, 0, ",
+ t->cnt, sp->idx, t->b - sp->b, lin, pos + 1);
+ if (t->tok == CSRC)
+ Fc(tl, 0, " \"C{\"},\n");
+ else
+ Fc(tl, 0, " \"%.*s\" },\n", PF(t));
+ }
+ Fc(tl, 0, "};\n");
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+EmitInitFunc(const struct vcc *tl)
+{
+
+ Fc(tl, 0, "\nstatic int\nVGC_Init(struct cli *cli)\n{\n\n");
+ AZ(VSB_finish(tl->fi));
+ VSB_cat(tl->fc, VSB_data(tl->fi));
+ Fc(tl, 0, "\treturn(0);\n");
+ Fc(tl, 0, "}\n");
+}
+
+static void
+EmitFiniFunc(const struct vcc *tl)
+{
+ unsigned u;
+
+ Fc(tl, 0, "\nstatic void\nVGC_Fini(struct cli *cli)\n{\n\n");
+
+ AZ(VSB_finish(tl->fd));
+ VSB_cat(tl->fc, VSB_data(tl->fd));
+
+ /*
+ * We do this here, so we are sure they happen before any
+ * per-vcl vmod_privs get cleaned.
+ */
+ for (u = 0; u < tl->nvmodpriv; u++)
+ Fc(tl, 0, "\tvmod_priv_fini(&vmod_priv_%u);\n", u);
+
+ AZ(VSB_finish(tl->ff));
+ VSB_cat(tl->fc, VSB_data(tl->ff));
+ Fc(tl, 0, "}\n");
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+EmitStruct(const struct vcc *tl)
+{
+ struct source *sp;
+
+ Fc(tl, 0, "\nconst char *srcname[%u] = {\n", tl->nsources);
+ VTAILQ_FOREACH(sp, &tl->sources, list) {
+ Fc(tl, 0, "\t");
+ EncString(tl->fc, sp->name, NULL, 0);
+ Fc(tl, 0, ",\n");
+ }
+ Fc(tl, 0, "};\n");
+
+ Fc(tl, 0, "\nconst char *srcbody[%u] = {\n", tl->nsources);
+ VTAILQ_FOREACH(sp, &tl->sources, list) {
+ Fc(tl, 0, " /* ");
+ EncString(tl->fc, sp->name, NULL, 0);
+ Fc(tl, 0, "*/\n");
+ Fc(tl, 0, "\t");
+ EncString(tl->fc, sp->b, sp->e, 1);
+ Fc(tl, 0, ",\n");
+ }
+ Fc(tl, 0, "};\n");
+
+ Fc(tl, 0, "\nstatic struct director\t*directors[%d];\n",
+ tl->ndirector);
+
+ Fc(tl, 0, "\nconst struct VCL_conf VCL_conf = {\n");
+ Fc(tl, 0, "\t.magic = VCL_CONF_MAGIC,\n");
+ Fc(tl, 0, "\t.init_vcl = VGC_Init,\n");
+ Fc(tl, 0, "\t.fini_vcl = VGC_Fini,\n");
+ Fc(tl, 0, "\t.ndirector = %d,\n", tl->ndirector);
+ Fc(tl, 0, "\t.director = directors,\n");
+ Fc(tl, 0, "\t.ref = VGC_ref,\n");
+ Fc(tl, 0, "\t.nref = VGC_NREFS,\n");
+ Fc(tl, 0, "\t.nsrc = %u,\n", tl->nsources);
+ Fc(tl, 0, "\t.srcname = srcname,\n");
+ Fc(tl, 0, "\t.srcbody = srcbody,\n");
+#define VCL_MET_MAC(l,u,b) \
+ Fc(tl, 0, "\t." #l "_func = VGC_function_vcl_" #l ",\n");
+#include "tbl/vcl_returns.h"
+#undef VCL_MET_MAC
+ Fc(tl, 0, "};\n");
+}
+
+/*--------------------------------------------------------------------*/
+
+static struct source *
+vcc_new_source(const char *b, const char *e, const char *name)
+{
+ struct source *sp;
+
+ if (e == NULL)
+ e = strchr(b, '\0');
+ sp = calloc(sizeof *sp, 1);
+ assert(sp != NULL);
+ sp->name = strdup(name);
+ AN(sp->name);
+ sp->b = b;
+ sp->e = e;
+ return (sp);
+}
+
+static void
+vcc_destroy_source(struct source *sp)
+{
+
+ if (sp->freeit != NULL)
+ free(sp->freeit);
+ free(sp->name);
+ free(sp);
+}
+
+/*--------------------------------------------------------------------*/
+
+static struct source *
+vcc_file_source(const struct vcc *tl, struct vsb *sb, const char *fn)
+{
+ char *f;
+ struct source *sp;
+
+ if (!tl->unsafe_path && strchr(fn, '/') != NULL) {
+ VSB_printf(sb, "Include path is unsafe '%s'\n", fn);
+ return (NULL);
+ }
+ f = VFIL_readfile(tl->vcl_dir, fn, NULL);
+ if (f == NULL) {
+ VSB_printf(sb, "Cannot read file '%s': %s\n",
+ fn, strerror(errno));
+ return (NULL);
+ }
+ sp = vcc_new_source(f, NULL, fn);
+ sp->freeit = f;
+ return (sp);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+vcc_resolve_includes(struct vcc *tl)
+{
+ struct token *t, *t1, *t2;
+ struct source *sp;
+
+ VTAILQ_FOREACH(t, &tl->tokens, list) {
+ if (t->tok != ID || !vcc_IdIs(t, "include"))
+ continue;
+
+ t1 = VTAILQ_NEXT(t, list);
+ assert(t1 != NULL); /* There's always an EOI */
+ if (t1->tok != CSTR) {
+ VSB_printf(tl->sb,
+ "include not followed by string constant.\n");
+ vcc_ErrWhere(tl, t1);
+ return;
+ }
+ t2 = VTAILQ_NEXT(t1, list);
+ assert(t2 != NULL); /* There's always an EOI */
+
+ if (t2->tok != ';') {
+ VSB_printf(tl->sb,
+ "include <string> not followed by semicolon.\n");
+ vcc_ErrWhere(tl, t1);
+ return;
+ }
+
+ sp = vcc_file_source(tl, tl->sb, t1->dec);
+ if (sp == NULL) {
+ vcc_ErrWhere(tl, t1);
+ return;
+ }
+ VTAILQ_INSERT_TAIL(&tl->sources, sp, list);
+ sp->idx = tl->nsources++;
+ tl->t = t2;
+ vcc_Lexer(tl, sp);
+
+ VTAILQ_REMOVE(&tl->tokens, t, list);
+ VTAILQ_REMOVE(&tl->tokens, t1, list);
+ VTAILQ_REMOVE(&tl->tokens, t2, list);
+ if (!tl->err)
+ vcc_resolve_includes(tl);
+ return;
+ }
+}
+
+/*--------------------------------------------------------------------*/
+
+static struct vcc *
+vcc_NewVcc(const struct vcc *tl0)
+{
+ struct vcc *tl;
+ int i;
+
+ ALLOC_OBJ(tl, VCC_MAGIC);
+ AN(tl);
+ if (tl0 != NULL) {
+ REPLACE(tl->default_vcl, tl0->default_vcl);
+ REPLACE(tl->vcl_dir, tl0->vcl_dir);
+ REPLACE(tl->vmod_dir, tl0->vmod_dir);
+ tl->vars = tl0->vars;
+ tl->err_unref = tl0->err_unref;
+ tl->allow_inline_c = tl0->allow_inline_c;
+ tl->unsafe_path = tl0->unsafe_path;
+ } else {
+ tl->err_unref = 1;
+ }
+ VTAILQ_INIT(&tl->symbols);
+ VTAILQ_INIT(&tl->membits);
+ VTAILQ_INIT(&tl->tokens);
+ VTAILQ_INIT(&tl->sources);
+
+ tl->nsources = 0;
+ tl->ndirector = 1;
+
+ /* General C code */
+ tl->fc = VSB_new_auto();
+ assert(tl->fc != NULL);
+
+ /* Forward decls (.h like) */
+ tl->fh = VSB_new_auto();
+ assert(tl->fh != NULL);
+
+ /* Init C code */
+ tl->fi = VSB_new_auto();
+ assert(tl->fi != NULL);
+
+ /* Destroy Objects */
+ tl->fd = VSB_new_auto();
+ assert(tl->fd != NULL);
+
+ /* Finish C code */
+ tl->ff = VSB_new_auto();
+ assert(tl->ff != NULL);
+
+ /* body code of methods */
+ for (i = 0; i < VCL_MET_MAX; i++) {
+ tl->fm[i] = VSB_new_auto();
+ assert(tl->fm[i] != NULL);
+ }
+ return (tl);
+}
+
+/*--------------------------------------------------------------------*/
+
+static char *
+vcc_DestroyTokenList(struct vcc *tl, char *ret)
+{
+ struct membit *mb;
+ struct source *sp;
+ struct symbol *sym;
+ int i;
+
+ while (!VTAILQ_EMPTY(&tl->membits)) {
+ mb = VTAILQ_FIRST(&tl->membits);
+ VTAILQ_REMOVE(&tl->membits, mb, list);
+ free(mb->ptr);
+ free(mb);
+ }
+ while (!VTAILQ_EMPTY(&tl->sources)) {
+ sp = VTAILQ_FIRST(&tl->sources);
+ VTAILQ_REMOVE(&tl->sources, sp, list);
+ vcc_destroy_source(sp);
+ }
+
+ while (!VTAILQ_EMPTY(&tl->symbols)) {
+ sym = VTAILQ_FIRST(&tl->symbols);
+ VTAILQ_REMOVE(&tl->symbols, sym, list);
+ FREE_OBJ(sym);
+ }
+
+ VSB_delete(tl->fh);
+ VSB_delete(tl->fc);
+ VSB_delete(tl->fi);
+ VSB_delete(tl->ff);
+ for (i = 0; i < VCL_MET_MAX; i++)
+ VSB_delete(tl->fm[i]);
+
+ free(tl);
+ return (ret);
+}
+
+/*--------------------------------------------------------------------
+ * Compile the VCL code from the given source and return the C-source
+ */
+
+static char *
+vcc_CompileSource(const struct vcc *tl0, struct vsb *sb, struct source *sp)
+{
+ struct vcc *tl;
+ struct symbol *sym;
+ const struct var *v;
+ char *of;
+ int i;
+
+ tl = vcc_NewVcc(tl0);
+ tl->sb = sb;
+
+ vcc_Expr_Init(tl);
+
+ for (v = tl->vars; v->name != NULL; v++) {
+ if (v->fmt == HEADER) {
+ sym = VCC_AddSymbolStr(tl, v->name, SYM_WILDCARD);
+ sym->wildcard = vcc_Var_Wildcard;
+ } else {
+ sym = VCC_AddSymbolStr(tl, v->name, SYM_VAR);
+ }
+ sym->var = v;
+ sym->fmt = v->fmt;
+ sym->eval = vcc_Eval_Var;
+ sym->r_methods = v->r_methods;
+ }
+
+ sym = VCC_AddSymbolStr(tl, "storage.", SYM_WILDCARD);
+ sym->wildcard = vcc_Stv_Wildcard;
+
+ vcl_output_lang_h(tl->fh);
+ Fh(tl, 0, "\n/* ---===### VCC generated below here ###===---*/\n");
+ Fh(tl, 0, "\nextern const struct VCL_conf VCL_conf;\n");
+
+ /* Macro for accessing directors */
+ Fh(tl, 0, "#define VGCDIR(n) VCL_conf.director[VGC_backend_##n]\n");
+
+ Fh(tl, 0, "#define __match_proto__(xxx) /*lint -e{818} */\n");
+
+ /* Register and lex the main source */
+ VTAILQ_INSERT_TAIL(&tl->sources, sp, list);
+ sp->idx = tl->nsources++;
+ vcc_Lexer(tl, sp);
+ if (tl->err)
+ return (vcc_DestroyTokenList(tl, NULL));
+
+ /* Register and lex the default VCL */
+ sp = vcc_new_source(tl->default_vcl, NULL, "Default");
+ assert(sp != NULL);
+ VTAILQ_INSERT_TAIL(&tl->sources, sp, list);
+ sp->idx = tl->nsources++;
+ vcc_Lexer(tl, sp);
+ if (tl->err)
+ return (vcc_DestroyTokenList(tl, NULL));
+
+ /* Add "END OF INPUT" token */
+ vcc_AddToken(tl, EOI, sp->e, sp->e);
+ if (tl->err)
+ return (vcc_DestroyTokenList(tl, NULL));
+
+ /* Expand and lex any includes in the token string */
+ vcc_resolve_includes(tl);
+ if (tl->err)
+ return (vcc_DestroyTokenList(tl, NULL));
+
+ /* Parse the token string */
+ tl->t = VTAILQ_FIRST(&tl->tokens);
+ vcc_Parse(tl);
+ if (tl->err)
+ return (vcc_DestroyTokenList(tl, NULL));
+
+ /* Check if we have any backends at all */
+ if (tl->ndirector == 1) {
+ VSB_printf(tl->sb,
+ "No backends or directors found in VCL program, "
+ "at least one is necessary.\n");
+ tl->err = 1;
+ return (vcc_DestroyTokenList(tl, NULL));
+ }
+
+ /* Configure the default director */
+ Fi(tl, 0, "\tVCL_conf.director[0] = VCL_conf.director[%d];\n",
+ tl->defaultdir);
+ vcc_AddRef(tl, tl->t_defaultdir, SYM_BACKEND);
+
+ /* Check for orphans */
+ if (vcc_CheckReferences(tl))
+ return (vcc_DestroyTokenList(tl, NULL));
+
+ /* Check that all action returns are legal */
+ if (vcc_CheckAction(tl) || tl->err)
+ return (vcc_DestroyTokenList(tl, NULL));
+
+ /* Check that all variable uses are legal */
+ if (vcc_CheckUses(tl) || tl->err)
+ return (vcc_DestroyTokenList(tl, NULL));
+
+ /* Emit method functions */
+ for (i = 0; i < VCL_MET_MAX; i++) {
+ Fc(tl, 1, "\nstatic int __match_proto__(vcl_func_f)\n");
+ Fc(tl, 1,
+ "VGC_function_%s(const struct vrt_ctx *ctx)\n",
+ method_tab[i].name);
+ AZ(VSB_finish(tl->fm[i]));
+ Fc(tl, 1, "{\n");
+ Fc(tl, 1, "%s", VSB_data(tl->fm[i]));
+ Fc(tl, 1, "}\n");
+ }
+
+ LocTable(tl);
+
+ EmitInitFunc(tl);
+
+ EmitFiniFunc(tl);
+
+ EmitStruct(tl);
+
+ /* Combine it all in the fh vsb */
+ AZ(VSB_finish(tl->fc));
+ VSB_cat(tl->fh, VSB_data(tl->fc));
+ AZ(VSB_finish(tl->fh));
+
+ of = strdup(VSB_data(tl->fh));
+ AN(of);
+
+ /* done */
+ return (vcc_DestroyTokenList(tl, of));
+}
+
+/*--------------------------------------------------------------------
+ * Compile the VCL code in the argument. Error messages, if any are
+ * formatted into the vsb.
+ */
+
+char *
+VCC_Compile(const struct vcc *tl, struct vsb *sb, const char *b)
+{
+ struct source *sp;
+ char *r;
+
+ sp = vcc_new_source(b, NULL, "input");
+ if (sp == NULL)
+ return (NULL);
+ r = vcc_CompileSource(tl, sb, sp);
+ return (r);
+}
+
+/*--------------------------------------------------------------------
+ * Allocate a compiler instance
+ */
+
+struct vcc *
+VCC_New(void)
+{
+ struct vcc *tl;
+
+ tl = vcc_NewVcc(NULL);
+
+ tl->vars = vcc_vars;
+
+ return (tl);
+}
+
+/*--------------------------------------------------------------------
+ * Configure default VCL source code
+ */
+
+void
+VCC_Default_VCL(struct vcc *tl, const char *str)
+{
+
+ CHECK_OBJ_NOTNULL(tl, VCC_MAGIC);
+ REPLACE(tl->default_vcl, str);
+}
+
+/*--------------------------------------------------------------------
+ * Configure default VCL source directory
+ */
+
+void
+VCC_VCL_dir(struct vcc *tl, const char *str)
+{
+
+ CHECK_OBJ_NOTNULL(tl, VCC_MAGIC);
+ REPLACE(tl->vcl_dir, str);
+}
+
+/*--------------------------------------------------------------------
+ * Configure default VMOD directory
+ */
+
+void
+VCC_VMOD_dir(struct vcc *tl, const char *str)
+{
+
+ CHECK_OBJ_NOTNULL(tl, VCC_MAGIC);
+ REPLACE(tl->vmod_dir, str);
+}
+
+/*--------------------------------------------------------------------
+ * Configure settings
+ */
+
+void
+VCC_Err_Unref(struct vcc *tl, unsigned u)
+{
+
+ CHECK_OBJ_NOTNULL(tl, VCC_MAGIC);
+ tl->err_unref = u;
+}
+
+void
+VCC_Allow_InlineC(struct vcc *tl, unsigned u)
+{
+
+ CHECK_OBJ_NOTNULL(tl, VCC_MAGIC);
+ tl->allow_inline_c = u;
+}
+
+void
+VCC_Unsafe_Path(struct vcc *tl, unsigned u)
+{
+
+ CHECK_OBJ_NOTNULL(tl, VCC_MAGIC);
+ tl->unsafe_path = u;
+}
diff --git a/lib/libvcc/vcc_compile.h b/lib/libvcc/vcc_compile.h
new file mode 100644
index 0000000..b0983cc
--- /dev/null
+++ b/lib/libvcc/vcc_compile.h
@@ -0,0 +1,351 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2013 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#include "miniobj.h"
+#include "vas.h"
+#include "vcl.h"
+#include "vdef.h"
+#include "vqueue.h"
+#include "vsb.h"
+
+
+#include "vcc_token_defs.h"
+
+#ifndef NULL
+#define NULL ((void*)0)
+#endif
+
+struct vsb;
+struct token;
+struct sockaddr_storage;
+
+#define isident1(c) (isalpha(c))
+#define isident(c) (isalpha(c) || isdigit(c) || (c) == '_' || (c) == '-')
+#define isvar(c) (isident(c) || (c) == '.')
+int vcc_isCid(const struct token *t);
+unsigned vcl_fixed_token(const char *p, const char **q);
+extern const char * const vcl_tnames[256];
+void vcl_output_lang_h(struct vsb *sb);
+
+#define PF(t) (int)((t)->e - (t)->b), (t)->b
+
+#define INDENT 2
+
+struct acl_e;
+struct proc;
+struct expr;
+struct vcc;
+struct symbol;
+
+enum var_type {
+#define VCC_TYPE(foo) foo,
+#include "tbl/vcc_types.h"
+#undef VCC_TYPE
+};
+
+struct membit {
+ VTAILQ_ENTRY(membit) list;
+ void *ptr;
+};
+
+struct source {
+ VTAILQ_ENTRY(source) list;
+ char *name;
+ const char *b;
+ const char *e;
+ unsigned idx;
+ char *freeit;
+};
+
+struct token {
+ unsigned tok;
+ const char *b;
+ const char *e;
+ struct source *src;
+ VTAILQ_ENTRY(token) list;
+ unsigned cnt;
+ char *dec;
+};
+
+enum symkind {
+#define VCC_SYMB(uu, ll) SYM_##uu,
+#include "tbl/symbol_kind.h"
+#undef VCC_SYMB
+};
+
+typedef void sym_expr_t(struct vcc *tl, struct expr **,
+ const struct symbol *sym);
+typedef struct symbol *sym_wildcard_t(struct vcc *tl, const struct token *t,
+ const struct symbol *sym);
+
+struct symbol {
+ unsigned magic;
+#define SYMBOL_MAGIC 0x3368c9fb
+ VTAILQ_ENTRY(symbol) list;
+
+ char *name;
+ unsigned nlen;
+ sym_wildcard_t *wildcard;
+ enum symkind kind;
+
+ const struct token *def_b, *def_e;
+
+ enum var_type fmt;
+
+ sym_expr_t *eval;
+ void *eval_priv;
+
+ /* xref.c */
+ struct proc *proc;
+ unsigned nref, ndef;
+
+ /* SYM_PROC, SYM_FUNC */
+ const char *cfunc;
+ const char *extra;
+ const char *args;
+
+ /* SYM_VAR */
+ const struct var *var;
+ unsigned r_methods;
+};
+
+VTAILQ_HEAD(tokenhead, token);
+
+struct vcc {
+ unsigned magic;
+#define VCC_MAGIC 0x24ad719d
+
+ /* Parameter/Template section */
+ char *default_vcl;
+ char *vcl_dir;
+ char *vmod_dir;
+
+ const struct var *vars;
+ VTAILQ_HEAD(, symbol) symbols;
+
+ /* Instance section */
+ struct tokenhead tokens;
+ VTAILQ_HEAD(, source) sources;
+ VTAILQ_HEAD(, membit) membits;
+ unsigned nsources;
+ struct source *src;
+ struct token *t;
+ int indent;
+ int hindent;
+ int iindent;
+ int findent;
+ unsigned cnt;
+
+ struct vsb *fc; /* C-code */
+ struct vsb *fh; /* H-code (before C-code) */
+ struct vsb *fi; /* Init func code */
+ struct vsb *fd; /* Object destructors */
+ struct vsb *ff; /* Finish func code */
+ struct vsb *fb; /* Body of current sub
+ * NULL otherwise
+ */
+ struct vsb *fm[VCL_MET_MAX]; /* Method bodies */
+ struct vsb *sb;
+ int err;
+ int ndirector;
+ struct proc *curproc;
+ struct proc *mprocs[VCL_MET_MAX];
+
+ VTAILQ_HEAD(, acl_e) acl;
+
+ int nprobe;
+
+ int defaultdir;
+ struct token *t_defaultdir;
+
+ unsigned unique;
+ unsigned nvmodpriv;
+
+ unsigned err_unref;
+ unsigned allow_inline_c;
+ unsigned unsafe_path;
+};
+
+struct var {
+ const char *name;
+ enum var_type fmt;
+ unsigned len;
+ const char *rname;
+ unsigned r_methods;
+ const char *lname;
+ unsigned w_methods;
+};
+
+struct method {
+ const char *name;
+ unsigned ret_bitmap;
+ unsigned bitval;
+};
+
+/*--------------------------------------------------------------------*/
+
+/* vcc_acl.c */
+
+void vcc_Acl(struct vcc *tl);
+void vcc_Acl_Hack(struct vcc *tl, char *b);
+
+/* vcc_action.c */
+int vcc_ParseAction(struct vcc *tl);
+
+/* vcc_backend.c */
+#define MAX_BACKEND_NAME 64
+struct fld_spec;
+
+void vcc_ParseProbe(struct vcc *tl);
+void vcc_ParseBackend(struct vcc *tl);
+struct fld_spec * vcc_FldSpec(struct vcc *tl, const char *first, ...);
+void vcc_IsField(struct vcc *tl, struct token **t, struct fld_spec *fs);
+void vcc_FieldsOk(struct vcc *tl, const struct fld_spec *fs);
+
+/* vcc_compile.c */
+extern struct method method_tab[];
+/*
+ * H -> Header, before the C code
+ * C -> C-code
+ * B -> Body of function, ends up in C once function is completed
+ * I -> Initializer function
+ * F -> Finish function
+ */
+void Fh(const struct vcc *tl, int indent, const char *fmt, ...)
+ __printflike(3, 4);
+void Fc(const struct vcc *tl, int indent, const char *fmt, ...)
+ __printflike(3, 4);
+void Fb(const struct vcc *tl, int indent, const char *fmt, ...)
+ __printflike(3, 4);
+void Fi(const struct vcc *tl, int indent, const char *fmt, ...)
+ __printflike(3, 4);
+void Ff(const struct vcc *tl, int indent, const char *fmt, ...)
+ __printflike(3, 4);
+void Fd(const struct vcc *tl, int indent, const char *fmt, ...)
+ __printflike(3, 4);
+void EncToken(struct vsb *sb, const struct token *t);
+int IsMethod(const struct token *t);
+void *TlAlloc(struct vcc *tl, unsigned len);
+char *TlDup(struct vcc *tl, const char *s);
+char *TlDupTok(struct vcc *tl, const struct token *tok);
+
+void EncString(struct vsb *sb, const char *b, const char *e, int mode);
+
+/* vcc_expr.c */
+void vcc_Duration(struct vcc *tl, double *);
+unsigned vcc_UintVal(struct vcc *tl);
+void vcc_Expr(struct vcc *tl, enum var_type typ);
+void vcc_Expr_Call(struct vcc *tl, const struct symbol *sym);
+void vcc_Expr_Init(struct vcc *tl);
+sym_expr_t vcc_Eval_Var;
+sym_expr_t vcc_Eval_SymFunc;
+void vcc_Eval_Func(struct vcc *tl, const char *cfunc, const char *extra,
+ const char *name, const char *args);
+sym_expr_t vcc_Eval_Backend;
+
+/* vcc_obj.c */
+extern const struct var vcc_vars[];
+
+/* vcc_parse.c */
+void vcc_Parse(struct vcc *tl);
+
+/* vcc_storage.c */
+sym_wildcard_t vcc_Stv_Wildcard;
+
+/* vcc_utils.c */
+const char *vcc_regexp(struct vcc *tl);
+void Resolve_Sockaddr(struct vcc *tl, const char *host, const char *port, \
+ const char **ipv4, const char **ipv4_ascii, const char **ipv6, \
+ const char **ipv6_ascii, const char **p_ascii, int maxips,
+ const struct token *t_err, const char *errid);
+
+/* vcc_symb.c */
+struct symbol *VCC_AddSymbolStr(struct vcc *tl, const char *name, enum symkind);
+struct symbol *VCC_AddSymbolTok(struct vcc *tl, const struct token *t,
+ enum symkind kind);
+struct symbol *VCC_GetSymbolTok(struct vcc *tl, const struct token *tok,
+ enum symkind);
+struct symbol *VCC_FindSymbol(struct vcc *tl,
+ const struct token *t, enum symkind kind);
+const char * VCC_SymKind(struct vcc *tl, const struct symbol *s);
+typedef void symwalk_f(struct vcc *tl, const struct symbol *s);
+void VCC_WalkSymbols(struct vcc *tl, symwalk_f *func, enum symkind kind);
+
+/* vcc_token.c */
+void vcc_Coord(const struct vcc *tl, struct vsb *vsb,
+ const struct token *t);
+void vcc_ErrToken(const struct vcc *tl, const struct token *t);
+void vcc_ErrWhere(struct vcc *, const struct token *);
+void vcc_ErrWhere2(struct vcc *, const struct token *, const struct token *);
+
+void vcc__Expect(struct vcc *tl, unsigned tok, unsigned line);
+int vcc_IdIs(const struct token *t, const char *p);
+void vcc_ExpectCid(struct vcc *tl);
+void vcc_Lexer(struct vcc *tl, struct source *sp);
+void vcc_NextToken(struct vcc *tl);
+void vcc__ErrInternal(struct vcc *tl, const char *func,
+ unsigned line);
+void vcc_AddToken(struct vcc *tl, unsigned tok, const char *b,
+ const char *e);
+
+/* vcc_var.c */
+sym_wildcard_t vcc_Var_Wildcard;
+const struct var *vcc_FindVar(struct vcc *tl, const struct token *t,
+ int wr_access, const char *use);
+
+/* vcc_vmod.c */
+void vcc_ParseImport(struct vcc *tl);
+
+/* vcc_xref.c */
+int vcc_AddDef(struct vcc *tl, const struct token *t, enum symkind type);
+void vcc_AddRef(struct vcc *tl, const struct token *t, enum symkind type);
+int vcc_CheckReferences(struct vcc *tl);
+
+void vcc_AddCall(struct vcc *tl, struct token *t);
+struct proc *vcc_AddProc(struct vcc *tl, struct token *t);
+void vcc_ProcAction(struct proc *p, unsigned action, struct token *t);
+int vcc_CheckAction(struct vcc *tl);
+void vcc_AddUses(struct vcc *tl, const struct token *t, unsigned mask,
+ const char *use);
+int vcc_CheckUses(struct vcc *tl);
+
+#define ERRCHK(tl) do { if ((tl)->err) return; } while (0)
+#define ErrInternal(tl) vcc__ErrInternal(tl, __func__, __LINE__)
+#define Expect(a, b) vcc__Expect(a, b, __LINE__)
+#define ExpectErr(a, b) \
+ do { vcc__Expect(a, b, __LINE__); ERRCHK(a);} while (0)
+#define SkipToken(a, b) \
+ do { vcc__Expect(a, b, __LINE__); ERRCHK(a); vcc_NextToken(a); } while (0)
diff --git a/lib/libvcc/vcc_expr.c b/lib/libvcc/vcc_expr.c
new file mode 100644
index 0000000..164a8d6
--- /dev/null
+++ b/lib/libvcc/vcc_expr.c
@@ -0,0 +1,1257 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2011 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * XXX: add VRT_count()'s
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "vcc_compile.h"
+
+static const char *
+vcc_Type(enum var_type fmt)
+{
+ switch(fmt) {
+#define VCC_TYPE(a) case a: return(#a);
+#include "tbl/vcc_types.h"
+#undef VCC_TYPE
+ default:
+ assert("Unknown Type");
+ return(NULL);
+ }
+}
+
+/*--------------------------------------------------------------------
+ * Recognize and convert units of time, return seconds.
+ */
+
+static double
+vcc_TimeUnit(struct vcc *tl)
+{
+ double sc = 1.0;
+
+ assert(tl->t->tok == ID);
+ if (vcc_IdIs(tl->t, "ms"))
+ sc = 1e-3;
+ else if (vcc_IdIs(tl->t, "s"))
+ sc = 1.0;
+ else if (vcc_IdIs(tl->t, "m"))
+ sc = 60.0;
+ else if (vcc_IdIs(tl->t, "h"))
+ sc = 60.0 * 60.0;
+ else if (vcc_IdIs(tl->t, "d"))
+ sc = 60.0 * 60.0 * 24.0;
+ else if (vcc_IdIs(tl->t, "w"))
+ sc = 60.0 * 60.0 * 24.0 * 7.0;
+ else {
+ VSB_printf(tl->sb, "Unknown time unit ");
+ vcc_ErrToken(tl, tl->t);
+ VSB_printf(tl->sb, ". Legal are 's', 'm', 'h' and 'd'\n");
+ vcc_ErrWhere(tl, tl->t);
+ return (1.0);
+ }
+ vcc_NextToken(tl);
+ return (sc);
+}
+
+/*--------------------------------------------------------------------
+ * Recognize and convert { CNUM } to unsigned value
+ * The tokenizer made sure we only get digits.
+ */
+
+unsigned
+vcc_UintVal(struct vcc *tl)
+{
+ unsigned d = 0;
+ const char *p;
+
+ Expect(tl, CNUM);
+ for (p = tl->t->b; p < tl->t->e; p++) {
+ d *= 10;
+ d += *p - '0';
+ }
+ vcc_NextToken(tl);
+ return (d);
+}
+
+/*--------------------------------------------------------------------
+ * Recognize and convert { CNUM [ '.' [ CNUM ] ] } to double value
+ * The tokenizer made sure we only get digits and a '.'
+ */
+
+static void
+vcc_NumVal(struct vcc *tl, double *d, int *frac)
+{
+ double e = 0.1;
+ const char *p;
+
+ *frac = 0;
+ *d = 0.0;
+ Expect(tl, CNUM);
+ if (tl->err) {
+ *d = NAN;
+ return;
+ }
+ for (p = tl->t->b; p < tl->t->e; p++) {
+ *d *= 10;
+ *d += *p - '0';
+ }
+ vcc_NextToken(tl);
+ if (tl->t->tok != '.')
+ return;
+ *frac = 1;
+ vcc_NextToken(tl);
+ if (tl->t->tok != CNUM)
+ return;
+ for (p = tl->t->b; p < tl->t->e; p++) {
+ *d += (*p - '0') * e;
+ e *= 0.1;
+ }
+ vcc_NextToken(tl);
+}
+
+static double
+vcc_DoubleVal(struct vcc *tl)
+{
+ double d;
+ int i;
+
+ vcc_NumVal(tl, &d, &i);
+ return (d);
+}
+
+/*--------------------------------------------------------------------*/
+
+void
+vcc_Duration(struct vcc *tl, double *d)
+{
+ double v, sc;
+
+ v = vcc_DoubleVal(tl);
+ ERRCHK(tl);
+ ExpectErr(tl, ID);
+ sc = vcc_TimeUnit(tl);
+ *d = v * sc;
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+vcc_ByteVal(struct vcc *tl, double *d)
+{
+ double v, sc;
+
+ v = vcc_DoubleVal(tl);
+ ERRCHK(tl);
+ if (tl->t->tok != ID) {
+ VSB_printf(tl->sb, "Expected BYTES unit (B, KB, MB...) got ");
+ vcc_ErrToken(tl, tl->t);
+ VSB_printf(tl->sb, "\n");
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+ if (vcc_IdIs(tl->t, "B"))
+ sc = 1.;
+ else if (vcc_IdIs(tl->t, "KB"))
+ sc = 1024.;
+ else if (vcc_IdIs(tl->t, "MB"))
+ sc = 1024. * 1024.;
+ else if (vcc_IdIs(tl->t, "GB"))
+ sc = 1024. * 1024. * 1024.;
+ else if (vcc_IdIs(tl->t, "TB"))
+ sc = 1024. * 1024. * 1024. * 1024.;
+ else {
+ VSB_printf(tl->sb, "Unknown BYTES unit ");
+ vcc_ErrToken(tl, tl->t);
+ VSB_printf(tl->sb,
+ ". Legal are 'B', 'KB', 'MB', 'GB' and 'TB'\n");
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+ vcc_NextToken(tl);
+ *d = v * sc;
+}
+
+/*--------------------------------------------------------------------
+ * Facility for carrying expressions around and do text-processing on
+ * them.
+ */
+
+struct expr {
+ unsigned magic;
+#define EXPR_MAGIC 0x38c794ab
+ enum var_type fmt;
+ struct vsb *vsb;
+ uint8_t constant;
+#define EXPR_VAR (1<<0)
+#define EXPR_CONST (1<<1)
+#define EXPR_STR_CONST (1<<2)
+ struct token *t1, *t2;
+};
+
+static inline int
+vcc_isconst(const struct expr *e)
+{
+ AN(e->constant);
+ return (e->constant & EXPR_CONST);
+}
+
+static void vcc_expr0(struct vcc *tl, struct expr **e, enum var_type fmt);
+
+static struct expr *
+vcc_new_expr(void)
+{
+ struct expr *e;
+
+ /* XXX: use TlAlloc() ? */
+ ALLOC_OBJ(e, EXPR_MAGIC);
+ AN(e);
+ e->vsb = VSB_new_auto();
+ e->fmt = VOID;
+ e->constant = EXPR_VAR;
+ return (e);
+}
+
+static struct expr *
+vcc_mk_expr(enum var_type fmt, const char *str, ...)
+ __printflike(2, 3);
+
+static struct expr *
+vcc_mk_expr(enum var_type fmt, const char *str, ...)
+{
+ va_list ap;
+ struct expr *e;
+
+ e = vcc_new_expr();
+ e->fmt = fmt;
+ va_start(ap, str);
+ VSB_vprintf(e->vsb, str, ap);
+ va_end(ap);
+ AZ(VSB_finish(e->vsb));
+ return (e);
+}
+
+static void
+vcc_delete_expr(struct expr *e)
+{
+ if (e == NULL)
+ return;
+ CHECK_OBJ_NOTNULL(e, EXPR_MAGIC);
+ VSB_delete(e->vsb);
+ FREE_OBJ(e);
+}
+/*--------------------------------------------------------------------
+ * We want to get the indentation right in the emitted C code so we have
+ * to represent it symbolically until we are ready to render.
+ *
+ * Many of the operations have very schematic output syntaxes, so we
+ * use the same facility to simplify the text-processing of emitting
+ * a given operation on two subexpressions.
+ *
+ * We use '\v' as the magic escape character.
+ * \v1 insert subexpression 1
+ * \v2 insert subexpression 2
+ * \v+ increase indentation
+ * \v- increase indentation
+ * anything else is literal
+ *
+ * When editing, we check if any of the subexpressions contain a newline
+ * and issue it as an indented block of so.
+ *
+ * XXX: check line lengths in edit, should pass indent in for this
+ */
+
+static struct expr *
+vcc_expr_edit(enum var_type fmt, const char *p, struct expr *e1,
+ struct expr *e2)
+{
+ struct expr *e;
+ int nl = 1;
+
+ AN(e1);
+ e = vcc_new_expr();
+ while (*p != '\0') {
+ if (*p != '\v') {
+ if (*p != '\n' || !nl)
+ VSB_putc(e->vsb, *p);
+ nl = (*p == '\n');
+ p++;
+ continue;
+ }
+ assert(*p == '\v');
+ switch(*++p) {
+ case '+': VSB_cat(e->vsb, "\v+"); break;
+ case '-': VSB_cat(e->vsb, "\v-"); break;
+ case '1':
+ VSB_cat(e->vsb, VSB_data(e1->vsb));
+ break;
+ case '2':
+ AN(e2);
+ VSB_cat(e->vsb, VSB_data(e2->vsb));
+ break;
+ default:
+ WRONG("Illegal edit in VCC expression");
+ }
+ p++;
+ }
+ AZ(VSB_finish(e->vsb));
+ e->t1 = e1->t1;
+ e->t2 = e1->t2;
+ if (e2 != NULL)
+ e->t2 = e2->t2;
+ vcc_delete_expr(e1);
+ vcc_delete_expr(e2);
+ e->fmt = fmt;
+ return (e);
+}
+
+/*--------------------------------------------------------------------
+ * Expand finished expression into C-source code
+ */
+
+static void
+vcc_expr_fmt(struct vsb *d, int ind, const struct expr *e1)
+{
+ char *p;
+ int i;
+
+ for (i = 0; i < ind; i++)
+ VSB_cat(d, " ");
+ p = VSB_data(e1->vsb);
+ while (*p != '\0') {
+ if (*p == '\n') {
+ VSB_putc(d, '\n');
+ if (p[1] != '\0') {
+ for (i = 0; i < ind; i++)
+ VSB_cat(d, " ");
+ }
+ p++;
+ continue;
+ }
+ if (*p != '\v') {
+ VSB_putc(d, *p);
+ p++;
+ continue;
+ }
+ p++;
+ switch(*p) {
+ case '+': ind += 2; break;
+ case '-': ind -= 2; break;
+ default:
+ WRONG("Illegal format in VCC expression");
+ }
+ p++;
+ }
+}
+
+/*--------------------------------------------------------------------
+ */
+
+static enum var_type
+vcc_arg_type(const char **p)
+{
+
+#define VCC_TYPE(a) if (!strcmp(#a, *p)) { *p += strlen(#a) + 1; return (a);}
+#include "tbl/vcc_types.h"
+#undef VCC_TYPE
+ return (VOID);
+}
+
+/*--------------------------------------------------------------------
+ */
+
+static void
+vcc_expr_tostring(struct expr **e, enum var_type fmt)
+{
+ const char *p;
+ uint8_t constant = EXPR_VAR;
+
+ CHECK_OBJ_NOTNULL(*e, EXPR_MAGIC);
+ AN(fmt == STRING || fmt == STRING_LIST);
+
+ p = NULL;
+ switch((*e)->fmt) {
+ case BACKEND: p = "VRT_BACKEND_string(\v1)"; break;
+ case BOOL: p = "VRT_BOOL_string(\v1)"; break;
+ case DURATION: p = "VRT_REAL_string(ctx, \v1)"; break;
+ /* XXX: should DURATION insist on "s" suffix ? */
+ case INT:
+ if (vcc_isconst(*e)) {
+ p = "\"\v1\"";
+ constant = EXPR_CONST;
+ } else {
+ p = "VRT_INT_string(ctx, \v1)";
+ }
+ break;
+ case IP: p = "VRT_IP_string(ctx, \v1)"; break;
+ case BYTES: p = "VRT_REAL_string(ctx, \v1)"; break; /* XXX */
+ case REAL: p = "VRT_REAL_string(ctx, \v1)"; break;
+ case TIME: p = "VRT_TIME_string(ctx, \v1)"; break;
+ case HEADER: p = "VRT_GetHdr(ctx, \v1)"; break;
+ case ENUM:
+ case STRING:
+ case STRING_LIST:
+ break;
+ default:
+ INCOMPL();
+ break;
+ }
+ if (p != NULL) {
+ *e = vcc_expr_edit(fmt, p, *e, NULL);
+ (*e)->constant = constant;
+ }
+}
+
+/*--------------------------------------------------------------------
+ */
+
+static void
+vcc_Eval_Regsub(struct vcc *tl, struct expr **e, const struct symbol *sym)
+{
+ struct expr *e2;
+ int all = sym->eval_priv == NULL ? 0 : 1;
+ const char *p;
+ char buf[128];
+
+ vcc_delete_expr(*e);
+ SkipToken(tl, ID);
+ SkipToken(tl, '(');
+
+ vcc_expr0(tl, &e2, STRING);
+ if (e2 == NULL)
+ return;
+ if (e2->fmt != STRING)
+ vcc_expr_tostring(&e2, STRING);
+
+ SkipToken(tl, ',');
+ ExpectErr(tl, CSTR);
+ p = vcc_regexp(tl);
+ vcc_NextToken(tl);
+
+ bprintf(buf, "VRT_regsub(ctx, %d,\v+\n\v1,\n%s", all, p);
+ *e = vcc_expr_edit(STRING, buf, e2, *e);
+
+ SkipToken(tl, ',');
+ vcc_expr0(tl, &e2, STRING);
+ if (e2 == NULL)
+ return;
+ if (e2->fmt != STRING)
+ vcc_expr_tostring(&e2, STRING);
+ *e = vcc_expr_edit(STRING, "\v1,\n\v2)\v-", *e, e2);
+ SkipToken(tl, ')');
+}
+
+/*--------------------------------------------------------------------
+ */
+
+static void
+vcc_Eval_BoolConst(struct vcc *tl, struct expr **e, const struct symbol *sym)
+{
+
+ vcc_NextToken(tl);
+ *e = vcc_mk_expr(BOOL, "(0==%d)", sym->eval_priv == NULL ? 1 : 0);
+ (*e)->constant = EXPR_CONST;
+}
+
+/*--------------------------------------------------------------------
+ */
+
+void
+vcc_Eval_Backend(struct vcc *tl, struct expr **e, const struct symbol *sym)
+{
+
+ assert(sym->kind == SYM_BACKEND);
+
+ vcc_ExpectCid(tl);
+ vcc_AddRef(tl, tl->t, SYM_BACKEND);
+ *e = vcc_mk_expr(BACKEND, "VGCDIR(_%.*s)", PF(tl->t));
+ (*e)->constant = EXPR_VAR; /* XXX ? */
+ vcc_NextToken(tl);
+}
+
+/*--------------------------------------------------------------------
+ */
+void
+vcc_Eval_Var(struct vcc *tl, struct expr **e, const struct symbol *sym)
+{
+ const struct var *vp;
+
+ assert(sym->kind == SYM_VAR);
+ vcc_AddUses(tl, tl->t, sym->r_methods, "Not available");
+ vp = vcc_FindVar(tl, tl->t, 0, "cannot be read");
+ ERRCHK(tl);
+ assert(vp != NULL);
+ *e = vcc_mk_expr(vp->fmt, "%s", vp->rname);
+ vcc_NextToken(tl);
+}
+
+/*--------------------------------------------------------------------
+ */
+
+static void
+vcc_func(struct vcc *tl, struct expr **e, const char *cfunc,
+ const char *extra, const char *name, const char *args)
+{
+ const char *p, *r;
+ struct expr *e1, *e2;
+ enum var_type fmt;
+ char buf[32];
+
+ AN(cfunc);
+ AN(args);
+ AN(name);
+ SkipToken(tl, '(');
+ p = args;
+ if (extra == NULL)
+ extra = "";
+ e2 = vcc_mk_expr(vcc_arg_type(&p), "%s(ctx%s\v+", cfunc, extra);
+ while (*p != '\0') {
+ e1 = NULL;
+ fmt = vcc_arg_type(&p);
+ if (fmt == VOID && !strcmp(p, "PRIV_VCL")) {
+ r = strchr(name, '.');
+ AN(r);
+ e1 = vcc_mk_expr(VOID, "&vmod_priv_%.*s",
+ (int) (r - name), name);
+ p += strlen(p) + 1;
+ } else if (fmt == VOID && !strcmp(p, "PRIV_CALL")) {
+ bprintf(buf, "vmod_priv_%u", tl->nvmodpriv++);
+ 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') /*lint !e448 */
+ SkipToken(tl, ',');
+ } else {
+ vcc_expr0(tl, &e1, fmt);
+ ERRCHK(tl);
+ if (e1->fmt != fmt) {
+ VSB_printf(tl->sb, "Wrong argument type.");
+ VSB_printf(tl->sb, " Expected %s.",
+ vcc_Type(fmt));
+ VSB_printf(tl->sb, " Got %s.\n",
+ vcc_Type(e1->fmt));
+ vcc_ErrWhere2(tl, e1->t1, tl->t);
+ return;
+ }
+ assert(e1->fmt == fmt);
+ if (e1->fmt == STRING_LIST) {
+ e1 = vcc_expr_edit(STRING_LIST,
+ "\v+\n\v1,\nvrt_magic_string_end\v-",
+ e1, NULL);
+ }
+ if (*p != '\0')
+ SkipToken(tl, ',');
+ }
+ e2 = vcc_expr_edit(e2->fmt, "\v1,\n\v2", e2, e1);
+ }
+ SkipToken(tl, ')');
+ e2 = vcc_expr_edit(e2->fmt, "\v1\n)\v-", e2, NULL);
+ *e = e2;
+}
+
+/*--------------------------------------------------------------------
+ */
+
+void
+vcc_Eval_Func(struct vcc *tl, const char *cfunc,
+ const char *extra, const char *name, const char *args)
+{
+ struct expr *e = NULL;
+ struct token *t1;
+
+ t1 = tl->t;
+ vcc_func(tl, &e, cfunc, extra, name, args);
+ if (!tl->err) {
+ vcc_expr_fmt(tl->fb, tl->indent, e);
+ VSB_cat(tl->fb, ";\n");
+ } else if (t1 != tl->t) {
+ vcc_ErrWhere2(tl, t1, tl->t);
+ }
+ vcc_delete_expr(e);
+}
+
+/*--------------------------------------------------------------------
+ */
+
+void
+vcc_Eval_SymFunc(struct vcc *tl, struct expr **e, const struct symbol *sym)
+{
+
+ assert(sym->kind == SYM_FUNC || sym->kind == SYM_PROC);
+ AN(sym->cfunc);
+ AN(sym->name);
+ AN(sym->args);
+ SkipToken(tl, ID);
+ vcc_func(tl, e, sym->cfunc, sym->extra, sym->name, sym->args);
+}
+
+/*--------------------------------------------------------------------
+ * SYNTAX:
+ * Expr4:
+ * '(' Expr0 ')'
+ * CNUM
+ * CSTR
+ */
+
+static void
+vcc_expr4(struct vcc *tl, struct expr **e, enum var_type fmt)
+{
+ struct expr *e1, *e2;
+ const char *ip;
+ const struct symbol *sym;
+ double d;
+
+ *e = NULL;
+ if (tl->t->tok == '(') {
+ SkipToken(tl, '(');
+ vcc_expr0(tl, &e2, fmt);
+ ERRCHK(tl);
+ SkipToken(tl, ')');
+ *e = vcc_expr_edit(e2->fmt, "(\v1)", e2, NULL);
+ return;
+ }
+ switch(tl->t->tok) {
+ case ID:
+ /*
+ * XXX: what if var and func/proc had same name ?
+ * XXX: look for SYM_VAR first for consistency ?
+ */
+ sym = VCC_FindSymbol(tl, tl->t, SYM_NONE);
+ if (sym == NULL || sym->eval == NULL) {
+ VSB_printf(tl->sb, "Symbol not found: ");
+ vcc_ErrToken(tl, tl->t);
+ VSB_printf(tl->sb, " (expected type %s):\n",
+ vcc_Type(fmt));
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+ AN(sym);
+ switch(sym->kind) {
+ case SYM_VAR:
+ case SYM_FUNC:
+ case SYM_BACKEND:
+ AN(sym->eval);
+ AZ(*e);
+ sym->eval(tl, e, sym);
+ return;
+ default:
+ break;
+ }
+ VSB_printf(tl->sb,
+ "Symbol type (%s) can not be used in expression.\n",
+ VCC_SymKind(tl, sym));
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ case CSTR:
+ assert(fmt != VOID);
+ if (fmt == IP) {
+ Resolve_Sockaddr(tl, tl->t->dec, "80",
+ &ip, NULL, &ip, NULL, NULL, 1,
+ tl->t, "IP constant");
+ ERRCHK(tl);
+ e1 = vcc_mk_expr(IP, "%s", ip);
+ ERRCHK(tl);
+ } else {
+ e1 = vcc_new_expr();
+ EncToken(e1->vsb, tl->t);
+ e1->fmt = STRING;
+ AZ(VSB_finish(e1->vsb));
+ }
+ e1->t1 = tl->t;
+ e1->constant = EXPR_CONST;
+ vcc_NextToken(tl);
+ *e = e1;
+ break;
+ case CNUM:
+ /*
+ * XXX: %g may not have enough decimals by default
+ * XXX: but %a is ugly, isn't it ?
+ */
+ assert(fmt != VOID);
+ if (fmt == DURATION) {
+ vcc_Duration(tl, &d);
+ ERRCHK(tl);
+ e1 = vcc_mk_expr(DURATION, "%g", d);
+ } else if (fmt == BYTES) {
+ vcc_ByteVal(tl, &d);
+ ERRCHK(tl);
+ e1 = vcc_mk_expr(BYTES, "%.1f", d);
+ ERRCHK(tl);
+ } else if (fmt == REAL) {
+ e1 = vcc_mk_expr(REAL, "%g", vcc_DoubleVal(tl));
+ ERRCHK(tl);
+ } else {
+ e1 = vcc_mk_expr(INT, "%.*s", PF(tl->t));
+ vcc_NextToken(tl);
+ }
+ e1->constant = EXPR_CONST;
+ *e = e1;
+ break;
+ default:
+ VSB_printf(tl->sb, "Unknown token ");
+ vcc_ErrToken(tl, tl->t);
+ VSB_printf(tl->sb, " when looking for %s\n\n", vcc_Type(fmt));
+ vcc_ErrWhere(tl, tl->t);
+ break;
+ }
+}
+
+/*--------------------------------------------------------------------
+ * SYNTAX:
+ * Expr3:
+ * Expr4 { {'*'|'/'} Expr4 } *
+ */
+
+static void
+vcc_expr_mul(struct vcc *tl, struct expr **e, enum var_type fmt)
+{
+ struct expr *e2;
+ enum var_type f2, f3;
+ struct token *tk;
+
+ *e = NULL;
+ vcc_expr4(tl, e, fmt);
+ ERRCHK(tl);
+ f3 = f2 = (*e)->fmt;
+
+ switch(f2) {
+ case INT: f2 = INT; break;
+ case DURATION: f2 = REAL; break;
+ case BYTES: f2 = REAL; break;
+ default:
+ if (tl->t->tok != '*' && tl->t->tok != '/')
+ return;
+ VSB_printf(tl->sb, "Operator %.*s not possible on type %s.\n",
+ PF(tl->t), vcc_Type(f2));
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+
+ while (tl->t->tok == '*' || tl->t->tok == '/') {
+ tk = tl->t;
+ vcc_NextToken(tl);
+ vcc_expr4(tl, &e2, f2);
+ ERRCHK(tl);
+ assert(e2->fmt == f2);
+ if (tk->tok == '*')
+ *e = vcc_expr_edit(f3, "(\v1*\v2)", *e, e2);
+ else
+ *e = vcc_expr_edit(f3, "(\v1/\v2)", *e, e2);
+ }
+}
+
+/*--------------------------------------------------------------------
+ * SYNTAX:
+ * ExprAdd:
+ * ExprMul { {'+'|'-'} ExprMul } *
+ *
+ * For reasons of memory allocation/copying and general performance,
+ * STRINGs in VCL are quite special. Addition/concatenation is split
+ * into it's own subfunction to encapsulate this.
+ */
+
+static void
+vcc_expr_string_add(struct vcc *tl, struct expr **e)
+{
+ struct expr *e2;
+ enum var_type f2;
+
+ f2 = (*e)->fmt;
+
+ while (tl->t->tok == '+') {
+ vcc_NextToken(tl);
+ vcc_expr_mul(tl, &e2, STRING);
+ ERRCHK(tl);
+ if (e2->fmt != STRING && e2->fmt != STRING_LIST)
+ vcc_expr_tostring(&e2, f2);
+ ERRCHK(tl);
+ assert(e2->fmt == STRING || e2->fmt == STRING_LIST);
+
+ if (vcc_isconst(*e) && vcc_isconst(e2)) {
+ assert((*e)->fmt == STRING);
+ assert(e2->fmt == STRING);
+ *e = vcc_expr_edit(STRING, "\v1\n\v2", *e, e2);
+ (*e)->constant = EXPR_CONST;
+ } else if (((*e)->constant & EXPR_STR_CONST) &&
+ vcc_isconst(e2)) {
+ assert((*e)->fmt == STRING_LIST);
+ assert(e2->fmt == STRING);
+ *e = vcc_expr_edit(STRING_LIST, "\v1\n\v2", *e, e2);
+ (*e)->constant = EXPR_VAR | EXPR_STR_CONST;
+ } else if (e2->fmt == STRING && vcc_isconst(e2)) {
+ *e = vcc_expr_edit(STRING_LIST, "\v1,\n\v2", *e, e2);
+ (*e)->constant = EXPR_VAR | EXPR_STR_CONST;
+ } else {
+ *e = vcc_expr_edit(STRING_LIST, "\v1,\n\v2", *e, e2);
+ (*e)->constant = EXPR_VAR;
+ }
+ }
+}
+
+static void
+vcc_expr_add(struct vcc *tl, struct expr **e, enum var_type fmt)
+{
+ struct expr *e2;
+ enum var_type f2;
+ struct token *tk;
+
+ *e = NULL;
+ vcc_expr_mul(tl, e, fmt);
+ ERRCHK(tl);
+ f2 = (*e)->fmt;
+
+ /* Unless we specifically ask for a HEADER, fold them to string here */
+ if (fmt != HEADER && f2 == HEADER) {
+ vcc_expr_tostring(e, STRING);
+ f2 = (*e)->fmt;
+ assert(f2 == STRING);
+ }
+
+ if (tl->t->tok != '+' && tl->t->tok != '-')
+ return;
+
+ switch(f2) {
+ case STRING:
+ case STRING_LIST:
+ vcc_expr_string_add(tl, e);
+ return;
+ case INT: break;
+ case TIME: break;
+ case DURATION: break;
+ case BYTES: break;
+ default:
+ VSB_printf(tl->sb, "Operator %.*s not possible on type %s.\n",
+ PF(tl->t), vcc_Type(f2));
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+
+ while (tl->t->tok == '+' || tl->t->tok == '-') {
+ if (f2 == TIME)
+ f2 = DURATION;
+ tk = tl->t;
+ vcc_NextToken(tl);
+ vcc_expr_mul(tl, &e2, f2);
+ ERRCHK(tl);
+ if (tk->tok == '-' && (*e)->fmt == TIME && e2->fmt == TIME) {
+ /* OK */
+ } else if ((*e)->fmt == TIME && e2->fmt == DURATION) {
+ f2 = TIME;
+ /* OK */
+ } else if (tk->tok == '-' &&
+ (*e)->fmt == BYTES && e2->fmt == BYTES) {
+ /* OK */
+ } else if (e2->fmt != f2) {
+ VSB_printf(tl->sb, "%s %.*s %s not possible.\n",
+ vcc_Type((*e)->fmt), PF(tk), vcc_Type(e2->fmt));
+ vcc_ErrWhere2(tl, tk, tl->t);
+ return;
+ }
+ if (tk->tok == '+')
+ *e = vcc_expr_edit(f2, "(\v1+\v2)", *e, e2);
+ else if (f2 == TIME && e2->fmt == TIME)
+ *e = vcc_expr_edit(DURATION, "(\v1-\v2)", *e, e2);
+ else
+ *e = vcc_expr_edit(f2, "(\v1-\v2)", *e, e2);
+ }
+}
+
+/*--------------------------------------------------------------------
+ * Fold the STRING types correctly
+ */
+
+static void
+vcc_expr_strfold(struct vcc *tl, struct expr **e, enum var_type fmt)
+{
+
+ vcc_expr_add(tl, e, fmt);
+ ERRCHK(tl);
+
+ if (fmt != STRING_LIST && (*e)->fmt == STRING_LIST)
+ *e = vcc_expr_edit(STRING,
+ "\v+VRT_CollectString(ctx,\n\v1,\nvrt_magic_string_end)\v-",
+ *e, NULL);
+ if (fmt == STRING_LIST && (*e)->fmt == STRING)
+ (*e)->fmt = STRING_LIST;
+}
+
+/*--------------------------------------------------------------------
+ * SYNTAX:
+ * ExprCmp:
+ * ExprAdd
+ * ExprAdd Relation ExprAdd
+ * ExprAdd(STRING) '~' CString
+ * ExprAdd(STRING) '!~' CString
+ * ExprAdd(IP) '~' IP
+ * ExprAdd(IP) '!~' IP
+ */
+
+#define NUM_REL(typ) \
+ {typ, T_EQ, "(\v1 == \v2)" }, \
+ {typ, T_NEQ, "(\v1 != \v2)" }, \
+ {typ, T_LEQ, "(\v1 <= \v2)" }, \
+ {typ, T_GEQ, "(\v1 >= \v2)" }, \
+ {typ, '<', "(\v1 < \v2)" }, \
+ {typ, '>', "(\v1 > \v2)" }
+
+static const struct cmps {
+ enum var_type fmt;
+ unsigned token;
+ const char *emit;
+} vcc_cmps[] = {
+ NUM_REL(INT),
+ NUM_REL(DURATION),
+ NUM_REL(BYTES),
+ NUM_REL(REAL),
+
+ {STRING, T_EQ, "!VRT_strcmp(\v1, \v2)" },
+ {STRING, T_NEQ, "VRT_strcmp(\v1, \v2)" },
+
+ {VOID, 0, NULL}
+};
+
+#undef NUM_REL
+
+static void
+vcc_expr_cmp(struct vcc *tl, struct expr **e, enum var_type fmt)
+{
+ struct expr *e2;
+ const struct cmps *cp;
+ char buf[256];
+ const char *re;
+ const char *not;
+ struct token *tk;
+
+ *e = NULL;
+
+ vcc_expr_strfold(tl, e, fmt);
+ ERRCHK(tl);
+
+ if ((*e)->fmt == BOOL)
+ return;
+
+ tk = tl->t;
+ for (cp = vcc_cmps; cp->fmt != VOID; cp++)
+ if ((*e)->fmt == cp->fmt && tl->t->tok == cp->token)
+ break;
+ if (cp->fmt != VOID) {
+ vcc_NextToken(tl);
+ vcc_expr_strfold(tl, &e2, (*e)->fmt);
+ ERRCHK(tl);
+ if (e2->fmt != (*e)->fmt) { /* XXX */
+ VSB_printf(tl->sb, "Comparison of different types: ");
+ VSB_printf(tl->sb, "%s ", vcc_Type((*e)->fmt));
+ vcc_ErrToken(tl, tk);
+ VSB_printf(tl->sb, " %s\n", vcc_Type(e2->fmt));
+ vcc_ErrWhere(tl, tk);
+ return;
+ }
+ *e = vcc_expr_edit(BOOL, cp->emit, *e, e2);
+ return;
+ }
+ if ((*e)->fmt == STRING &&
+ (tl->t->tok == '~' || tl->t->tok == T_NOMATCH)) {
+ not = tl->t->tok == '~' ? "" : "!";
+ vcc_NextToken(tl);
+ ExpectErr(tl, CSTR);
+ re = vcc_regexp(tl);
+ ERRCHK(tl);
+ vcc_NextToken(tl);
+ bprintf(buf, "%sVRT_re_match(ctx, \v1, %s)", not, re);
+ *e = vcc_expr_edit(BOOL, buf, *e, NULL);
+ return;
+ }
+ if ((*e)->fmt == IP &&
+ (tl->t->tok == '~' || tl->t->tok == T_NOMATCH)) {
+ not = tl->t->tok == '~' ? "" : "!";
+ vcc_NextToken(tl);
+ ExpectErr(tl, ID);
+ vcc_AddRef(tl, tl->t, SYM_ACL);
+ bprintf(buf, "%smatch_acl_named_%.*s(ctx, \v1)",
+ not, PF(tl->t));
+ vcc_NextToken(tl);
+ *e = vcc_expr_edit(BOOL, buf, *e, NULL);
+ return;
+ }
+ if ((*e)->fmt == IP && (tl->t->tok == T_EQ || tl->t->tok == T_NEQ)) {
+ vcc_Acl_Hack(tl, buf);
+ *e = vcc_expr_edit(BOOL, buf, *e, NULL);
+ return;
+ }
+ if ((*e)->fmt == BACKEND &&
+ (tl->t->tok == T_EQ || tl->t->tok == T_NEQ)) {
+ vcc_NextToken(tl);
+ ExpectErr(tl, ID);
+ vcc_AddRef(tl, tl->t, SYM_BACKEND);
+ bprintf(buf, "(\v1 %.*s VGCDIR(_%.*s))", PF(tk), PF(tl->t));
+ vcc_NextToken(tl);
+ *e = vcc_expr_edit(BOOL, buf, *e, NULL);
+ return;
+ }
+ switch (tl->t->tok) {
+ case T_EQ:
+ case T_NEQ:
+ case '<':
+ case T_LEQ:
+ case '>':
+ case T_GEQ:
+ case '~':
+ case T_NOMATCH:
+ VSB_printf(tl->sb, "Operator %.*s not possible on %s\n",
+ PF(tl->t), vcc_Type((*e)->fmt));
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ default:
+ break;
+ }
+ if (fmt == BOOL && (*e)->fmt == STRING) {
+ *e = vcc_expr_edit(BOOL, "(\v1 != 0)", *e, NULL);
+ return;
+ }
+}
+
+/*--------------------------------------------------------------------
+ * SYNTAX:
+ * ExprNot:
+ * '!' ExprCmp
+ */
+
+static void
+vcc_expr_not(struct vcc *tl, struct expr **e, enum var_type fmt)
+{
+ struct expr *e2;
+ struct token *tk;
+
+ *e = NULL;
+ if (fmt != BOOL || tl->t->tok != '!') {
+ vcc_expr_cmp(tl, e, fmt);
+ return;
+ }
+
+ vcc_NextToken(tl);
+ tk = tl->t;
+ vcc_expr_cmp(tl, &e2, fmt);
+ ERRCHK(tl);
+ if (e2->fmt == BOOL) {
+ *e = vcc_expr_edit(BOOL, "!(\v1)", e2, NULL);
+ return;
+ }
+ VSB_printf(tl->sb, "'!' must be followed by BOOL, found ");
+ VSB_printf(tl->sb, "%s.\n", vcc_Type(e2->fmt));
+ vcc_ErrWhere2(tl, tk, tl->t);
+}
+
+/*--------------------------------------------------------------------
+ * SYNTAX:
+ * ExprCand:
+ * ExprNot { '&&' ExprNot } *
+ */
+
+static void
+vcc_expr_cand(struct vcc *tl, struct expr **e, enum var_type fmt)
+{
+ struct expr *e2;
+ struct token *tk;
+
+ *e = NULL;
+ vcc_expr_not(tl, e, fmt);
+ ERRCHK(tl);
+ if ((*e)->fmt != BOOL || tl->t->tok != T_CAND)
+ return;
+ *e = vcc_expr_edit(BOOL, "(\v+\n\v1", *e, NULL);
+ while (tl->t->tok == T_CAND) {
+ vcc_NextToken(tl);
+ tk = tl->t;
+ vcc_expr_not(tl, &e2, fmt);
+ ERRCHK(tl);
+ if (e2->fmt != BOOL) {
+ VSB_printf(tl->sb,
+ "'&&' must be followed by BOOL, found ");
+ VSB_printf(tl->sb, "%s.\n", vcc_Type(e2->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(BOOL, "\v1\v-\n)", *e, NULL);
+}
+
+/*--------------------------------------------------------------------
+ * SYNTAX:
+ * Expr0:
+ * ExprCand { '||' ExprCand } *
+ */
+
+static void
+vcc_expr0(struct vcc *tl, struct expr **e, enum var_type fmt)
+{
+ struct expr *e2;
+ struct token *tk;
+
+ *e = NULL;
+ vcc_expr_cand(tl, e, fmt);
+ ERRCHK(tl);
+ if ((*e)->fmt != BOOL || tl->t->tok != T_COR)
+ return;
+ *e = vcc_expr_edit(BOOL, "(\v+\n\v1", *e, NULL);
+ while (tl->t->tok == T_COR) {
+ vcc_NextToken(tl);
+ tk = tl->t;
+ vcc_expr_cand(tl, &e2, fmt);
+ ERRCHK(tl);
+ if (e2->fmt != BOOL) {
+ VSB_printf(tl->sb,
+ "'||' must be followed by BOOL, found ");
+ VSB_printf(tl->sb, "%s.\n", vcc_Type(e2->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(BOOL, "\v1\v-\n)", *e, NULL);
+}
+
+/*--------------------------------------------------------------------
+ * This function parses and emits the C-code to evaluate an expression
+ *
+ * We know up front what kind of type we want the expression to be,
+ * and this function is the backstop if that doesn't succeed.
+ */
+
+void
+vcc_Expr(struct vcc *tl, enum var_type fmt)
+{
+ struct expr *e;
+ struct token *t1;
+
+ assert(fmt != VOID);
+
+ t1 = tl->t;
+ vcc_expr0(tl, &e, fmt);
+ ERRCHK(tl);
+ if (fmt == STRING || fmt == STRING_LIST)
+ vcc_expr_tostring(&e, fmt);
+ if (!tl->err && fmt != e->fmt) {
+ VSB_printf(tl->sb, "Expression has type %s, expected %s\n",
+ vcc_Type(e->fmt), vcc_Type(fmt));
+ tl->err = 1;
+ }
+ if (!tl->err) {
+ if (e->fmt == STRING_LIST) {
+ e = vcc_expr_edit(STRING_LIST,
+ "\v+\n\v1,\nvrt_magic_string_end\v-", e, NULL);
+ }
+ vcc_expr_fmt(tl->fb, tl->indent, e);
+ VSB_putc(tl->fb, '\n');
+ } else {
+ if (t1 != tl->t)
+ vcc_ErrWhere2(tl, t1, tl->t);
+ }
+ vcc_delete_expr(e);
+}
+
+/*--------------------------------------------------------------------
+ */
+
+void
+vcc_Expr_Call(struct vcc *tl, const struct symbol *sym)
+{
+
+ struct expr *e;
+ struct token *t1;
+
+ t1 = tl->t;
+ e = NULL;
+ vcc_Eval_SymFunc(tl, &e, sym);
+ if (!tl->err) {
+ vcc_expr_fmt(tl->fb, tl->indent, e);
+ VSB_cat(tl->fb, ";\n");
+ } else if (t1 != tl->t) {
+ vcc_ErrWhere2(tl, t1, tl->t);
+ }
+ vcc_delete_expr(e);
+}
+
+/*--------------------------------------------------------------------
+ */
+
+void
+vcc_Expr_Init(struct vcc *tl)
+{
+ struct symbol *sym;
+
+ sym = VCC_AddSymbolStr(tl, "regsub", SYM_FUNC);
+ AN(sym);
+ sym->eval = vcc_Eval_Regsub;
+ sym->eval_priv = NULL;
+
+ sym = VCC_AddSymbolStr(tl, "regsuball", SYM_FUNC);
+ AN(sym);
+ sym->eval = vcc_Eval_Regsub;
+ sym->eval_priv = sym;
+
+ sym = VCC_AddSymbolStr(tl, "true", SYM_FUNC);
+ AN(sym);
+ sym->eval = vcc_Eval_BoolConst;
+ sym->eval_priv = sym;
+
+ sym = VCC_AddSymbolStr(tl, "false", SYM_FUNC);
+ AN(sym);
+ sym->eval = vcc_Eval_BoolConst;
+ sym->eval_priv = NULL;
+}
diff --git a/lib/libvcc/vcc_parse.c b/lib/libvcc/vcc_parse.c
new file mode 100644
index 0000000..ab562f5
--- /dev/null
+++ b/lib/libvcc/vcc_parse.c
@@ -0,0 +1,359 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2013 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "vcc_compile.h"
+
+/*--------------------------------------------------------------------*/
+
+static void vcc_Compound(struct vcc *tl);
+
+/*--------------------------------------------------------------------*/
+
+#define L(tl, foo) do { \
+ tl->indent += INDENT; \
+ foo; \
+ tl->indent -= INDENT; \
+} while (0)
+
+#define C(tl, sep) do { \
+ Fb(tl, 1, "VRT_count(ctx, %u)%s\n", ++tl->cnt, sep); \
+ tl->t->cnt = tl->cnt; \
+} while (0)
+
+/*--------------------------------------------------------------------
+ * SYNTAX:
+ * Conditional:
+ * '(' Cond_0 ')'
+ */
+
+static void
+vcc_Conditional(struct vcc *tl)
+{
+
+ SkipToken(tl, '(');
+ Fb(tl, 0, "(\n");
+ L(tl, vcc_Expr(tl, BOOL));
+ ERRCHK(tl);
+ Fb(tl, 1, ")\n");
+ SkipToken(tl, ')');
+}
+
+/*--------------------------------------------------------------------
+ * SYNTAX:
+ * IfStmt:
+ * 'if' Conditional Compound Branch1* Branch2
+ * Branch1:
+ * 'elseif' Conditional Compound
+ * Branch2:
+ * 'else' Compound
+ * null
+ */
+
+static void
+vcc_IfStmt(struct vcc *tl)
+{
+
+ SkipToken(tl, ID);
+ Fb(tl, 1, "if ");
+ vcc_Conditional(tl);
+ ERRCHK(tl);
+ L(tl, vcc_Compound(tl));
+ ERRCHK(tl);
+ while (tl->t->tok == ID) {
+ if (vcc_IdIs(tl->t, "else")) {
+ vcc_NextToken(tl);
+ if (tl->t->tok == '{') {
+ Fb(tl, 1, "else\n");
+ L(tl, vcc_Compound(tl));
+ ERRCHK(tl);
+ return;
+ }
+ if (tl->t->tok != ID || !vcc_IdIs(tl->t, "if")) {
+ VSB_printf(tl->sb,
+ "'else' must be followed by 'if' or '{'\n");
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+ Fb(tl, 1, "else if ");
+ vcc_NextToken(tl);
+ vcc_Conditional(tl);
+ ERRCHK(tl);
+ L(tl, vcc_Compound(tl));
+ ERRCHK(tl);
+ } else if (vcc_IdIs(tl->t, "elseif") ||
+ vcc_IdIs(tl->t, "elsif") ||
+ vcc_IdIs(tl->t, "elif")) {
+ Fb(tl, 1, "else if ");
+ vcc_NextToken(tl);
+ vcc_Conditional(tl);
+ ERRCHK(tl);
+ L(tl, vcc_Compound(tl));
+ ERRCHK(tl);
+ } else {
+ break;
+ }
+ }
+ C(tl, ";");
+}
+
+/*--------------------------------------------------------------------
+ * SYNTAX:
+ * Compound:
+ * '{' Stmt* '}'
+ *
+ * Stmt:
+ * Compound
+ * IfStmt
+ * CSRC
+ * Id(Action) (XXX)
+ */
+
+static void
+vcc_Compound(struct vcc *tl)
+{
+ int i;
+
+ SkipToken(tl, '{');
+ Fb(tl, 1, "{\n");
+ tl->indent += INDENT;
+ C(tl, ";");
+ while (1) {
+ ERRCHK(tl);
+ switch (tl->t->tok) {
+ case '{':
+ vcc_Compound(tl);
+ break;
+ case '}':
+ vcc_NextToken(tl);
+ tl->indent -= INDENT;
+ Fb(tl, 1, "}\n");
+ return;
+ case CSRC:
+ if (tl->allow_inline_c) {
+ Fb(tl, 1, "%.*s\n",
+ (int) (tl->t->e - (tl->t->b + 2)),
+ tl->t->b + 1);
+ vcc_NextToken(tl);
+ } else {
+ VSB_printf(tl->sb,
+ "Inline-C not allowed\n");
+ vcc_ErrWhere(tl, tl->t);
+ }
+ break;
+ case EOI:
+ VSB_printf(tl->sb,
+ "End of input while in compound statement\n");
+ tl->err = 1;
+ return;
+ case ID:
+ if (vcc_IdIs(tl->t, "if")) {
+ vcc_IfStmt(tl);
+ break;
+ } else {
+ i = vcc_ParseAction(tl);
+ ERRCHK(tl);
+ if (i) {
+ SkipToken(tl, ';');
+ break;
+ }
+ }
+ /* FALLTHROUGH */
+ default:
+ /* We deliberately do not mention inline C */
+ VSB_printf(tl->sb,
+ "Expected an action, 'if', '{' or '}'\n");
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+ }
+}
+
+/*--------------------------------------------------------------------
+ * SYNTAX:
+ * Function:
+ * 'sub' ID(name) Compound
+ */
+
+static void
+vcc_Function(struct vcc *tl)
+{
+ int m, i;
+
+ vcc_NextToken(tl);
+ ExpectErr(tl, ID);
+ if (!vcc_isCid(tl->t)) {
+ VSB_printf(tl->sb,
+ "Names of VCL sub's cannot contain '-'\n");
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+
+ m = IsMethod(tl->t);
+ if (m == -2) {
+ VSB_printf(tl->sb,
+ "VCL sub's named 'vcl*' are reserved names.\n");
+ vcc_ErrWhere(tl, tl->t);
+ VSB_printf(tl->sb, "Valid vcl_* methods are:\n");
+ for (i = 0; method_tab[i].name != NULL; i++)
+ VSB_printf(tl->sb, "\t%s\n", method_tab[i].name);
+ return;
+ } else if (m != -1) {
+ assert(m < VCL_MET_MAX);
+ tl->fb = tl->fm[m];
+ if (tl->mprocs[m] == NULL) {
+ (void)vcc_AddDef(tl, tl->t, SYM_SUB);
+ vcc_AddRef(tl, tl->t, SYM_SUB);
+ tl->mprocs[m] = vcc_AddProc(tl, tl->t);
+ }
+ tl->curproc = tl->mprocs[m];
+ Fb(tl, 1, " /* ... from ");
+ vcc_Coord(tl, tl->fb, NULL);
+ Fb(tl, 0, " */\n");
+ } else {
+ tl->fb = tl->fc;
+ i = vcc_AddDef(tl, tl->t, SYM_SUB);
+ if (i > 1) {
+ VSB_printf(tl->sb,
+ "Function %.*s redefined\n", PF(tl->t));
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+ tl->curproc = vcc_AddProc(tl, tl->t);
+ Fh(tl, 0, "static int VGC_function_%.*s "
+ "(struct vrt_ctx *ctx);\n", PF(tl->t));
+ Fc(tl, 1, "\nstatic int __match_proto__(vcl_func_t)\n");
+ Fc(tl, 1, "VGC_function_%.*s(struct vrt_ctx *ctx)\n",
+ PF(tl->t));
+ }
+ vcc_NextToken(tl);
+ tl->indent += INDENT;
+ Fb(tl, 1, "{\n");
+ L(tl, vcc_Compound(tl));
+ if (m == -1) {
+ /*
+ * non-method subroutines must have an explicit non-action
+ * return in case they just fall through the bottom.
+ */
+ Fb(tl, 1, " return(0);\n");
+ }
+ Fb(tl, 1, "}\n");
+ tl->indent -= INDENT;
+ tl->fb = NULL;
+ tl->curproc = NULL;
+}
+
+/*--------------------------------------------------------------------
+ */
+
+static void
+vcc_Director(struct vcc *tl)
+{
+ VSB_printf(tl->sb, "\ndirectors are now in directors VMOD.\n");
+ vcc_ErrWhere(tl, tl->t);
+}
+
+/*--------------------------------------------------------------------
+ * Top level of parser, recognize:
+ * Inline C-code
+ * ACL definitions
+ * Function definitions
+ * Backend & Director definitions
+ * End of input
+ */
+
+typedef void parse_f(struct vcc *tl);
+
+static struct toplev {
+ const char *name;
+ parse_f *func;
+} toplev[] = {
+ { "acl", vcc_Acl },
+ { "sub", vcc_Function },
+ { "backend", vcc_ParseBackend },
+ { "director", vcc_Director },
+ { "probe", vcc_ParseProbe },
+ { "import", vcc_ParseImport },
+ { NULL, NULL }
+};
+
+void
+vcc_Parse(struct vcc *tl)
+{
+ struct toplev *tp;
+
+ while (tl->t->tok != EOI) {
+ ERRCHK(tl);
+ switch (tl->t->tok) {
+ case CSRC:
+ if (tl->allow_inline_c) {
+ Fc(tl, 0, "%.*s\n",
+ (int) (tl->t->e - (tl->t->b + 4)),
+ tl->t->b + 2);
+ vcc_NextToken(tl);
+ } else {
+ VSB_printf(tl->sb,
+ "Inline-C not allowed\n");
+ vcc_ErrWhere(tl, tl->t);
+ }
+ break;
+ case EOI:
+ break;
+ case ID:
+ for (tp = toplev; tp->name != NULL; tp++) {
+ if (!vcc_IdIs(tl->t, tp->name))
+ continue;
+ tp->func(tl);
+ break;
+ }
+ if (tp->name != NULL)
+ break;
+ /* FALLTHROUGH */
+ default:
+ /* We deliberately do not mention inline-C */
+ VSB_printf(tl->sb, "Expected one of\n\t");
+ for (tp = toplev; tp->name != NULL; tp++) {
+ if (tp[1].name == NULL)
+ VSB_printf(tl->sb, " or ");
+ VSB_printf(tl->sb, "'%s'", tp->name);
+ if (tp[1].name != NULL)
+ VSB_printf(tl->sb, ", ");
+ }
+ VSB_printf(tl->sb, "\nFound: ");
+ vcc_ErrToken(tl, tl->t);
+ VSB_printf(tl->sb, " at\n");
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+ }
+}
diff --git a/lib/libvcc/vcc_storage.c b/lib/libvcc/vcc_storage.c
new file mode 100644
index 0000000..5f9712a
--- /dev/null
+++ b/lib/libvcc/vcc_storage.c
@@ -0,0 +1,149 @@
+/*-
+ * Copyright (c) 2010 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * All stuff related to the storage.* part of the namespace.
+ *
+ * "All" is actually only a wildcard function, which instantiates variables
+ * on demand under the storage.* tree of the namespace.
+ *
+ * About the syntax:
+ * -----------------
+ *
+ * One of our long term goals is to have dynamic storage configuration, such
+ * as the ability to add or remove a stevedore on the fly, without restarting
+ * the worker process.
+ *
+ * Even though this goal is far out in the future, it influences the syntax
+ * design of storage selection from VCL.
+ *
+ * In difference from backends, where we know the possible set of backends at
+ * compile time, we will not in the future know the identity of the stevedores
+ * available at compile time, so we have to rely on VRT name resolution.
+ *
+ * This indicates a namespace on the form storage.<stevedore>.<property>
+ *
+ * For each property, we must define a default value if the named stevedore
+ * does not exists, such that for instance stevedore.forgetit.freespace
+ * returns zero etc.
+ *
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "vcc_compile.h"
+
+#define PFX "storage."
+
+/*--------------------------------------------------------------------
+ *
+ */
+
+static struct var *
+vcc_Stv_mkvar(struct vcc *tl, const struct token *t, enum var_type fmt)
+{
+ struct var *v;
+
+ v = TlAlloc(tl, sizeof *v);
+ AN(v);
+
+ v->name = TlDupTok(tl, t);
+ v->r_methods = 0
+#define VCL_MET_MAC(l,u,b) | VCL_MET_##u
+#include "tbl/vcl_returns.h"
+#undef VCL_MET_MAC
+ ;
+ v->fmt = fmt;
+
+ return (v);
+}
+
+static struct stvars {
+ const char *name;
+ enum var_type fmt;
+} stvars[] = {
+#define VRTSTVVAR(nm, vtype, ctype, dval) { #nm, vtype },
+#include "tbl/vrt_stv_var.h"
+#undef VRTSTVVAR
+ { NULL, BOOL }
+};
+
+struct symbol *
+vcc_Stv_Wildcard(struct vcc *tl, const struct token *t,
+ const struct symbol *wcsym)
+{
+ const char *p, *q;
+ struct var *v = NULL;
+ struct symbol *sym;
+ struct stvars *sv;
+ char stv[1024];
+ char buf[1024];
+
+ (void)wcsym;
+ assert((t->e - t->b) > strlen(PFX));
+ assert(!memcmp(t->b, PFX, strlen(PFX)));
+
+ p = t->b + strlen(PFX);
+ for (q = p; q < t->e && *q != '.'; q++)
+ continue;
+ bprintf(stv, "%.*s", (int)(q - p), p);
+
+ if (q == t->e) {
+ v = vcc_Stv_mkvar(tl, t, BOOL);
+ bprintf(buf, "VRT_Stv(\"%s\")", stv);
+ v->rname = TlDup(tl, buf);
+ } else {
+ assert(*q == '.');
+ q++;
+ for(sv = stvars; sv->name != NULL; sv++) {
+ if (strncmp(q, sv->name, t->e - q))
+ continue;
+ if (sv->name[t->e - q] != '\0')
+ continue;
+ v = vcc_Stv_mkvar(tl, t, sv->fmt);
+ bprintf(buf, "VRT_Stv_%s(\"%s\")", sv->name, stv);
+ v->rname = TlDup(tl, buf);
+ break;
+ }
+ }
+
+ if (v == NULL)
+ return (NULL);
+
+ sym = VCC_AddSymbolTok(tl, t, SYM_VAR);
+ AN(sym);
+ sym->var = v;
+ sym->fmt = v->fmt;
+ sym->eval = vcc_Eval_Var;
+ sym->r_methods = v->r_methods;
+
+ return (sym);
+}
diff --git a/lib/libvcc/vcc_symb.c b/lib/libvcc/vcc_symb.c
new file mode 100644
index 0000000..c3d8a13
--- /dev/null
+++ b/lib/libvcc/vcc_symb.c
@@ -0,0 +1,142 @@
+/*-
+ * Copyright (c) 2010 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "vcc_compile.h"
+
+/*--------------------------------------------------------------------*/
+
+const char *
+VCC_SymKind(struct vcc *tl, const struct symbol *s)
+{
+ switch(s->kind) {
+#define VCC_SYMB(uu, ll) case SYM_##uu: return(#ll);
+#include "tbl/symbol_kind.h"
+#undef VCC_SYMB
+ default:
+ ErrInternal(tl);
+ VSB_printf(tl->sb, "Symbol Kind 0x%x\n", s->kind);
+ return("INTERNALERROR");
+ }
+}
+
+
+static struct symbol *
+vcc_AddSymbol(struct vcc *tl, const char *nb, int l, enum symkind kind)
+{
+ struct symbol *sym;
+
+ VTAILQ_FOREACH(sym, &tl->symbols, list) {
+ if (sym->nlen != l)
+ continue;
+ if (memcmp(nb, sym->name, l))
+ continue;
+ if (kind != sym->kind)
+ continue;
+ VSB_printf(tl->sb, "Name Collision: <%.*s> <%s>\n",
+ l, nb, VCC_SymKind(tl, sym));
+ ErrInternal(tl);
+ return (NULL);
+ }
+ ALLOC_OBJ(sym, SYMBOL_MAGIC);
+ AN(sym);
+ sym->name = malloc(l + 1L);
+ AN(sym->name);
+ memcpy(sym->name, nb, l);
+ sym->name[l] = '\0';
+ sym->nlen = l;
+ VTAILQ_INSERT_HEAD(&tl->symbols, sym, list);
+ sym->kind = kind;
+ return (sym);
+}
+
+struct symbol *
+VCC_AddSymbolStr(struct vcc *tl, const char *name, enum symkind kind)
+{
+
+ return (vcc_AddSymbol(tl, name, strlen(name), kind));
+}
+
+struct symbol *
+VCC_AddSymbolTok(struct vcc *tl, const struct token *t, enum symkind kind)
+{
+
+ return (vcc_AddSymbol(tl, t->b, t->e - t->b, kind));
+}
+
+struct symbol *
+VCC_GetSymbolTok(struct vcc *tl, const struct token *tok, enum symkind kind)
+{
+ struct symbol *sym;
+
+ sym = VCC_FindSymbol(tl, tok, kind);
+ if (sym == NULL) {
+ sym = vcc_AddSymbol(tl, tok->b, tok->e - tok->b, kind);
+ AN(sym);
+ sym->def_b = tok;
+ }
+ return (sym);
+}
+
+struct symbol *
+VCC_FindSymbol(struct vcc *tl, const struct token *t, enum symkind kind)
+{
+ struct symbol *sym;
+
+ assert(t->tok == ID);
+ VTAILQ_FOREACH(sym, &tl->symbols, list) {
+ if (sym->kind == SYM_WILDCARD &&
+ (t->e - t->b > sym->nlen) &&
+ !memcmp(sym->name, t->b, sym->nlen)) {
+ AN(sym->wildcard);
+ return (sym->wildcard(tl, t, sym));
+ }
+ if (kind != SYM_NONE && kind != sym->kind)
+ continue;
+ if (vcc_IdIs(t, sym->name))
+ return (sym);
+ }
+ return (NULL);
+}
+
+void
+VCC_WalkSymbols(struct vcc *tl, symwalk_f *func, enum symkind kind)
+{
+ struct symbol *sym;
+
+ VTAILQ_FOREACH(sym, &tl->symbols, list) {
+ if (kind == SYM_NONE || kind == sym->kind)
+ func(tl, sym);
+ ERRCHK(tl);
+ }
+}
diff --git a/lib/libvcc/vcc_token.c b/lib/libvcc/vcc_token.c
new file mode 100644
index 0000000..6201fea
--- /dev/null
+++ b/lib/libvcc/vcc_token.c
@@ -0,0 +1,523 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2011 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "vcc_compile.h"
+
+/*--------------------------------------------------------------------*/
+
+void
+vcc_ErrToken(const struct vcc *tl, const struct token *t)
+{
+
+ if (t->tok == EOI)
+ VSB_printf(tl->sb, "end of input");
+ else if (t->tok == CSRC)
+ VSB_printf(tl->sb, "C{ ... }C");
+ else
+ VSB_printf(tl->sb, "'%.*s'", PF(t));
+}
+
+void
+vcc__ErrInternal(struct vcc *tl, const char *func, unsigned line)
+{
+
+ VSB_printf(tl->sb, "VCL compiler internal error at %s():%u\n",
+ func, line);
+ tl->err = 1;
+}
+
+/*--------------------------------------------------------------------
+ * Find start of source-line of token
+ */
+
+static void
+vcc_iline(const struct token *t, const char **ll, int tail)
+{
+ const char *p, *b, *x;
+
+ b = t->src->b;
+ if (ll != NULL)
+ *ll = b;
+ x = tail ? t->e - 1 : t->b;
+ for (p = b; p < x; p++) {
+ if (*p == '\n') {
+ if (ll != NULL)
+ *ll = p + 1;
+ }
+ }
+}
+
+/*--------------------------------------------------------------------
+ * Find and print src+line+pos of this token
+ */
+
+static void
+vcc_icoord(struct vsb *vsb, const struct token *t, int tail)
+{
+ unsigned lin, pos;
+ const char *p, *b, *x;
+
+ lin = 1;
+ pos = 0;
+ b = t->src->b;
+ x = tail ? t->e - 1 : t->b;
+ for (p = b; p < x; p++) {
+ if (*p == '\n') {
+ lin++;
+ pos = 0;
+ } else if (*p == '\t') {
+ pos &= ~7;
+ pos += 8;
+ } else
+ pos++;
+ }
+ VSB_printf(vsb, "('%s' Line %u Pos %u)", t->src->name, lin, pos + 1);
+}
+
+/*--------------------------------------------------------------------*/
+
+void
+vcc_Coord(const struct vcc *tl, struct vsb *vsb, const struct token *t)
+{
+
+ if (t == NULL)
+ t = tl->t;
+ vcc_icoord(vsb, t, 0);
+}
+
+/*--------------------------------------------------------------------
+ * Output one line of source code, starting at 'l' and ending at the
+ * first NL or 'le'.
+ */
+
+static void
+vcc_quoteline(const struct vcc *tl, const char *l, const char *le)
+{
+ const char *p;
+ unsigned x, y;
+
+ x = y = 0;
+ for (p = l; p < le && *p != '\n'; p++) {
+ if (*p == '\t') {
+ y &= ~7;
+ y += 8;
+ while (x < y) {
+ VSB_bcat(tl->sb, " ", 1);
+ x++;
+ }
+ } else {
+ x++;
+ y++;
+ VSB_bcat(tl->sb, p, 1);
+ }
+ }
+ VSB_putc(tl->sb, '\n');
+}
+
+/*--------------------------------------------------------------------
+ * Output a marker line for a sourceline starting at 'l' and ending at
+ * the first NL or 'le'. Characters between 'b' and 'e' are marked.
+ */
+
+static void
+vcc_markline(const struct vcc *tl, const char *l, const char *le,
+ const char *b, const char *e)
+{
+ const char *p;
+ unsigned x, y;
+ char c;
+
+ x = y = 0;
+ for (p = l; p < le && *p != '\n'; p++) {
+ if (p >= b && p < e)
+ c = '#';
+ else
+ c = '-';
+
+ if (*p == '\t') {
+ y &= ~7;
+ y += 8;
+ } else
+ y++;
+ while (x < y) {
+ VSB_putc(tl->sb, c);
+ x++;
+ }
+ }
+ VSB_putc(tl->sb, '\n');
+}
+
+/*--------------------------------------------------------------------*/
+/* XXX: should take first+last token */
+
+void
+vcc_ErrWhere2(struct vcc *tl, const struct token *t, const struct token *t2)
+{
+ const char *l1, *l2, *l3;
+
+ if (t == NULL) {
+ vcc_ErrWhere(tl, t2);
+ return;
+ }
+ vcc_iline(t, &l1, 0);
+ t2 = VTAILQ_PREV(t2, tokenhead, list);
+ vcc_iline(t2, &l2, 1);
+
+
+ if (l1 == l2) {
+ vcc_icoord(tl->sb, t, 0);
+ VSB_cat(tl->sb, " -- ");
+ vcc_icoord(tl->sb, t2, 1);
+ VSB_putc(tl->sb, '\n');
+ /* Two tokens on same line */
+ vcc_quoteline(tl, l1, t->src->e);
+ vcc_markline(tl, l1, t->src->e, t->b, t2->e);
+ } else {
+ /* Two tokens different lines */
+ l3 = strchr(l1, '\n');
+ AN(l3);
+ /* XXX: t had better be before t2 */
+ vcc_icoord(tl->sb, t, 0);
+ if (l3 + 1 == l2) {
+ VSB_cat(tl->sb, " -- ");
+ vcc_icoord(tl->sb, t2, 1);
+ }
+ VSB_putc(tl->sb, '\n');
+ vcc_quoteline(tl, l1, t->src->e);
+ vcc_markline(tl, l1, t->src->e, t->b, t2->e);
+ if (l3 + 1 != l2) {
+ VSB_cat(tl->sb, "[...]\n");
+ vcc_icoord(tl->sb, t2, 1);
+ VSB_putc(tl->sb, '\n');
+ }
+ vcc_quoteline(tl, l2, t->src->e);
+ vcc_markline(tl, l2, t->src->e, t->b, t2->e);
+ }
+ VSB_putc(tl->sb, '\n');
+ tl->err = 1;
+}
+
+void
+vcc_ErrWhere(struct vcc *tl, const struct token *t)
+{
+ const char *l1;
+
+ vcc_iline(t, &l1, 0);
+ vcc_icoord(tl->sb, t, 0);
+ VSB_putc(tl->sb, '\n');
+ vcc_quoteline(tl, l1, t->src->e);
+ vcc_markline(tl, l1, t->src->e, t->b, t->e);
+ VSB_putc(tl->sb, '\n');
+ tl->err = 1;
+}
+
+/*--------------------------------------------------------------------*/
+
+void
+vcc_NextToken(struct vcc *tl)
+{
+
+ tl->t = VTAILQ_NEXT(tl->t, list);
+ if (tl->t == NULL) {
+ VSB_printf(tl->sb,
+ "Ran out of input, something is missing or"
+ " maybe unbalanced (...) or {...}\n");
+ tl->err = 1;
+ return;
+ }
+}
+
+void
+vcc__Expect(struct vcc *tl, unsigned tok, unsigned line)
+{
+ if (tl->t->tok == tok)
+ return;
+ VSB_printf(tl->sb, "Expected %s got ", vcl_tnames[tok]);
+ vcc_ErrToken(tl, tl->t);
+ VSB_printf(tl->sb, "\n(program line %u), at\n", line);
+ vcc_ErrWhere(tl, tl->t);
+}
+
+/*--------------------------------------------------------------------
+ * Compare ID token to string, return true of match
+ */
+
+int
+vcc_IdIs(const struct token *t, const char *p)
+{
+ const char *q;
+
+ assert(t->tok == ID);
+ for (q = t->b; q < t->e && *p != '\0'; p++, q++)
+ if (*q != *p)
+ return (0);
+ if (q != t->e || *p != '\0')
+ return (0);
+ return (1);
+}
+
+/*--------------------------------------------------------------------
+ * Check that we have a C-identifier
+ */
+
+int
+vcc_isCid(const struct token *t)
+{
+ const char *q;
+
+ assert(t->tok == ID);
+ for (q = t->b; q < t->e; q++) {
+ if (!isalnum(*q) && *q != '_')
+ return (0);
+ }
+ return (1);
+}
+
+void
+vcc_ExpectCid(struct vcc *tl)
+{
+
+ ExpectErr(tl, ID);
+ ERRCHK(tl);
+ if (vcc_isCid(tl->t))
+ return;
+ VSB_printf(tl->sb, "Identifier ");
+ vcc_ErrToken(tl, tl->t);
+ VSB_printf(tl->sb,
+ " contains illegal characters, use [0-9a-zA-Z_] only.\n");
+ vcc_ErrWhere(tl, tl->t);
+}
+
+/*--------------------------------------------------------------------
+ * Decode a string
+ */
+
+static int
+vcc_decstr(struct vcc *tl)
+{
+ char *q;
+ unsigned int l;
+
+ assert(tl->t->tok == CSTR);
+ l = (tl->t->e - tl->t->b) - 2;
+ tl->t->dec = TlAlloc(tl, l + 1);
+ assert(tl->t->dec != NULL);
+ q = tl->t->dec;
+ memcpy(q, tl->t->b + 1, l);
+ q[l] = '\0';
+ return (0);
+}
+
+/*--------------------------------------------------------------------
+ * Add a token to the token list.
+ */
+
+void
+vcc_AddToken(struct vcc *tl, unsigned tok, const char *b, const char *e)
+{
+ struct token *t;
+
+ t = TlAlloc(tl, sizeof *t);
+ assert(t != NULL);
+ t->tok = tok;
+ t->b = b;
+ t->e = e;
+ t->src = tl->src;
+ if (tl->t != NULL)
+ VTAILQ_INSERT_AFTER(&tl->tokens, tl->t, t, list);
+ else
+ VTAILQ_INSERT_TAIL(&tl->tokens, t, list);
+ tl->t = t;
+}
+
+/*--------------------------------------------------------------------
+ * Lexical analysis and token generation
+ */
+
+void
+vcc_Lexer(struct vcc *tl, struct source *sp)
+{
+ const char *p, *q;
+ unsigned u;
+
+ tl->src = sp;
+ for (p = sp->b; p < sp->e; ) {
+
+ /* Skip any whitespace */
+ if (isspace(*p)) {
+ p++;
+ continue;
+ }
+
+ /* Skip '#.*\n' comments */
+ if (*p == '#') {
+ while (p < sp->e && *p != '\n')
+ p++;
+ continue;
+ }
+
+ /* Skip C-style comments */
+ if (*p == '/' && p[1] == '*') {
+ for (q = p + 2; q < sp->e; q++) {
+ if (*q == '/' && q[1] == '*') {
+ VSB_printf(tl->sb,
+ "/* ... */ comment contains /*\n");
+ vcc_AddToken(tl, EOI, p, p + 2);
+ vcc_ErrWhere(tl, tl->t);
+ vcc_AddToken(tl, EOI, q, q + 2);
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+ if (*q == '*' && q[1] == '/') {
+ p = q + 2;
+ break;
+ }
+ }
+ if (q < sp->e)
+ continue;
+ vcc_AddToken(tl, EOI, p, p + 2);
+ VSB_printf(tl->sb,
+ "Unterminated /* ... */ comment, starting at\n");
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+
+ /* Skip C++-style comments */
+ if (*p == '/' && p[1] == '/') {
+ while (p < sp->e && *p != '\n')
+ p++;
+ continue;
+ }
+
+ /* Recognize inline C-code */
+ if (*p == 'C' && p[1] == '{') {
+ for (q = p + 2; q < sp->e; q++) {
+ if (*q == '}' && q[1] == 'C') {
+ vcc_AddToken(tl, CSRC, p, q + 2);
+ break;
+ }
+ }
+ if (q < sp->e) {
+ p = q + 2;
+ continue;
+ }
+ vcc_AddToken(tl, EOI, p, p + 2);
+ VSB_printf(tl->sb,
+ "Unterminated inline C source, starting at\n");
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+
+ /* Recognize long-strings */
+ if (*p == '{' && p[1] == '"') {
+ for (q = p + 2; q < sp->e; q++) {
+ if (*q == '"' && q[1] == '}') {
+ vcc_AddToken(tl, CSTR, p, q + 2);
+ break;
+ }
+ }
+ if (q < sp->e) {
+ p = q + 2;
+ u = tl->t->e - tl->t->b;
+ u -= 4; /* {" ... "} */
+ tl->t->dec = TlAlloc(tl, u + 1 );
+ AN(tl->t->dec);
+ memcpy(tl->t->dec, tl->t->b + 2, u);
+ tl->t->dec[u] = '\0';
+ continue;
+ }
+ vcc_AddToken(tl, EOI, p, p + 2);
+ VSB_printf(tl->sb,
+ "Unterminated long-string, starting at\n");
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+
+ /* Match for the fixed tokens (see token.tcl) */
+ u = vcl_fixed_token(p, &q);
+ if (u != 0) {
+ vcc_AddToken(tl, u, p, q);
+ p = q;
+ continue;
+ }
+
+ /* Match strings */
+ if (*p == '"') {
+ for (q = p + 1; q < sp->e; q++) {
+ if (*q == '"') {
+ q++;
+ break;
+ }
+ if (*q == '\r' || *q == '\n') {
+ vcc_AddToken(tl, EOI, p, q);
+ VSB_printf(tl->sb,
+ "Unterminated string at\n");
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+ }
+ vcc_AddToken(tl, CSTR, p, q);
+ if (vcc_decstr(tl))
+ return;
+ p = q;
+ continue;
+ }
+
+ /* Match Identifiers */
+ if (isident1(*p)) {
+ for (q = p; q < sp->e; q++)
+ if (!isvar(*q))
+ break;
+ vcc_AddToken(tl, ID, p, q);
+ p = q;
+ continue;
+ }
+
+ /* Match numbers { [0-9]+ } */
+ if (isdigit(*p)) {
+ for (q = p; q < sp->e; q++)
+ if (!isdigit(*q))
+ break;
+ vcc_AddToken(tl, CNUM, p, q);
+ p = q;
+ continue;
+ }
+ vcc_AddToken(tl, EOI, p, p + 1);
+ VSB_printf(tl->sb, "Syntax error at\n");
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+}
diff --git a/lib/libvcc/vcc_utils.c b/lib/libvcc/vcc_utils.c
new file mode 100644
index 0000000..5870af5
--- /dev/null
+++ b/lib/libvcc/vcc_utils.c
@@ -0,0 +1,255 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2013 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#include "vcc_compile.h"
+
+#include "vre.h"
+#include "vrt.h"
+#include "vsa.h"
+
+/*--------------------------------------------------------------------*/
+
+const char *
+vcc_regexp(struct vcc *tl)
+{
+ char buf[BUFSIZ], *p;
+ vre_t *t;
+ const char *error;
+ int erroroffset;
+
+ Expect(tl, CSTR);
+ if (tl->err)
+ return (NULL);
+ memset(&t, 0, sizeof t);
+ t = VRE_compile(tl->t->dec, 0, &error, &erroroffset);
+ if (t == NULL) {
+ VSB_printf(tl->sb,
+ "Regexp compilation error:\n\n%s\n\n", error);
+ vcc_ErrWhere(tl, tl->t);
+ return (NULL);
+ }
+ VRE_free(&t);
+ sprintf(buf, "VGC_re_%u", tl->unique++);
+ p = TlAlloc(tl, strlen(buf) + 1);
+ strcpy(p, buf);
+
+ Fh(tl, 0, "static void *%s;\n", buf);
+ Fi(tl, 0, "\tVRT_re_init(&%s, ",buf);
+ EncToken(tl->fi, tl->t);
+ Fi(tl, 0, ");\n");
+ Ff(tl, 0, "\tVRT_re_fini(%s);\n", buf);
+ return (p);
+}
+
+/*
+ * The IPv6 crew royally screwed up the entire idea behind
+ * struct sockaddr, and combined with various other incomptency
+ * in the OS business, that means that there is no sane or even
+ * remotely portable way to initialize a sockaddr at compile time.
+ *
+ * In our case it is slightly more tricky than that, because we don't
+ * even want to #include the struct sockaddr* definitions.
+ *
+ * Instead we make sure the sockaddr is sane (for our values of sane)
+ * and dump it in binary, using a 64 bit integertype, hoping that this
+ * will ensure good enough alignment.
+ */
+
+static const char *
+vcc_sockaddr(struct vcc *tl, const void *sa, unsigned sal)
+{
+ unsigned n = (sal + 7) / 8, len;
+ uint64_t b[n];
+ char *p;
+
+ assert(VSA_Sane(sa));
+ AN(sa);
+ AN(sal);
+ assert(sal < sizeof(struct sockaddr_storage));
+ assert(sizeof(unsigned long long) == 8);
+
+ p = TlAlloc(tl, 20);
+ sprintf(p, "sockaddr_%u", tl->unique++);
+
+ Fh(tl, 0, "static const unsigned long long");
+ Fh(tl, 0, " %s[%d] = {\n", p, n);
+ memcpy(b, sa, sal);
+ for (len = 0; len <n; len++) {
+ Fh(tl, 0, "%s 0x%016jx",
+ len ? ",\n" : "",
+ (uintmax_t)b[len]);
+ }
+ Fh(tl, 0, "\n};\n");
+ return (p);
+}
+
+/*--------------------------------------------------------------------
+ * This routine is a monster, but at least we only have one such monster.
+ * Look up a IP number, and return IPv4/IPv6 address as VGC produced names
+ * and optionally ascii strings.
+ *
+ * For IP compile time constants we only want one IP#, but it can be
+ * IPv4 or IPv6.
+ *
+ * For backends, we accept up to one IPv4 and one IPv6.
+ */
+
+struct foo_proto {
+ const char *name;
+ int family;
+ struct sockaddr_storage sa;
+ socklen_t l;
+ const char **dst;
+ const char **dst_ascii;
+};
+
+void
+Resolve_Sockaddr(struct vcc *tl,
+ const char *host,
+ const char *port,
+ const char **ipv4,
+ const char **ipv4_ascii,
+ const char **ipv6,
+ const char **ipv6_ascii,
+ const char **p_ascii,
+ int maxips,
+ const struct token *t_err,
+ const char *errid)
+{
+ struct foo_proto protos[3], *pp;
+ struct addrinfo *res, *res0, *res1, hint;
+ int error, retval;
+ char hbuf[NI_MAXHOST];
+
+ memset(protos, 0, sizeof protos);
+ protos[0].name = "ipv4";
+ protos[0].family = PF_INET;
+ protos[0].dst = ipv4;
+ protos[0].dst_ascii = ipv4_ascii;
+ *ipv4 = NULL;
+
+ protos[1].name = "ipv6";
+ protos[1].family = PF_INET6;
+ protos[1].dst = ipv6;
+ protos[1].dst_ascii = ipv6_ascii;
+ *ipv6 = NULL;
+
+ retval = 0;
+ memset(&hint, 0, sizeof hint);
+ hint.ai_family = PF_UNSPEC;
+ hint.ai_socktype = SOCK_STREAM;
+
+ error = getaddrinfo(host, port, &hint, &res0);
+ if (error) {
+ VSB_printf(tl->sb,
+ "%s '%.*s' could not be resolved to an IP address:\n",
+ errid, PF(t_err));
+ VSB_printf(tl->sb,
+ "\t%s\n"
+ "(Sorry if that error message is gibberish.)\n",
+ gai_strerror(error));
+ vcc_ErrWhere(tl, t_err);
+ return;
+ }
+
+ for (res = res0; res; res = res->ai_next) {
+ for (pp = protos; pp->name != NULL; pp++)
+ if (res->ai_family == pp->family)
+ break;
+ if (pp->name == NULL) {
+ /* Unknown proto, ignore */
+ continue;
+ }
+ if (pp->l == res->ai_addrlen &&
+ !memcmp(&pp->sa, res->ai_addr, pp->l)) {
+ /*
+ * Same address we already emitted.
+ * This can happen using /etc/hosts
+ */
+ continue;
+ }
+
+ if (pp->l != 0 || retval == maxips) {
+ VSB_printf(tl->sb,
+ "%s %.*s: resolves to too many addresses.\n"
+ "Only one IPv4 %s IPv6 are allowed.\n"
+ "Please specify which exact address "
+ "you want to use, we found all of these:\n",
+ errid, PF(t_err),
+ maxips > 1 ? "and one" : "or");
+ for (res1 = res0; res1 != NULL; res1 = res1->ai_next) {
+ error = getnameinfo(res1->ai_addr,
+ res1->ai_addrlen, hbuf, sizeof hbuf,
+ NULL, 0, NI_NUMERICHOST);
+ AZ(error);
+ VSB_printf(tl->sb, "\t%s\n", hbuf);
+ }
+ freeaddrinfo(res0);
+ vcc_ErrWhere(tl, t_err);
+ return;
+ }
+
+ pp->l = res->ai_addrlen;
+ assert(pp->l < sizeof(struct sockaddr_storage));
+ memcpy(&pp->sa, res->ai_addr, pp->l);
+
+ error = getnameinfo(res->ai_addr, res->ai_addrlen,
+ hbuf, sizeof hbuf, NULL, 0, NI_NUMERICHOST);
+ AZ(error);
+
+ Fh(tl, 0, "\n/* \"%s\" -> %s */\n", host, hbuf);
+ *(pp->dst) = vcc_sockaddr(tl, &pp->sa, pp->l);
+ if (pp->dst_ascii != NULL) {
+ *pp->dst_ascii = TlDup(tl, hbuf);
+ }
+ retval++;
+ }
+ if (p_ascii != NULL) {
+ error = getnameinfo(res0->ai_addr,
+ res0->ai_addrlen, NULL, 0, hbuf, sizeof hbuf,
+ NI_NUMERICSERV);
+ AZ(error);
+ *p_ascii = TlDup(tl, hbuf);
+ }
+ if (retval == 0) {
+ VSB_printf(tl->sb,
+ "%s '%.*s': resolves to "
+ "neither IPv4 nor IPv6 addresses.\n",
+ errid, PF(t_err) );
+ vcc_ErrWhere(tl, t_err);
+ }
+}
diff --git a/lib/libvcc/vcc_var.c b/lib/libvcc/vcc_var.c
new file mode 100644
index 0000000..74713b8
--- /dev/null
+++ b/lib/libvcc/vcc_var.c
@@ -0,0 +1,134 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2011 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "vcc_compile.h"
+#include "vct.h"
+
+/*--------------------------------------------------------------------*/
+
+struct symbol *
+vcc_Var_Wildcard(struct vcc *tl, const struct token *t, const struct symbol *wc)
+{
+ struct symbol *sym;
+ struct var *v;
+ const struct var *vh;
+ int l, i;
+ char c;
+ char buf[258];
+ char cnam[256];
+
+ vh = wc->var;
+
+ v = TlAlloc(tl, sizeof *v);
+ AN(v);
+
+ assert(vh->fmt == HEADER);
+ v->name = TlDupTok(tl, t);
+ v->r_methods = vh->r_methods;
+ v->w_methods = vh->w_methods;
+ v->fmt = vh->fmt;
+
+ /* Create a C-name version of the header name */
+ l = strlen(v->name + vh->len) + 1;
+ for (i = 0; i < l - 1; i++) {
+ c = *(v->name + vh->len + i);
+ if (vct_isalpha(c) || vct_isdigit(c))
+ cnam[i] = c;
+ else
+ cnam[i] = '_';
+ }
+ cnam[i] = '\0';
+
+ /* Create the static identifier */
+ Fh(tl, 0, "static const struct gethdr_s VGC_%s_%s =\n",
+ vh->rname, cnam);
+ Fh(tl, 0, " { %s, \"\\%03o%s:\"};\n",
+ vh->rname, (unsigned)l, v->name + vh->len);
+
+ bprintf(buf, "&VGC_%s_%s", vh->rname, cnam);
+ v->rname = TlDup(tl, buf);
+ bprintf(buf, "VRT_SetHdr(ctx, %s, ", v->rname);
+ v->lname = TlDup(tl, buf);
+
+ sym = VCC_AddSymbolTok(tl, t, SYM_VAR);
+ AN(sym);
+ sym->var = v;
+ sym->fmt = v->fmt;
+ sym->eval = vcc_Eval_Var;
+ sym->r_methods = v->r_methods;
+ return (sym);
+}
+
+/*--------------------------------------------------------------------*/
+
+const struct var *
+vcc_FindVar(struct vcc *tl, const struct token *t, int wr_access,
+ const char *use)
+{
+ const struct var *v;
+ const struct symbol *sym;
+
+ AN(tl->vars);
+ sym = VCC_FindSymbol(tl, t, SYM_VAR);
+ if (sym != NULL) {
+ v = sym->var;
+ AN(v);
+
+ if (wr_access && v->w_methods == 0) {
+ VSB_printf(tl->sb, "Variable ");
+ vcc_ErrToken(tl, t);
+ VSB_printf(tl->sb, " is read only.");
+ VSB_cat(tl->sb, "\nAt: ");
+ vcc_ErrWhere(tl, t);
+ return (NULL);
+ } else if (wr_access) {
+ vcc_AddUses(tl, t, v->w_methods, use);
+ } else if (v->r_methods == 0) {
+ VSB_printf(tl->sb, "Variable ");
+ vcc_ErrToken(tl, t);
+ VSB_printf(tl->sb, " is write only.");
+ VSB_cat(tl->sb, "\nAt: ");
+ vcc_ErrWhere(tl, t);
+ return (NULL);
+ } else {
+ vcc_AddUses(tl, t, v->r_methods, use);
+ }
+ return (v);
+ }
+ VSB_printf(tl->sb, "Unknown variable ");
+ vcc_ErrToken(tl, t);
+ VSB_cat(tl->sb, "\nAt: ");
+ vcc_ErrWhere(tl, t);
+ return (NULL);
+}
diff --git a/lib/libvcc/vcc_vmod.c b/lib/libvcc/vcc_vmod.c
new file mode 100644
index 0000000..7eb9d32c
--- /dev/null
+++ b/lib/libvcc/vcc_vmod.c
@@ -0,0 +1,204 @@
+/*-
+ * Copyright (c) 2010-2013 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "vcc_compile.h"
+
+#include "vmod_abi.h"
+
+void
+vcc_ParseImport(struct vcc *tl)
+{
+ void *hdl;
+ char fn[1024];
+ char buf[256];
+ struct token *mod, *t1;
+ const char *modname;
+ const char *proto;
+ const char *abi;
+ const char **spec;
+ struct symbol *sym;
+ const struct symbol *osym;
+ const char *p;
+ // int *modlen;
+
+ t1 = tl->t;
+ SkipToken(tl, ID); /* "import" */
+
+ ExpectErr(tl, ID);
+ mod = tl->t;
+ vcc_NextToken(tl);
+
+ osym = VCC_FindSymbol(tl, mod, SYM_NONE);
+ if (osym != NULL && osym->kind != SYM_VMOD) {
+ VSB_printf(tl->sb, "Module %.*s conflics with other symbol.\n",
+ PF(mod));
+ vcc_ErrWhere2(tl, t1, tl->t);
+ return;
+ }
+ if (osym != NULL) {
+ VSB_printf(tl->sb, "Module %.*s already imported.\n",
+ PF(mod));
+ vcc_ErrWhere2(tl, t1, tl->t);
+ VSB_printf(tl->sb, "Previous import was here:\n");
+ vcc_ErrWhere2(tl, osym->def_b, osym->def_e);
+ return;
+ }
+
+ bprintf(fn, "%.*s", PF(mod));
+ sym = VCC_AddSymbolStr(tl, fn, SYM_VMOD);
+ ERRCHK(tl);
+ AN(sym);
+ sym->def_b = t1;
+ sym->def_e = tl->t;
+
+ if (tl->t->tok == ID) {
+ if (!tl->unsafe_path) {
+ VSB_printf(tl->sb,
+ "'import ... from path...'"
+ " not allowed.\nAt:");
+ vcc_ErrToken(tl, tl->t);
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+ if (!vcc_IdIs(tl->t, "from")) {
+ VSB_printf(tl->sb, "Expected 'from path...'\n");
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+ vcc_NextToken(tl);
+ ExpectErr(tl, CSTR);
+ bprintf(fn, "%s", tl->t->dec);
+ vcc_NextToken(tl);
+ } else {
+ bprintf(fn, "%s/libvmod_%.*s.so", tl->vmod_dir, PF(mod));
+ }
+
+ Fh(tl, 0, "static void *VGC_vmod_%.*s;\n", PF(mod));
+
+ Fi(tl, 0, "\tif (VRT_Vmod_Init(&VGC_vmod_%.*s,\n", PF(mod));
+ Fi(tl, 0, "\t &Vmod_%.*s_Func,\n", PF(mod));
+ Fi(tl, 0, "\t sizeof(Vmod_%.*s_Func),\n", PF(mod));
+ Fi(tl, 0, "\t \"%.*s\",\n", PF(mod));
+ Fi(tl, 0, "\t ");
+ EncString(tl->fi, fn, NULL, 0);
+ Fi(tl, 0, ",\n\t ");
+ Fi(tl, 0, "cli))\n");
+ Fi(tl, 0, "\t\treturn(1);\n");
+
+ SkipToken(tl, ';');
+
+ hdl = dlopen(fn, RTLD_NOW | RTLD_LOCAL);
+ if (hdl == NULL) {
+ VSB_printf(tl->sb, "Could not load module %.*s\n\t%s\n\t%s\n",
+ PF(mod), fn, dlerror());
+ vcc_ErrWhere(tl, mod);
+ return;
+ }
+
+ bprintf(buf, "Vmod_%.*s_Name", PF(mod));
+ modname = dlsym(hdl, buf);
+ if (modname == NULL) {
+ VSB_printf(tl->sb, "Could not load module %.*s\n\t%s\n\t%s\n",
+ PF(mod), fn, "Symbol Vmod_Name not found");
+ vcc_ErrWhere(tl, mod);
+ return;
+ }
+ if (!vcc_IdIs(mod, modname)) {
+ VSB_printf(tl->sb, "Could not load module %.*s\n\t%s\n",
+ PF(mod), fn);
+ VSB_printf(tl->sb, "\tModule has wrong name: <%s>\n", modname);
+ vcc_ErrWhere(tl, mod);
+ return;
+ }
+
+ bprintf(buf, "Vmod_%.*s_ABI", PF(mod));
+ abi = dlsym(hdl, buf);
+ if (abi == NULL || strcmp(abi, VMOD_ABI_Version) != 0) {
+ VSB_printf(tl->sb, "Could not load module %.*s\n\t%s\n",
+ PF(mod), fn);
+ VSB_printf(tl->sb, "\tABI mismatch, expected <%s>, got <%s>\n",
+ VMOD_ABI_Version, abi);
+ vcc_ErrWhere(tl, mod);
+ return;
+ }
+
+ bprintf(buf, "Vmod_%.*s_Proto", PF(mod));
+ proto = dlsym(hdl, buf);
+ if (proto == NULL) {
+ VSB_printf(tl->sb, "Could not load module %.*s\n\t%s\n\t%s\n",
+ PF(mod), fn, "Symbol Vmod_Proto not found");
+ vcc_ErrWhere(tl, mod);
+ return;
+ }
+ bprintf(buf, "Vmod_%.*s_Spec", PF(mod));
+ spec = dlsym(hdl, buf);
+ if (spec == NULL) {
+ VSB_printf(tl->sb, "Could not load module %.*s\n\t%s\n\t%s\n",
+ PF(mod), fn, "Symbol Vmod_Spec not found");
+ vcc_ErrWhere(tl, mod);
+ return;
+ }
+ Fh(tl, 0, "static struct vmod_priv vmod_priv_%.*s;\n", PF(mod));
+ for (; *spec != NULL; spec++) {
+ p = *spec;
+ if (!strcmp(p, "OBJ")) {
+ p += strlen(p) + 1;
+ sym = VCC_AddSymbolStr(tl, p, SYM_OBJECT);
+ XXXAN(sym);
+ sym->args = p;
+ } else if (!strcmp(p, "INIT")) {
+ p += strlen(p) + 1;
+ Fi(tl, 0, "\t%s(&vmod_priv_%.*s, &VCL_conf);\n",
+ p, PF(mod));
+ } else {
+ sym = VCC_AddSymbolStr(tl, p, SYM_FUNC);
+ ERRCHK(tl);
+ AN(sym);
+ sym->eval = vcc_Eval_SymFunc;
+ p += strlen(p) + 1;
+ sym->cfunc = p;
+ p += strlen(p) + 1;
+ sym->args = p;
+
+ /* Functions which return VOID are procedures */
+ if (!memcmp(p, "VOID\0", 5))
+ sym->kind = SYM_PROC;
+ }
+ }
+ Fh(tl, 0, "\n%s\n", proto);
+
+ /* XXX: zero the function pointer structure ?*/
+ Ff(tl, 0, "\tvmod_priv_fini(&vmod_priv_%.*s);\n", PF(mod));
+ Ff(tl, 0, "\tVRT_Vmod_Fini(&VGC_vmod_%.*s);\n", PF(mod));
+}
diff --git a/lib/libvcc/vcc_xref.c b/lib/libvcc/vcc_xref.c
new file mode 100644
index 0000000..c3ef375
--- /dev/null
+++ b/lib/libvcc/vcc_xref.c
@@ -0,0 +1,388 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2011 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file contains code for two cross-reference or consistency checks.
+ *
+ * The first check is simply that all subroutine, acls and backends are
+ * both defined and referenced. Complaints about referenced but undefined
+ * or defined but unreferenced objects will be emitted.
+ *
+ * The second check recursively decends through subroutine calls to make
+ * sure that action actions are correct for the methods through which
+ * they are called.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+
+#include "vcc_compile.h"
+
+/*--------------------------------------------------------------------*/
+
+struct proccall {
+ VTAILQ_ENTRY(proccall) list;
+ struct proc *p;
+ struct token *t;
+};
+
+struct procuse {
+ VTAILQ_ENTRY(procuse) list;
+ const struct token *t;
+ unsigned mask;
+ const char *use;
+};
+
+struct proc {
+ VTAILQ_HEAD(,proccall) calls;
+ VTAILQ_HEAD(,procuse) uses;
+ struct token *name;
+ unsigned ret_bitmap;
+ unsigned exists;
+ unsigned called;
+ unsigned active;
+ struct token *return_tok[VCL_RET_MAX];
+};
+
+/*--------------------------------------------------------------------
+ * Keep track of definitions and references
+ */
+
+void
+vcc_AddRef(struct vcc *tl, const struct token *t, enum symkind kind)
+{
+ struct symbol *sym;
+
+ sym = VCC_GetSymbolTok(tl, t, kind);
+ AN(sym);
+ sym->nref++;
+}
+
+int
+vcc_AddDef(struct vcc *tl, const struct token *t, enum symkind kind)
+{
+ struct symbol *sym;
+
+ sym = VCC_GetSymbolTok(tl, t, kind);
+ AN(sym);
+ sym->ndef++;
+ return (sym->ndef);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+vcc_checkref(struct vcc *tl, const struct symbol *sym)
+{
+
+ if (sym->ndef == 0 && sym->nref != 0) {
+ VSB_printf(tl->sb, "Undefined %s %.*s, first reference:\n",
+ VCC_SymKind(tl, sym), PF(sym->def_b));
+ vcc_ErrWhere(tl, sym->def_b);
+ } else if (sym->ndef != 0 && sym->nref == 0) {
+ VSB_printf(tl->sb, "Unused %s %.*s, defined:\n",
+ VCC_SymKind(tl, sym), PF(sym->def_b));
+ vcc_ErrWhere(tl, sym->def_b);
+ if (!tl->err_unref) {
+ VSB_printf(tl->sb, "(That was just a warning)\n");
+ tl->err = 0;
+ }
+ }
+}
+
+int
+vcc_CheckReferences(struct vcc *tl)
+{
+
+ VCC_WalkSymbols(tl, vcc_checkref, SYM_NONE);
+ return (tl->err);
+}
+
+/*--------------------------------------------------------------------
+ * Returns checks
+ */
+
+static struct proc *
+vcc_findproc(struct vcc *tl, struct token *t)
+{
+ struct symbol *sym;
+ struct proc *p;
+
+
+ sym = VCC_GetSymbolTok(tl, t, SYM_SUB);
+ AN(sym);
+ if (sym->proc != NULL)
+ return (sym->proc);
+
+ p = TlAlloc(tl, sizeof *p);
+ assert(p != NULL);
+ VTAILQ_INIT(&p->calls);
+ VTAILQ_INIT(&p->uses);
+ p->name = t;
+ sym->proc = p;
+ return (p);
+}
+
+struct proc *
+vcc_AddProc(struct vcc *tl, struct token *t)
+{
+ struct proc *p;
+
+ p = vcc_findproc(tl, t);
+ p->name = t; /* make sure the name matches the definition */
+ p->exists++;
+ return (p);
+}
+
+void
+vcc_AddUses(struct vcc *tl, const struct token *t, unsigned mask,
+ const char *use)
+{
+ struct procuse *pu;
+
+ if (tl->curproc == NULL) /* backend */
+ return;
+ pu = TlAlloc(tl, sizeof *pu);
+ assert(pu != NULL);
+ pu->t = t;
+ pu->mask = mask;
+ pu->use = use;
+ VTAILQ_INSERT_TAIL(&tl->curproc->uses, pu, list);
+}
+
+void
+vcc_AddCall(struct vcc *tl, struct token *t)
+{
+ struct proccall *pc;
+ struct proc *p;
+
+ p = vcc_findproc(tl, t);
+ pc = TlAlloc(tl, sizeof *pc);
+ assert(pc != NULL);
+ pc->p = p;
+ pc->t = t;
+ VTAILQ_INSERT_TAIL(&tl->curproc->calls, pc, list);
+}
+
+void
+vcc_ProcAction(struct proc *p, unsigned returns, struct token *t)
+{
+
+ assert(returns < VCL_RET_MAX);
+ p->ret_bitmap |= (1U << returns);
+ /* Record the first instance of this return */
+ if (p->return_tok[returns] == NULL)
+ p->return_tok[returns] = t;
+}
+
+static int
+vcc_CheckActionRecurse(struct vcc *tl, struct proc *p, unsigned bitmap)
+{
+ unsigned u;
+ struct proccall *pc;
+
+ if (!p->exists) {
+ VSB_printf(tl->sb, "Function %.*s does not exist\n",
+ PF(p->name));
+ return (1);
+ }
+ if (p->active) {
+ VSB_printf(tl->sb, "Function recurses on\n");
+ vcc_ErrWhere(tl, p->name);
+ return (1);
+ }
+ u = p->ret_bitmap & ~bitmap;
+ if (u) {
+
+#define VCL_RET_MAC(l, U, B) \
+ if (u & (1 << (VCL_RET_##U))) { \
+ VSB_printf(tl->sb, "Invalid return \"" #l "\"\n");\
+ vcc_ErrWhere(tl, p->return_tok[VCL_RET_##U]); \
+ }
+#include "tbl/vcl_returns.h"
+#undef VCL_RET_MAC
+
+ VSB_printf(tl->sb, "\n...in subroutine \"%.*s\"\n",
+ PF(p->name));
+ vcc_ErrWhere(tl, p->name);
+ return (1);
+ }
+ p->active = 1;
+ VTAILQ_FOREACH(pc, &p->calls, list) {
+ if (vcc_CheckActionRecurse(tl, pc->p, bitmap)) {
+ VSB_printf(tl->sb, "\n...called from \"%.*s\"\n",
+ PF(p->name));
+ vcc_ErrWhere(tl, pc->t);
+ return (1);
+ }
+ }
+ p->active = 0;
+ p->called++;
+ return (0);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+vcc_checkaction1(struct vcc *tl, const struct symbol *sym)
+{
+ struct proc *p;
+ struct method *m;
+ int i;
+
+ p = sym->proc;
+ AN(p);
+ i = IsMethod(p->name);
+ if (i < 0)
+ return;
+ m = method_tab + i;
+ if (vcc_CheckActionRecurse(tl, p, m->ret_bitmap)) {
+ VSB_printf(tl->sb,
+ "\n...which is the \"%s\" method\n", m->name);
+ VSB_printf(tl->sb, "Legal returns are:");
+#define VCL_RET_MAC(l, U, B) \
+ if (m->ret_bitmap & ((1 << VCL_RET_##U))) \
+ VSB_printf(tl->sb, " \"%s\"", #l);
+
+#include "tbl/vcl_returns.h"
+#undef VCL_RET_MAC
+ VSB_printf(tl->sb, "\n");
+ tl->err = 1;
+ }
+
+}
+
+static void
+vcc_checkaction2(struct vcc *tl, const struct symbol *sym)
+{
+ struct proc *p;
+
+ p = sym->proc;
+ AN(p);
+
+ if (p->called)
+ return;
+ VSB_printf(tl->sb, "Function unused\n");
+ vcc_ErrWhere(tl, p->name);
+ if (!tl->err_unref) {
+ VSB_printf(tl->sb, "(That was just a warning)\n");
+ tl->err = 0;
+ }
+}
+
+int
+vcc_CheckAction(struct vcc *tl)
+{
+
+ VCC_WalkSymbols(tl, vcc_checkaction1, SYM_SUB);
+ if (tl->err)
+ return (tl->err);
+ VCC_WalkSymbols(tl, vcc_checkaction2, SYM_SUB);
+ return (tl->err);
+}
+
+/*--------------------------------------------------------------------*/
+
+static struct procuse *
+vcc_FindIllegalUse(const struct proc *p, const struct method *m)
+{
+ struct procuse *pu;
+
+ VTAILQ_FOREACH(pu, &p->uses, list)
+ if (!(pu->mask & m->bitval))
+ return (pu);
+ return (NULL);
+}
+
+static int
+vcc_CheckUseRecurse(struct vcc *tl, const struct proc *p,
+ struct method *m)
+{
+ struct proccall *pc;
+ struct procuse *pu;
+
+ pu = vcc_FindIllegalUse(p, m);
+ if (pu != NULL) {
+ VSB_printf(tl->sb,
+ "'%.*s': %s from method '%.*s'.\n",
+ PF(pu->t), pu->use, PF(p->name));
+ vcc_ErrWhere(tl, pu->t);
+ VSB_printf(tl->sb, "\n...in subroutine \"%.*s\"\n",
+ PF(p->name));
+ vcc_ErrWhere(tl, p->name);
+ return (1);
+ }
+ VTAILQ_FOREACH(pc, &p->calls, list) {
+ if (vcc_CheckUseRecurse(tl, pc->p, m)) {
+ VSB_printf(tl->sb, "\n...called from \"%.*s\"\n",
+ PF(p->name));
+ vcc_ErrWhere(tl, pc->t);
+ return (1);
+ }
+ }
+ return (0);
+}
+
+static void
+vcc_checkuses(struct vcc *tl, const struct symbol *sym)
+{
+ struct proc *p;
+ struct method *m;
+ struct procuse *pu;
+ int i;
+
+ p = sym->proc;
+ AN(p);
+
+ i = IsMethod(p->name);
+ if (i < 0)
+ return;
+ m = method_tab + i;
+ pu = vcc_FindIllegalUse(p, m);
+ if (pu != NULL) {
+ VSB_printf(tl->sb,
+ "'%.*s': %s in method '%.*s'.",
+ PF(pu->t), pu->use, PF(p->name));
+ VSB_cat(tl->sb, "\nAt: ");
+ vcc_ErrWhere(tl, pu->t);
+ return;
+ }
+ if (vcc_CheckUseRecurse(tl, p, m)) {
+ VSB_printf(tl->sb,
+ "\n...which is the \"%s\" method\n", m->name);
+ return;
+ }
+}
+
+int
+vcc_CheckUses(struct vcc *tl)
+{
+
+ VCC_WalkSymbols(tl, vcc_checkuses, SYM_SUB);
+ return (tl->err);
+}
diff --git a/lib/libvcc/vmodtool.py b/lib/libvcc/vmodtool.py
new file mode 100755
index 0000000..2b6db42
--- /dev/null
+++ b/lib/libvcc/vmodtool.py
@@ -0,0 +1,553 @@
+#!/usr/bin/env python
+#-
+# Copyright (c) 2010-2013 Varnish Software AS
+# All rights reserved.
+#
+# Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# Read the vmod.spec file and produce the vmod.h and vmod.c files.
+#
+# vmod.h contains the prototypes for the published functions, the module
+# C-code should include this file to ensure type-consistency.
+#
+# vmod.c contains the symbols which VCC and varnishd will use to access
+# the module: A structure of properly typed function pointers, the
+# size of this structure in bytes, and the definition of the structure
+# as a string, suitable for inclusion in the C-source of the compile VCL
+# program.
+
+import sys
+import re
+
+if len(sys.argv) == 2:
+ specfile = sys.argv[1]
+else:
+ specfile = "vmod.vcc"
+
+ctypes = {
+ 'BACKEND': "VCL_BACKEND",
+ 'BOOL': "VCL_BOOL",
+ 'DURATION': "VCL_DURATION",
+ 'ENUM': "VCL_ENUM",
+ 'HEADER': "const struct gethdr_s *",
+ 'INT': "VCL_INT",
+ 'IP': "VCL_IP",
+ 'PRIV_CALL': "struct vmod_priv *",
+ 'PRIV_VCL': "struct vmod_priv *",
+ 'REAL': "VCL_REAL",
+ 'STRING': "VCL_STRING",
+ 'STRING_LIST': "const char *, ...",
+ 'TIME': "VCL_TIME",
+ 'VOID': "VCL_VOID",
+}
+
+#######################################################################
+
+def file_header(fo):
+ fo.write("""/*
+ * NB: This file is machine generated, DO NOT EDIT!
+ *
+ * Edit vmod.vcc and run vmod.py instead
+ */
+
+""")
+
+#######################################################################
+
+def is_c_name(s):
+ return None != re.match("^[a-z][a-z0-9_]*$", s)
+
+#######################################################################
+
+class token(object):
+ def __init__(self, ln, ch, str):
+ self.ln = ln
+ self.ch = ch
+ self.str = str
+
+ def __repr__(self):
+ return "<@%d \"%s\">" % (self.ln, self.str)
+
+#######################################################################
+
+class vmod(object):
+ def __init__(self, nam):
+ if not is_c_name(nam):
+ raise Exception("Module name '%s' is illegal" % nam)
+ self.nam = nam
+ self.init = None
+ self.funcs = list()
+ self.objs = list()
+
+ def set_init(self, nam):
+ if self.init != None:
+ raise Exception("Module %s already has Init" % self.nam)
+ if not is_c_name(nam):
+ raise Exception("Init name '%s' is illegal" % nam)
+ self.init = nam
+
+ def add_func(self, fn):
+ self.funcs.append(fn)
+
+ def add_obj(self, obj):
+ self.objs.append(obj)
+ obj.set_modnam(self.nam)
+
+ def c_proto(self, fo):
+ for o in self.objs:
+ o.c_proto(fo)
+ fo.write("\n")
+ for f in self.funcs:
+ f.c_proto(fo)
+ if self.init != None:
+ fo.write("\n")
+ fo.write("int " + self.init)
+ fo.write(
+ "(struct vmod_priv *, const struct VCL_conf *);\n")
+ #fo.write("\n")
+ #fo.write("extern const void * const Vmod_" + self.nam + "_Id;\n")
+
+ def c_typedefs_(self):
+ l = list()
+ for o in self.objs:
+ for t in o.c_typedefs(self.nam):
+ l.append(t)
+ l.append("")
+ l.append("/* Functions */")
+ for f in self.funcs:
+ l.append(f.c_typedef(self.nam))
+ l.append("")
+ return l
+
+ def c_typedefs(self, fo):
+ for i in self.c_typedefs_():
+ fo.write(i + "\n")
+
+ def c_vmod(self, fo):
+ fo.write('const char Vmod_' + self.nam + '_Name[] =')
+ fo.write(' \"' + self.nam + '";\n')
+ fo.write("\n")
+
+ cs = self.c_struct()
+ fo.write("const " + cs + ' Vmod_' + self.nam + '_Func = ')
+ fo.write(self.c_initializer())
+ fo.write("\n")
+
+ fo.write("\n")
+ fo.write("const int Vmod_" + self.nam + '_Len =')
+ fo.write(" sizeof(Vmod_" + self.nam + "_Func);\n")
+ fo.write("\n")
+
+ fo.write("const char Vmod_" + self.nam + "_Proto[] =\n")
+ for t in self.c_typedefs_():
+ fo.write('\t"' + t + '\\n"\n')
+ fo.write('\t"\\n"\n')
+ for i in (cs + " Vmod_" + self.nam + '_Func;').split("\n"):
+ fo.write('\n\t"' + i + '\\n"')
+ fo.write(";\n\n")
+
+ fo.write(self.c_strspec())
+
+ fo.write("\n")
+ fo.write('const char Vmod_' + self.nam + '_ABI[] =')
+ fo.write(' VMOD_ABI_Version;\n')
+ #fo.write("\n")
+ #fo.write('const void * const Vmod_' + self.nam + '_Id =')
+ #fo.write(' &Vmod_' + self.nam + '_Id;\n')
+
+ def c_initializer(self):
+ s = '{\n'
+ for o in self.objs:
+ s += o.c_initializer()
+
+ s += "\n\t/* Functions */\n"
+ for f in self.funcs:
+ s += f.c_initializer()
+
+ s += "\n\t/* Init/Fini */\n"
+ if self.init != None:
+ s += "\t" + self.init + ",\n"
+ s += "};"
+
+ return s
+
+ def c_struct(self):
+ s = 'struct Vmod_' + self.nam + '_Func {\n'
+ for o in self.objs:
+ s += o.c_struct(self.nam)
+
+ s += "\n\t/* Functions */\n"
+ for f in self.funcs:
+ s += f.c_struct(self.nam)
+
+ s += "\n\t/* Init/Fini */\n"
+ if self.init != None:
+ s += "\tvmod_init_f\t*_init;\n"
+ s += '}'
+ return s
+
+ def c_strspec(self):
+ s = "const char * const Vmod_" + self.nam + "_Spec[] = {\n"
+
+ for o in self.objs:
+ s += o.c_strspec(self.nam)
+
+ s += "\n\t/* Functions */\n"
+ for f in self.funcs:
+ s += '\t"' + f.c_strspec(self.nam) + '",\n'
+
+ s += "\n\t/* Init/Fini */\n"
+ if self.init != None:
+ s += '\t"INIT\\0Vmod_' + self.nam + '_Func._init",\n'
+
+ s += "\t0\n"
+ s += "};\n"
+ return s
+
+#######################################################################
+
+class func(object):
+ def __init__(self, nam, retval, al):
+ #if not is_c_name(nam):
+ # raise Exception("Func name '%s' is illegal" % nam)
+ if retval not in ctypes:
+ raise Exception(
+ "Return type '%s' not a valid type" % retval)
+ self.nam = nam
+ self.cnam = nam.replace(".", "_")
+ self.al = al
+ self.retval = retval
+ self.pfx = None
+
+ def __repr__(self):
+ return "<FUNC %s %s>" % (self.retval, self.nam)
+
+ def set_pfx(self, s):
+ self.pfx = s
+
+ def c_proto(self, fo, fini=False):
+ fo.write(ctypes[self.retval])
+ fo.write(" vmod_" + self.cnam + "(")
+ p = ""
+ if not fini:
+ fo.write("const struct vrt_ctx *")
+ p = ", "
+ if self.pfx != None:
+ fo.write(p + self.pfx)
+ p = ", "
+ for a in self.al:
+ fo.write(p + ctypes[a.typ])
+ p = ", "
+ if a.nam != None:
+ fo.write(" " + a.nam)
+ fo.write(");\n")
+
+ def c_typedef(self, modname, fini=False):
+ s = "typedef "
+ s += ctypes[self.retval]
+ s += " td_" + modname + "_" + self.cnam + "("
+ p = ""
+ if not fini:
+ s += "const struct vrt_ctx *"
+ p = ", "
+ if self.pfx != None:
+ s += p + self.pfx
+ p = ", "
+ for a in self.al:
+ s += p + ctypes[a.typ]
+ p = ", "
+ s += ");"
+ return s
+
+ def c_struct(self, modname):
+ s = '\ttd_' + modname + "_" + self.cnam
+ while len(s.expandtabs()) < 40:
+ s += "\t"
+ s += "*" + self.cnam + ";\n"
+ return s
+
+ def c_initializer(self):
+ return "\tvmod_" + self.cnam + ",\n"
+
+ def c_strspec(self, modnam):
+ s = modnam + "." + self.nam
+ s += "\\0"
+ s += "Vmod_" + modnam + "_Func." + self.cnam + "\\0"
+ s += self.retval + "\\0"
+ for a in self.al:
+ s += a.c_strspec()
+ return s
+
+#######################################################################
+
+class obj(object):
+ def __init__(self, nam):
+ self.nam = nam
+ self.init = None
+ self.fini = None
+ self.methods = list()
+
+ def set_modnam(self, modnam):
+ self.st = "struct vmod_" + modnam + "_" + self.nam
+ self.init.set_pfx(self.st + " **, const char *")
+ self.fini.set_pfx(self.st + " **")
+ for m in self.methods:
+ m.set_pfx(self.st + " *")
+
+ def set_init(self, f):
+ self.init = f
+ self.fini = func(f.nam, "VOID", [])
+ self.init.cnam += "__init"
+ self.fini.cnam += "__fini"
+
+ def add_method(self, m):
+ self.methods.append(m)
+
+ def c_typedefs(self, modnam):
+ l = list()
+ l.append("/* Object " + self.nam + " */")
+ l.append(self.st + ";")
+ l.append(self.init.c_typedef(modnam) + "")
+ l.append(self.fini.c_typedef(modnam, fini=True) + "")
+ for m in self.methods:
+ l.append(m.c_typedef(modnam) + "")
+ return l
+
+ def c_proto(self, fo):
+ fo.write(self.st + ";\n")
+ self.init.c_proto(fo)
+ self.fini.c_proto(fo, fini = True)
+ for m in self.methods:
+ m.c_proto(fo)
+
+ def c_struct(self, modnam):
+ s = "\t/* Object " + self.nam + " */\n"
+ s += self.init.c_struct(modnam)
+ s += self.fini.c_struct(modnam)
+ for m in self.methods:
+ s += m.c_struct(modnam)
+ return s
+
+ def c_initializer(self):
+ s = "\t/* Object " + self.nam + " */\n"
+ s += self.init.c_initializer()
+ s += self.fini.c_initializer()
+ for m in self.methods:
+ s += m.c_initializer()
+ return s
+
+ def c_strspec(self, modnam):
+ s = "\t/* Object " + self.nam + " */\n"
+ s += '\t"OBJ\\0"\n'
+ s += '\t\t"' + self.init.c_strspec(modnam) + '\\0"\n'
+ s += '\t\t"' + self.st + '\\0"\n'
+ s += '\t\t"' + self.fini.c_strspec(modnam) + '\\0"\n'
+ for m in self.methods:
+ s += '\t\t"' + m.c_strspec(modnam) + '\\0"\n'
+ s += '\t\t"\\0",\n'
+ return s
+
+#######################################################################
+
+class arg(object):
+ def __init__(self, typ, nam = None, det = None):
+ self.nam = nam
+ self.typ = typ
+ self.det = det
+
+ def __repr__(self):
+ return "<ARG %s %s %s>" % (self.nam, self.typ, str(self.det))
+
+ def c_strspec(self):
+ if self.det == None:
+ return self.typ + "\\0"
+ else:
+ return self.det
+ return "??"
+
+#######################################################################
+
+f = open(specfile, "r")
+tl = list()
+lines = list()
+ln = 0
+for l in f:
+ ln += 1
+ lines.append(l)
+ if l == "":
+ continue
+ l = re.sub("[ \t]*#.*$", "", l)
+ l = re.sub("[ \t]*\n", "", l)
+ l = re.sub("([(){},])", r' \1 ', l)
+ if l == "":
+ continue
+ for j in l.split():
+ tl.append(token(ln, 0, j))
+f.close()
+
+#######################################################################
+#
+#
+def parse_enum2(tl):
+ t = tl.pop(0)
+ if t.str != "{":
+ raise Exception("expected \"{\"")
+ s = "ENUM\\0"
+ while True:
+ t = tl.pop(0)
+ if t.str == "}":
+ break
+ s += t.str + "\\0"
+ if tl[0].str == ",":
+ tl.pop(0)
+ elif tl[0].str != "}":
+ raise Exception("Expceted \"}\" or \",\"")
+ s += "\\0"
+ return arg("ENUM", det=s)
+
+#######################################################################
+#
+#
+
+def parse_func(tl, rt_type = None, obj=None):
+ al = list()
+ if rt_type == None:
+ t = tl.pop(0)
+ rt_type = t.str
+ if rt_type not in ctypes:
+ raise Exception(
+ "Return type '%s' not a valid type" % rt_type)
+
+ t = tl.pop(0)
+ fname = t.str
+ if obj != None and fname[0] == "." and is_c_name(fname[1:]):
+ fname = obj + fname
+ elif not is_c_name(fname):
+ raise Exception("Function name '%s' is illegal" % fname)
+
+ t = tl.pop(0)
+ if t.str != "(":
+ raise Exception("Expected \"(\" got \"%s\"", t.str)
+
+ while True:
+ t = tl.pop(0)
+ if t.str == ")":
+ break
+ if t.str == "ENUM":
+ al.append(parse_enum2(tl))
+ elif t.str in ctypes:
+ al.append(arg(t.str))
+ else:
+ raise Exception("ARG? %s" % t.str)
+ if is_c_name(tl[0].str):
+ al[-1].nam = tl[0].str
+ t = tl.pop(0)
+ if tl[0].str == ",":
+ tl.pop(0)
+ elif tl[0].str != ")":
+ raise Exception("Expceted \")\" or \",\"")
+ if t.str != ")":
+ raise Exception("End Of Input looking for ')'")
+ f = func(fname, rt_type, al)
+ return f
+
+#######################################################################
+#
+#
+
+def parse_obj(tl):
+ o = obj(tl[0].str)
+ f = parse_func(tl, "VOID")
+ o.set_init(f)
+ t = tl.pop(0)
+ assert t.str == "{"
+ while True:
+ t = tl.pop(0)
+ if t.str == "}":
+ break
+ assert t.str == "Method"
+ f = parse_func(tl, obj=o.nam)
+ o.add_method(f)
+ return o
+
+#######################################################################
+# The first thing in the file must be the Module declaration
+#
+
+t = tl.pop(0)
+if t.str != "Module":
+ raise Exception("\"Module\" must be first in file")
+t = tl.pop(0)
+vmod = vmod(t.str)
+
+#######################################################################
+# Parse the rest of the file
+#
+
+while len(tl) > 0:
+ t = tl.pop(0)
+
+ if t.str == "Init":
+ t = tl.pop(0)
+ vmod.set_init(t.str)
+ elif t.str == "Function":
+ f = parse_func(tl)
+ vmod.add_func(f)
+ elif t.str == "Object":
+ o = parse_obj(tl)
+ vmod.add_obj(o)
+ else:
+ raise Exception("Expected \"Init\", \"Fini\" or \"Function\"")
+
+#######################################################################
+# Parsing done, now process
+#
+
+fc = open("vcc_if.c", "w")
+fh = open("vcc_if.h", "w")
+
+file_header(fc)
+file_header(fh)
+
+fh.write('struct vrt_ctx;\n')
+fh.write('struct VCL_conf;\n')
+fh.write('struct vmod_priv;\n')
+fh.write("\n");
+
+vmod.c_proto(fh)
+
+fc.write("""#include "config.h"
+
+#include "vrt.h"
+#include "vcc_if.h"
+#include "vmod_abi.h"
+
+
+""")
+
+vmod.c_typedefs(fc)
+vmod.c_vmod(fc)
+
+fc.close()
+fh.close()
diff --git a/lib/libvcl/Makefile.am b/lib/libvcl/Makefile.am
deleted file mode 100644
index 91bc0d3..0000000
--- a/lib/libvcl/Makefile.am
+++ /dev/null
@@ -1,44 +0,0 @@
-#
-
-AM_LDFLAGS = $(AM_LT_LDFLAGS)
-
-AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include
-
-pkglib_LTLIBRARIES = libvcl.la
-
-libvcl_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
-
-libvcl_la_SOURCES = \
- vcc_compile.h \
- vcc_token_defs.h \
- \
- vcc_acl.c \
- vcc_action.c \
- vcc_backend.c \
- vcc_backend_util.c \
- vcc_compile.c \
- vcc_expr.c \
- vcc_parse.c \
- vcc_fixed_token.c \
- vcc_obj.c \
- vcc_storage.c \
- vcc_utils.c \
- vcc_symb.c \
- vcc_token.c \
- vcc_var.c \
- vcc_vmod.c \
- vcc_xref.c
-
-EXTRA_DIST = \
- generate.py
-
-dist_pkgdata_SCRIPTS = \
- vmodtool.py
-
-vcc_obj.c vcc_fixed_token.c vcc_token_defs.h: \
- $(srcdir)/generate.py $(top_srcdir)/include/vrt.h
- @PYTHON@ $(srcdir)/generate.py $(srcdir) $(top_builddir)
-
-CLEANFILES = $(builddir)/vcc_token_defs.h \
- $(builddir)/vcc_fixed_token.c \
- $(builddir)/vcc_obj.c
diff --git a/lib/libvcl/flint.lnt b/lib/libvcl/flint.lnt
deleted file mode 100644
index 60b3850..0000000
--- a/lib/libvcl/flint.lnt
+++ /dev/null
@@ -1,46 +0,0 @@
--passes=3
-
-// Review all below this line
-
--printf_code( H, void *, unsigned)
--printf_code( ju, long long unsigned)
--printf_code( jx, long long unsigned)
-
-+libh ../../config.h
--header(../../config.h)
--sem(lbv_assert, r_no)
--sem(strchr, 1p, type(1), 2n == 0 ? (@p < 1p) : (@p < 1p || @p == 0 ))
--sem(vcc_new_source, custodial(1))
-
--emacro((???),va_arg) // the va_arg() macro can yield 415, 416, 661, 662
- // 796 and 797 (out-of-bounds errors).
-
-
--emacro(413, offsetof) // likely null pointer
-
-// -ffc // No automatic custody
-
--esym(534, vsb_printf) // Ignoring return value of function
--esym(534, vsb_cat) // Ignoring return value of function
--esym(534, vsb_bcat) // Ignoring return value of function
--esym(534, vsb_vprintf) // Ignoring return value of function
--esym(534, memset) // Ignoring return value of function
--e788 // enum constant 'HND_Unclass' not used within defaulted switch
--e716 // while(1) ...
--e786 // String concatenation within initializer
--e732 // Loss of sign (arg. no. 2) (int to unsigned int)
-
-
--e763 // Redundant declaration for symbol '...' previously declared
-
-
--e737 // Loss of sign in promotion from int to unsigned int
--e534 // Ignoring return value of function
--e506 // Constant value boolean
--e774 // Boolean within 'if' always evaluates to False
--e713 // Loss of precision (assignment) (unsigned long long to long long)
--e574 // Signed-unsigned mix with relational
--e539 // Did not expect positive indentation
--e734 // Loss of precision (assignment) (31 bits to 8 bits)
--e747 // Significant prototype coercion (arg. no. 2) long
--e712 // Loss of precision (assignment) (long long to
diff --git a/lib/libvcl/flint.sh b/lib/libvcl/flint.sh
deleted file mode 100755
index 3bb465a..0000000
--- a/lib/libvcl/flint.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/sh
-
-flexelint \
- -I/usr/include \
- -I. \
- -I../.. \
- -I../../include \
- -I../../contrib/libevent \
- flint.lnt \
- *.c
diff --git a/lib/libvcl/generate.py b/lib/libvcl/generate.py
deleted file mode 100755
index 012098a..0000000
--- a/lib/libvcl/generate.py
+++ /dev/null
@@ -1,952 +0,0 @@
-#!/usr/local/bin/python3.1
-#-
-# Copyright (c) 2006 Verdens Gang AS
-# Copyright (c) 2006-2013 Varnish Software AS
-# All rights reserved.
-#
-# Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
-# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-# SUCH DAMAGE.
-#
-# Generate various .c and .h files for the VCL compiler and the interfaces
-# for it.
-
-#######################################################################
-# These are our tokens
-
-# We could drop all words such as "include", "if" etc, and use the
-# ID type instead, but declaring them tokens makes them reserved words
-# which hopefully makes for better error messages.
-# XXX: does it actually do that ?
-
-import sys
-
-srcroot = "../.."
-buildroot = "../.."
-if len(sys.argv) == 3:
- srcroot = sys.argv[1]
- buildroot = sys.argv[2]
-
-tokens = {
- "T_INC": "++",
- "T_DEC": "--",
- "T_CAND": "&&",
- "T_COR": "||",
- "T_LEQ": "<=",
- "T_EQ": "==",
- "T_NEQ": "!=",
- "T_GEQ": ">=",
- "T_SHR": ">>",
- "T_SHL": "<<",
- "T_INCR": "+=",
- "T_DECR": "-=",
- "T_MUL": "*=",
- "T_DIV": "/=",
- "T_NOMATCH": "!~",
-
- # Single char tokens, for convenience on one line
- None: "{}()*+-/%><=;!&.|~,",
-
- # These have handwritten recognizers
- "ID": None,
- "CNUM": None,
- "CSTR": None,
- "EOI": None,
- "CSRC": None,
-}
-
-#######################################################################
-# Our methods and actions
-
-returns =(
- ('recv', "C", ('error', 'pass', 'pipe', 'hash', 'purge',)),
- ('pipe', "C", ('error', 'pipe',)),
- ('pass', "C", ('error', 'restart', 'fetch',)),
- ('hash', "C", ('lookup',)),
- ('purge', "C", ('error', 'fetch',)),
- ('miss', "C", ('error', 'restart', 'pass', 'fetch',)),
- ('hit', "C", ('error', 'restart', 'pass', 'fetch', 'deliver',)),
- ('backend_fetch', "B", ('fetch', 'abandon')),
- ('backend_response', "B", ('deliver', 'retry', 'abandon')),
- ('deliver', "C", ('restart', 'deliver',)),
- ('error', "C", ('restart', 'deliver',)),
- ('init', "", ('ok',)),
- ('fini', "", ('ok',)),
-)
-
-#######################################################################
-# Variables available in sessions
-#
-# 'all' means all methods
-# 'client' means all methods tagged "C"
-# 'backend' means all methods tagged "B"
-# 'both' means all methods tagged "B" or "C"
-
-sp_variables = [
- ('client.ip',
- 'IP',
- ( 'both',),
- ( ),
- ),
- ('client.identity',
- 'STRING',
- ( 'both',),
- ( 'both',),
- ),
- ('server.ip',
- 'IP',
- ( 'client',),
- ( ),
- ),
- ('server.hostname',
- 'STRING',
- ( 'client',),
- ( ),
- ),
- ('server.identity',
- 'STRING',
- ( 'client',),
- ( ),
- ),
- ('server.port',
- 'INT',
- ( 'client',),
- ( ),
- ),
- ('req.method',
- 'STRING',
- ( 'client',),
- ( 'client',),
- ),
- ('req.request',
- 'STRING',
- ( 'client',),
- ( 'client',),
- ),
- ('req.url',
- 'STRING',
- ( 'client',),
- ( 'client',),
- ),
- ('req.proto',
- 'STRING',
- ( 'client',),
- ( 'client',),
- ),
- ('req.http.',
- 'HEADER',
- ( 'client',),
- ( 'client',),
- ),
- ('req.restarts',
- 'INT',
- ( 'client',),
- ( ),
- ),
- ('req.esi_level',
- 'INT',
- ( 'client',),
- ( ),
- ),
- ('req.ttl',
- 'DURATION',
- ( 'client',),
- ( 'client',),
- ),
- ('req.grace',
- 'DURATION',
- ( 'client',),
- ( 'client',),
- ),
- ('req.keep',
- 'DURATION',
- ( 'client',),
- ( 'client',),
- ),
- ('req.xid',
- 'STRING',
- ( 'client',),
- ( ),
- ),
- ('req.esi',
- 'BOOL',
- ( 'recv', 'backend_response', 'deliver', 'error',),
- ( 'recv', 'backend_response', 'deliver', 'error',),
- ),
- ('req.can_gzip',
- 'BOOL',
- ( 'client',),
- ( ),
- ),
- ('req.backend',
- 'BACKEND',
- ( 'client',),
- ( 'client',),
- ),
- ('req.backend.healthy',
- 'BOOL',
- ( 'client',),
- ( ),
- ),
- ('req.hash_ignore_busy',
- 'BOOL',
- ( 'recv',),
- ( 'recv',),
- ),
- ('req.hash_always_miss',
- 'BOOL',
- ( 'recv',),
- ( 'recv',),
- ),
- ('bereq.retries',
- 'INT',
- ( 'backend',),
- ( ),
- ),
- ('bereq.backend',
- 'BACKEND',
- ( 'pipe', 'backend', ),
- ( 'pipe', 'backend', ),
- ),
- ('bereq.backend.healthy',
- 'BOOL',
- ( 'pipe', 'backend', ),
- ( ),
- ),
- ('bereq.method',
- 'STRING',
- ( 'pipe', 'backend', ),
- ( 'pipe', 'backend', ),
- ),
- ('bereq.request',
- 'STRING',
- ( 'pipe', 'backend', ),
- ( 'pipe', 'backend', ),
- ),
- ('bereq.url',
- 'STRING',
- ( 'pipe', 'backend', ),
- ( 'pipe', 'backend', ),
- ),
- ('bereq.proto',
- 'STRING',
- ( 'pipe', 'backend', ),
- ( 'pipe', 'backend', ),
- ),
- ('bereq.http.',
- 'HEADER',
- ( 'pipe', 'backend', ),
- ( 'pipe', 'backend', ),
- ),
- ('bereq.uncacheable',
- 'BOOL',
- ( 'backend', ),
- ( 'backend', ),
- ),
- ('bereq.connect_timeout',
- 'DURATION',
- ( 'pipe', 'backend', ),
- ( 'pipe', 'backend', ),
- ),
- ('bereq.first_byte_timeout',
- 'DURATION',
- ( 'pipe', 'backend', ),
- ( 'pipe', 'backend', ),
- ),
- ('bereq.between_bytes_timeout',
- 'DURATION',
- ( 'pipe', 'backend', ),
- ( 'pipe', 'backend', ),
- ),
- ('beresp.proto',
- 'STRING',
- ( 'backend_response',),
- ( 'backend_response',),
- ),
- ('beresp.status',
- 'INT',
- ( 'backend_response',),
- ( 'backend_response',),
- ),
- ('beresp.response',
- 'STRING',
- ( 'backend_response',),
- ( 'backend_response',),
- ),
- ('beresp.http.',
- 'HEADER',
- ( 'backend_response',),
- ( 'backend_response',),
- ),
- ('beresp.do_esi',
- 'BOOL',
- ( 'backend_response',),
- ( 'backend_response',),
- ),
- ('beresp.do_stream',
- 'BOOL',
- ( 'backend_response',),
- ( 'backend_response',),
- ),
- ('beresp.do_gzip',
- 'BOOL',
- ( 'backend_response',),
- ( 'backend_response',),
- ),
- ('beresp.do_gunzip',
- 'BOOL',
- ( 'backend_response',),
- ( 'backend_response',),
- ),
- ('beresp.uncacheable',
- 'BOOL',
- ( 'backend_response',),
- ( 'backend_response',),
- ),
- ('beresp.ttl',
- 'DURATION',
- ( 'backend_response',),
- ( 'backend_response',),
- ),
- ('beresp.grace',
- 'DURATION',
- ( 'backend_response',),
- ( 'backend_response',),
- ),
- ('beresp.keep',
- 'DURATION',
- ( 'backend_response',),
- ( 'backend_response',),
- ),
- ('beresp.backend.name',
- 'STRING',
- ( 'backend_response',),
- ( ),
- ),
- ('beresp.backend.ip',
- 'IP',
- ( 'backend_response',),
- ( ),
- ),
- ('beresp.backend.port',
- 'INT',
- ( 'backend_response',),
- ( ),
- ),
- ('beresp.storage',
- 'STRING',
- ( 'backend_response',),
- ( 'backend_response',),
- ),
- ('obj.proto',
- 'STRING',
- ( 'hit', 'error',),
- ( 'hit', 'error',),
- ),
- ('obj.status',
- 'INT',
- ( 'error',),
- ( 'error',),
- ),
- ('obj.response',
- 'STRING',
- ( 'error',),
- ( 'error',),
- ),
- ('obj.hits',
- 'INT',
- ( 'hit', 'deliver',),
- ( 'hit', 'deliver',),
- ),
- ('obj.http.',
- 'HEADER',
- ( 'hit', 'error',),
- ( 'error',), # XXX ?
- ),
- ('obj.ttl',
- 'DURATION',
- ( 'hit', 'error',),
- ( 'hit', 'error',),
- ),
- ('obj.grace',
- 'DURATION',
- ( 'hit', 'error',),
- ( 'hit', 'error',),
- ),
- ('obj.keep',
- 'DURATION',
- ( 'hit', 'error',),
- ( 'hit', 'error',),
- ),
- ('obj.last_use',
- 'TIME',
- ( 'hit', 'deliver',),
- ( 'hit', 'deliver',),
- ),
- ('obj.uncacheable',
- 'BOOL',
- ( 'hit', 'deliver', 'error',),
- ( ),
- ),
- ('resp.proto',
- 'STRING',
- ( 'deliver',),
- ( 'deliver',),
- ),
- ('resp.status',
- 'INT',
- ( 'deliver',),
- ( 'deliver',),
- ),
- ('resp.response',
- 'STRING',
- ( 'deliver',),
- ( 'deliver',),
- ),
- ('resp.http.',
- 'HEADER',
- ( 'deliver',),
- ( 'deliver',),
- ),
- ('now',
- 'TIME',
- ( 'all',),
- ( ),
- ),
-]
-
-stv_variables = (
- ('free_space', 'BYTES', "0."),
- ('used_space', 'BYTES', "0."),
- ('happy', 'BOOL', "0"),
-)
-
-#######################################################################
-# VCL to C type conversion
-
-vcltypes = {
- 'STRING_LIST': "void*",
-}
-
-fi = open(srcroot + "/include/vrt.h")
-
-for i in fi:
- j = i.split();
- if len(j) < 3:
- continue
- if j[0] != "typedef":
- continue
- if j[-1][-1] != ";":
- continue
- if j[-1][:4] != "VCL_":
- continue
- d = " ".join(j[1:-1])
- vcltypes[j[-1][4:-1]] = d
-fi.close()
-
-#######################################################################
-# Nothing is easily configurable below this line.
-#######################################################################
-
-import sys
-import copy
-
-#######################################################################
-# Emit a function to recognize tokens in a string
-
-def emit_vcl_fixed_token(fo, tokens):
-
- recog = list()
- emit = dict()
- for i in tokens:
- j = tokens[i]
- if (j != None):
- recog.append(j)
- emit[j] = i
-
- recog.sort()
- rrecog = copy.copy(recog)
- rrecog.sort(key = lambda x: -len(x))
-
- fo.write("""
-#define M1()\tdo {*q = p + 1; return (p[0]); } while (0)
-#define M2(c,t)\tdo {if (p[1] == (c)) { *q = p + 2; return (t); }} while (0)
-
-unsigned
-vcl_fixed_token(const char *p, const char **q)
-{
-
-\tswitch (p[0]) {
-""")
- last_initial = None
- for i in recog:
- if (i[0] == last_initial):
- continue
- last_initial = i[0]
- fo.write("\tcase '%s':\n" % last_initial)
- need_ret = True
- for j in rrecog:
- if (j[0] != last_initial):
- continue
- if len(j) == 2:
- fo.write("\t\tM2('%s', %s);\n" %
- (j[1], emit[j]))
- elif len(j) == 1:
- fo.write("\t\tM1();\n")
- need_ret = False
- else:
- fo.write("\t\tif (")
- k = 1
- l = len(j)
- while (k < l):
- fo.write("p[%d] == '%s'" % (k, j[k]))
- fo.write(" &&")
- if (k % 3) == 0:
- fo.write("\n\t\t ")
- else:
- fo.write(" ")
- k += 1
- fo.write("!isvar(p[%d])) {\n" % l)
- fo.write("\t\t\t*q = p + %d;\n" % l)
- fo.write("\t\t\treturn (%s);\n" % emit[j])
- fo.write("\t\t}\n")
- if need_ret:
- fo.write("\t\treturn (0);\n")
- fo.write("\tdefault:\n\t\treturn (0);\n\t}\n}\n")
-
-#######################################################################
-# Emit the vcl_tnames (token->string) conversion array
-
-def emit_vcl_tnames(fo, tokens):
- fo.write("\nconst char * const vcl_tnames[256] = {\n")
- l = list(tokens.keys())
- l.sort()
- for i in l:
- j = tokens[i]
- if j == None:
- j = i
- if i[0] == "'":
- j = i
- fo.write("\t[%s] = \"%s\",\n" % (i, j))
- fo.write("};\n")
-
-#######################################################################
-# Read a C-source file and spit out code that outputs it with VSB_cat()
-
-def emit_file(fo, fn):
- fi = open(fn)
- fc = fi.read()
- fi.close()
-
- w = 66 # Width of lines, after white space prefix
- maxlen = 10240 # Max length of string literal
-
- x = 0
- l = 0
- fo.write("\n\t/* %s */\n\n" % fn)
- for c in fc:
- if l == 0:
- fo.write("\tVSB_cat(sb, \"")
- l += 12
- x += 12
- if x == 0:
- fo.write("\t \"")
- d = c
- if c == '\n':
- d = "\\n"
- elif c == '\t':
- d = "\\t"
- elif c == '"':
- d = "\\\""
- elif c == '\\':
- d = "\\\\"
-
- if c == '\n' and x > w - 20:
- fo.write(d + "\"\n")
- x = 0
- continue
- if c.isspace() and x > w - 10:
- fo.write(d + "\"\n")
- x = 0
- continue
-
- fo.write(d)
- x += len(d)
- l += len(d)
- if l > maxlen:
- fo.write("\");\n")
- l = 0;
- x = 0
- if x > w - 3:
- fo.write("\"\n")
- x = 0
- if x != 0:
- fo.write("\"")
- if l != 0:
- fo.write("\t);\n")
-
-#######################################################################
-
-def polish_tokens(tokens):
- # Expand single char tokens
- st = tokens[None]
- del tokens[None]
-
- for i in st:
- tokens["'" + i + "'"] = i
-#######################################################################
-
-def file_header(fo):
- fo.write("""/*
- * NB: This file is machine generated, DO NOT EDIT!
- *
- * Edit and run generate.py instead
- */
-""")
-
-#######################################################################
-
-polish_tokens(tokens)
-
-fo = open(buildroot + "/lib/libvcl/vcc_token_defs.h", "w")
-
-file_header(fo)
-
-j = 128
-l = list(tokens.keys())
-l.sort()
-for i in l:
- if i[0] == "'":
- continue
- fo.write("#define\t%s %d\n" % (i, j))
- j += 1
- assert j < 256
-
-fo.close()
-
-#######################################################################
-
-rets = dict()
-vcls = list()
-vcls_client = list()
-vcls_backend = list()
-for i in returns:
- vcls.append(i[0])
- for j in i[1]:
- if j == "B":
- vcls_backend.append(i[0])
- elif j == "C":
- vcls_client.append(i[0])
- for j in i[2]:
- rets[j] = True
-
-#######################################################################
-
-fo = open(buildroot + "/include/tbl/vcl_returns.h", "w")
-
-file_header(fo)
-
-fo.write("\n/*lint -save -e525 -e539 */\n")
-
-fo.write("\n#ifdef VCL_RET_MAC\n")
-l = list(rets.keys())
-l.sort()
-for i in l:
- fo.write("VCL_RET_MAC(%s, %s" % (i.lower(), i.upper()))
- s=", "
- for j in returns:
- if i in j[2]:
- fo.write("%sVCL_MET_%s" % (s, j[0].upper()))
- s = " | "
- fo.write(")\n")
-fo.write("#endif\n")
-
-fo.write("\n#ifdef VCL_MET_MAC\n")
-for i in returns:
- fo.write("VCL_MET_MAC(%s,%s,\n" % (i[0].lower(), i[0].upper()))
- p = " ("
- for j in i[2]:
- fo.write(" %s(1U << VCL_RET_%s)\n" % (p, j.upper()))
- p = "| "
- fo.write("))\n")
-fo.write("#endif\n")
-fo.write("\n/*lint -restore */\n")
-fo.close()
-
-#######################################################################
-
-fo = open(buildroot + "/include/vcl.h", "w")
-
-file_header(fo)
-
-fo.write("""
-struct vrt_ctx;
-struct req;
-struct busyobj;
-struct ws;
-struct cli;
-struct worker;
-
-typedef int vcl_init_f(struct cli *);
-typedef void vcl_fini_f(struct cli *);
-typedef int vcl_func_f(const struct vrt_ctx *ctx);
-""")
-
-
-fo.write("\n/* VCL Methods */\n")
-n = 0
-for i in returns:
- fo.write("#define VCL_MET_%s\t\t(1U << %d)\n" % (i[0].upper(), n))
- n += 1
-
-fo.write("\n#define VCL_MET_MAX\t\t%d\n" % n)
-fo.write("\n#define VCL_MET_MASK\t\t0x%x\n" % ((1 << n) - 1))
-
-
-fo.write("\n/* VCL Returns */\n")
-n = 0
-l = list(rets.keys())
-l.sort()
-for i in l:
- fo.write("#define VCL_RET_%s\t\t%d\n" % (i.upper(), n))
- n += 1
-
-fo.write("\n#define VCL_RET_MAX\t\t%d\n" % n)
-
-
-fo.write("""
-struct VCL_conf {
- unsigned magic;
-#define VCL_CONF_MAGIC 0x7406c509 /* from /dev/random */
-
- struct director **director;
- unsigned ndirector;
- struct vrt_ref *ref;
- unsigned nref;
- unsigned busy;
- unsigned discard;
-
- unsigned nsrc;
- const char **srcname;
- const char **srcbody;
-
- vcl_init_f *init_vcl;
- vcl_fini_f *fini_vcl;
-""")
-
-for i in returns:
- fo.write("\tvcl_func_f\t*" + i[0] + "_func;\n")
-
-fo.write("""
-};
-""")
-
-fo.close()
-
-#######################################################################
-
-def restrict(fo, spec):
- d = dict()
- for j in spec:
- if j == 'all':
- for i in vcls:
- d[i] = True
- elif j == 'backend':
- for i in vcls_backend:
- d[i] = True
- elif j == 'client':
- for i in vcls_client:
- d[i] = True
- elif j == 'both':
- for i in vcls_client:
- d[i] = True
- for i in vcls_backend:
- d[i] = True
- else:
- assert j in vcls
- d[j] = True
- p = ""
- n = 0
- l = list(d.keys())
- l.sort()
- w = 0
- fo.write("\t\t")
- for j in l:
- x = p + "VCL_MET_" + j.upper()
- if w + len(x) > 60:
- fo.write("\n\t\t")
- w = 0
- fo.write(x)
- w += len(x)
- p = " | "
- if len(d) == 0:
- fo.write("0")
- fo.write(",\n")
-
-#######################################################################
-
-fh = open(buildroot + "/include/vrt_obj.h", "w")
-file_header(fh)
-
-fo = open(buildroot + "/lib/libvcl/vcc_obj.c", "w")
-file_header(fo)
-
-fo.write("""
-#include "config.h"
-
-#include <stdio.h>
-
-#include "vcc_compile.h"
-
-const struct var vcc_vars[] = {
-""")
-
-sp_variables.sort()
-for i in sp_variables:
- typ = i[1]
- cnam = i[0].replace(".", "_")
- ctyp = vcltypes[typ]
-
- fo.write("\t{ \"%s\", %s, %d,\n" % (i[0], typ, len(i[0])))
-
- if len(i[2]) == 0:
- fo.write('\t NULL,\t/* No reads allowed */\n')
- elif typ == "HEADER":
- fo.write('\t "HDR_')
- fo.write(i[0].split(".")[0].upper())
- fo.write('",\n')
- else:
- fo.write('\t "VRT_r_%s(ctx)",\n' % cnam)
- fh.write(ctyp + " VRT_r_%s(const struct vrt_ctx *);\n" % cnam )
- restrict(fo, i[2])
-
- if len(i[3]) == 0:
- fo.write('\t NULL,\t/* No writes allowed */\n')
- elif typ == "HEADER":
- fo.write('\t "HDR_')
- fo.write(i[0].split(".")[0].upper())
- fo.write('",\n')
- else:
- fo.write('\t "VRT_l_%s(ctx, ",\n' % cnam)
- fh.write("void VRT_l_%s(const struct vrt_ctx *, " % cnam)
- if typ != "STRING":
- fh.write(ctyp + ");\n")
- else:
- fh.write(ctyp + ", ...);\n")
- restrict(fo, i[3])
-
- fo.write("\t},\n")
-
-fo.write("\t{ NULL }\n};\n")
-
-for i in stv_variables:
- fh.write(vcltypes[i[1]] + " VRT_Stv_" + i[0] + "(const char *);\n")
-
-fo.close()
-fh.close()
-
-#######################################################################
-
-fo = open(buildroot + "/lib/libvcl/vcc_fixed_token.c", "w")
-
-file_header(fo)
-fo.write("""
-
-#include "config.h"
-
-#include <ctype.h>
-#include <stdio.h>
-
-#include "vcc_compile.h"
-""")
-
-emit_vcl_fixed_token(fo, tokens)
-emit_vcl_tnames(fo, tokens)
-
-fo.write("""
-void
-vcl_output_lang_h(struct vsb *sb)
-{
-""")
-
-emit_file(fo, buildroot + "/include/vcl.h")
-emit_file(fo, srcroot + "/include/vrt.h")
-emit_file(fo, buildroot + "/include/vrt_obj.h")
-
-fo.write("""
-}
-""")
-
-fo.close()
-
-#######################################################################
-ft = open(buildroot + "/include/tbl/vcc_types.h", "w")
-file_header(ft)
-
-ft.write("/*lint -save -e525 -e539 */\n")
-
-i = list(vcltypes.keys())
-i.sort()
-for j in i:
- ft.write("VCC_TYPE(" + j + ")\n")
-ft.write("/*lint -restore */\n")
-ft.close()
-
-#######################################################################
-
-fo = open(buildroot + "/include/tbl/vrt_stv_var.h", "w")
-
-file_header(fo)
-
-fo.write("""
-#ifndef VRTSTVTYPE
-#define VRTSTVTYPE(ct)
-#define VRTSTVTYPEX
-#endif
-#ifndef VRTSTVVAR
-#define VRTSTVVAR(nm, vtype, ctype, dval)
-#define VRTSTVVARX
-#endif
-""")
-
-x=dict()
-for i in stv_variables:
- ct = vcltypes[i[1]]
- if not ct in x:
- fo.write("VRTSTVTYPE(" + ct + ")\n")
- x[ct] = 1
- fo.write("VRTSTVVAR(" + i[0] + ",\t" + i[1] + ",\t")
- fo.write(ct + ",\t" + i[2] + ")")
- fo.write("\n")
-
-fo.write("""
-#ifdef VRTSTVTYPEX
-#undef VRTSTVTYPEX
-#undef VRTSTVTYPE
-#endif
-#ifdef VRTSTVVARX
-#undef VRTSTVVARX
-#undef VRTSTVVAR
-#endif
-""")
-
-fo.close
diff --git a/lib/libvcl/vcc_acl.c b/lib/libvcl/vcc_acl.c
deleted file mode 100644
index fa8a7d7..0000000
--- a/lib/libvcl/vcc_acl.c
+++ /dev/null
@@ -1,502 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2010 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include <netinet/in.h>
-
-#include <netdb.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "vcc_compile.h"
-
-#include "vrt.h"
-
-struct acl_e {
- VTAILQ_ENTRY(acl_e) list;
- unsigned char data[VRT_ACL_MAXADDR + 1];
- unsigned mask;
- unsigned not;
- unsigned para;
- struct token *t_addr;
- struct token *t_mask;
-};
-
-/* Compare two acl rules for ordering */
-
-#define CMP(a, b) \
- do { \
- if ((a) < (b)) \
- return (-1); \
- else if ((b) < (a)) \
- return (1); \
- } while (0)
-
-static int
-vcl_acl_cmp(struct acl_e *ae1, struct acl_e *ae2)
-{
- unsigned char *p1, *p2;
- unsigned m;
-
- p1 = ae1->data;
- p2 = ae2->data;
- m = ae1->mask;
- if (ae2->mask < m)
- m = ae2->mask;
- for (; m >= 8; m -= 8) {
- CMP(*p1, *p2);
- p1++;
- p2++;
- }
- if (m) {
- m = 0xff00 >> m;
- m &= 0xff;
- CMP(*p1 & m, *p2 & m);
- }
- /* Long mask is less than short mask */
- CMP(ae2->mask, ae1->mask);
-
- return (0);
-}
-
-
-static void
-vcc_acl_add_entry(struct vcc *tl, const struct acl_e *ae, int l,
- const unsigned char *u, int fam)
-{
- struct acl_e *ae2, *aen;
- int i;
-
- if (fam == PF_INET && ae->mask > 32) {
- VSB_printf(tl->sb,
- "Too wide mask (%u) for IPv4 address\n", ae->mask);
- if (ae->t_mask != NULL)
- vcc_ErrWhere(tl, ae->t_mask);
- else
- vcc_ErrWhere(tl, ae->t_addr);
- return;
- }
- if (fam == PF_INET6 && ae->mask > 128) {
- VSB_printf(tl->sb,
- "Too wide mask (%u) for IPv6 address\n", ae->mask);
- vcc_ErrWhere(tl, ae->t_mask);
- return;
- }
-
- /* Make a copy from the template */
- aen = TlAlloc(tl, sizeof *ae2);
- AN(aen);
- *aen = *ae;
-
- /* We treat family as part of address, it saves code */
- assert(fam <= 0xff);
- aen->data[0] = fam & 0xff;
- aen->mask += 8;
-
- memcpy(aen->data + 1, u, l);
-
- VTAILQ_FOREACH(ae2, &tl->acl, list) {
- i = vcl_acl_cmp(aen, ae2);
- if (i == 0) {
- /*
- * If the two rules agree, silently ignore it
- * XXX: is that counter intuitive ?
- */
- if (aen->not == ae2->not)
- return;
- VSB_printf(tl->sb, "Conflicting ACL entries:\n");
- vcc_ErrWhere(tl, ae2->t_addr);
- VSB_printf(tl->sb, "vs:\n");
- vcc_ErrWhere(tl, aen->t_addr);
- return;
- }
- /*
- * We could eliminate pointless rules here, for instance in:
- * "10.1.0.1";
- * "10.1";
- * The first rule is clearly pointless, as the second one
- * covers it.
- *
- * We do not do this however, because the shmlog may
- * be used to gather statistics.
- */
- if (i < 0) {
- VTAILQ_INSERT_BEFORE(ae2, aen, list);
- return;
- }
- }
- VTAILQ_INSERT_TAIL(&tl->acl, aen, list);
-}
-
-static void
-vcc_acl_try_getaddrinfo(struct vcc *tl, struct acl_e *ae)
-{
- struct addrinfo *res0, *res, hint;
- struct sockaddr_in *sin4;
- struct sockaddr_in6 *sin6;
- unsigned char *u, i4, i6;
- int error;
-
- memset(&hint, 0, sizeof hint);
- hint.ai_family = PF_UNSPEC;
- hint.ai_socktype = SOCK_STREAM;
- error = getaddrinfo(ae->t_addr->dec, "0", &hint, &res0);
- if (error) {
- if (ae->para) {
- VSB_printf(tl->sb,
- "Warning: %s ignored\n -- %s\n",
- ae->t_addr->dec, gai_strerror(error));
- Fh(tl, 1, "/* Ignored ACL entry: %s%s",
- ae->para ? "\"(\" " : "", ae->not ? "\"!\" " : "");
- EncToken(tl->fh, ae->t_addr);
- if (ae->t_mask)
- Fh(tl, 0, "/%u", ae->mask);
- Fh(tl, 0, "%s\n", ae->para ? " \")\"" : "");
- Fh(tl, 1, " * getaddrinfo: %s */\n",
- gai_strerror(error));
- } else {
- VSB_printf(tl->sb,
- "DNS lookup(%s): %s\n",
- ae->t_addr->dec, gai_strerror(error));
- vcc_ErrWhere(tl, ae->t_addr);
- }
- return;
- }
-
- i4 = i6 = 0;
- for(res = res0; res != NULL; res = res->ai_next) {
- switch(res->ai_family) {
- case PF_INET:
- assert(PF_INET < 256);
- sin4 = (void*)res->ai_addr;
- assert(sizeof(sin4->sin_addr) == 4);
- u = (void*)&sin4->sin_addr;
- if (ae->t_mask == NULL)
- ae->mask = 32;
- i4++;
- vcc_acl_add_entry(tl, ae, 4, u, res->ai_family);
- break;
- case PF_INET6:
- assert(PF_INET6 < 256);
- sin6 = (void*)res->ai_addr;
- assert(sizeof(sin6->sin6_addr) == 16);
- u = (void*)&sin6->sin6_addr;
- if (ae->t_mask == NULL)
- ae->mask = 128;
- i6++;
- vcc_acl_add_entry(tl, ae, 16, u, res->ai_family);
- break;
- default:
- VSB_printf(tl->sb,
- "Ignoring unknown protocol family (%d) for %.*s\n",
- res->ai_family, PF(ae->t_addr));
- continue;
- }
- ERRCHK(tl);
- }
- freeaddrinfo(res0);
-
- if (ae->t_mask != NULL && i4 > 0 && i6 > 0) {
- VSB_printf(tl->sb,
- "Mask (%u) specified, but string resolves to"
- " both IPv4 and IPv6 addresses.\n", ae->mask);
- vcc_ErrWhere(tl, ae->t_mask);
- return;
- }
-}
-
-/*--------------------------------------------------------------------
- * Ancient stupidity on the part of X/Open and other standards orgs
- * dictate that "192.168" be translated to 192.0.0.168. Ever since
- * CIDR happened, "192.168/16" notation has been used, but appearantly
- * no API supports parsing this, so roll our own.
- */
-
-static int
-vcc_acl_try_netnotation(struct vcc *tl, struct acl_e *ae)
-{
- unsigned char b[4];
- int i, j, k;
- unsigned u;
- const char *p;
-
- memset(b, 0, sizeof b);
- p = ae->t_addr->dec;
- for (i = 0; i < 4; i++) {
- j = sscanf(p, "%u%n", &u, &k);
- if (j != 1)
- return (0);
- if (u & ~0xff)
- return (0);
- b[i] = (unsigned char)u;
- if (p[k] == '\0')
- break;
- if (p[k] != '.')
- return (0);
- p += k + 1;
- }
- if (ae->t_mask == NULL)
- ae->mask = 8 + 8 * i;
- vcc_acl_add_entry(tl, ae, 4, b, AF_INET);
- return (1);
-}
-
-static void
-vcc_acl_entry(struct vcc *tl)
-{
- struct acl_e *ae;
-
- ae = TlAlloc(tl, sizeof *ae);
- AN(ae);
-
- if (tl->t->tok == '!') {
- ae->not = 1;
- vcc_NextToken(tl);
- }
-
- if (tl->t->tok == '(') {
- ae->para = 1;
- vcc_NextToken(tl);
- }
-
- if (!ae->not && tl->t->tok == '!') {
- ae->not = 1;
- vcc_NextToken(tl);
- }
-
- ExpectErr(tl, CSTR);
- ae->t_addr = tl->t;
- vcc_NextToken(tl);
-
- if (tl->t->tok == '/') {
- vcc_NextToken(tl);
- ae->t_mask = tl->t;
- ExpectErr(tl, CNUM);
- ae->mask = vcc_UintVal(tl);
- }
-
- if (ae->para)
- SkipToken(tl, ')');
-
- if (!vcc_acl_try_netnotation(tl, ae)) {
- ERRCHK(tl);
- vcc_acl_try_getaddrinfo(tl, ae);
- }
- ERRCHK(tl);
-}
-
-/*********************************************************************
- * Emit a function to match the ACL we have collected
- */
-
-/*
- * XXX: this is semi-silly. We try really hard to not depend in the
- * XXX: systems include files while compiling VCL, but we need to know
- * XXX: the size of the sa_familiy member.
- * XXX: FlexeLint complains about these antics, so isolate it in a
- * XXX: separate function.
- */
-
-/*lint -save -e506 -e774 -e550 */
-static void
-c_is_a_silly_language(const struct vcc *tl)
-{
- struct sockaddr sa;
-
- assert(sizeof (unsigned char) == 1);
- assert(sizeof (unsigned short) == 2);
- assert(sizeof (unsigned int) == 4);
- if (sizeof sa.sa_family == 1)
- Fh(tl, 0, "\tunsigned char fam;\n");
- else if (sizeof sa.sa_family == 2)
- Fh(tl, 0, "\tunsigned short fam;\n");
- else if (sizeof sa.sa_family == 4)
- Fh(tl, 0, "\tunsigned int fam;\n");
- else
- assert(0 == __LINE__);
-}
-/*lint -restore */
-
-static void
-vcc_acl_emit(const struct vcc *tl, const char *acln, int anon)
-{
- struct acl_e *ae;
- int depth, l, m, i;
- unsigned at[VRT_ACL_MAXADDR + 1];
- const char *oc;
-
- Fh(tl, 0, "\nstatic int\n");
- Fh(tl, 0, "match_acl_%s_%s(const struct vrt_ctx *ctx, const void *p)\n",
- anon ? "anon" : "named", acln);
- Fh(tl, 0, "{\n");
- Fh(tl, 0, "\tconst unsigned char *a;\n");
- c_is_a_silly_language(tl);
-
- Fh(tl, 0, "\n");
- Fh(tl, 0, "\ta = p;\n");
- Fh(tl, 0, "\tVRT_memmove(&fam, a + %zd, sizeof fam);\n",
- offsetof(struct sockaddr, sa_family));
- Fh(tl, 0, "\tif (fam == %d)\n", PF_INET);
- Fh(tl, 0, "\t\ta += %zd;\n", offsetof(struct sockaddr_in, sin_addr));
- Fh(tl, 0, "\telse if (fam == %d)\n", PF_INET6);
- Fh(tl, 0, "\t\ta += %zd;\n", offsetof(struct sockaddr_in6, sin6_addr));
- Fh(tl, 0, "\telse {\n");
- Fh(tl, 0, "\t\tVRT_acl_log(ctx, \"NO_FAM %s\");\n", acln);
- Fh(tl, 0, "\t\treturn(0);\n");
- Fh(tl, 0, "\t}\n\n");
- depth = -1;
- oc = 0;
- at[0] = 256;
- VTAILQ_FOREACH(ae, &tl->acl, list) {
-
- /* Find how much common prefix we have */
- for (l = 0; l <= depth && l * 8 < ae->mask - 7; l++) {
- assert(l >= 0);
- if (ae->data[l] != at[l])
- break;
- }
-
- /* Back down, if necessary */
- oc = "";
- while (l <= depth) {
- Fh(tl, 0, "\t%*s}\n", -depth, "");
- depth--;
- }
-
- m = ae->mask;
- m -= l * 8;
- assert(m >= 0);
-
- /* Do whole byte compares */
- for (i = l; m >= 8; m -= 8, i++) {
- if (i == 0)
- Fh(tl, 0, "\t%*s%sif (fam == %d) {\n",
- -i, "", oc, ae->data[i]);
- else
- Fh(tl, 0, "\t%*s%sif (a[%d] == %d) {\n",
- -i, "", oc, i - 1, ae->data[i]);
- at[i] = ae->data[i];
- depth = i;
- oc = "";
- }
-
- if (m > 0) {
- /* Do fractional byte compares */
- Fh(tl, 0, "\t%*s%sif ((a[%d] & 0x%x) == %d) {\n",
- -i, "", oc, i - 1, (0xff00 >> m) & 0xff,
- ae->data[i] & ((0xff00 >> m) & 0xff));
- at[i] = 256;
- depth = i;
- oc = "";
- }
-
- i = (ae->mask + 7) / 8;
-
- if (!anon) {
- Fh(tl, 0, "\t%*sVRT_acl_log(ctx, \"%sMATCH %s \" ",
- -i, "", ae->not ? "NEG_" : "", acln);
- EncToken(tl->fh, ae->t_addr);
- if (ae->t_mask != NULL)
- Fh(tl, 0, " \"/%.*s\" ", PF(ae->t_mask));
- Fh(tl, 0, ");\n");
- }
-
- Fh(tl, 0, "\t%*sreturn (%d);\n", -i, "", ae->not ? 0 : 1);
- }
-
- /* Unwind */
- for (; 0 <= depth; depth--)
- Fh(tl, 0, "\t%*.*s}\n", depth, depth, "");
-
- /* Deny by default */
- if (!anon)
- Fh(tl, 0, "\tVRT_acl_log(ctx, \"NO_MATCH %s\");\n", acln);
- Fh(tl, 0, "\treturn (0);\n}\n");
-}
-
-void
-vcc_Acl_Hack(struct vcc *tl, char *b)
-{
- char acln[32];
- unsigned tcond;
-
- VTAILQ_INIT(&tl->acl);
- tcond = tl->t->tok;
- vcc_NextToken(tl);
- bprintf(acln, "%u", tl->unique++);
- vcc_acl_entry(tl);
- vcc_acl_emit(tl, acln, 1);
- sprintf(b, "%smatch_acl_anon_%s(ctx, \v1)",
- (tcond == T_NEQ ? "!" : ""), acln);
-}
-
-void
-vcc_Acl(struct vcc *tl)
-{
- struct token *an;
- int i;
- char acln[1024];
-
- vcc_NextToken(tl);
- VTAILQ_INIT(&tl->acl);
-
- ExpectErr(tl, ID);
- if (!vcc_isCid(tl->t)) {
- VSB_printf(tl->sb,
- "Names of VCL acl's cannot contain '-'\n");
- vcc_ErrWhere(tl, tl->t);
- return;
- }
- an = tl->t;
- vcc_NextToken(tl);
-
- i = vcc_AddDef(tl, an, SYM_ACL);
- if (i > 1) {
- VSB_printf(tl->sb, "ACL %.*s redefined\n", PF(an));
- vcc_ErrWhere(tl, an);
- return;
- }
- bprintf(acln, "%.*s", PF(an));
-
- SkipToken(tl, '{');
-
- while (tl->t->tok != '}') {
- vcc_acl_entry(tl);
- ERRCHK(tl);
- SkipToken(tl, ';');
- }
- SkipToken(tl, '}');
-
- vcc_acl_emit(tl, acln, 0);
-}
diff --git a/lib/libvcl/vcc_action.c b/lib/libvcl/vcc_action.c
deleted file mode 100644
index 4e441d2..0000000
--- a/lib/libvcl/vcc_action.c
+++ /dev/null
@@ -1,445 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2013 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * This file parses the real action of the VCL code, the procedure
- * statements which do the actual work.
- */
-
-#include "config.h"
-
-#include <string.h>
-
-#include "vcc_compile.h"
-
-/*--------------------------------------------------------------------*/
-
-static void
-parse_call(struct vcc *tl)
-{
-
- vcc_NextToken(tl);
- ExpectErr(tl, ID);
- vcc_AddCall(tl, tl->t);
- vcc_AddRef(tl, tl->t, SYM_SUB);
- Fb(tl, 1, "if (VGC_function_%.*s(ctx))\n", PF(tl->t));
- Fb(tl, 1, "\treturn (1);\n");
- vcc_NextToken(tl);
- return;
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-parse_error(struct vcc *tl)
-{
-
- VSB_printf(tl->sb,
- "Syntax has changed, use:\n"
- "\treturn(error(999));\n"
- "or\n"
- "\treturn(error(999, \"Response text\"));\n");
- vcc_ErrWhere(tl, tl->t);
- return;
-}
-
-/*--------------------------------------------------------------------*/
-
-static const struct arith {
- enum var_type type;
- unsigned oper;
- enum var_type want;
-} arith[] = {
- { INT, T_INCR, INT },
- { INT, T_DECR, INT },
- { INT, T_MUL, INT },
- { INT, T_DIV, INT },
- { INT, '=', INT },
- { INT, 0, INT },
- { TIME, T_INCR, DURATION },
- { TIME, T_DECR, DURATION },
- { TIME, T_MUL, REAL },
- { TIME, T_DIV, REAL },
- { TIME, '=', TIME },
- { TIME, 0, TIME },
- { DURATION, T_INCR, DURATION },
- { DURATION, T_DECR, DURATION },
- { DURATION, T_MUL, REAL },
- { DURATION, T_DIV, REAL },
- { DURATION, '=', DURATION },
- { DURATION, 0, DURATION },
- { VOID, '=', VOID }
-};
-
-static void
-parse_set(struct vcc *tl)
-{
- const struct var *vp;
- const struct arith *ap;
- enum var_type fmt;
-
- vcc_NextToken(tl);
- ExpectErr(tl, ID);
- vp = vcc_FindVar(tl, tl->t, 1, "cannot be set");
- ERRCHK(tl);
- assert(vp != NULL);
- Fb(tl, 1, "%s\n", vp->lname);
- tl->indent += INDENT;
- vcc_NextToken(tl);
- fmt = vp->fmt;
- for (ap = arith; ap->type != VOID; ap++) {
- if (ap->type != fmt)
- continue;
- if (ap->oper != tl->t->tok)
- continue;
- if (ap->oper != '=')
- Fb(tl, 1, "%s %c ", vp->rname, *tl->t->b);
- vcc_NextToken(tl);
- fmt = ap->want;
- break;
- }
- if (ap->type == VOID)
- SkipToken(tl, ap->oper);
- if (fmt == HEADER) {
- vcc_Expr(tl, STRING_LIST);
- } else if (fmt == STRING) {
- vcc_Expr(tl, STRING_LIST);
- } else {
- vcc_Expr(tl, fmt);
- }
- tl->indent -= INDENT;
- Fb(tl, 1, ");\n");
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-parse_unset(struct vcc *tl)
-{
- const struct var *vp;
-
- /* XXX: Wrong, should use VCC_Expr(HEADER) */
- vcc_NextToken(tl);
- ExpectErr(tl, ID);
- vp = vcc_FindVar(tl, tl->t, 1, "cannot be unset");
- ERRCHK(tl);
- assert(vp != NULL);
- if (vp->fmt != HEADER) {
- VSB_printf(tl->sb,
- "Only http header variables can be unset.\n");
- vcc_ErrWhere(tl, tl->t);
- return;
- }
- ERRCHK(tl);
- Fb(tl, 1, "%svrt_magic_string_unset);\n", vp->lname);
- vcc_NextToken(tl);
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-parse_new(struct vcc *tl)
-{
- struct symbol *sy1, *sy2, *sy3;
- const char *p, *s_obj, *s_init, *s_struct, *s_fini;
- char buf1[128];
- char buf2[128];
-
- vcc_NextToken(tl);
- ExpectErr(tl, ID);
- if (!vcc_isCid(tl->t)) {
- VSB_printf(tl->sb,
- "Names of VCL objects cannot contain '-'\n");
- vcc_ErrWhere(tl, tl->t);
- return;
- }
- sy1 = VCC_FindSymbol(tl, tl->t, SYM_NONE);
- XXXAZ(sy1);
-
- sy1 = VCC_AddSymbolTok(tl, tl->t, SYM_NONE); // XXX: NONE ?
- XXXAN(sy1);
- vcc_NextToken(tl);
-
- ExpectErr(tl, '=');
- vcc_NextToken(tl);
-
- ExpectErr(tl, ID);
- sy2 = VCC_FindSymbol(tl, tl->t, SYM_OBJECT);
- XXXAN(sy2);
-
- /*lint -save -e448 */
- /* Split the first three args */
- p = sy2->args;
- s_obj = p;
- p += strlen(p) + 1;
- s_init = p;
- while (p[0] != '\0' || p[1] != '\0')
- p++;
- p += 2;
- s_struct = p;
- p += strlen(p) + 1;
- s_fini = p + strlen(p) + 1;
- while (p[0] != '\0' || p[1] != '\0')
- p++;
- p += 2;
-
- Fh(tl, 0, "static %s *%s;\n\n", s_struct, sy1->name);
-
- vcc_NextToken(tl);
-
- bprintf(buf1, ", &%s, \"%s\"", sy1->name, sy1->name);
- vcc_Eval_Func(tl, s_init, buf1, "ASDF", s_init + strlen(s_init) + 1);
- Fd(tl, 0, "\t%s(&%s);\n", s_fini, sy1->name);
- ExpectErr(tl, ';');
-
- bprintf(buf1, ", %s", sy1->name);
- /* Split the methods from the args */
- while (*p != '\0') {
- p += strlen(s_obj);
- bprintf(buf2, "%s%s", sy1->name, p);
- sy3 = VCC_AddSymbolStr(tl, buf2, SYM_FUNC);
- AN(sy3);
- sy3->eval = vcc_Eval_SymFunc;
- p += strlen(p) + 1;
- sy3->cfunc = p;
- p += strlen(p) + 1;
-
- /* Functions which return VOID are procedures */
- if (!memcmp(p, "VOID\0", 5))
- sy3->kind = SYM_PROC;
-
- sy3->args = p;
- sy3->extra = TlDup(tl, buf1);
- while (p[0] != '\0' || p[1] != '\0') {
- if (!memcmp(p, "ENUM\0", 5)) {
- /* XXX: Special case for ENUM that has
- it's own \0\0 end marker. Not exactly
- elegant, we should consider
- alternatives here. Maybe runlength
- encode the entire block? */
- p += strlen(p) + 1;
- while (p[0] != '\0' || p[1] != '\0')
- p++;
- }
- p++;
- }
- p += 2;
- }
- /*lint -restore */
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-parse_ban(struct vcc *tl)
-{
-
- vcc_NextToken(tl);
-
- ExpectErr(tl, '(');
- vcc_NextToken(tl);
-
- Fb(tl, 1, "VRT_ban_string(\n");
- tl->indent += INDENT;
- vcc_Expr(tl, STRING);
- tl->indent -= INDENT;
- ERRCHK(tl);
- Fb(tl, 1, ");\n");
-
- ExpectErr(tl, ')');
- vcc_NextToken(tl);
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-parse_hash_data(struct vcc *tl)
-{
- vcc_NextToken(tl);
- SkipToken(tl, '(');
-
- Fb(tl, 1, "VRT_hashdata(ctx, ");
- vcc_Expr(tl, STRING_LIST);
- ERRCHK(tl);
- Fb(tl, 0, ");\n");
- SkipToken(tl, ')');
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-parse_return(struct vcc *tl)
-{
- int retval = 0;
-
- vcc_NextToken(tl);
- ExpectErr(tl, '(');
- vcc_NextToken(tl);
- ExpectErr(tl, ID);
-
- /* 'error' gets special handling, to allow optional status/response */
- if (vcc_IdIs(tl->t, "error")) {
- vcc_NextToken(tl);
- if (tl->t->tok == ')') {
- VSB_printf(tl->sb,
- "Syntax has changed, use:\n"
- "\treturn(error(999));\n"
- "or\n"
- "\treturn(error(999, \"Response text\"));\n");
- vcc_ErrWhere(tl, tl->t);
- return;
- }
- ExpectErr(tl, '(');
- vcc_NextToken(tl);
- Fb(tl, 1, "VRT_error(ctx,\n");
- tl->indent += INDENT;
- vcc_Expr(tl, INT);
- ERRCHK(tl);
- Fb(tl, 1, ",\n");
- if (tl->t->tok == ',') {
- vcc_NextToken(tl);
- vcc_Expr(tl, STRING);
- ERRCHK(tl);
- } else {
- Fb(tl, 1, "(const char*)0\n");
- }
- tl->indent -= INDENT;
- ExpectErr(tl, ')');
- vcc_NextToken(tl);
- Fb(tl, 1, ");\n");
- Fb(tl, 1, "VRT_handling(ctx, VCL_RET_ERROR);\n");
- Fb(tl, 1, "return (1);\n");
- vcc_ProcAction(tl->curproc, VCL_RET_ERROR, tl->t);
- ExpectErr(tl, ')');
- vcc_NextToken(tl);
- return;
- }
-
-#define VCL_RET_MAC(l, U, B) \
- do { \
- if (vcc_IdIs(tl->t, #l)) { \
- Fb(tl, 1, "VRT_handling(ctx, VCL_RET_" #U ");\n"); \
- Fb(tl, 1, "return (1);\n"); \
- vcc_ProcAction(tl->curproc, VCL_RET_##U, tl->t);\
- retval = 1; \
- } \
- } while (0);
-#include "tbl/vcl_returns.h"
-#undef VCL_RET_MAC
- if (!retval) {
- VSB_printf(tl->sb, "Expected return action name.\n");
- vcc_ErrWhere(tl, tl->t);
- ERRCHK(tl);
- }
- vcc_NextToken(tl);
- ExpectErr(tl, ')');
- vcc_NextToken(tl);
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-parse_rollback(struct vcc *tl)
-{
-
- vcc_NextToken(tl);
- Fb(tl, 1, "VRT_Rollback(ctx);\n");
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-parse_purge(struct vcc *tl)
-{
-
- vcc_NextToken(tl);
- Fb(tl, 1, "VRT_purge(ctx, 0, 0);\n");
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-parse_synthetic(struct vcc *tl)
-{
- vcc_NextToken(tl);
-
- Fb(tl, 1, "VRT_synth_page(ctx, 0, ");
- vcc_Expr(tl, STRING_LIST);
- ERRCHK(tl);
- Fb(tl, 0, ");\n");
-}
-
-/*--------------------------------------------------------------------*/
-
-typedef void action_f(struct vcc *tl);
-
-static struct action_table {
- const char *name;
- action_f *func;
- unsigned bitmask;
-} action_table[] = {
- /* Keep list sorted from here */
- { "ban", parse_ban },
- { "call", parse_call },
- { "error", parse_error },
- { "hash_data", parse_hash_data, VCL_MET_HASH },
- { "new", parse_new, VCL_MET_INIT},
- { "purge", parse_purge, VCL_MET_MISS | VCL_MET_HIT },
- { "remove", parse_unset }, /* backward compatibility */
- { "return", parse_return },
- { "rollback", parse_rollback },
- { "set", parse_set },
- { "synthetic", parse_synthetic, VCL_MET_ERROR },
- { "unset", parse_unset },
- { NULL, NULL }
-};
-
-int
-vcc_ParseAction(struct vcc *tl)
-{
- struct token *at;
- struct action_table *atp;
- const struct symbol *sym;
-
- at = tl->t;
- assert(at->tok == ID);
- for(atp = action_table; atp->name != NULL; atp++) {
- if (vcc_IdIs(at, atp->name)) {
- if (atp->bitmask != 0)
- vcc_AddUses(tl, at, atp->bitmask,
- "not a valid action");
- atp->func(tl);
- return (1);
- }
- }
- sym = VCC_FindSymbol(tl, tl->t, SYM_NONE);
- if (sym != NULL && sym->kind == SYM_PROC) {
- vcc_Expr_Call(tl, sym);
- return (1);
- }
- return (0);
-}
diff --git a/lib/libvcl/vcc_backend.c b/lib/libvcl/vcc_backend.c
deleted file mode 100644
index b548d94..0000000
--- a/lib/libvcl/vcc_backend.c
+++ /dev/null
@@ -1,484 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2013 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "vcc_compile.h"
-
-#include "vss.h"
-
-/*--------------------------------------------------------------------
- * Struct sockaddr is not really designed to be a compile time
- * initialized data structure, so we encode it as a byte-string
- * and put it in an official sockaddr when we load the VCL.
- */
-
-static void
-Emit_Sockaddr(struct vcc *tl, const struct token *t_host, const char *port)
-{
- const char *ipv4, *ipv4a, *ipv6, *ipv6a, *pa;
- const char *err;
- char *hop, *pop;
-
- AN(t_host->dec);
-
- err = VSS_parse(t_host->dec, &hop, &pop);
- if (err != NULL) {
- VSB_printf(tl->sb,
- "Backend host '%.*s': %s\n", PF(t_host), err);
- vcc_ErrWhere(tl, t_host);
- return;
- }
- Resolve_Sockaddr(tl,
- hop != NULL ? hop : t_host->dec,
- pop != NULL ? pop : port,
- &ipv4, &ipv4a, &ipv6, &ipv6a, &pa, 2, t_host, "Backend host");
- ERRCHK(tl);
- if (ipv4 != NULL) {
- Fb(tl, 0, "\t.ipv4_sockaddr = %s,\n", ipv4);
- Fb(tl, 0, "\t.ipv4_addr = \"%s\",\n", ipv4a);
- }
- if (ipv6 != NULL) {
- Fb(tl, 0, "\t.ipv6_sockaddr = %s,\n", ipv6);
- Fb(tl, 0, "\t.ipv6_addr = \"%s\",\n", ipv6a);
- }
- Fb(tl, 0, "\t.port = \"%s\",\n", pa);
-}
-
-/*--------------------------------------------------------------------
- * Parse a backend probe specification
- */
-
-static void
-vcc_ProbeRedef(struct vcc *tl, struct token **t_did,
- struct token *t_field)
-{
- /* .url and .request are mutually exclusive */
-
- if (*t_did != NULL) {
- VSB_printf(tl->sb, "Probe request redefinition at:\n");
- vcc_ErrWhere(tl, t_field);
- VSB_printf(tl->sb, "Previous definition:\n");
- vcc_ErrWhere(tl, *t_did);
- return;
- }
- *t_did = t_field;
-}
-
-static void
-vcc_ParseProbeSpec(struct vcc *tl)
-{
- struct fld_spec *fs;
- struct token *t_field;
- struct token *t_did = NULL, *t_window = NULL, *t_threshold = NULL;
- struct token *t_initial = NULL;
- unsigned window, threshold, initial, status;
- double t;
-
- fs = vcc_FldSpec(tl,
- "?url",
- "?request",
- "?expected_response",
- "?timeout",
- "?interval",
- "?window",
- "?threshold",
- "?initial",
- NULL);
-
- SkipToken(tl, '{');
-
- window = 0;
- threshold = 0;
- initial = 0;
- status = 0;
- Fh(tl, 0, "static const struct vrt_backend_probe vgc_probe__%d = {\n",
- tl->nprobe++);
- while (tl->t->tok != '}') {
-
- vcc_IsField(tl, &t_field, fs);
- ERRCHK(tl);
- if (vcc_IdIs(t_field, "url")) {
- vcc_ProbeRedef(tl, &t_did, t_field);
- ERRCHK(tl);
- ExpectErr(tl, CSTR);
- Fh(tl, 0, "\t.url = ");
- EncToken(tl->fh, tl->t);
- Fh(tl, 0, ",\n");
- vcc_NextToken(tl);
- } else if (vcc_IdIs(t_field, "request")) {
- vcc_ProbeRedef(tl, &t_did, t_field);
- ERRCHK(tl);
- ExpectErr(tl, CSTR);
- Fh(tl, 0, "\t.request =\n");
- while (tl->t->tok == CSTR) {
- Fh(tl, 0, "\t\t");
- EncToken(tl->fh, tl->t);
- Fh(tl, 0, " \"\\r\\n\"\n");
- vcc_NextToken(tl);
- }
- Fh(tl, 0, "\t\t\"\\r\\n\",\n");
- } else if (vcc_IdIs(t_field, "timeout")) {
- Fh(tl, 0, "\t.timeout = ");
- vcc_Duration(tl, &t);
- ERRCHK(tl);
- Fh(tl, 0, "%g,\n", t);
- } else if (vcc_IdIs(t_field, "interval")) {
- Fh(tl, 0, "\t.interval = ");
- vcc_Duration(tl, &t);
- ERRCHK(tl);
- Fh(tl, 0, "%g,\n", t);
- } else if (vcc_IdIs(t_field, "window")) {
- t_window = tl->t;
- window = vcc_UintVal(tl);
- ERRCHK(tl);
- } else if (vcc_IdIs(t_field, "initial")) {
- t_initial = tl->t;
- initial = vcc_UintVal(tl);
- ERRCHK(tl);
- } else if (vcc_IdIs(t_field, "expected_response")) {
- status = vcc_UintVal(tl);
- if (status < 100 || status > 999) {
- VSB_printf(tl->sb,
- "Must specify .expected_response with "
- "exactly three digits "
- "(100 <= x <= 999)\n");
- vcc_ErrWhere(tl, tl->t);
- return;
- }
- ERRCHK(tl);
- } else if (vcc_IdIs(t_field, "threshold")) {
- t_threshold = tl->t;
- threshold = vcc_UintVal(tl);
- ERRCHK(tl);
- } else {
- vcc_ErrToken(tl, t_field);
- vcc_ErrWhere(tl, t_field);
- ErrInternal(tl);
- return;
- }
-
- SkipToken(tl, ';');
- }
-
- if (t_threshold != NULL || t_window != NULL) {
- if (t_threshold == NULL && t_window != NULL) {
- VSB_printf(tl->sb,
- "Must specify .threshold with .window\n");
- vcc_ErrWhere(tl, t_window);
- return;
- } else if (t_threshold != NULL && t_window == NULL) {
- if (threshold > 64) {
- VSB_printf(tl->sb,
- "Threshold must be 64 or less.\n");
- vcc_ErrWhere(tl, t_threshold);
- return;
- }
- window = threshold + 1;
- } else if (window > 64) {
- AN(t_window);
- VSB_printf(tl->sb, "Window must be 64 or less.\n");
- vcc_ErrWhere(tl, t_window);
- return;
- }
- if (threshold > window ) {
- VSB_printf(tl->sb,
- "Threshold can not be greater than window.\n");
- AN(t_threshold);
- vcc_ErrWhere(tl, t_threshold);
- AN(t_window);
- vcc_ErrWhere(tl, t_window);
- }
- Fh(tl, 0, "\t.window = %u,\n", window);
- Fh(tl, 0, "\t.threshold = %u,\n", threshold);
- }
- if (t_initial != NULL)
- Fh(tl, 0, "\t.initial = %u,\n", initial);
- else
- Fh(tl, 0, "\t.initial = ~0U,\n");
- if (status > 0)
- Fh(tl, 0, "\t.exp_status = %u,\n", status);
- Fh(tl, 0, "};\n");
- SkipToken(tl, '}');
-}
-
-/*--------------------------------------------------------------------
- * Parse and emit a probe definition
- */
-
-void
-vcc_ParseProbe(struct vcc *tl)
-{
- struct token *t_probe;
- int i;
-
- vcc_NextToken(tl); /* ID: probe */
-
- vcc_ExpectCid(tl); /* ID: name */
- ERRCHK(tl);
- t_probe = tl->t;
- vcc_NextToken(tl);
- i = vcc_AddDef(tl, t_probe, SYM_PROBE);
- if (i > 1) {
- VSB_printf(tl->sb, "Probe %.*s redefined\n", PF(t_probe));
- vcc_ErrWhere(tl, t_probe);
- }
-
- Fh(tl, 0, "\n#define vgc_probe_%.*s\tvgc_probe__%d\n",
- PF(t_probe), tl->nprobe);
- vcc_ParseProbeSpec(tl);
-}
-
-/*--------------------------------------------------------------------
- * Parse and emit a backend host definition
- *
- * The struct vrt_backend is emitted to Fh().
- */
-
-static void
-vcc_ParseHostDef(struct vcc *tl, const struct token *t_be)
-{
- struct token *t_field;
- struct token *t_host = NULL;
- struct token *t_port = NULL;
- struct token *t_hosthdr = NULL;
- struct fld_spec *fs;
- struct vsb *vsb;
- unsigned u;
- double t;
- char vgcname[MAX_BACKEND_NAME + 8];
-
- sprintf(vgcname, "_%.*s", PF(t_be));
-
- Fh(tl, 1, "\n#define VGC_backend_%s %d\n", vgcname, tl->ndirector);
-
- fs = vcc_FldSpec(tl,
- "!host",
- "?port",
- "?host_header",
- "?connect_timeout",
- "?first_byte_timeout",
- "?between_bytes_timeout",
- "?probe",
- "?max_connections",
- NULL);
-
- SkipToken(tl, '{');
-
- vsb = VSB_new_auto();
- AN(vsb);
- tl->fb = vsb;
-
- Fb(tl, 0, "\nstatic const struct vrt_backend vgc_dir_priv_%s = {\n",
- vgcname);
-
- Fb(tl, 0, "\t.vcl_name = \"%.*s", PF(t_be));
- Fb(tl, 0, "\",\n");
-
- /* Check for old syntax */
- if (tl->t->tok == ID && vcc_IdIs(tl->t, "set")) {
- VSB_printf(tl->sb,
- "NB: Backend Syntax has changed:\n"
- "Remove \"set\" and \"backend\" in front"
- " of backend fields.\n" );
- vcc_ErrToken(tl, tl->t);
- VSB_printf(tl->sb, " at ");
- vcc_ErrWhere(tl, tl->t);
- return;
- }
-
- while (tl->t->tok != '}') {
-
- vcc_IsField(tl, &t_field, fs);
- ERRCHK(tl);
- if (vcc_IdIs(t_field, "host")) {
- ExpectErr(tl, CSTR);
- assert(tl->t->dec != NULL);
- t_host = tl->t;
- vcc_NextToken(tl);
- SkipToken(tl, ';');
- } else if (vcc_IdIs(t_field, "port")) {
- ExpectErr(tl, CSTR);
- assert(tl->t->dec != NULL);
- t_port = tl->t;
- vcc_NextToken(tl);
- SkipToken(tl, ';');
- } else if (vcc_IdIs(t_field, "host_header")) {
- ExpectErr(tl, CSTR);
- assert(tl->t->dec != NULL);
- t_hosthdr = tl->t;
- vcc_NextToken(tl);
- SkipToken(tl, ';');
- } else if (vcc_IdIs(t_field, "connect_timeout")) {
- Fb(tl, 0, "\t.connect_timeout = ");
- vcc_Duration(tl, &t);
- ERRCHK(tl);
- Fb(tl, 0, "%g,\n", t);
- SkipToken(tl, ';');
- } else if (vcc_IdIs(t_field, "first_byte_timeout")) {
- Fb(tl, 0, "\t.first_byte_timeout = ");
- vcc_Duration(tl, &t);
- ERRCHK(tl);
- Fb(tl, 0, "%g,\n", t);
- SkipToken(tl, ';');
- } else if (vcc_IdIs(t_field, "between_bytes_timeout")) {
- Fb(tl, 0, "\t.between_bytes_timeout = ");
- vcc_Duration(tl, &t);
- ERRCHK(tl);
- Fb(tl, 0, "%g,\n", t);
- SkipToken(tl, ';');
- } else if (vcc_IdIs(t_field, "max_connections")) {
- u = vcc_UintVal(tl);
- ERRCHK(tl);
- SkipToken(tl, ';');
- Fb(tl, 0, "\t.max_connections = %u,\n", u);
- } else if (vcc_IdIs(t_field, "probe") && tl->t->tok == '{') {
- Fb(tl, 0, "\t.probe = &vgc_probe__%d,\n", tl->nprobe);
- vcc_ParseProbeSpec(tl);
- ERRCHK(tl);
- } else if (vcc_IdIs(t_field, "probe") && tl->t->tok == ID) {
- Fb(tl, 0, "\t.probe = &vgc_probe_%.*s,\n", PF(tl->t));
- vcc_AddRef(tl, tl->t, SYM_PROBE);
- vcc_NextToken(tl);
- SkipToken(tl, ';');
- } else if (vcc_IdIs(t_field, "probe")) {
- VSB_printf(tl->sb,
- "Expected '{' or name of probe, got ");
- vcc_ErrToken(tl, tl->t);
- VSB_printf(tl->sb, " at\n");
- vcc_ErrWhere(tl, tl->t);
- return;
- } else {
- ErrInternal(tl);
- return;
- }
-
- }
-
- vcc_FieldsOk(tl, fs);
- ERRCHK(tl);
-
- /* Check that the hostname makes sense */
- assert(t_host != NULL);
- if (t_port != NULL)
- Emit_Sockaddr(tl, t_host, t_port->dec);
- else
- Emit_Sockaddr(tl, t_host, "80");
- ERRCHK(tl);
-
- ExpectErr(tl, '}');
-
- /* We have parsed it all, emit the ident string */
-
- /* Emit the hosthdr field, fall back to .host if not specified */
- Fb(tl, 0, "\t.hosthdr = ");
- if (t_hosthdr != NULL)
- EncToken(tl->fb, t_hosthdr);
- else
- EncToken(tl->fb, t_host);
- Fb(tl, 0, ",\n");
-
- /* Close the struct */
- Fb(tl, 0, "};\n");
-
- vcc_NextToken(tl);
-
- tl->fb = NULL;
- AZ(VSB_finish(vsb));
- Fh(tl, 0, "%s", VSB_data(vsb));
- VSB_delete(vsb);
-
- Fi(tl, 0, "\tVRT_init_dir(cli, VCL_conf.director,\n"
- "\t VGC_backend_%s, &vgc_dir_priv_%s);\n", vgcname, vgcname);
- Ff(tl, 0, "\tVRT_fini_dir(cli, VGCDIR(%s));\n", vgcname);
- tl->ndirector++;
-}
-
-/*--------------------------------------------------------------------
- * Parse directors and backends
- */
-
-void
-vcc_ParseBackend(struct vcc *tl)
-{
- struct token *t_first, *t_be;
- int isfirst;
- struct symbol *sym;
-
- t_first = tl->t;
- vcc_NextToken(tl); /* ID: backend */
-
- vcc_ExpectCid(tl); /* ID: name */
- ERRCHK(tl);
-
- if (tl->t->e - tl->t->b > MAX_BACKEND_NAME) {
- VSB_printf(tl->sb,
- "Name of %.*s too long (max %d, is %zu):\n",
- PF(t_first), MAX_BACKEND_NAME,
- (size_t)(tl->t->e - tl->t->b));
- vcc_ErrWhere(tl, tl->t);
- return;
- }
-
- t_be = tl->t;
- vcc_NextToken(tl);
-
- isfirst = tl->ndirector;
-
- sym = VCC_GetSymbolTok(tl, t_be, SYM_BACKEND);
- AN(sym);
- if (sym->ndef > 0) {
- VSB_printf(tl->sb, "Backend %.*s redefined\n", PF(t_be));
- vcc_ErrWhere(tl, t_be);
- return;
- }
- sym->fmt = BACKEND;
- sym->eval = vcc_Eval_Backend;
- sym->ndef++;
- ERRCHK(tl);
-
- vcc_ParseHostDef(tl, t_be);
- ERRCHK(tl);
-
- if (tl->err) {
- VSB_printf(tl->sb,
- "\nIn %.*s specification starting at:\n", PF(t_first));
- vcc_ErrWhere(tl, t_first);
- return;
- }
-
- if (isfirst == 1 || vcc_IdIs(t_be, "default")) {
- tl->defaultdir = tl->ndirector - 1;
- tl->t_defaultdir = t_be;
- }
-}
diff --git a/lib/libvcl/vcc_backend_util.c b/lib/libvcl/vcc_backend_util.c
deleted file mode 100644
index de361a5..0000000
--- a/lib/libvcl/vcc_backend_util.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2011 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
-
-#include "config.h"
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "vcc_compile.h"
-
-/*--------------------------------------------------------------------
- * Helper functions to complain about duplicate and missing fields
- *
- * XXX: idea: add groups to check for exclusivity, such that
- * XXX: ("!foo", "?bar", "!{", "this", "that", "}", NULL)
- * XXX: means exactly one of "this" or "that", and
- * XXX: ("!foo", "?bar", "?{", "this", "that", "}", NULL)
- * XXX: means at most one of "this" or "that".
- */
-
-struct fld_spec {
- const char *name;
- struct token *found;
-};
-
-static void
-vcc_ResetFldSpec(struct fld_spec *f)
-{
-
- for (; f->name != NULL; f++)
- f->found = NULL;
-}
-
-struct fld_spec *
-vcc_FldSpec(struct vcc *tl, const char *first, ...)
-{
- struct fld_spec f[100], *r;
- int n = 0;
- va_list ap;
- const char *p;
-
- f[n++].name = first;
- va_start(ap, first);
- while (1) {
- p = va_arg(ap, const char *);
- if (p == NULL)
- break;
- f[n++].name = p;
- assert(n < 100);
- }
- va_end(ap);
- f[n++].name = NULL;
-
- vcc_ResetFldSpec(f);
-
- r = TlAlloc(tl, sizeof *r * n);
- memcpy(r, f, n * sizeof *r);
- return (r);
-}
-
-void
-vcc_IsField(struct vcc *tl, struct token **t, struct fld_spec *fs)
-{
- struct token *t_field;
-
- SkipToken(tl, '.');
- ExpectErr(tl, ID);
- t_field = tl->t;
- *t = t_field;
- vcc_NextToken(tl);
- SkipToken(tl, '=');
-
- for (; fs->name != NULL; fs++) {
- if (!vcc_IdIs(t_field, fs->name + 1))
- continue;
- if (fs->found == NULL) {
- fs->found = t_field;
- return;
- }
- VSB_printf(tl->sb, "Field ");
- vcc_ErrToken(tl, t_field);
- VSB_printf(tl->sb, " redefined at:\n");
- vcc_ErrWhere(tl, t_field);
- VSB_printf(tl->sb, "\nFirst defined at:\n");
- vcc_ErrWhere(tl, fs->found);
- return;
- }
- VSB_printf(tl->sb, "Unknown field: ");
- vcc_ErrToken(tl, t_field);
- VSB_printf(tl->sb, " at\n");
- vcc_ErrWhere(tl, t_field);
- return;
-}
-
-void
-vcc_FieldsOk(struct vcc *tl, const struct fld_spec *fs)
-{
-
- for (; fs->name != NULL; fs++) {
- if (*fs->name == '!' && fs->found == NULL) {
- VSB_printf(tl->sb,
- "Mandatory field '%s' missing.\n", fs->name + 1);
- tl->err = 1;
- }
- }
-}
diff --git a/lib/libvcl/vcc_compile.c b/lib/libvcl/vcc_compile.c
deleted file mode 100644
index 07eef41..0000000
--- a/lib/libvcl/vcc_compile.c
+++ /dev/null
@@ -1,823 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2013 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * XXX:
- * Better error messages, throughout.
- * >It also accured to me that we could link the errors to the error
- * >documentation.
- * >
- * >Unreferenced function 'request_policy', first mention is
- * > Line 8 Pos 4
- * > sub request_policy {
- * > ----##############--
- * >Read more about this type of error:
- * >http://varnish/doc/error.html#Unreferenced%20function
- * >
- * >
- * > Unknown variable 'obj.bandwidth'
- * > At: Line 88 Pos 12
- * > if (obj.bandwidth < 1 kb/h) {
- * > ------------#############------------
- * >Read more about this type of error:
- * >http://varnish/doc/error.html#Unknown%20variable
- *
- */
-
-#include "config.h"
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "vcc_compile.h"
-
-#include "libvcl.h"
-#include "vfil.h"
-
-struct method method_tab[] = {
-#define VCL_MET_MAC(l,U,m) { "vcl_"#l, m, VCL_MET_##U },
-#include "tbl/vcl_returns.h"
-#undef VCL_MET_MAC
- { NULL, 0U, 0}
-};
-
-/*--------------------------------------------------------------------*/
-
-static void
-TlDoFree(struct vcc *tl, void *p)
-{
- struct membit *mb;
-
- mb = calloc(sizeof *mb, 1);
- assert(mb != NULL);
- mb->ptr = p;
- VTAILQ_INSERT_TAIL(&tl->membits, mb, list);
-}
-
-
-void *
-TlAlloc(struct vcc *tl, unsigned len)
-{
- void *p;
-
- p = calloc(len, 1);
- assert(p != NULL);
- TlDoFree(tl, p);
- return (p);
-}
-
-char *
-TlDup(struct vcc *tl, const char *s)
-{
- char *p;
-
- p = TlAlloc(tl, strlen(s) + 1);
- AN(p);
- strcpy(p, s);
- return (p);
-}
-
-char *
-TlDupTok(struct vcc *tl, const struct token *tok)
-{
- char *p;
- int i;
-
- i = tok->e - tok->b;
- p = TlAlloc(tl, i + 1);
- AN(p);
- memcpy(p, tok->b, i);
- p[i] = '\0';
- return (p);
-}
-
-/*--------------------------------------------------------------------*/
-
-int
-IsMethod(const struct token *t)
-{
- struct method *m;
-
- assert(t->tok == ID);
- for(m = method_tab; m->name != NULL; m++) {
- if (vcc_IdIs(t, m->name))
- return (m - method_tab);
- }
- if ((t->b[0] == 'v'|| t->b[0] == 'V') &&
- (t->b[1] == 'c'|| t->b[1] == 'C') &&
- (t->b[2] == 'l'|| t->b[2] == 'L'))
- return (-2);
- return (-1);
-}
-
-/*--------------------------------------------------------------------
- * Printf output to the vsbs, possibly indented
- */
-
-void
-Fh(const struct vcc *tl, int indent, const char *fmt, ...)
-{
- va_list ap;
-
- if (indent)
- VSB_printf(tl->fh, "%*.*s", tl->hindent, tl->hindent, "");
- va_start(ap, fmt);
- VSB_vprintf(tl->fh, fmt, ap);
- va_end(ap);
-}
-
-void
-Fb(const struct vcc *tl, int indent, const char *fmt, ...)
-{
- va_list ap;
-
- assert(tl->fb != NULL);
- if (indent)
- VSB_printf(tl->fb, "%*.*s", tl->indent, tl->indent, "");
- va_start(ap, fmt);
- VSB_vprintf(tl->fb, fmt, ap);
- va_end(ap);
-}
-
-void
-Fc(const struct vcc *tl, int indent, const char *fmt, ...)
-{
- va_list ap;
-
- if (indent)
- VSB_printf(tl->fc, "%*.*s", tl->indent, tl->indent, "");
- va_start(ap, fmt);
- VSB_vprintf(tl->fc, fmt, ap);
- va_end(ap);
-}
-
-void
-Fi(const struct vcc *tl, int indent, const char *fmt, ...)
-{
- va_list ap;
-
- if (indent)
- VSB_printf(tl->fi, "%*.*s", tl->iindent, tl->iindent, "");
- va_start(ap, fmt);
- VSB_vprintf(tl->fi, fmt, ap);
- va_end(ap);
-}
-
-void
-Fd(const struct vcc *tl, int indent, const char *fmt, ...)
-{
- va_list ap;
-
- if (indent)
- VSB_printf(tl->fd, "%*.*s", tl->findent, tl->findent, "");
- va_start(ap, fmt);
- VSB_vprintf(tl->fd, fmt, ap);
- va_end(ap);
-}
-
-
-void
-Ff(const struct vcc *tl, int indent, const char *fmt, ...)
-{
- va_list ap;
-
- if (indent)
- VSB_printf(tl->ff, "%*.*s", tl->findent, tl->findent, "");
- va_start(ap, fmt);
- VSB_vprintf(tl->ff, fmt, ap);
- va_end(ap);
-}
-
-/*--------------------------------------------------------------------*/
-
-void
-EncString(struct vsb *sb, const char *b, const char *e, int mode)
-{
-
- if (e == NULL)
- e = strchr(b, '\0');
-
- VSB_cat(sb, "\"");
- for (; b < e; b++) {
- switch (*b) {
- case '\\':
- case '"':
- VSB_printf(sb, "\\%c", *b);
- break;
- case '\n':
- VSB_printf(sb, "\\n");
- if (mode)
- VSB_printf(sb, "\"\n\t\"");
- break;
- case '\t': VSB_printf(sb, "\\t"); break;
- case '\r': VSB_printf(sb, "\\r"); break;
- case ' ': VSB_printf(sb, " "); break;
- default:
- if (isgraph(*b))
- VSB_printf(sb, "%c", *b);
- else
- VSB_printf(sb, "\\%03o", (uint8_t)*b);
- break;
- }
- }
- VSB_cat(sb, "\"");
-}
-
-void
-EncToken(struct vsb *sb, const struct token *t)
-{
-
- assert(t->tok == CSTR);
- EncString(sb, t->dec, NULL, 1);
-}
-
-/*--------------------------------------------------------------------
- * Output the location/profiling table. For each counted token, we
- * record source+line+charpos for the first character in the token.
- */
-
-static void
-LocTable(const struct vcc *tl)
-{
- struct token *t;
- unsigned lin, pos;
- struct source *sp;
- const char *p;
-
- Fh(tl, 0, "\n#define VGC_NREFS %u\n", tl->cnt + 1);
- Fc(tl, 0, "\nstatic struct vrt_ref VGC_ref[VGC_NREFS] = {\n");
- lin = 1;
- pos = 0;
- sp = 0;
- p = NULL;
- VTAILQ_FOREACH(t, &tl->tokens, list) {
- if (t->cnt == 0)
- continue;
- assert(t->src != NULL);
- if (t->src != sp) {
- lin = 1;
- pos = 0;
- sp = t->src;
- p = sp->b;
- }
- assert(sp != NULL);
- assert(p != NULL);
- for (;p < t->b; p++) {
- if (*p == '\n') {
- lin++;
- pos = 0;
- } else if (*p == '\t') {
- pos &= ~7;
- pos += 8;
- } else
- pos++;
-
- }
- Fc(tl, 0, " [%3u] = { %d, %8tu, %4u, %3u, 0, ",
- t->cnt, sp->idx, t->b - sp->b, lin, pos + 1);
- if (t->tok == CSRC)
- Fc(tl, 0, " \"C{\"},\n");
- else
- Fc(tl, 0, " \"%.*s\" },\n", PF(t));
- }
- Fc(tl, 0, "};\n");
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-EmitInitFunc(const struct vcc *tl)
-{
-
- Fc(tl, 0, "\nstatic int\nVGC_Init(struct cli *cli)\n{\n\n");
- AZ(VSB_finish(tl->fi));
- VSB_cat(tl->fc, VSB_data(tl->fi));
- Fc(tl, 0, "\treturn(0);\n");
- Fc(tl, 0, "}\n");
-}
-
-static void
-EmitFiniFunc(const struct vcc *tl)
-{
- unsigned u;
-
- Fc(tl, 0, "\nstatic void\nVGC_Fini(struct cli *cli)\n{\n\n");
-
- AZ(VSB_finish(tl->fd));
- VSB_cat(tl->fc, VSB_data(tl->fd));
-
- /*
- * We do this here, so we are sure they happen before any
- * per-vcl vmod_privs get cleaned.
- */
- for (u = 0; u < tl->nvmodpriv; u++)
- Fc(tl, 0, "\tvmod_priv_fini(&vmod_priv_%u);\n", u);
-
- AZ(VSB_finish(tl->ff));
- VSB_cat(tl->fc, VSB_data(tl->ff));
- Fc(tl, 0, "}\n");
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-EmitStruct(const struct vcc *tl)
-{
- struct source *sp;
-
- Fc(tl, 0, "\nconst char *srcname[%u] = {\n", tl->nsources);
- VTAILQ_FOREACH(sp, &tl->sources, list) {
- Fc(tl, 0, "\t");
- EncString(tl->fc, sp->name, NULL, 0);
- Fc(tl, 0, ",\n");
- }
- Fc(tl, 0, "};\n");
-
- Fc(tl, 0, "\nconst char *srcbody[%u] = {\n", tl->nsources);
- VTAILQ_FOREACH(sp, &tl->sources, list) {
- Fc(tl, 0, " /* ");
- EncString(tl->fc, sp->name, NULL, 0);
- Fc(tl, 0, "*/\n");
- Fc(tl, 0, "\t");
- EncString(tl->fc, sp->b, sp->e, 1);
- Fc(tl, 0, ",\n");
- }
- Fc(tl, 0, "};\n");
-
- Fc(tl, 0, "\nstatic struct director\t*directors[%d];\n",
- tl->ndirector);
-
- Fc(tl, 0, "\nconst struct VCL_conf VCL_conf = {\n");
- Fc(tl, 0, "\t.magic = VCL_CONF_MAGIC,\n");
- Fc(tl, 0, "\t.init_vcl = VGC_Init,\n");
- Fc(tl, 0, "\t.fini_vcl = VGC_Fini,\n");
- Fc(tl, 0, "\t.ndirector = %d,\n", tl->ndirector);
- Fc(tl, 0, "\t.director = directors,\n");
- Fc(tl, 0, "\t.ref = VGC_ref,\n");
- Fc(tl, 0, "\t.nref = VGC_NREFS,\n");
- Fc(tl, 0, "\t.nsrc = %u,\n", tl->nsources);
- Fc(tl, 0, "\t.srcname = srcname,\n");
- Fc(tl, 0, "\t.srcbody = srcbody,\n");
-#define VCL_MET_MAC(l,u,b) \
- Fc(tl, 0, "\t." #l "_func = VGC_function_vcl_" #l ",\n");
-#include "tbl/vcl_returns.h"
-#undef VCL_MET_MAC
- Fc(tl, 0, "};\n");
-}
-
-/*--------------------------------------------------------------------*/
-
-static struct source *
-vcc_new_source(const char *b, const char *e, const char *name)
-{
- struct source *sp;
-
- if (e == NULL)
- e = strchr(b, '\0');
- sp = calloc(sizeof *sp, 1);
- assert(sp != NULL);
- sp->name = strdup(name);
- AN(sp->name);
- sp->b = b;
- sp->e = e;
- return (sp);
-}
-
-static void
-vcc_destroy_source(struct source *sp)
-{
-
- if (sp->freeit != NULL)
- free(sp->freeit);
- free(sp->name);
- free(sp);
-}
-
-/*--------------------------------------------------------------------*/
-
-static struct source *
-vcc_file_source(const struct vcc *tl, struct vsb *sb, const char *fn)
-{
- char *f;
- struct source *sp;
-
- if (!tl->unsafe_path && strchr(fn, '/') != NULL) {
- VSB_printf(sb, "Include path is unsafe '%s'\n", fn);
- return (NULL);
- }
- f = VFIL_readfile(tl->vcl_dir, fn, NULL);
- if (f == NULL) {
- VSB_printf(sb, "Cannot read file '%s': %s\n",
- fn, strerror(errno));
- return (NULL);
- }
- sp = vcc_new_source(f, NULL, fn);
- sp->freeit = f;
- return (sp);
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-vcc_resolve_includes(struct vcc *tl)
-{
- struct token *t, *t1, *t2;
- struct source *sp;
-
- VTAILQ_FOREACH(t, &tl->tokens, list) {
- if (t->tok != ID || !vcc_IdIs(t, "include"))
- continue;
-
- t1 = VTAILQ_NEXT(t, list);
- assert(t1 != NULL); /* There's always an EOI */
- if (t1->tok != CSTR) {
- VSB_printf(tl->sb,
- "include not followed by string constant.\n");
- vcc_ErrWhere(tl, t1);
- return;
- }
- t2 = VTAILQ_NEXT(t1, list);
- assert(t2 != NULL); /* There's always an EOI */
-
- if (t2->tok != ';') {
- VSB_printf(tl->sb,
- "include <string> not followed by semicolon.\n");
- vcc_ErrWhere(tl, t1);
- return;
- }
-
- sp = vcc_file_source(tl, tl->sb, t1->dec);
- if (sp == NULL) {
- vcc_ErrWhere(tl, t1);
- return;
- }
- VTAILQ_INSERT_TAIL(&tl->sources, sp, list);
- sp->idx = tl->nsources++;
- tl->t = t2;
- vcc_Lexer(tl, sp);
-
- VTAILQ_REMOVE(&tl->tokens, t, list);
- VTAILQ_REMOVE(&tl->tokens, t1, list);
- VTAILQ_REMOVE(&tl->tokens, t2, list);
- if (!tl->err)
- vcc_resolve_includes(tl);
- return;
- }
-}
-
-/*--------------------------------------------------------------------*/
-
-static struct vcc *
-vcc_NewVcc(const struct vcc *tl0)
-{
- struct vcc *tl;
- int i;
-
- ALLOC_OBJ(tl, VCC_MAGIC);
- AN(tl);
- if (tl0 != NULL) {
- REPLACE(tl->default_vcl, tl0->default_vcl);
- REPLACE(tl->vcl_dir, tl0->vcl_dir);
- REPLACE(tl->vmod_dir, tl0->vmod_dir);
- tl->vars = tl0->vars;
- tl->err_unref = tl0->err_unref;
- tl->allow_inline_c = tl0->allow_inline_c;
- tl->unsafe_path = tl0->unsafe_path;
- } else {
- tl->err_unref = 1;
- }
- VTAILQ_INIT(&tl->symbols);
- VTAILQ_INIT(&tl->membits);
- VTAILQ_INIT(&tl->tokens);
- VTAILQ_INIT(&tl->sources);
-
- tl->nsources = 0;
- tl->ndirector = 1;
-
- /* General C code */
- tl->fc = VSB_new_auto();
- assert(tl->fc != NULL);
-
- /* Forward decls (.h like) */
- tl->fh = VSB_new_auto();
- assert(tl->fh != NULL);
-
- /* Init C code */
- tl->fi = VSB_new_auto();
- assert(tl->fi != NULL);
-
- /* Destroy Objects */
- tl->fd = VSB_new_auto();
- assert(tl->fd != NULL);
-
- /* Finish C code */
- tl->ff = VSB_new_auto();
- assert(tl->ff != NULL);
-
- /* body code of methods */
- for (i = 0; i < VCL_MET_MAX; i++) {
- tl->fm[i] = VSB_new_auto();
- assert(tl->fm[i] != NULL);
- }
- return (tl);
-}
-
-/*--------------------------------------------------------------------*/
-
-static char *
-vcc_DestroyTokenList(struct vcc *tl, char *ret)
-{
- struct membit *mb;
- struct source *sp;
- struct symbol *sym;
- int i;
-
- while (!VTAILQ_EMPTY(&tl->membits)) {
- mb = VTAILQ_FIRST(&tl->membits);
- VTAILQ_REMOVE(&tl->membits, mb, list);
- free(mb->ptr);
- free(mb);
- }
- while (!VTAILQ_EMPTY(&tl->sources)) {
- sp = VTAILQ_FIRST(&tl->sources);
- VTAILQ_REMOVE(&tl->sources, sp, list);
- vcc_destroy_source(sp);
- }
-
- while (!VTAILQ_EMPTY(&tl->symbols)) {
- sym = VTAILQ_FIRST(&tl->symbols);
- VTAILQ_REMOVE(&tl->symbols, sym, list);
- FREE_OBJ(sym);
- }
-
- VSB_delete(tl->fh);
- VSB_delete(tl->fc);
- VSB_delete(tl->fi);
- VSB_delete(tl->ff);
- for (i = 0; i < VCL_MET_MAX; i++)
- VSB_delete(tl->fm[i]);
-
- free(tl);
- return (ret);
-}
-
-/*--------------------------------------------------------------------
- * Compile the VCL code from the given source and return the C-source
- */
-
-static char *
-vcc_CompileSource(const struct vcc *tl0, struct vsb *sb, struct source *sp)
-{
- struct vcc *tl;
- struct symbol *sym;
- const struct var *v;
- char *of;
- int i;
-
- tl = vcc_NewVcc(tl0);
- tl->sb = sb;
-
- vcc_Expr_Init(tl);
-
- for (v = tl->vars; v->name != NULL; v++) {
- if (v->fmt == HEADER) {
- sym = VCC_AddSymbolStr(tl, v->name, SYM_WILDCARD);
- sym->wildcard = vcc_Var_Wildcard;
- } else {
- sym = VCC_AddSymbolStr(tl, v->name, SYM_VAR);
- }
- sym->var = v;
- sym->fmt = v->fmt;
- sym->eval = vcc_Eval_Var;
- sym->r_methods = v->r_methods;
- }
-
- sym = VCC_AddSymbolStr(tl, "storage.", SYM_WILDCARD);
- sym->wildcard = vcc_Stv_Wildcard;
-
- vcl_output_lang_h(tl->fh);
- Fh(tl, 0, "\n/* ---===### VCC generated below here ###===---*/\n");
- Fh(tl, 0, "\nextern const struct VCL_conf VCL_conf;\n");
-
- /* Macro for accessing directors */
- Fh(tl, 0, "#define VGCDIR(n) VCL_conf.director[VGC_backend_##n]\n");
-
- Fh(tl, 0, "#define __match_proto__(xxx) /*lint -e{818} */\n");
-
- /* Register and lex the main source */
- VTAILQ_INSERT_TAIL(&tl->sources, sp, list);
- sp->idx = tl->nsources++;
- vcc_Lexer(tl, sp);
- if (tl->err)
- return (vcc_DestroyTokenList(tl, NULL));
-
- /* Register and lex the default VCL */
- sp = vcc_new_source(tl->default_vcl, NULL, "Default");
- assert(sp != NULL);
- VTAILQ_INSERT_TAIL(&tl->sources, sp, list);
- sp->idx = tl->nsources++;
- vcc_Lexer(tl, sp);
- if (tl->err)
- return (vcc_DestroyTokenList(tl, NULL));
-
- /* Add "END OF INPUT" token */
- vcc_AddToken(tl, EOI, sp->e, sp->e);
- if (tl->err)
- return (vcc_DestroyTokenList(tl, NULL));
-
- /* Expand and lex any includes in the token string */
- vcc_resolve_includes(tl);
- if (tl->err)
- return (vcc_DestroyTokenList(tl, NULL));
-
- /* Parse the token string */
- tl->t = VTAILQ_FIRST(&tl->tokens);
- vcc_Parse(tl);
- if (tl->err)
- return (vcc_DestroyTokenList(tl, NULL));
-
- /* Check if we have any backends at all */
- if (tl->ndirector == 1) {
- VSB_printf(tl->sb,
- "No backends or directors found in VCL program, "
- "at least one is necessary.\n");
- tl->err = 1;
- return (vcc_DestroyTokenList(tl, NULL));
- }
-
- /* Configure the default director */
- Fi(tl, 0, "\tVCL_conf.director[0] = VCL_conf.director[%d];\n",
- tl->defaultdir);
- vcc_AddRef(tl, tl->t_defaultdir, SYM_BACKEND);
-
- /* Check for orphans */
- if (vcc_CheckReferences(tl))
- return (vcc_DestroyTokenList(tl, NULL));
-
- /* Check that all action returns are legal */
- if (vcc_CheckAction(tl) || tl->err)
- return (vcc_DestroyTokenList(tl, NULL));
-
- /* Check that all variable uses are legal */
- if (vcc_CheckUses(tl) || tl->err)
- return (vcc_DestroyTokenList(tl, NULL));
-
- /* Emit method functions */
- for (i = 0; i < VCL_MET_MAX; i++) {
- Fc(tl, 1, "\nstatic int __match_proto__(vcl_func_f)\n");
- Fc(tl, 1,
- "VGC_function_%s(const struct vrt_ctx *ctx)\n",
- method_tab[i].name);
- AZ(VSB_finish(tl->fm[i]));
- Fc(tl, 1, "{\n");
- Fc(tl, 1, "%s", VSB_data(tl->fm[i]));
- Fc(tl, 1, "}\n");
- }
-
- LocTable(tl);
-
- EmitInitFunc(tl);
-
- EmitFiniFunc(tl);
-
- EmitStruct(tl);
-
- /* Combine it all in the fh vsb */
- AZ(VSB_finish(tl->fc));
- VSB_cat(tl->fh, VSB_data(tl->fc));
- AZ(VSB_finish(tl->fh));
-
- of = strdup(VSB_data(tl->fh));
- AN(of);
-
- /* done */
- return (vcc_DestroyTokenList(tl, of));
-}
-
-/*--------------------------------------------------------------------
- * Compile the VCL code in the argument. Error messages, if any are
- * formatted into the vsb.
- */
-
-char *
-VCC_Compile(const struct vcc *tl, struct vsb *sb, const char *b)
-{
- struct source *sp;
- char *r;
-
- sp = vcc_new_source(b, NULL, "input");
- if (sp == NULL)
- return (NULL);
- r = vcc_CompileSource(tl, sb, sp);
- return (r);
-}
-
-/*--------------------------------------------------------------------
- * Allocate a compiler instance
- */
-
-struct vcc *
-VCC_New(void)
-{
- struct vcc *tl;
-
- tl = vcc_NewVcc(NULL);
-
- tl->vars = vcc_vars;
-
- return (tl);
-}
-
-/*--------------------------------------------------------------------
- * Configure default VCL source code
- */
-
-void
-VCC_Default_VCL(struct vcc *tl, const char *str)
-{
-
- CHECK_OBJ_NOTNULL(tl, VCC_MAGIC);
- REPLACE(tl->default_vcl, str);
-}
-
-/*--------------------------------------------------------------------
- * Configure default VCL source directory
- */
-
-void
-VCC_VCL_dir(struct vcc *tl, const char *str)
-{
-
- CHECK_OBJ_NOTNULL(tl, VCC_MAGIC);
- REPLACE(tl->vcl_dir, str);
-}
-
-/*--------------------------------------------------------------------
- * Configure default VMOD directory
- */
-
-void
-VCC_VMOD_dir(struct vcc *tl, const char *str)
-{
-
- CHECK_OBJ_NOTNULL(tl, VCC_MAGIC);
- REPLACE(tl->vmod_dir, str);
-}
-
-/*--------------------------------------------------------------------
- * Configure settings
- */
-
-void
-VCC_Err_Unref(struct vcc *tl, unsigned u)
-{
-
- CHECK_OBJ_NOTNULL(tl, VCC_MAGIC);
- tl->err_unref = u;
-}
-
-void
-VCC_Allow_InlineC(struct vcc *tl, unsigned u)
-{
-
- CHECK_OBJ_NOTNULL(tl, VCC_MAGIC);
- tl->allow_inline_c = u;
-}
-
-void
-VCC_Unsafe_Path(struct vcc *tl, unsigned u)
-{
-
- CHECK_OBJ_NOTNULL(tl, VCC_MAGIC);
- tl->unsafe_path = u;
-}
diff --git a/lib/libvcl/vcc_compile.h b/lib/libvcl/vcc_compile.h
deleted file mode 100644
index b0983cc..0000000
--- a/lib/libvcl/vcc_compile.h
+++ /dev/null
@@ -1,351 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2013 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
-
-#include <sys/types.h>
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdint.h>
-
-#include "miniobj.h"
-#include "vas.h"
-#include "vcl.h"
-#include "vdef.h"
-#include "vqueue.h"
-#include "vsb.h"
-
-
-#include "vcc_token_defs.h"
-
-#ifndef NULL
-#define NULL ((void*)0)
-#endif
-
-struct vsb;
-struct token;
-struct sockaddr_storage;
-
-#define isident1(c) (isalpha(c))
-#define isident(c) (isalpha(c) || isdigit(c) || (c) == '_' || (c) == '-')
-#define isvar(c) (isident(c) || (c) == '.')
-int vcc_isCid(const struct token *t);
-unsigned vcl_fixed_token(const char *p, const char **q);
-extern const char * const vcl_tnames[256];
-void vcl_output_lang_h(struct vsb *sb);
-
-#define PF(t) (int)((t)->e - (t)->b), (t)->b
-
-#define INDENT 2
-
-struct acl_e;
-struct proc;
-struct expr;
-struct vcc;
-struct symbol;
-
-enum var_type {
-#define VCC_TYPE(foo) foo,
-#include "tbl/vcc_types.h"
-#undef VCC_TYPE
-};
-
-struct membit {
- VTAILQ_ENTRY(membit) list;
- void *ptr;
-};
-
-struct source {
- VTAILQ_ENTRY(source) list;
- char *name;
- const char *b;
- const char *e;
- unsigned idx;
- char *freeit;
-};
-
-struct token {
- unsigned tok;
- const char *b;
- const char *e;
- struct source *src;
- VTAILQ_ENTRY(token) list;
- unsigned cnt;
- char *dec;
-};
-
-enum symkind {
-#define VCC_SYMB(uu, ll) SYM_##uu,
-#include "tbl/symbol_kind.h"
-#undef VCC_SYMB
-};
-
-typedef void sym_expr_t(struct vcc *tl, struct expr **,
- const struct symbol *sym);
-typedef struct symbol *sym_wildcard_t(struct vcc *tl, const struct token *t,
- const struct symbol *sym);
-
-struct symbol {
- unsigned magic;
-#define SYMBOL_MAGIC 0x3368c9fb
- VTAILQ_ENTRY(symbol) list;
-
- char *name;
- unsigned nlen;
- sym_wildcard_t *wildcard;
- enum symkind kind;
-
- const struct token *def_b, *def_e;
-
- enum var_type fmt;
-
- sym_expr_t *eval;
- void *eval_priv;
-
- /* xref.c */
- struct proc *proc;
- unsigned nref, ndef;
-
- /* SYM_PROC, SYM_FUNC */
- const char *cfunc;
- const char *extra;
- const char *args;
-
- /* SYM_VAR */
- const struct var *var;
- unsigned r_methods;
-};
-
-VTAILQ_HEAD(tokenhead, token);
-
-struct vcc {
- unsigned magic;
-#define VCC_MAGIC 0x24ad719d
-
- /* Parameter/Template section */
- char *default_vcl;
- char *vcl_dir;
- char *vmod_dir;
-
- const struct var *vars;
- VTAILQ_HEAD(, symbol) symbols;
-
- /* Instance section */
- struct tokenhead tokens;
- VTAILQ_HEAD(, source) sources;
- VTAILQ_HEAD(, membit) membits;
- unsigned nsources;
- struct source *src;
- struct token *t;
- int indent;
- int hindent;
- int iindent;
- int findent;
- unsigned cnt;
-
- struct vsb *fc; /* C-code */
- struct vsb *fh; /* H-code (before C-code) */
- struct vsb *fi; /* Init func code */
- struct vsb *fd; /* Object destructors */
- struct vsb *ff; /* Finish func code */
- struct vsb *fb; /* Body of current sub
- * NULL otherwise
- */
- struct vsb *fm[VCL_MET_MAX]; /* Method bodies */
- struct vsb *sb;
- int err;
- int ndirector;
- struct proc *curproc;
- struct proc *mprocs[VCL_MET_MAX];
-
- VTAILQ_HEAD(, acl_e) acl;
-
- int nprobe;
-
- int defaultdir;
- struct token *t_defaultdir;
-
- unsigned unique;
- unsigned nvmodpriv;
-
- unsigned err_unref;
- unsigned allow_inline_c;
- unsigned unsafe_path;
-};
-
-struct var {
- const char *name;
- enum var_type fmt;
- unsigned len;
- const char *rname;
- unsigned r_methods;
- const char *lname;
- unsigned w_methods;
-};
-
-struct method {
- const char *name;
- unsigned ret_bitmap;
- unsigned bitval;
-};
-
-/*--------------------------------------------------------------------*/
-
-/* vcc_acl.c */
-
-void vcc_Acl(struct vcc *tl);
-void vcc_Acl_Hack(struct vcc *tl, char *b);
-
-/* vcc_action.c */
-int vcc_ParseAction(struct vcc *tl);
-
-/* vcc_backend.c */
-#define MAX_BACKEND_NAME 64
-struct fld_spec;
-
-void vcc_ParseProbe(struct vcc *tl);
-void vcc_ParseBackend(struct vcc *tl);
-struct fld_spec * vcc_FldSpec(struct vcc *tl, const char *first, ...);
-void vcc_IsField(struct vcc *tl, struct token **t, struct fld_spec *fs);
-void vcc_FieldsOk(struct vcc *tl, const struct fld_spec *fs);
-
-/* vcc_compile.c */
-extern struct method method_tab[];
-/*
- * H -> Header, before the C code
- * C -> C-code
- * B -> Body of function, ends up in C once function is completed
- * I -> Initializer function
- * F -> Finish function
- */
-void Fh(const struct vcc *tl, int indent, const char *fmt, ...)
- __printflike(3, 4);
-void Fc(const struct vcc *tl, int indent, const char *fmt, ...)
- __printflike(3, 4);
-void Fb(const struct vcc *tl, int indent, const char *fmt, ...)
- __printflike(3, 4);
-void Fi(const struct vcc *tl, int indent, const char *fmt, ...)
- __printflike(3, 4);
-void Ff(const struct vcc *tl, int indent, const char *fmt, ...)
- __printflike(3, 4);
-void Fd(const struct vcc *tl, int indent, const char *fmt, ...)
- __printflike(3, 4);
-void EncToken(struct vsb *sb, const struct token *t);
-int IsMethod(const struct token *t);
-void *TlAlloc(struct vcc *tl, unsigned len);
-char *TlDup(struct vcc *tl, const char *s);
-char *TlDupTok(struct vcc *tl, const struct token *tok);
-
-void EncString(struct vsb *sb, const char *b, const char *e, int mode);
-
-/* vcc_expr.c */
-void vcc_Duration(struct vcc *tl, double *);
-unsigned vcc_UintVal(struct vcc *tl);
-void vcc_Expr(struct vcc *tl, enum var_type typ);
-void vcc_Expr_Call(struct vcc *tl, const struct symbol *sym);
-void vcc_Expr_Init(struct vcc *tl);
-sym_expr_t vcc_Eval_Var;
-sym_expr_t vcc_Eval_SymFunc;
-void vcc_Eval_Func(struct vcc *tl, const char *cfunc, const char *extra,
- const char *name, const char *args);
-sym_expr_t vcc_Eval_Backend;
-
-/* vcc_obj.c */
-extern const struct var vcc_vars[];
-
-/* vcc_parse.c */
-void vcc_Parse(struct vcc *tl);
-
-/* vcc_storage.c */
-sym_wildcard_t vcc_Stv_Wildcard;
-
-/* vcc_utils.c */
-const char *vcc_regexp(struct vcc *tl);
-void Resolve_Sockaddr(struct vcc *tl, const char *host, const char *port, \
- const char **ipv4, const char **ipv4_ascii, const char **ipv6, \
- const char **ipv6_ascii, const char **p_ascii, int maxips,
- const struct token *t_err, const char *errid);
-
-/* vcc_symb.c */
-struct symbol *VCC_AddSymbolStr(struct vcc *tl, const char *name, enum symkind);
-struct symbol *VCC_AddSymbolTok(struct vcc *tl, const struct token *t,
- enum symkind kind);
-struct symbol *VCC_GetSymbolTok(struct vcc *tl, const struct token *tok,
- enum symkind);
-struct symbol *VCC_FindSymbol(struct vcc *tl,
- const struct token *t, enum symkind kind);
-const char * VCC_SymKind(struct vcc *tl, const struct symbol *s);
-typedef void symwalk_f(struct vcc *tl, const struct symbol *s);
-void VCC_WalkSymbols(struct vcc *tl, symwalk_f *func, enum symkind kind);
-
-/* vcc_token.c */
-void vcc_Coord(const struct vcc *tl, struct vsb *vsb,
- const struct token *t);
-void vcc_ErrToken(const struct vcc *tl, const struct token *t);
-void vcc_ErrWhere(struct vcc *, const struct token *);
-void vcc_ErrWhere2(struct vcc *, const struct token *, const struct token *);
-
-void vcc__Expect(struct vcc *tl, unsigned tok, unsigned line);
-int vcc_IdIs(const struct token *t, const char *p);
-void vcc_ExpectCid(struct vcc *tl);
-void vcc_Lexer(struct vcc *tl, struct source *sp);
-void vcc_NextToken(struct vcc *tl);
-void vcc__ErrInternal(struct vcc *tl, const char *func,
- unsigned line);
-void vcc_AddToken(struct vcc *tl, unsigned tok, const char *b,
- const char *e);
-
-/* vcc_var.c */
-sym_wildcard_t vcc_Var_Wildcard;
-const struct var *vcc_FindVar(struct vcc *tl, const struct token *t,
- int wr_access, const char *use);
-
-/* vcc_vmod.c */
-void vcc_ParseImport(struct vcc *tl);
-
-/* vcc_xref.c */
-int vcc_AddDef(struct vcc *tl, const struct token *t, enum symkind type);
-void vcc_AddRef(struct vcc *tl, const struct token *t, enum symkind type);
-int vcc_CheckReferences(struct vcc *tl);
-
-void vcc_AddCall(struct vcc *tl, struct token *t);
-struct proc *vcc_AddProc(struct vcc *tl, struct token *t);
-void vcc_ProcAction(struct proc *p, unsigned action, struct token *t);
-int vcc_CheckAction(struct vcc *tl);
-void vcc_AddUses(struct vcc *tl, const struct token *t, unsigned mask,
- const char *use);
-int vcc_CheckUses(struct vcc *tl);
-
-#define ERRCHK(tl) do { if ((tl)->err) return; } while (0)
-#define ErrInternal(tl) vcc__ErrInternal(tl, __func__, __LINE__)
-#define Expect(a, b) vcc__Expect(a, b, __LINE__)
-#define ExpectErr(a, b) \
- do { vcc__Expect(a, b, __LINE__); ERRCHK(a);} while (0)
-#define SkipToken(a, b) \
- do { vcc__Expect(a, b, __LINE__); ERRCHK(a); vcc_NextToken(a); } while (0)
diff --git a/lib/libvcl/vcc_expr.c b/lib/libvcl/vcc_expr.c
deleted file mode 100644
index 164a8d6..0000000
--- a/lib/libvcl/vcc_expr.c
+++ /dev/null
@@ -1,1257 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2011 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * XXX: add VRT_count()'s
- */
-
-#include "config.h"
-
-#include <math.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "vcc_compile.h"
-
-static const char *
-vcc_Type(enum var_type fmt)
-{
- switch(fmt) {
-#define VCC_TYPE(a) case a: return(#a);
-#include "tbl/vcc_types.h"
-#undef VCC_TYPE
- default:
- assert("Unknown Type");
- return(NULL);
- }
-}
-
-/*--------------------------------------------------------------------
- * Recognize and convert units of time, return seconds.
- */
-
-static double
-vcc_TimeUnit(struct vcc *tl)
-{
- double sc = 1.0;
-
- assert(tl->t->tok == ID);
- if (vcc_IdIs(tl->t, "ms"))
- sc = 1e-3;
- else if (vcc_IdIs(tl->t, "s"))
- sc = 1.0;
- else if (vcc_IdIs(tl->t, "m"))
- sc = 60.0;
- else if (vcc_IdIs(tl->t, "h"))
- sc = 60.0 * 60.0;
- else if (vcc_IdIs(tl->t, "d"))
- sc = 60.0 * 60.0 * 24.0;
- else if (vcc_IdIs(tl->t, "w"))
- sc = 60.0 * 60.0 * 24.0 * 7.0;
- else {
- VSB_printf(tl->sb, "Unknown time unit ");
- vcc_ErrToken(tl, tl->t);
- VSB_printf(tl->sb, ". Legal are 's', 'm', 'h' and 'd'\n");
- vcc_ErrWhere(tl, tl->t);
- return (1.0);
- }
- vcc_NextToken(tl);
- return (sc);
-}
-
-/*--------------------------------------------------------------------
- * Recognize and convert { CNUM } to unsigned value
- * The tokenizer made sure we only get digits.
- */
-
-unsigned
-vcc_UintVal(struct vcc *tl)
-{
- unsigned d = 0;
- const char *p;
-
- Expect(tl, CNUM);
- for (p = tl->t->b; p < tl->t->e; p++) {
- d *= 10;
- d += *p - '0';
- }
- vcc_NextToken(tl);
- return (d);
-}
-
-/*--------------------------------------------------------------------
- * Recognize and convert { CNUM [ '.' [ CNUM ] ] } to double value
- * The tokenizer made sure we only get digits and a '.'
- */
-
-static void
-vcc_NumVal(struct vcc *tl, double *d, int *frac)
-{
- double e = 0.1;
- const char *p;
-
- *frac = 0;
- *d = 0.0;
- Expect(tl, CNUM);
- if (tl->err) {
- *d = NAN;
- return;
- }
- for (p = tl->t->b; p < tl->t->e; p++) {
- *d *= 10;
- *d += *p - '0';
- }
- vcc_NextToken(tl);
- if (tl->t->tok != '.')
- return;
- *frac = 1;
- vcc_NextToken(tl);
- if (tl->t->tok != CNUM)
- return;
- for (p = tl->t->b; p < tl->t->e; p++) {
- *d += (*p - '0') * e;
- e *= 0.1;
- }
- vcc_NextToken(tl);
-}
-
-static double
-vcc_DoubleVal(struct vcc *tl)
-{
- double d;
- int i;
-
- vcc_NumVal(tl, &d, &i);
- return (d);
-}
-
-/*--------------------------------------------------------------------*/
-
-void
-vcc_Duration(struct vcc *tl, double *d)
-{
- double v, sc;
-
- v = vcc_DoubleVal(tl);
- ERRCHK(tl);
- ExpectErr(tl, ID);
- sc = vcc_TimeUnit(tl);
- *d = v * sc;
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-vcc_ByteVal(struct vcc *tl, double *d)
-{
- double v, sc;
-
- v = vcc_DoubleVal(tl);
- ERRCHK(tl);
- if (tl->t->tok != ID) {
- VSB_printf(tl->sb, "Expected BYTES unit (B, KB, MB...) got ");
- vcc_ErrToken(tl, tl->t);
- VSB_printf(tl->sb, "\n");
- vcc_ErrWhere(tl, tl->t);
- return;
- }
- if (vcc_IdIs(tl->t, "B"))
- sc = 1.;
- else if (vcc_IdIs(tl->t, "KB"))
- sc = 1024.;
- else if (vcc_IdIs(tl->t, "MB"))
- sc = 1024. * 1024.;
- else if (vcc_IdIs(tl->t, "GB"))
- sc = 1024. * 1024. * 1024.;
- else if (vcc_IdIs(tl->t, "TB"))
- sc = 1024. * 1024. * 1024. * 1024.;
- else {
- VSB_printf(tl->sb, "Unknown BYTES unit ");
- vcc_ErrToken(tl, tl->t);
- VSB_printf(tl->sb,
- ". Legal are 'B', 'KB', 'MB', 'GB' and 'TB'\n");
- vcc_ErrWhere(tl, tl->t);
- return;
- }
- vcc_NextToken(tl);
- *d = v * sc;
-}
-
-/*--------------------------------------------------------------------
- * Facility for carrying expressions around and do text-processing on
- * them.
- */
-
-struct expr {
- unsigned magic;
-#define EXPR_MAGIC 0x38c794ab
- enum var_type fmt;
- struct vsb *vsb;
- uint8_t constant;
-#define EXPR_VAR (1<<0)
-#define EXPR_CONST (1<<1)
-#define EXPR_STR_CONST (1<<2)
- struct token *t1, *t2;
-};
-
-static inline int
-vcc_isconst(const struct expr *e)
-{
- AN(e->constant);
- return (e->constant & EXPR_CONST);
-}
-
-static void vcc_expr0(struct vcc *tl, struct expr **e, enum var_type fmt);
-
-static struct expr *
-vcc_new_expr(void)
-{
- struct expr *e;
-
- /* XXX: use TlAlloc() ? */
- ALLOC_OBJ(e, EXPR_MAGIC);
- AN(e);
- e->vsb = VSB_new_auto();
- e->fmt = VOID;
- e->constant = EXPR_VAR;
- return (e);
-}
-
-static struct expr *
-vcc_mk_expr(enum var_type fmt, const char *str, ...)
- __printflike(2, 3);
-
-static struct expr *
-vcc_mk_expr(enum var_type fmt, const char *str, ...)
-{
- va_list ap;
- struct expr *e;
-
- e = vcc_new_expr();
- e->fmt = fmt;
- va_start(ap, str);
- VSB_vprintf(e->vsb, str, ap);
- va_end(ap);
- AZ(VSB_finish(e->vsb));
- return (e);
-}
-
-static void
-vcc_delete_expr(struct expr *e)
-{
- if (e == NULL)
- return;
- CHECK_OBJ_NOTNULL(e, EXPR_MAGIC);
- VSB_delete(e->vsb);
- FREE_OBJ(e);
-}
-/*--------------------------------------------------------------------
- * We want to get the indentation right in the emitted C code so we have
- * to represent it symbolically until we are ready to render.
- *
- * Many of the operations have very schematic output syntaxes, so we
- * use the same facility to simplify the text-processing of emitting
- * a given operation on two subexpressions.
- *
- * We use '\v' as the magic escape character.
- * \v1 insert subexpression 1
- * \v2 insert subexpression 2
- * \v+ increase indentation
- * \v- increase indentation
- * anything else is literal
- *
- * When editing, we check if any of the subexpressions contain a newline
- * and issue it as an indented block of so.
- *
- * XXX: check line lengths in edit, should pass indent in for this
- */
-
-static struct expr *
-vcc_expr_edit(enum var_type fmt, const char *p, struct expr *e1,
- struct expr *e2)
-{
- struct expr *e;
- int nl = 1;
-
- AN(e1);
- e = vcc_new_expr();
- while (*p != '\0') {
- if (*p != '\v') {
- if (*p != '\n' || !nl)
- VSB_putc(e->vsb, *p);
- nl = (*p == '\n');
- p++;
- continue;
- }
- assert(*p == '\v');
- switch(*++p) {
- case '+': VSB_cat(e->vsb, "\v+"); break;
- case '-': VSB_cat(e->vsb, "\v-"); break;
- case '1':
- VSB_cat(e->vsb, VSB_data(e1->vsb));
- break;
- case '2':
- AN(e2);
- VSB_cat(e->vsb, VSB_data(e2->vsb));
- break;
- default:
- WRONG("Illegal edit in VCC expression");
- }
- p++;
- }
- AZ(VSB_finish(e->vsb));
- e->t1 = e1->t1;
- e->t2 = e1->t2;
- if (e2 != NULL)
- e->t2 = e2->t2;
- vcc_delete_expr(e1);
- vcc_delete_expr(e2);
- e->fmt = fmt;
- return (e);
-}
-
-/*--------------------------------------------------------------------
- * Expand finished expression into C-source code
- */
-
-static void
-vcc_expr_fmt(struct vsb *d, int ind, const struct expr *e1)
-{
- char *p;
- int i;
-
- for (i = 0; i < ind; i++)
- VSB_cat(d, " ");
- p = VSB_data(e1->vsb);
- while (*p != '\0') {
- if (*p == '\n') {
- VSB_putc(d, '\n');
- if (p[1] != '\0') {
- for (i = 0; i < ind; i++)
- VSB_cat(d, " ");
- }
- p++;
- continue;
- }
- if (*p != '\v') {
- VSB_putc(d, *p);
- p++;
- continue;
- }
- p++;
- switch(*p) {
- case '+': ind += 2; break;
- case '-': ind -= 2; break;
- default:
- WRONG("Illegal format in VCC expression");
- }
- p++;
- }
-}
-
-/*--------------------------------------------------------------------
- */
-
-static enum var_type
-vcc_arg_type(const char **p)
-{
-
-#define VCC_TYPE(a) if (!strcmp(#a, *p)) { *p += strlen(#a) + 1; return (a);}
-#include "tbl/vcc_types.h"
-#undef VCC_TYPE
- return (VOID);
-}
-
-/*--------------------------------------------------------------------
- */
-
-static void
-vcc_expr_tostring(struct expr **e, enum var_type fmt)
-{
- const char *p;
- uint8_t constant = EXPR_VAR;
-
- CHECK_OBJ_NOTNULL(*e, EXPR_MAGIC);
- AN(fmt == STRING || fmt == STRING_LIST);
-
- p = NULL;
- switch((*e)->fmt) {
- case BACKEND: p = "VRT_BACKEND_string(\v1)"; break;
- case BOOL: p = "VRT_BOOL_string(\v1)"; break;
- case DURATION: p = "VRT_REAL_string(ctx, \v1)"; break;
- /* XXX: should DURATION insist on "s" suffix ? */
- case INT:
- if (vcc_isconst(*e)) {
- p = "\"\v1\"";
- constant = EXPR_CONST;
- } else {
- p = "VRT_INT_string(ctx, \v1)";
- }
- break;
- case IP: p = "VRT_IP_string(ctx, \v1)"; break;
- case BYTES: p = "VRT_REAL_string(ctx, \v1)"; break; /* XXX */
- case REAL: p = "VRT_REAL_string(ctx, \v1)"; break;
- case TIME: p = "VRT_TIME_string(ctx, \v1)"; break;
- case HEADER: p = "VRT_GetHdr(ctx, \v1)"; break;
- case ENUM:
- case STRING:
- case STRING_LIST:
- break;
- default:
- INCOMPL();
- break;
- }
- if (p != NULL) {
- *e = vcc_expr_edit(fmt, p, *e, NULL);
- (*e)->constant = constant;
- }
-}
-
-/*--------------------------------------------------------------------
- */
-
-static void
-vcc_Eval_Regsub(struct vcc *tl, struct expr **e, const struct symbol *sym)
-{
- struct expr *e2;
- int all = sym->eval_priv == NULL ? 0 : 1;
- const char *p;
- char buf[128];
-
- vcc_delete_expr(*e);
- SkipToken(tl, ID);
- SkipToken(tl, '(');
-
- vcc_expr0(tl, &e2, STRING);
- if (e2 == NULL)
- return;
- if (e2->fmt != STRING)
- vcc_expr_tostring(&e2, STRING);
-
- SkipToken(tl, ',');
- ExpectErr(tl, CSTR);
- p = vcc_regexp(tl);
- vcc_NextToken(tl);
-
- bprintf(buf, "VRT_regsub(ctx, %d,\v+\n\v1,\n%s", all, p);
- *e = vcc_expr_edit(STRING, buf, e2, *e);
-
- SkipToken(tl, ',');
- vcc_expr0(tl, &e2, STRING);
- if (e2 == NULL)
- return;
- if (e2->fmt != STRING)
- vcc_expr_tostring(&e2, STRING);
- *e = vcc_expr_edit(STRING, "\v1,\n\v2)\v-", *e, e2);
- SkipToken(tl, ')');
-}
-
-/*--------------------------------------------------------------------
- */
-
-static void
-vcc_Eval_BoolConst(struct vcc *tl, struct expr **e, const struct symbol *sym)
-{
-
- vcc_NextToken(tl);
- *e = vcc_mk_expr(BOOL, "(0==%d)", sym->eval_priv == NULL ? 1 : 0);
- (*e)->constant = EXPR_CONST;
-}
-
-/*--------------------------------------------------------------------
- */
-
-void
-vcc_Eval_Backend(struct vcc *tl, struct expr **e, const struct symbol *sym)
-{
-
- assert(sym->kind == SYM_BACKEND);
-
- vcc_ExpectCid(tl);
- vcc_AddRef(tl, tl->t, SYM_BACKEND);
- *e = vcc_mk_expr(BACKEND, "VGCDIR(_%.*s)", PF(tl->t));
- (*e)->constant = EXPR_VAR; /* XXX ? */
- vcc_NextToken(tl);
-}
-
-/*--------------------------------------------------------------------
- */
-void
-vcc_Eval_Var(struct vcc *tl, struct expr **e, const struct symbol *sym)
-{
- const struct var *vp;
-
- assert(sym->kind == SYM_VAR);
- vcc_AddUses(tl, tl->t, sym->r_methods, "Not available");
- vp = vcc_FindVar(tl, tl->t, 0, "cannot be read");
- ERRCHK(tl);
- assert(vp != NULL);
- *e = vcc_mk_expr(vp->fmt, "%s", vp->rname);
- vcc_NextToken(tl);
-}
-
-/*--------------------------------------------------------------------
- */
-
-static void
-vcc_func(struct vcc *tl, struct expr **e, const char *cfunc,
- const char *extra, const char *name, const char *args)
-{
- const char *p, *r;
- struct expr *e1, *e2;
- enum var_type fmt;
- char buf[32];
-
- AN(cfunc);
- AN(args);
- AN(name);
- SkipToken(tl, '(');
- p = args;
- if (extra == NULL)
- extra = "";
- e2 = vcc_mk_expr(vcc_arg_type(&p), "%s(ctx%s\v+", cfunc, extra);
- while (*p != '\0') {
- e1 = NULL;
- fmt = vcc_arg_type(&p);
- if (fmt == VOID && !strcmp(p, "PRIV_VCL")) {
- r = strchr(name, '.');
- AN(r);
- e1 = vcc_mk_expr(VOID, "&vmod_priv_%.*s",
- (int) (r - name), name);
- p += strlen(p) + 1;
- } else if (fmt == VOID && !strcmp(p, "PRIV_CALL")) {
- bprintf(buf, "vmod_priv_%u", tl->nvmodpriv++);
- 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') /*lint !e448 */
- SkipToken(tl, ',');
- } else {
- vcc_expr0(tl, &e1, fmt);
- ERRCHK(tl);
- if (e1->fmt != fmt) {
- VSB_printf(tl->sb, "Wrong argument type.");
- VSB_printf(tl->sb, " Expected %s.",
- vcc_Type(fmt));
- VSB_printf(tl->sb, " Got %s.\n",
- vcc_Type(e1->fmt));
- vcc_ErrWhere2(tl, e1->t1, tl->t);
- return;
- }
- assert(e1->fmt == fmt);
- if (e1->fmt == STRING_LIST) {
- e1 = vcc_expr_edit(STRING_LIST,
- "\v+\n\v1,\nvrt_magic_string_end\v-",
- e1, NULL);
- }
- if (*p != '\0')
- SkipToken(tl, ',');
- }
- e2 = vcc_expr_edit(e2->fmt, "\v1,\n\v2", e2, e1);
- }
- SkipToken(tl, ')');
- e2 = vcc_expr_edit(e2->fmt, "\v1\n)\v-", e2, NULL);
- *e = e2;
-}
-
-/*--------------------------------------------------------------------
- */
-
-void
-vcc_Eval_Func(struct vcc *tl, const char *cfunc,
- const char *extra, const char *name, const char *args)
-{
- struct expr *e = NULL;
- struct token *t1;
-
- t1 = tl->t;
- vcc_func(tl, &e, cfunc, extra, name, args);
- if (!tl->err) {
- vcc_expr_fmt(tl->fb, tl->indent, e);
- VSB_cat(tl->fb, ";\n");
- } else if (t1 != tl->t) {
- vcc_ErrWhere2(tl, t1, tl->t);
- }
- vcc_delete_expr(e);
-}
-
-/*--------------------------------------------------------------------
- */
-
-void
-vcc_Eval_SymFunc(struct vcc *tl, struct expr **e, const struct symbol *sym)
-{
-
- assert(sym->kind == SYM_FUNC || sym->kind == SYM_PROC);
- AN(sym->cfunc);
- AN(sym->name);
- AN(sym->args);
- SkipToken(tl, ID);
- vcc_func(tl, e, sym->cfunc, sym->extra, sym->name, sym->args);
-}
-
-/*--------------------------------------------------------------------
- * SYNTAX:
- * Expr4:
- * '(' Expr0 ')'
- * CNUM
- * CSTR
- */
-
-static void
-vcc_expr4(struct vcc *tl, struct expr **e, enum var_type fmt)
-{
- struct expr *e1, *e2;
- const char *ip;
- const struct symbol *sym;
- double d;
-
- *e = NULL;
- if (tl->t->tok == '(') {
- SkipToken(tl, '(');
- vcc_expr0(tl, &e2, fmt);
- ERRCHK(tl);
- SkipToken(tl, ')');
- *e = vcc_expr_edit(e2->fmt, "(\v1)", e2, NULL);
- return;
- }
- switch(tl->t->tok) {
- case ID:
- /*
- * XXX: what if var and func/proc had same name ?
- * XXX: look for SYM_VAR first for consistency ?
- */
- sym = VCC_FindSymbol(tl, tl->t, SYM_NONE);
- if (sym == NULL || sym->eval == NULL) {
- VSB_printf(tl->sb, "Symbol not found: ");
- vcc_ErrToken(tl, tl->t);
- VSB_printf(tl->sb, " (expected type %s):\n",
- vcc_Type(fmt));
- vcc_ErrWhere(tl, tl->t);
- return;
- }
- AN(sym);
- switch(sym->kind) {
- case SYM_VAR:
- case SYM_FUNC:
- case SYM_BACKEND:
- AN(sym->eval);
- AZ(*e);
- sym->eval(tl, e, sym);
- return;
- default:
- break;
- }
- VSB_printf(tl->sb,
- "Symbol type (%s) can not be used in expression.\n",
- VCC_SymKind(tl, sym));
- vcc_ErrWhere(tl, tl->t);
- return;
- case CSTR:
- assert(fmt != VOID);
- if (fmt == IP) {
- Resolve_Sockaddr(tl, tl->t->dec, "80",
- &ip, NULL, &ip, NULL, NULL, 1,
- tl->t, "IP constant");
- ERRCHK(tl);
- e1 = vcc_mk_expr(IP, "%s", ip);
- ERRCHK(tl);
- } else {
- e1 = vcc_new_expr();
- EncToken(e1->vsb, tl->t);
- e1->fmt = STRING;
- AZ(VSB_finish(e1->vsb));
- }
- e1->t1 = tl->t;
- e1->constant = EXPR_CONST;
- vcc_NextToken(tl);
- *e = e1;
- break;
- case CNUM:
- /*
- * XXX: %g may not have enough decimals by default
- * XXX: but %a is ugly, isn't it ?
- */
- assert(fmt != VOID);
- if (fmt == DURATION) {
- vcc_Duration(tl, &d);
- ERRCHK(tl);
- e1 = vcc_mk_expr(DURATION, "%g", d);
- } else if (fmt == BYTES) {
- vcc_ByteVal(tl, &d);
- ERRCHK(tl);
- e1 = vcc_mk_expr(BYTES, "%.1f", d);
- ERRCHK(tl);
- } else if (fmt == REAL) {
- e1 = vcc_mk_expr(REAL, "%g", vcc_DoubleVal(tl));
- ERRCHK(tl);
- } else {
- e1 = vcc_mk_expr(INT, "%.*s", PF(tl->t));
- vcc_NextToken(tl);
- }
- e1->constant = EXPR_CONST;
- *e = e1;
- break;
- default:
- VSB_printf(tl->sb, "Unknown token ");
- vcc_ErrToken(tl, tl->t);
- VSB_printf(tl->sb, " when looking for %s\n\n", vcc_Type(fmt));
- vcc_ErrWhere(tl, tl->t);
- break;
- }
-}
-
-/*--------------------------------------------------------------------
- * SYNTAX:
- * Expr3:
- * Expr4 { {'*'|'/'} Expr4 } *
- */
-
-static void
-vcc_expr_mul(struct vcc *tl, struct expr **e, enum var_type fmt)
-{
- struct expr *e2;
- enum var_type f2, f3;
- struct token *tk;
-
- *e = NULL;
- vcc_expr4(tl, e, fmt);
- ERRCHK(tl);
- f3 = f2 = (*e)->fmt;
-
- switch(f2) {
- case INT: f2 = INT; break;
- case DURATION: f2 = REAL; break;
- case BYTES: f2 = REAL; break;
- default:
- if (tl->t->tok != '*' && tl->t->tok != '/')
- return;
- VSB_printf(tl->sb, "Operator %.*s not possible on type %s.\n",
- PF(tl->t), vcc_Type(f2));
- vcc_ErrWhere(tl, tl->t);
- return;
- }
-
- while (tl->t->tok == '*' || tl->t->tok == '/') {
- tk = tl->t;
- vcc_NextToken(tl);
- vcc_expr4(tl, &e2, f2);
- ERRCHK(tl);
- assert(e2->fmt == f2);
- if (tk->tok == '*')
- *e = vcc_expr_edit(f3, "(\v1*\v2)", *e, e2);
- else
- *e = vcc_expr_edit(f3, "(\v1/\v2)", *e, e2);
- }
-}
-
-/*--------------------------------------------------------------------
- * SYNTAX:
- * ExprAdd:
- * ExprMul { {'+'|'-'} ExprMul } *
- *
- * For reasons of memory allocation/copying and general performance,
- * STRINGs in VCL are quite special. Addition/concatenation is split
- * into it's own subfunction to encapsulate this.
- */
-
-static void
-vcc_expr_string_add(struct vcc *tl, struct expr **e)
-{
- struct expr *e2;
- enum var_type f2;
-
- f2 = (*e)->fmt;
-
- while (tl->t->tok == '+') {
- vcc_NextToken(tl);
- vcc_expr_mul(tl, &e2, STRING);
- ERRCHK(tl);
- if (e2->fmt != STRING && e2->fmt != STRING_LIST)
- vcc_expr_tostring(&e2, f2);
- ERRCHK(tl);
- assert(e2->fmt == STRING || e2->fmt == STRING_LIST);
-
- if (vcc_isconst(*e) && vcc_isconst(e2)) {
- assert((*e)->fmt == STRING);
- assert(e2->fmt == STRING);
- *e = vcc_expr_edit(STRING, "\v1\n\v2", *e, e2);
- (*e)->constant = EXPR_CONST;
- } else if (((*e)->constant & EXPR_STR_CONST) &&
- vcc_isconst(e2)) {
- assert((*e)->fmt == STRING_LIST);
- assert(e2->fmt == STRING);
- *e = vcc_expr_edit(STRING_LIST, "\v1\n\v2", *e, e2);
- (*e)->constant = EXPR_VAR | EXPR_STR_CONST;
- } else if (e2->fmt == STRING && vcc_isconst(e2)) {
- *e = vcc_expr_edit(STRING_LIST, "\v1,\n\v2", *e, e2);
- (*e)->constant = EXPR_VAR | EXPR_STR_CONST;
- } else {
- *e = vcc_expr_edit(STRING_LIST, "\v1,\n\v2", *e, e2);
- (*e)->constant = EXPR_VAR;
- }
- }
-}
-
-static void
-vcc_expr_add(struct vcc *tl, struct expr **e, enum var_type fmt)
-{
- struct expr *e2;
- enum var_type f2;
- struct token *tk;
-
- *e = NULL;
- vcc_expr_mul(tl, e, fmt);
- ERRCHK(tl);
- f2 = (*e)->fmt;
-
- /* Unless we specifically ask for a HEADER, fold them to string here */
- if (fmt != HEADER && f2 == HEADER) {
- vcc_expr_tostring(e, STRING);
- f2 = (*e)->fmt;
- assert(f2 == STRING);
- }
-
- if (tl->t->tok != '+' && tl->t->tok != '-')
- return;
-
- switch(f2) {
- case STRING:
- case STRING_LIST:
- vcc_expr_string_add(tl, e);
- return;
- case INT: break;
- case TIME: break;
- case DURATION: break;
- case BYTES: break;
- default:
- VSB_printf(tl->sb, "Operator %.*s not possible on type %s.\n",
- PF(tl->t), vcc_Type(f2));
- vcc_ErrWhere(tl, tl->t);
- return;
- }
-
- while (tl->t->tok == '+' || tl->t->tok == '-') {
- if (f2 == TIME)
- f2 = DURATION;
- tk = tl->t;
- vcc_NextToken(tl);
- vcc_expr_mul(tl, &e2, f2);
- ERRCHK(tl);
- if (tk->tok == '-' && (*e)->fmt == TIME && e2->fmt == TIME) {
- /* OK */
- } else if ((*e)->fmt == TIME && e2->fmt == DURATION) {
- f2 = TIME;
- /* OK */
- } else if (tk->tok == '-' &&
- (*e)->fmt == BYTES && e2->fmt == BYTES) {
- /* OK */
- } else if (e2->fmt != f2) {
- VSB_printf(tl->sb, "%s %.*s %s not possible.\n",
- vcc_Type((*e)->fmt), PF(tk), vcc_Type(e2->fmt));
- vcc_ErrWhere2(tl, tk, tl->t);
- return;
- }
- if (tk->tok == '+')
- *e = vcc_expr_edit(f2, "(\v1+\v2)", *e, e2);
- else if (f2 == TIME && e2->fmt == TIME)
- *e = vcc_expr_edit(DURATION, "(\v1-\v2)", *e, e2);
- else
- *e = vcc_expr_edit(f2, "(\v1-\v2)", *e, e2);
- }
-}
-
-/*--------------------------------------------------------------------
- * Fold the STRING types correctly
- */
-
-static void
-vcc_expr_strfold(struct vcc *tl, struct expr **e, enum var_type fmt)
-{
-
- vcc_expr_add(tl, e, fmt);
- ERRCHK(tl);
-
- if (fmt != STRING_LIST && (*e)->fmt == STRING_LIST)
- *e = vcc_expr_edit(STRING,
- "\v+VRT_CollectString(ctx,\n\v1,\nvrt_magic_string_end)\v-",
- *e, NULL);
- if (fmt == STRING_LIST && (*e)->fmt == STRING)
- (*e)->fmt = STRING_LIST;
-}
-
-/*--------------------------------------------------------------------
- * SYNTAX:
- * ExprCmp:
- * ExprAdd
- * ExprAdd Relation ExprAdd
- * ExprAdd(STRING) '~' CString
- * ExprAdd(STRING) '!~' CString
- * ExprAdd(IP) '~' IP
- * ExprAdd(IP) '!~' IP
- */
-
-#define NUM_REL(typ) \
- {typ, T_EQ, "(\v1 == \v2)" }, \
- {typ, T_NEQ, "(\v1 != \v2)" }, \
- {typ, T_LEQ, "(\v1 <= \v2)" }, \
- {typ, T_GEQ, "(\v1 >= \v2)" }, \
- {typ, '<', "(\v1 < \v2)" }, \
- {typ, '>', "(\v1 > \v2)" }
-
-static const struct cmps {
- enum var_type fmt;
- unsigned token;
- const char *emit;
-} vcc_cmps[] = {
- NUM_REL(INT),
- NUM_REL(DURATION),
- NUM_REL(BYTES),
- NUM_REL(REAL),
-
- {STRING, T_EQ, "!VRT_strcmp(\v1, \v2)" },
- {STRING, T_NEQ, "VRT_strcmp(\v1, \v2)" },
-
- {VOID, 0, NULL}
-};
-
-#undef NUM_REL
-
-static void
-vcc_expr_cmp(struct vcc *tl, struct expr **e, enum var_type fmt)
-{
- struct expr *e2;
- const struct cmps *cp;
- char buf[256];
- const char *re;
- const char *not;
- struct token *tk;
-
- *e = NULL;
-
- vcc_expr_strfold(tl, e, fmt);
- ERRCHK(tl);
-
- if ((*e)->fmt == BOOL)
- return;
-
- tk = tl->t;
- for (cp = vcc_cmps; cp->fmt != VOID; cp++)
- if ((*e)->fmt == cp->fmt && tl->t->tok == cp->token)
- break;
- if (cp->fmt != VOID) {
- vcc_NextToken(tl);
- vcc_expr_strfold(tl, &e2, (*e)->fmt);
- ERRCHK(tl);
- if (e2->fmt != (*e)->fmt) { /* XXX */
- VSB_printf(tl->sb, "Comparison of different types: ");
- VSB_printf(tl->sb, "%s ", vcc_Type((*e)->fmt));
- vcc_ErrToken(tl, tk);
- VSB_printf(tl->sb, " %s\n", vcc_Type(e2->fmt));
- vcc_ErrWhere(tl, tk);
- return;
- }
- *e = vcc_expr_edit(BOOL, cp->emit, *e, e2);
- return;
- }
- if ((*e)->fmt == STRING &&
- (tl->t->tok == '~' || tl->t->tok == T_NOMATCH)) {
- not = tl->t->tok == '~' ? "" : "!";
- vcc_NextToken(tl);
- ExpectErr(tl, CSTR);
- re = vcc_regexp(tl);
- ERRCHK(tl);
- vcc_NextToken(tl);
- bprintf(buf, "%sVRT_re_match(ctx, \v1, %s)", not, re);
- *e = vcc_expr_edit(BOOL, buf, *e, NULL);
- return;
- }
- if ((*e)->fmt == IP &&
- (tl->t->tok == '~' || tl->t->tok == T_NOMATCH)) {
- not = tl->t->tok == '~' ? "" : "!";
- vcc_NextToken(tl);
- ExpectErr(tl, ID);
- vcc_AddRef(tl, tl->t, SYM_ACL);
- bprintf(buf, "%smatch_acl_named_%.*s(ctx, \v1)",
- not, PF(tl->t));
- vcc_NextToken(tl);
- *e = vcc_expr_edit(BOOL, buf, *e, NULL);
- return;
- }
- if ((*e)->fmt == IP && (tl->t->tok == T_EQ || tl->t->tok == T_NEQ)) {
- vcc_Acl_Hack(tl, buf);
- *e = vcc_expr_edit(BOOL, buf, *e, NULL);
- return;
- }
- if ((*e)->fmt == BACKEND &&
- (tl->t->tok == T_EQ || tl->t->tok == T_NEQ)) {
- vcc_NextToken(tl);
- ExpectErr(tl, ID);
- vcc_AddRef(tl, tl->t, SYM_BACKEND);
- bprintf(buf, "(\v1 %.*s VGCDIR(_%.*s))", PF(tk), PF(tl->t));
- vcc_NextToken(tl);
- *e = vcc_expr_edit(BOOL, buf, *e, NULL);
- return;
- }
- switch (tl->t->tok) {
- case T_EQ:
- case T_NEQ:
- case '<':
- case T_LEQ:
- case '>':
- case T_GEQ:
- case '~':
- case T_NOMATCH:
- VSB_printf(tl->sb, "Operator %.*s not possible on %s\n",
- PF(tl->t), vcc_Type((*e)->fmt));
- vcc_ErrWhere(tl, tl->t);
- return;
- default:
- break;
- }
- if (fmt == BOOL && (*e)->fmt == STRING) {
- *e = vcc_expr_edit(BOOL, "(\v1 != 0)", *e, NULL);
- return;
- }
-}
-
-/*--------------------------------------------------------------------
- * SYNTAX:
- * ExprNot:
- * '!' ExprCmp
- */
-
-static void
-vcc_expr_not(struct vcc *tl, struct expr **e, enum var_type fmt)
-{
- struct expr *e2;
- struct token *tk;
-
- *e = NULL;
- if (fmt != BOOL || tl->t->tok != '!') {
- vcc_expr_cmp(tl, e, fmt);
- return;
- }
-
- vcc_NextToken(tl);
- tk = tl->t;
- vcc_expr_cmp(tl, &e2, fmt);
- ERRCHK(tl);
- if (e2->fmt == BOOL) {
- *e = vcc_expr_edit(BOOL, "!(\v1)", e2, NULL);
- return;
- }
- VSB_printf(tl->sb, "'!' must be followed by BOOL, found ");
- VSB_printf(tl->sb, "%s.\n", vcc_Type(e2->fmt));
- vcc_ErrWhere2(tl, tk, tl->t);
-}
-
-/*--------------------------------------------------------------------
- * SYNTAX:
- * ExprCand:
- * ExprNot { '&&' ExprNot } *
- */
-
-static void
-vcc_expr_cand(struct vcc *tl, struct expr **e, enum var_type fmt)
-{
- struct expr *e2;
- struct token *tk;
-
- *e = NULL;
- vcc_expr_not(tl, e, fmt);
- ERRCHK(tl);
- if ((*e)->fmt != BOOL || tl->t->tok != T_CAND)
- return;
- *e = vcc_expr_edit(BOOL, "(\v+\n\v1", *e, NULL);
- while (tl->t->tok == T_CAND) {
- vcc_NextToken(tl);
- tk = tl->t;
- vcc_expr_not(tl, &e2, fmt);
- ERRCHK(tl);
- if (e2->fmt != BOOL) {
- VSB_printf(tl->sb,
- "'&&' must be followed by BOOL, found ");
- VSB_printf(tl->sb, "%s.\n", vcc_Type(e2->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(BOOL, "\v1\v-\n)", *e, NULL);
-}
-
-/*--------------------------------------------------------------------
- * SYNTAX:
- * Expr0:
- * ExprCand { '||' ExprCand } *
- */
-
-static void
-vcc_expr0(struct vcc *tl, struct expr **e, enum var_type fmt)
-{
- struct expr *e2;
- struct token *tk;
-
- *e = NULL;
- vcc_expr_cand(tl, e, fmt);
- ERRCHK(tl);
- if ((*e)->fmt != BOOL || tl->t->tok != T_COR)
- return;
- *e = vcc_expr_edit(BOOL, "(\v+\n\v1", *e, NULL);
- while (tl->t->tok == T_COR) {
- vcc_NextToken(tl);
- tk = tl->t;
- vcc_expr_cand(tl, &e2, fmt);
- ERRCHK(tl);
- if (e2->fmt != BOOL) {
- VSB_printf(tl->sb,
- "'||' must be followed by BOOL, found ");
- VSB_printf(tl->sb, "%s.\n", vcc_Type(e2->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(BOOL, "\v1\v-\n)", *e, NULL);
-}
-
-/*--------------------------------------------------------------------
- * This function parses and emits the C-code to evaluate an expression
- *
- * We know up front what kind of type we want the expression to be,
- * and this function is the backstop if that doesn't succeed.
- */
-
-void
-vcc_Expr(struct vcc *tl, enum var_type fmt)
-{
- struct expr *e;
- struct token *t1;
-
- assert(fmt != VOID);
-
- t1 = tl->t;
- vcc_expr0(tl, &e, fmt);
- ERRCHK(tl);
- if (fmt == STRING || fmt == STRING_LIST)
- vcc_expr_tostring(&e, fmt);
- if (!tl->err && fmt != e->fmt) {
- VSB_printf(tl->sb, "Expression has type %s, expected %s\n",
- vcc_Type(e->fmt), vcc_Type(fmt));
- tl->err = 1;
- }
- if (!tl->err) {
- if (e->fmt == STRING_LIST) {
- e = vcc_expr_edit(STRING_LIST,
- "\v+\n\v1,\nvrt_magic_string_end\v-", e, NULL);
- }
- vcc_expr_fmt(tl->fb, tl->indent, e);
- VSB_putc(tl->fb, '\n');
- } else {
- if (t1 != tl->t)
- vcc_ErrWhere2(tl, t1, tl->t);
- }
- vcc_delete_expr(e);
-}
-
-/*--------------------------------------------------------------------
- */
-
-void
-vcc_Expr_Call(struct vcc *tl, const struct symbol *sym)
-{
-
- struct expr *e;
- struct token *t1;
-
- t1 = tl->t;
- e = NULL;
- vcc_Eval_SymFunc(tl, &e, sym);
- if (!tl->err) {
- vcc_expr_fmt(tl->fb, tl->indent, e);
- VSB_cat(tl->fb, ";\n");
- } else if (t1 != tl->t) {
- vcc_ErrWhere2(tl, t1, tl->t);
- }
- vcc_delete_expr(e);
-}
-
-/*--------------------------------------------------------------------
- */
-
-void
-vcc_Expr_Init(struct vcc *tl)
-{
- struct symbol *sym;
-
- sym = VCC_AddSymbolStr(tl, "regsub", SYM_FUNC);
- AN(sym);
- sym->eval = vcc_Eval_Regsub;
- sym->eval_priv = NULL;
-
- sym = VCC_AddSymbolStr(tl, "regsuball", SYM_FUNC);
- AN(sym);
- sym->eval = vcc_Eval_Regsub;
- sym->eval_priv = sym;
-
- sym = VCC_AddSymbolStr(tl, "true", SYM_FUNC);
- AN(sym);
- sym->eval = vcc_Eval_BoolConst;
- sym->eval_priv = sym;
-
- sym = VCC_AddSymbolStr(tl, "false", SYM_FUNC);
- AN(sym);
- sym->eval = vcc_Eval_BoolConst;
- sym->eval_priv = NULL;
-}
diff --git a/lib/libvcl/vcc_parse.c b/lib/libvcl/vcc_parse.c
deleted file mode 100644
index ab562f5..0000000
--- a/lib/libvcl/vcc_parse.c
+++ /dev/null
@@ -1,359 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2013 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#include <string.h>
-
-#include "vcc_compile.h"
-
-/*--------------------------------------------------------------------*/
-
-static void vcc_Compound(struct vcc *tl);
-
-/*--------------------------------------------------------------------*/
-
-#define L(tl, foo) do { \
- tl->indent += INDENT; \
- foo; \
- tl->indent -= INDENT; \
-} while (0)
-
-#define C(tl, sep) do { \
- Fb(tl, 1, "VRT_count(ctx, %u)%s\n", ++tl->cnt, sep); \
- tl->t->cnt = tl->cnt; \
-} while (0)
-
-/*--------------------------------------------------------------------
- * SYNTAX:
- * Conditional:
- * '(' Cond_0 ')'
- */
-
-static void
-vcc_Conditional(struct vcc *tl)
-{
-
- SkipToken(tl, '(');
- Fb(tl, 0, "(\n");
- L(tl, vcc_Expr(tl, BOOL));
- ERRCHK(tl);
- Fb(tl, 1, ")\n");
- SkipToken(tl, ')');
-}
-
-/*--------------------------------------------------------------------
- * SYNTAX:
- * IfStmt:
- * 'if' Conditional Compound Branch1* Branch2
- * Branch1:
- * 'elseif' Conditional Compound
- * Branch2:
- * 'else' Compound
- * null
- */
-
-static void
-vcc_IfStmt(struct vcc *tl)
-{
-
- SkipToken(tl, ID);
- Fb(tl, 1, "if ");
- vcc_Conditional(tl);
- ERRCHK(tl);
- L(tl, vcc_Compound(tl));
- ERRCHK(tl);
- while (tl->t->tok == ID) {
- if (vcc_IdIs(tl->t, "else")) {
- vcc_NextToken(tl);
- if (tl->t->tok == '{') {
- Fb(tl, 1, "else\n");
- L(tl, vcc_Compound(tl));
- ERRCHK(tl);
- return;
- }
- if (tl->t->tok != ID || !vcc_IdIs(tl->t, "if")) {
- VSB_printf(tl->sb,
- "'else' must be followed by 'if' or '{'\n");
- vcc_ErrWhere(tl, tl->t);
- return;
- }
- Fb(tl, 1, "else if ");
- vcc_NextToken(tl);
- vcc_Conditional(tl);
- ERRCHK(tl);
- L(tl, vcc_Compound(tl));
- ERRCHK(tl);
- } else if (vcc_IdIs(tl->t, "elseif") ||
- vcc_IdIs(tl->t, "elsif") ||
- vcc_IdIs(tl->t, "elif")) {
- Fb(tl, 1, "else if ");
- vcc_NextToken(tl);
- vcc_Conditional(tl);
- ERRCHK(tl);
- L(tl, vcc_Compound(tl));
- ERRCHK(tl);
- } else {
- break;
- }
- }
- C(tl, ";");
-}
-
-/*--------------------------------------------------------------------
- * SYNTAX:
- * Compound:
- * '{' Stmt* '}'
- *
- * Stmt:
- * Compound
- * IfStmt
- * CSRC
- * Id(Action) (XXX)
- */
-
-static void
-vcc_Compound(struct vcc *tl)
-{
- int i;
-
- SkipToken(tl, '{');
- Fb(tl, 1, "{\n");
- tl->indent += INDENT;
- C(tl, ";");
- while (1) {
- ERRCHK(tl);
- switch (tl->t->tok) {
- case '{':
- vcc_Compound(tl);
- break;
- case '}':
- vcc_NextToken(tl);
- tl->indent -= INDENT;
- Fb(tl, 1, "}\n");
- return;
- case CSRC:
- if (tl->allow_inline_c) {
- Fb(tl, 1, "%.*s\n",
- (int) (tl->t->e - (tl->t->b + 2)),
- tl->t->b + 1);
- vcc_NextToken(tl);
- } else {
- VSB_printf(tl->sb,
- "Inline-C not allowed\n");
- vcc_ErrWhere(tl, tl->t);
- }
- break;
- case EOI:
- VSB_printf(tl->sb,
- "End of input while in compound statement\n");
- tl->err = 1;
- return;
- case ID:
- if (vcc_IdIs(tl->t, "if")) {
- vcc_IfStmt(tl);
- break;
- } else {
- i = vcc_ParseAction(tl);
- ERRCHK(tl);
- if (i) {
- SkipToken(tl, ';');
- break;
- }
- }
- /* FALLTHROUGH */
- default:
- /* We deliberately do not mention inline C */
- VSB_printf(tl->sb,
- "Expected an action, 'if', '{' or '}'\n");
- vcc_ErrWhere(tl, tl->t);
- return;
- }
- }
-}
-
-/*--------------------------------------------------------------------
- * SYNTAX:
- * Function:
- * 'sub' ID(name) Compound
- */
-
-static void
-vcc_Function(struct vcc *tl)
-{
- int m, i;
-
- vcc_NextToken(tl);
- ExpectErr(tl, ID);
- if (!vcc_isCid(tl->t)) {
- VSB_printf(tl->sb,
- "Names of VCL sub's cannot contain '-'\n");
- vcc_ErrWhere(tl, tl->t);
- return;
- }
-
- m = IsMethod(tl->t);
- if (m == -2) {
- VSB_printf(tl->sb,
- "VCL sub's named 'vcl*' are reserved names.\n");
- vcc_ErrWhere(tl, tl->t);
- VSB_printf(tl->sb, "Valid vcl_* methods are:\n");
- for (i = 0; method_tab[i].name != NULL; i++)
- VSB_printf(tl->sb, "\t%s\n", method_tab[i].name);
- return;
- } else if (m != -1) {
- assert(m < VCL_MET_MAX);
- tl->fb = tl->fm[m];
- if (tl->mprocs[m] == NULL) {
- (void)vcc_AddDef(tl, tl->t, SYM_SUB);
- vcc_AddRef(tl, tl->t, SYM_SUB);
- tl->mprocs[m] = vcc_AddProc(tl, tl->t);
- }
- tl->curproc = tl->mprocs[m];
- Fb(tl, 1, " /* ... from ");
- vcc_Coord(tl, tl->fb, NULL);
- Fb(tl, 0, " */\n");
- } else {
- tl->fb = tl->fc;
- i = vcc_AddDef(tl, tl->t, SYM_SUB);
- if (i > 1) {
- VSB_printf(tl->sb,
- "Function %.*s redefined\n", PF(tl->t));
- vcc_ErrWhere(tl, tl->t);
- return;
- }
- tl->curproc = vcc_AddProc(tl, tl->t);
- Fh(tl, 0, "static int VGC_function_%.*s "
- "(struct vrt_ctx *ctx);\n", PF(tl->t));
- Fc(tl, 1, "\nstatic int __match_proto__(vcl_func_t)\n");
- Fc(tl, 1, "VGC_function_%.*s(struct vrt_ctx *ctx)\n",
- PF(tl->t));
- }
- vcc_NextToken(tl);
- tl->indent += INDENT;
- Fb(tl, 1, "{\n");
- L(tl, vcc_Compound(tl));
- if (m == -1) {
- /*
- * non-method subroutines must have an explicit non-action
- * return in case they just fall through the bottom.
- */
- Fb(tl, 1, " return(0);\n");
- }
- Fb(tl, 1, "}\n");
- tl->indent -= INDENT;
- tl->fb = NULL;
- tl->curproc = NULL;
-}
-
-/*--------------------------------------------------------------------
- */
-
-static void
-vcc_Director(struct vcc *tl)
-{
- VSB_printf(tl->sb, "\ndirectors are now in directors VMOD.\n");
- vcc_ErrWhere(tl, tl->t);
-}
-
-/*--------------------------------------------------------------------
- * Top level of parser, recognize:
- * Inline C-code
- * ACL definitions
- * Function definitions
- * Backend & Director definitions
- * End of input
- */
-
-typedef void parse_f(struct vcc *tl);
-
-static struct toplev {
- const char *name;
- parse_f *func;
-} toplev[] = {
- { "acl", vcc_Acl },
- { "sub", vcc_Function },
- { "backend", vcc_ParseBackend },
- { "director", vcc_Director },
- { "probe", vcc_ParseProbe },
- { "import", vcc_ParseImport },
- { NULL, NULL }
-};
-
-void
-vcc_Parse(struct vcc *tl)
-{
- struct toplev *tp;
-
- while (tl->t->tok != EOI) {
- ERRCHK(tl);
- switch (tl->t->tok) {
- case CSRC:
- if (tl->allow_inline_c) {
- Fc(tl, 0, "%.*s\n",
- (int) (tl->t->e - (tl->t->b + 4)),
- tl->t->b + 2);
- vcc_NextToken(tl);
- } else {
- VSB_printf(tl->sb,
- "Inline-C not allowed\n");
- vcc_ErrWhere(tl, tl->t);
- }
- break;
- case EOI:
- break;
- case ID:
- for (tp = toplev; tp->name != NULL; tp++) {
- if (!vcc_IdIs(tl->t, tp->name))
- continue;
- tp->func(tl);
- break;
- }
- if (tp->name != NULL)
- break;
- /* FALLTHROUGH */
- default:
- /* We deliberately do not mention inline-C */
- VSB_printf(tl->sb, "Expected one of\n\t");
- for (tp = toplev; tp->name != NULL; tp++) {
- if (tp[1].name == NULL)
- VSB_printf(tl->sb, " or ");
- VSB_printf(tl->sb, "'%s'", tp->name);
- if (tp[1].name != NULL)
- VSB_printf(tl->sb, ", ");
- }
- VSB_printf(tl->sb, "\nFound: ");
- vcc_ErrToken(tl, tl->t);
- VSB_printf(tl->sb, " at\n");
- vcc_ErrWhere(tl, tl->t);
- return;
- }
- }
-}
diff --git a/lib/libvcl/vcc_storage.c b/lib/libvcl/vcc_storage.c
deleted file mode 100644
index 5f9712a..0000000
--- a/lib/libvcl/vcc_storage.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*-
- * Copyright (c) 2010 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * All stuff related to the storage.* part of the namespace.
- *
- * "All" is actually only a wildcard function, which instantiates variables
- * on demand under the storage.* tree of the namespace.
- *
- * About the syntax:
- * -----------------
- *
- * One of our long term goals is to have dynamic storage configuration, such
- * as the ability to add or remove a stevedore on the fly, without restarting
- * the worker process.
- *
- * Even though this goal is far out in the future, it influences the syntax
- * design of storage selection from VCL.
- *
- * In difference from backends, where we know the possible set of backends at
- * compile time, we will not in the future know the identity of the stevedores
- * available at compile time, so we have to rely on VRT name resolution.
- *
- * This indicates a namespace on the form storage.<stevedore>.<property>
- *
- * For each property, we must define a default value if the named stevedore
- * does not exists, such that for instance stevedore.forgetit.freespace
- * returns zero etc.
- *
- */
-
-#include "config.h"
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "vcc_compile.h"
-
-#define PFX "storage."
-
-/*--------------------------------------------------------------------
- *
- */
-
-static struct var *
-vcc_Stv_mkvar(struct vcc *tl, const struct token *t, enum var_type fmt)
-{
- struct var *v;
-
- v = TlAlloc(tl, sizeof *v);
- AN(v);
-
- v->name = TlDupTok(tl, t);
- v->r_methods = 0
-#define VCL_MET_MAC(l,u,b) | VCL_MET_##u
-#include "tbl/vcl_returns.h"
-#undef VCL_MET_MAC
- ;
- v->fmt = fmt;
-
- return (v);
-}
-
-static struct stvars {
- const char *name;
- enum var_type fmt;
-} stvars[] = {
-#define VRTSTVVAR(nm, vtype, ctype, dval) { #nm, vtype },
-#include "tbl/vrt_stv_var.h"
-#undef VRTSTVVAR
- { NULL, BOOL }
-};
-
-struct symbol *
-vcc_Stv_Wildcard(struct vcc *tl, const struct token *t,
- const struct symbol *wcsym)
-{
- const char *p, *q;
- struct var *v = NULL;
- struct symbol *sym;
- struct stvars *sv;
- char stv[1024];
- char buf[1024];
-
- (void)wcsym;
- assert((t->e - t->b) > strlen(PFX));
- assert(!memcmp(t->b, PFX, strlen(PFX)));
-
- p = t->b + strlen(PFX);
- for (q = p; q < t->e && *q != '.'; q++)
- continue;
- bprintf(stv, "%.*s", (int)(q - p), p);
-
- if (q == t->e) {
- v = vcc_Stv_mkvar(tl, t, BOOL);
- bprintf(buf, "VRT_Stv(\"%s\")", stv);
- v->rname = TlDup(tl, buf);
- } else {
- assert(*q == '.');
- q++;
- for(sv = stvars; sv->name != NULL; sv++) {
- if (strncmp(q, sv->name, t->e - q))
- continue;
- if (sv->name[t->e - q] != '\0')
- continue;
- v = vcc_Stv_mkvar(tl, t, sv->fmt);
- bprintf(buf, "VRT_Stv_%s(\"%s\")", sv->name, stv);
- v->rname = TlDup(tl, buf);
- break;
- }
- }
-
- if (v == NULL)
- return (NULL);
-
- sym = VCC_AddSymbolTok(tl, t, SYM_VAR);
- AN(sym);
- sym->var = v;
- sym->fmt = v->fmt;
- sym->eval = vcc_Eval_Var;
- sym->r_methods = v->r_methods;
-
- return (sym);
-}
diff --git a/lib/libvcl/vcc_symb.c b/lib/libvcl/vcc_symb.c
deleted file mode 100644
index c3d8a13..0000000
--- a/lib/libvcl/vcc_symb.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/*-
- * Copyright (c) 2010 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "vcc_compile.h"
-
-/*--------------------------------------------------------------------*/
-
-const char *
-VCC_SymKind(struct vcc *tl, const struct symbol *s)
-{
- switch(s->kind) {
-#define VCC_SYMB(uu, ll) case SYM_##uu: return(#ll);
-#include "tbl/symbol_kind.h"
-#undef VCC_SYMB
- default:
- ErrInternal(tl);
- VSB_printf(tl->sb, "Symbol Kind 0x%x\n", s->kind);
- return("INTERNALERROR");
- }
-}
-
-
-static struct symbol *
-vcc_AddSymbol(struct vcc *tl, const char *nb, int l, enum symkind kind)
-{
- struct symbol *sym;
-
- VTAILQ_FOREACH(sym, &tl->symbols, list) {
- if (sym->nlen != l)
- continue;
- if (memcmp(nb, sym->name, l))
- continue;
- if (kind != sym->kind)
- continue;
- VSB_printf(tl->sb, "Name Collision: <%.*s> <%s>\n",
- l, nb, VCC_SymKind(tl, sym));
- ErrInternal(tl);
- return (NULL);
- }
- ALLOC_OBJ(sym, SYMBOL_MAGIC);
- AN(sym);
- sym->name = malloc(l + 1L);
- AN(sym->name);
- memcpy(sym->name, nb, l);
- sym->name[l] = '\0';
- sym->nlen = l;
- VTAILQ_INSERT_HEAD(&tl->symbols, sym, list);
- sym->kind = kind;
- return (sym);
-}
-
-struct symbol *
-VCC_AddSymbolStr(struct vcc *tl, const char *name, enum symkind kind)
-{
-
- return (vcc_AddSymbol(tl, name, strlen(name), kind));
-}
-
-struct symbol *
-VCC_AddSymbolTok(struct vcc *tl, const struct token *t, enum symkind kind)
-{
-
- return (vcc_AddSymbol(tl, t->b, t->e - t->b, kind));
-}
-
-struct symbol *
-VCC_GetSymbolTok(struct vcc *tl, const struct token *tok, enum symkind kind)
-{
- struct symbol *sym;
-
- sym = VCC_FindSymbol(tl, tok, kind);
- if (sym == NULL) {
- sym = vcc_AddSymbol(tl, tok->b, tok->e - tok->b, kind);
- AN(sym);
- sym->def_b = tok;
- }
- return (sym);
-}
-
-struct symbol *
-VCC_FindSymbol(struct vcc *tl, const struct token *t, enum symkind kind)
-{
- struct symbol *sym;
-
- assert(t->tok == ID);
- VTAILQ_FOREACH(sym, &tl->symbols, list) {
- if (sym->kind == SYM_WILDCARD &&
- (t->e - t->b > sym->nlen) &&
- !memcmp(sym->name, t->b, sym->nlen)) {
- AN(sym->wildcard);
- return (sym->wildcard(tl, t, sym));
- }
- if (kind != SYM_NONE && kind != sym->kind)
- continue;
- if (vcc_IdIs(t, sym->name))
- return (sym);
- }
- return (NULL);
-}
-
-void
-VCC_WalkSymbols(struct vcc *tl, symwalk_f *func, enum symkind kind)
-{
- struct symbol *sym;
-
- VTAILQ_FOREACH(sym, &tl->symbols, list) {
- if (kind == SYM_NONE || kind == sym->kind)
- func(tl, sym);
- ERRCHK(tl);
- }
-}
diff --git a/lib/libvcl/vcc_token.c b/lib/libvcl/vcc_token.c
deleted file mode 100644
index 6201fea..0000000
--- a/lib/libvcl/vcc_token.c
+++ /dev/null
@@ -1,523 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2011 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "vcc_compile.h"
-
-/*--------------------------------------------------------------------*/
-
-void
-vcc_ErrToken(const struct vcc *tl, const struct token *t)
-{
-
- if (t->tok == EOI)
- VSB_printf(tl->sb, "end of input");
- else if (t->tok == CSRC)
- VSB_printf(tl->sb, "C{ ... }C");
- else
- VSB_printf(tl->sb, "'%.*s'", PF(t));
-}
-
-void
-vcc__ErrInternal(struct vcc *tl, const char *func, unsigned line)
-{
-
- VSB_printf(tl->sb, "VCL compiler internal error at %s():%u\n",
- func, line);
- tl->err = 1;
-}
-
-/*--------------------------------------------------------------------
- * Find start of source-line of token
- */
-
-static void
-vcc_iline(const struct token *t, const char **ll, int tail)
-{
- const char *p, *b, *x;
-
- b = t->src->b;
- if (ll != NULL)
- *ll = b;
- x = tail ? t->e - 1 : t->b;
- for (p = b; p < x; p++) {
- if (*p == '\n') {
- if (ll != NULL)
- *ll = p + 1;
- }
- }
-}
-
-/*--------------------------------------------------------------------
- * Find and print src+line+pos of this token
- */
-
-static void
-vcc_icoord(struct vsb *vsb, const struct token *t, int tail)
-{
- unsigned lin, pos;
- const char *p, *b, *x;
-
- lin = 1;
- pos = 0;
- b = t->src->b;
- x = tail ? t->e - 1 : t->b;
- for (p = b; p < x; p++) {
- if (*p == '\n') {
- lin++;
- pos = 0;
- } else if (*p == '\t') {
- pos &= ~7;
- pos += 8;
- } else
- pos++;
- }
- VSB_printf(vsb, "('%s' Line %u Pos %u)", t->src->name, lin, pos + 1);
-}
-
-/*--------------------------------------------------------------------*/
-
-void
-vcc_Coord(const struct vcc *tl, struct vsb *vsb, const struct token *t)
-{
-
- if (t == NULL)
- t = tl->t;
- vcc_icoord(vsb, t, 0);
-}
-
-/*--------------------------------------------------------------------
- * Output one line of source code, starting at 'l' and ending at the
- * first NL or 'le'.
- */
-
-static void
-vcc_quoteline(const struct vcc *tl, const char *l, const char *le)
-{
- const char *p;
- unsigned x, y;
-
- x = y = 0;
- for (p = l; p < le && *p != '\n'; p++) {
- if (*p == '\t') {
- y &= ~7;
- y += 8;
- while (x < y) {
- VSB_bcat(tl->sb, " ", 1);
- x++;
- }
- } else {
- x++;
- y++;
- VSB_bcat(tl->sb, p, 1);
- }
- }
- VSB_putc(tl->sb, '\n');
-}
-
-/*--------------------------------------------------------------------
- * Output a marker line for a sourceline starting at 'l' and ending at
- * the first NL or 'le'. Characters between 'b' and 'e' are marked.
- */
-
-static void
-vcc_markline(const struct vcc *tl, const char *l, const char *le,
- const char *b, const char *e)
-{
- const char *p;
- unsigned x, y;
- char c;
-
- x = y = 0;
- for (p = l; p < le && *p != '\n'; p++) {
- if (p >= b && p < e)
- c = '#';
- else
- c = '-';
-
- if (*p == '\t') {
- y &= ~7;
- y += 8;
- } else
- y++;
- while (x < y) {
- VSB_putc(tl->sb, c);
- x++;
- }
- }
- VSB_putc(tl->sb, '\n');
-}
-
-/*--------------------------------------------------------------------*/
-/* XXX: should take first+last token */
-
-void
-vcc_ErrWhere2(struct vcc *tl, const struct token *t, const struct token *t2)
-{
- const char *l1, *l2, *l3;
-
- if (t == NULL) {
- vcc_ErrWhere(tl, t2);
- return;
- }
- vcc_iline(t, &l1, 0);
- t2 = VTAILQ_PREV(t2, tokenhead, list);
- vcc_iline(t2, &l2, 1);
-
-
- if (l1 == l2) {
- vcc_icoord(tl->sb, t, 0);
- VSB_cat(tl->sb, " -- ");
- vcc_icoord(tl->sb, t2, 1);
- VSB_putc(tl->sb, '\n');
- /* Two tokens on same line */
- vcc_quoteline(tl, l1, t->src->e);
- vcc_markline(tl, l1, t->src->e, t->b, t2->e);
- } else {
- /* Two tokens different lines */
- l3 = strchr(l1, '\n');
- AN(l3);
- /* XXX: t had better be before t2 */
- vcc_icoord(tl->sb, t, 0);
- if (l3 + 1 == l2) {
- VSB_cat(tl->sb, " -- ");
- vcc_icoord(tl->sb, t2, 1);
- }
- VSB_putc(tl->sb, '\n');
- vcc_quoteline(tl, l1, t->src->e);
- vcc_markline(tl, l1, t->src->e, t->b, t2->e);
- if (l3 + 1 != l2) {
- VSB_cat(tl->sb, "[...]\n");
- vcc_icoord(tl->sb, t2, 1);
- VSB_putc(tl->sb, '\n');
- }
- vcc_quoteline(tl, l2, t->src->e);
- vcc_markline(tl, l2, t->src->e, t->b, t2->e);
- }
- VSB_putc(tl->sb, '\n');
- tl->err = 1;
-}
-
-void
-vcc_ErrWhere(struct vcc *tl, const struct token *t)
-{
- const char *l1;
-
- vcc_iline(t, &l1, 0);
- vcc_icoord(tl->sb, t, 0);
- VSB_putc(tl->sb, '\n');
- vcc_quoteline(tl, l1, t->src->e);
- vcc_markline(tl, l1, t->src->e, t->b, t->e);
- VSB_putc(tl->sb, '\n');
- tl->err = 1;
-}
-
-/*--------------------------------------------------------------------*/
-
-void
-vcc_NextToken(struct vcc *tl)
-{
-
- tl->t = VTAILQ_NEXT(tl->t, list);
- if (tl->t == NULL) {
- VSB_printf(tl->sb,
- "Ran out of input, something is missing or"
- " maybe unbalanced (...) or {...}\n");
- tl->err = 1;
- return;
- }
-}
-
-void
-vcc__Expect(struct vcc *tl, unsigned tok, unsigned line)
-{
- if (tl->t->tok == tok)
- return;
- VSB_printf(tl->sb, "Expected %s got ", vcl_tnames[tok]);
- vcc_ErrToken(tl, tl->t);
- VSB_printf(tl->sb, "\n(program line %u), at\n", line);
- vcc_ErrWhere(tl, tl->t);
-}
-
-/*--------------------------------------------------------------------
- * Compare ID token to string, return true of match
- */
-
-int
-vcc_IdIs(const struct token *t, const char *p)
-{
- const char *q;
-
- assert(t->tok == ID);
- for (q = t->b; q < t->e && *p != '\0'; p++, q++)
- if (*q != *p)
- return (0);
- if (q != t->e || *p != '\0')
- return (0);
- return (1);
-}
-
-/*--------------------------------------------------------------------
- * Check that we have a C-identifier
- */
-
-int
-vcc_isCid(const struct token *t)
-{
- const char *q;
-
- assert(t->tok == ID);
- for (q = t->b; q < t->e; q++) {
- if (!isalnum(*q) && *q != '_')
- return (0);
- }
- return (1);
-}
-
-void
-vcc_ExpectCid(struct vcc *tl)
-{
-
- ExpectErr(tl, ID);
- ERRCHK(tl);
- if (vcc_isCid(tl->t))
- return;
- VSB_printf(tl->sb, "Identifier ");
- vcc_ErrToken(tl, tl->t);
- VSB_printf(tl->sb,
- " contains illegal characters, use [0-9a-zA-Z_] only.\n");
- vcc_ErrWhere(tl, tl->t);
-}
-
-/*--------------------------------------------------------------------
- * Decode a string
- */
-
-static int
-vcc_decstr(struct vcc *tl)
-{
- char *q;
- unsigned int l;
-
- assert(tl->t->tok == CSTR);
- l = (tl->t->e - tl->t->b) - 2;
- tl->t->dec = TlAlloc(tl, l + 1);
- assert(tl->t->dec != NULL);
- q = tl->t->dec;
- memcpy(q, tl->t->b + 1, l);
- q[l] = '\0';
- return (0);
-}
-
-/*--------------------------------------------------------------------
- * Add a token to the token list.
- */
-
-void
-vcc_AddToken(struct vcc *tl, unsigned tok, const char *b, const char *e)
-{
- struct token *t;
-
- t = TlAlloc(tl, sizeof *t);
- assert(t != NULL);
- t->tok = tok;
- t->b = b;
- t->e = e;
- t->src = tl->src;
- if (tl->t != NULL)
- VTAILQ_INSERT_AFTER(&tl->tokens, tl->t, t, list);
- else
- VTAILQ_INSERT_TAIL(&tl->tokens, t, list);
- tl->t = t;
-}
-
-/*--------------------------------------------------------------------
- * Lexical analysis and token generation
- */
-
-void
-vcc_Lexer(struct vcc *tl, struct source *sp)
-{
- const char *p, *q;
- unsigned u;
-
- tl->src = sp;
- for (p = sp->b; p < sp->e; ) {
-
- /* Skip any whitespace */
- if (isspace(*p)) {
- p++;
- continue;
- }
-
- /* Skip '#.*\n' comments */
- if (*p == '#') {
- while (p < sp->e && *p != '\n')
- p++;
- continue;
- }
-
- /* Skip C-style comments */
- if (*p == '/' && p[1] == '*') {
- for (q = p + 2; q < sp->e; q++) {
- if (*q == '/' && q[1] == '*') {
- VSB_printf(tl->sb,
- "/* ... */ comment contains /*\n");
- vcc_AddToken(tl, EOI, p, p + 2);
- vcc_ErrWhere(tl, tl->t);
- vcc_AddToken(tl, EOI, q, q + 2);
- vcc_ErrWhere(tl, tl->t);
- return;
- }
- if (*q == '*' && q[1] == '/') {
- p = q + 2;
- break;
- }
- }
- if (q < sp->e)
- continue;
- vcc_AddToken(tl, EOI, p, p + 2);
- VSB_printf(tl->sb,
- "Unterminated /* ... */ comment, starting at\n");
- vcc_ErrWhere(tl, tl->t);
- return;
- }
-
- /* Skip C++-style comments */
- if (*p == '/' && p[1] == '/') {
- while (p < sp->e && *p != '\n')
- p++;
- continue;
- }
-
- /* Recognize inline C-code */
- if (*p == 'C' && p[1] == '{') {
- for (q = p + 2; q < sp->e; q++) {
- if (*q == '}' && q[1] == 'C') {
- vcc_AddToken(tl, CSRC, p, q + 2);
- break;
- }
- }
- if (q < sp->e) {
- p = q + 2;
- continue;
- }
- vcc_AddToken(tl, EOI, p, p + 2);
- VSB_printf(tl->sb,
- "Unterminated inline C source, starting at\n");
- vcc_ErrWhere(tl, tl->t);
- return;
- }
-
- /* Recognize long-strings */
- if (*p == '{' && p[1] == '"') {
- for (q = p + 2; q < sp->e; q++) {
- if (*q == '"' && q[1] == '}') {
- vcc_AddToken(tl, CSTR, p, q + 2);
- break;
- }
- }
- if (q < sp->e) {
- p = q + 2;
- u = tl->t->e - tl->t->b;
- u -= 4; /* {" ... "} */
- tl->t->dec = TlAlloc(tl, u + 1 );
- AN(tl->t->dec);
- memcpy(tl->t->dec, tl->t->b + 2, u);
- tl->t->dec[u] = '\0';
- continue;
- }
- vcc_AddToken(tl, EOI, p, p + 2);
- VSB_printf(tl->sb,
- "Unterminated long-string, starting at\n");
- vcc_ErrWhere(tl, tl->t);
- return;
- }
-
- /* Match for the fixed tokens (see token.tcl) */
- u = vcl_fixed_token(p, &q);
- if (u != 0) {
- vcc_AddToken(tl, u, p, q);
- p = q;
- continue;
- }
-
- /* Match strings */
- if (*p == '"') {
- for (q = p + 1; q < sp->e; q++) {
- if (*q == '"') {
- q++;
- break;
- }
- if (*q == '\r' || *q == '\n') {
- vcc_AddToken(tl, EOI, p, q);
- VSB_printf(tl->sb,
- "Unterminated string at\n");
- vcc_ErrWhere(tl, tl->t);
- return;
- }
- }
- vcc_AddToken(tl, CSTR, p, q);
- if (vcc_decstr(tl))
- return;
- p = q;
- continue;
- }
-
- /* Match Identifiers */
- if (isident1(*p)) {
- for (q = p; q < sp->e; q++)
- if (!isvar(*q))
- break;
- vcc_AddToken(tl, ID, p, q);
- p = q;
- continue;
- }
-
- /* Match numbers { [0-9]+ } */
- if (isdigit(*p)) {
- for (q = p; q < sp->e; q++)
- if (!isdigit(*q))
- break;
- vcc_AddToken(tl, CNUM, p, q);
- p = q;
- continue;
- }
- vcc_AddToken(tl, EOI, p, p + 1);
- VSB_printf(tl->sb, "Syntax error at\n");
- vcc_ErrWhere(tl, tl->t);
- return;
- }
-}
diff --git a/lib/libvcl/vcc_utils.c b/lib/libvcl/vcc_utils.c
deleted file mode 100644
index 5870af5..0000000
--- a/lib/libvcl/vcc_utils.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2013 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-
-#include "vcc_compile.h"
-
-#include "vre.h"
-#include "vrt.h"
-#include "vsa.h"
-
-/*--------------------------------------------------------------------*/
-
-const char *
-vcc_regexp(struct vcc *tl)
-{
- char buf[BUFSIZ], *p;
- vre_t *t;
- const char *error;
- int erroroffset;
-
- Expect(tl, CSTR);
- if (tl->err)
- return (NULL);
- memset(&t, 0, sizeof t);
- t = VRE_compile(tl->t->dec, 0, &error, &erroroffset);
- if (t == NULL) {
- VSB_printf(tl->sb,
- "Regexp compilation error:\n\n%s\n\n", error);
- vcc_ErrWhere(tl, tl->t);
- return (NULL);
- }
- VRE_free(&t);
- sprintf(buf, "VGC_re_%u", tl->unique++);
- p = TlAlloc(tl, strlen(buf) + 1);
- strcpy(p, buf);
-
- Fh(tl, 0, "static void *%s;\n", buf);
- Fi(tl, 0, "\tVRT_re_init(&%s, ",buf);
- EncToken(tl->fi, tl->t);
- Fi(tl, 0, ");\n");
- Ff(tl, 0, "\tVRT_re_fini(%s);\n", buf);
- return (p);
-}
-
-/*
- * The IPv6 crew royally screwed up the entire idea behind
- * struct sockaddr, and combined with various other incomptency
- * in the OS business, that means that there is no sane or even
- * remotely portable way to initialize a sockaddr at compile time.
- *
- * In our case it is slightly more tricky than that, because we don't
- * even want to #include the struct sockaddr* definitions.
- *
- * Instead we make sure the sockaddr is sane (for our values of sane)
- * and dump it in binary, using a 64 bit integertype, hoping that this
- * will ensure good enough alignment.
- */
-
-static const char *
-vcc_sockaddr(struct vcc *tl, const void *sa, unsigned sal)
-{
- unsigned n = (sal + 7) / 8, len;
- uint64_t b[n];
- char *p;
-
- assert(VSA_Sane(sa));
- AN(sa);
- AN(sal);
- assert(sal < sizeof(struct sockaddr_storage));
- assert(sizeof(unsigned long long) == 8);
-
- p = TlAlloc(tl, 20);
- sprintf(p, "sockaddr_%u", tl->unique++);
-
- Fh(tl, 0, "static const unsigned long long");
- Fh(tl, 0, " %s[%d] = {\n", p, n);
- memcpy(b, sa, sal);
- for (len = 0; len <n; len++) {
- Fh(tl, 0, "%s 0x%016jx",
- len ? ",\n" : "",
- (uintmax_t)b[len]);
- }
- Fh(tl, 0, "\n};\n");
- return (p);
-}
-
-/*--------------------------------------------------------------------
- * This routine is a monster, but at least we only have one such monster.
- * Look up a IP number, and return IPv4/IPv6 address as VGC produced names
- * and optionally ascii strings.
- *
- * For IP compile time constants we only want one IP#, but it can be
- * IPv4 or IPv6.
- *
- * For backends, we accept up to one IPv4 and one IPv6.
- */
-
-struct foo_proto {
- const char *name;
- int family;
- struct sockaddr_storage sa;
- socklen_t l;
- const char **dst;
- const char **dst_ascii;
-};
-
-void
-Resolve_Sockaddr(struct vcc *tl,
- const char *host,
- const char *port,
- const char **ipv4,
- const char **ipv4_ascii,
- const char **ipv6,
- const char **ipv6_ascii,
- const char **p_ascii,
- int maxips,
- const struct token *t_err,
- const char *errid)
-{
- struct foo_proto protos[3], *pp;
- struct addrinfo *res, *res0, *res1, hint;
- int error, retval;
- char hbuf[NI_MAXHOST];
-
- memset(protos, 0, sizeof protos);
- protos[0].name = "ipv4";
- protos[0].family = PF_INET;
- protos[0].dst = ipv4;
- protos[0].dst_ascii = ipv4_ascii;
- *ipv4 = NULL;
-
- protos[1].name = "ipv6";
- protos[1].family = PF_INET6;
- protos[1].dst = ipv6;
- protos[1].dst_ascii = ipv6_ascii;
- *ipv6 = NULL;
-
- retval = 0;
- memset(&hint, 0, sizeof hint);
- hint.ai_family = PF_UNSPEC;
- hint.ai_socktype = SOCK_STREAM;
-
- error = getaddrinfo(host, port, &hint, &res0);
- if (error) {
- VSB_printf(tl->sb,
- "%s '%.*s' could not be resolved to an IP address:\n",
- errid, PF(t_err));
- VSB_printf(tl->sb,
- "\t%s\n"
- "(Sorry if that error message is gibberish.)\n",
- gai_strerror(error));
- vcc_ErrWhere(tl, t_err);
- return;
- }
-
- for (res = res0; res; res = res->ai_next) {
- for (pp = protos; pp->name != NULL; pp++)
- if (res->ai_family == pp->family)
- break;
- if (pp->name == NULL) {
- /* Unknown proto, ignore */
- continue;
- }
- if (pp->l == res->ai_addrlen &&
- !memcmp(&pp->sa, res->ai_addr, pp->l)) {
- /*
- * Same address we already emitted.
- * This can happen using /etc/hosts
- */
- continue;
- }
-
- if (pp->l != 0 || retval == maxips) {
- VSB_printf(tl->sb,
- "%s %.*s: resolves to too many addresses.\n"
- "Only one IPv4 %s IPv6 are allowed.\n"
- "Please specify which exact address "
- "you want to use, we found all of these:\n",
- errid, PF(t_err),
- maxips > 1 ? "and one" : "or");
- for (res1 = res0; res1 != NULL; res1 = res1->ai_next) {
- error = getnameinfo(res1->ai_addr,
- res1->ai_addrlen, hbuf, sizeof hbuf,
- NULL, 0, NI_NUMERICHOST);
- AZ(error);
- VSB_printf(tl->sb, "\t%s\n", hbuf);
- }
- freeaddrinfo(res0);
- vcc_ErrWhere(tl, t_err);
- return;
- }
-
- pp->l = res->ai_addrlen;
- assert(pp->l < sizeof(struct sockaddr_storage));
- memcpy(&pp->sa, res->ai_addr, pp->l);
-
- error = getnameinfo(res->ai_addr, res->ai_addrlen,
- hbuf, sizeof hbuf, NULL, 0, NI_NUMERICHOST);
- AZ(error);
-
- Fh(tl, 0, "\n/* \"%s\" -> %s */\n", host, hbuf);
- *(pp->dst) = vcc_sockaddr(tl, &pp->sa, pp->l);
- if (pp->dst_ascii != NULL) {
- *pp->dst_ascii = TlDup(tl, hbuf);
- }
- retval++;
- }
- if (p_ascii != NULL) {
- error = getnameinfo(res0->ai_addr,
- res0->ai_addrlen, NULL, 0, hbuf, sizeof hbuf,
- NI_NUMERICSERV);
- AZ(error);
- *p_ascii = TlDup(tl, hbuf);
- }
- if (retval == 0) {
- VSB_printf(tl->sb,
- "%s '%.*s': resolves to "
- "neither IPv4 nor IPv6 addresses.\n",
- errid, PF(t_err) );
- vcc_ErrWhere(tl, t_err);
- }
-}
diff --git a/lib/libvcl/vcc_var.c b/lib/libvcl/vcc_var.c
deleted file mode 100644
index 74713b8..0000000
--- a/lib/libvcl/vcc_var.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2011 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#include <string.h>
-
-#include "vcc_compile.h"
-#include "vct.h"
-
-/*--------------------------------------------------------------------*/
-
-struct symbol *
-vcc_Var_Wildcard(struct vcc *tl, const struct token *t, const struct symbol *wc)
-{
- struct symbol *sym;
- struct var *v;
- const struct var *vh;
- int l, i;
- char c;
- char buf[258];
- char cnam[256];
-
- vh = wc->var;
-
- v = TlAlloc(tl, sizeof *v);
- AN(v);
-
- assert(vh->fmt == HEADER);
- v->name = TlDupTok(tl, t);
- v->r_methods = vh->r_methods;
- v->w_methods = vh->w_methods;
- v->fmt = vh->fmt;
-
- /* Create a C-name version of the header name */
- l = strlen(v->name + vh->len) + 1;
- for (i = 0; i < l - 1; i++) {
- c = *(v->name + vh->len + i);
- if (vct_isalpha(c) || vct_isdigit(c))
- cnam[i] = c;
- else
- cnam[i] = '_';
- }
- cnam[i] = '\0';
-
- /* Create the static identifier */
- Fh(tl, 0, "static const struct gethdr_s VGC_%s_%s =\n",
- vh->rname, cnam);
- Fh(tl, 0, " { %s, \"\\%03o%s:\"};\n",
- vh->rname, (unsigned)l, v->name + vh->len);
-
- bprintf(buf, "&VGC_%s_%s", vh->rname, cnam);
- v->rname = TlDup(tl, buf);
- bprintf(buf, "VRT_SetHdr(ctx, %s, ", v->rname);
- v->lname = TlDup(tl, buf);
-
- sym = VCC_AddSymbolTok(tl, t, SYM_VAR);
- AN(sym);
- sym->var = v;
- sym->fmt = v->fmt;
- sym->eval = vcc_Eval_Var;
- sym->r_methods = v->r_methods;
- return (sym);
-}
-
-/*--------------------------------------------------------------------*/
-
-const struct var *
-vcc_FindVar(struct vcc *tl, const struct token *t, int wr_access,
- const char *use)
-{
- const struct var *v;
- const struct symbol *sym;
-
- AN(tl->vars);
- sym = VCC_FindSymbol(tl, t, SYM_VAR);
- if (sym != NULL) {
- v = sym->var;
- AN(v);
-
- if (wr_access && v->w_methods == 0) {
- VSB_printf(tl->sb, "Variable ");
- vcc_ErrToken(tl, t);
- VSB_printf(tl->sb, " is read only.");
- VSB_cat(tl->sb, "\nAt: ");
- vcc_ErrWhere(tl, t);
- return (NULL);
- } else if (wr_access) {
- vcc_AddUses(tl, t, v->w_methods, use);
- } else if (v->r_methods == 0) {
- VSB_printf(tl->sb, "Variable ");
- vcc_ErrToken(tl, t);
- VSB_printf(tl->sb, " is write only.");
- VSB_cat(tl->sb, "\nAt: ");
- vcc_ErrWhere(tl, t);
- return (NULL);
- } else {
- vcc_AddUses(tl, t, v->r_methods, use);
- }
- return (v);
- }
- VSB_printf(tl->sb, "Unknown variable ");
- vcc_ErrToken(tl, t);
- VSB_cat(tl->sb, "\nAt: ");
- vcc_ErrWhere(tl, t);
- return (NULL);
-}
diff --git a/lib/libvcl/vcc_vmod.c b/lib/libvcl/vcc_vmod.c
deleted file mode 100644
index 7eb9d32c..0000000
--- a/lib/libvcl/vcc_vmod.c
+++ /dev/null
@@ -1,204 +0,0 @@
-/*-
- * Copyright (c) 2010-2013 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#include <dlfcn.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "vcc_compile.h"
-
-#include "vmod_abi.h"
-
-void
-vcc_ParseImport(struct vcc *tl)
-{
- void *hdl;
- char fn[1024];
- char buf[256];
- struct token *mod, *t1;
- const char *modname;
- const char *proto;
- const char *abi;
- const char **spec;
- struct symbol *sym;
- const struct symbol *osym;
- const char *p;
- // int *modlen;
-
- t1 = tl->t;
- SkipToken(tl, ID); /* "import" */
-
- ExpectErr(tl, ID);
- mod = tl->t;
- vcc_NextToken(tl);
-
- osym = VCC_FindSymbol(tl, mod, SYM_NONE);
- if (osym != NULL && osym->kind != SYM_VMOD) {
- VSB_printf(tl->sb, "Module %.*s conflics with other symbol.\n",
- PF(mod));
- vcc_ErrWhere2(tl, t1, tl->t);
- return;
- }
- if (osym != NULL) {
- VSB_printf(tl->sb, "Module %.*s already imported.\n",
- PF(mod));
- vcc_ErrWhere2(tl, t1, tl->t);
- VSB_printf(tl->sb, "Previous import was here:\n");
- vcc_ErrWhere2(tl, osym->def_b, osym->def_e);
- return;
- }
-
- bprintf(fn, "%.*s", PF(mod));
- sym = VCC_AddSymbolStr(tl, fn, SYM_VMOD);
- ERRCHK(tl);
- AN(sym);
- sym->def_b = t1;
- sym->def_e = tl->t;
-
- if (tl->t->tok == ID) {
- if (!tl->unsafe_path) {
- VSB_printf(tl->sb,
- "'import ... from path...'"
- " not allowed.\nAt:");
- vcc_ErrToken(tl, tl->t);
- vcc_ErrWhere(tl, tl->t);
- return;
- }
- if (!vcc_IdIs(tl->t, "from")) {
- VSB_printf(tl->sb, "Expected 'from path...'\n");
- vcc_ErrWhere(tl, tl->t);
- return;
- }
- vcc_NextToken(tl);
- ExpectErr(tl, CSTR);
- bprintf(fn, "%s", tl->t->dec);
- vcc_NextToken(tl);
- } else {
- bprintf(fn, "%s/libvmod_%.*s.so", tl->vmod_dir, PF(mod));
- }
-
- Fh(tl, 0, "static void *VGC_vmod_%.*s;\n", PF(mod));
-
- Fi(tl, 0, "\tif (VRT_Vmod_Init(&VGC_vmod_%.*s,\n", PF(mod));
- Fi(tl, 0, "\t &Vmod_%.*s_Func,\n", PF(mod));
- Fi(tl, 0, "\t sizeof(Vmod_%.*s_Func),\n", PF(mod));
- Fi(tl, 0, "\t \"%.*s\",\n", PF(mod));
- Fi(tl, 0, "\t ");
- EncString(tl->fi, fn, NULL, 0);
- Fi(tl, 0, ",\n\t ");
- Fi(tl, 0, "cli))\n");
- Fi(tl, 0, "\t\treturn(1);\n");
-
- SkipToken(tl, ';');
-
- hdl = dlopen(fn, RTLD_NOW | RTLD_LOCAL);
- if (hdl == NULL) {
- VSB_printf(tl->sb, "Could not load module %.*s\n\t%s\n\t%s\n",
- PF(mod), fn, dlerror());
- vcc_ErrWhere(tl, mod);
- return;
- }
-
- bprintf(buf, "Vmod_%.*s_Name", PF(mod));
- modname = dlsym(hdl, buf);
- if (modname == NULL) {
- VSB_printf(tl->sb, "Could not load module %.*s\n\t%s\n\t%s\n",
- PF(mod), fn, "Symbol Vmod_Name not found");
- vcc_ErrWhere(tl, mod);
- return;
- }
- if (!vcc_IdIs(mod, modname)) {
- VSB_printf(tl->sb, "Could not load module %.*s\n\t%s\n",
- PF(mod), fn);
- VSB_printf(tl->sb, "\tModule has wrong name: <%s>\n", modname);
- vcc_ErrWhere(tl, mod);
- return;
- }
-
- bprintf(buf, "Vmod_%.*s_ABI", PF(mod));
- abi = dlsym(hdl, buf);
- if (abi == NULL || strcmp(abi, VMOD_ABI_Version) != 0) {
- VSB_printf(tl->sb, "Could not load module %.*s\n\t%s\n",
- PF(mod), fn);
- VSB_printf(tl->sb, "\tABI mismatch, expected <%s>, got <%s>\n",
- VMOD_ABI_Version, abi);
- vcc_ErrWhere(tl, mod);
- return;
- }
-
- bprintf(buf, "Vmod_%.*s_Proto", PF(mod));
- proto = dlsym(hdl, buf);
- if (proto == NULL) {
- VSB_printf(tl->sb, "Could not load module %.*s\n\t%s\n\t%s\n",
- PF(mod), fn, "Symbol Vmod_Proto not found");
- vcc_ErrWhere(tl, mod);
- return;
- }
- bprintf(buf, "Vmod_%.*s_Spec", PF(mod));
- spec = dlsym(hdl, buf);
- if (spec == NULL) {
- VSB_printf(tl->sb, "Could not load module %.*s\n\t%s\n\t%s\n",
- PF(mod), fn, "Symbol Vmod_Spec not found");
- vcc_ErrWhere(tl, mod);
- return;
- }
- Fh(tl, 0, "static struct vmod_priv vmod_priv_%.*s;\n", PF(mod));
- for (; *spec != NULL; spec++) {
- p = *spec;
- if (!strcmp(p, "OBJ")) {
- p += strlen(p) + 1;
- sym = VCC_AddSymbolStr(tl, p, SYM_OBJECT);
- XXXAN(sym);
- sym->args = p;
- } else if (!strcmp(p, "INIT")) {
- p += strlen(p) + 1;
- Fi(tl, 0, "\t%s(&vmod_priv_%.*s, &VCL_conf);\n",
- p, PF(mod));
- } else {
- sym = VCC_AddSymbolStr(tl, p, SYM_FUNC);
- ERRCHK(tl);
- AN(sym);
- sym->eval = vcc_Eval_SymFunc;
- p += strlen(p) + 1;
- sym->cfunc = p;
- p += strlen(p) + 1;
- sym->args = p;
-
- /* Functions which return VOID are procedures */
- if (!memcmp(p, "VOID\0", 5))
- sym->kind = SYM_PROC;
- }
- }
- Fh(tl, 0, "\n%s\n", proto);
-
- /* XXX: zero the function pointer structure ?*/
- Ff(tl, 0, "\tvmod_priv_fini(&vmod_priv_%.*s);\n", PF(mod));
- Ff(tl, 0, "\tVRT_Vmod_Fini(&VGC_vmod_%.*s);\n", PF(mod));
-}
diff --git a/lib/libvcl/vcc_xref.c b/lib/libvcl/vcc_xref.c
deleted file mode 100644
index c3ef375..0000000
--- a/lib/libvcl/vcc_xref.c
+++ /dev/null
@@ -1,388 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2011 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * This file contains code for two cross-reference or consistency checks.
- *
- * The first check is simply that all subroutine, acls and backends are
- * both defined and referenced. Complaints about referenced but undefined
- * or defined but unreferenced objects will be emitted.
- *
- * The second check recursively decends through subroutine calls to make
- * sure that action actions are correct for the methods through which
- * they are called.
- */
-
-#include "config.h"
-
-#include <stdio.h>
-
-#include "vcc_compile.h"
-
-/*--------------------------------------------------------------------*/
-
-struct proccall {
- VTAILQ_ENTRY(proccall) list;
- struct proc *p;
- struct token *t;
-};
-
-struct procuse {
- VTAILQ_ENTRY(procuse) list;
- const struct token *t;
- unsigned mask;
- const char *use;
-};
-
-struct proc {
- VTAILQ_HEAD(,proccall) calls;
- VTAILQ_HEAD(,procuse) uses;
- struct token *name;
- unsigned ret_bitmap;
- unsigned exists;
- unsigned called;
- unsigned active;
- struct token *return_tok[VCL_RET_MAX];
-};
-
-/*--------------------------------------------------------------------
- * Keep track of definitions and references
- */
-
-void
-vcc_AddRef(struct vcc *tl, const struct token *t, enum symkind kind)
-{
- struct symbol *sym;
-
- sym = VCC_GetSymbolTok(tl, t, kind);
- AN(sym);
- sym->nref++;
-}
-
-int
-vcc_AddDef(struct vcc *tl, const struct token *t, enum symkind kind)
-{
- struct symbol *sym;
-
- sym = VCC_GetSymbolTok(tl, t, kind);
- AN(sym);
- sym->ndef++;
- return (sym->ndef);
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-vcc_checkref(struct vcc *tl, const struct symbol *sym)
-{
-
- if (sym->ndef == 0 && sym->nref != 0) {
- VSB_printf(tl->sb, "Undefined %s %.*s, first reference:\n",
- VCC_SymKind(tl, sym), PF(sym->def_b));
- vcc_ErrWhere(tl, sym->def_b);
- } else if (sym->ndef != 0 && sym->nref == 0) {
- VSB_printf(tl->sb, "Unused %s %.*s, defined:\n",
- VCC_SymKind(tl, sym), PF(sym->def_b));
- vcc_ErrWhere(tl, sym->def_b);
- if (!tl->err_unref) {
- VSB_printf(tl->sb, "(That was just a warning)\n");
- tl->err = 0;
- }
- }
-}
-
-int
-vcc_CheckReferences(struct vcc *tl)
-{
-
- VCC_WalkSymbols(tl, vcc_checkref, SYM_NONE);
- return (tl->err);
-}
-
-/*--------------------------------------------------------------------
- * Returns checks
- */
-
-static struct proc *
-vcc_findproc(struct vcc *tl, struct token *t)
-{
- struct symbol *sym;
- struct proc *p;
-
-
- sym = VCC_GetSymbolTok(tl, t, SYM_SUB);
- AN(sym);
- if (sym->proc != NULL)
- return (sym->proc);
-
- p = TlAlloc(tl, sizeof *p);
- assert(p != NULL);
- VTAILQ_INIT(&p->calls);
- VTAILQ_INIT(&p->uses);
- p->name = t;
- sym->proc = p;
- return (p);
-}
-
-struct proc *
-vcc_AddProc(struct vcc *tl, struct token *t)
-{
- struct proc *p;
-
- p = vcc_findproc(tl, t);
- p->name = t; /* make sure the name matches the definition */
- p->exists++;
- return (p);
-}
-
-void
-vcc_AddUses(struct vcc *tl, const struct token *t, unsigned mask,
- const char *use)
-{
- struct procuse *pu;
-
- if (tl->curproc == NULL) /* backend */
- return;
- pu = TlAlloc(tl, sizeof *pu);
- assert(pu != NULL);
- pu->t = t;
- pu->mask = mask;
- pu->use = use;
- VTAILQ_INSERT_TAIL(&tl->curproc->uses, pu, list);
-}
-
-void
-vcc_AddCall(struct vcc *tl, struct token *t)
-{
- struct proccall *pc;
- struct proc *p;
-
- p = vcc_findproc(tl, t);
- pc = TlAlloc(tl, sizeof *pc);
- assert(pc != NULL);
- pc->p = p;
- pc->t = t;
- VTAILQ_INSERT_TAIL(&tl->curproc->calls, pc, list);
-}
-
-void
-vcc_ProcAction(struct proc *p, unsigned returns, struct token *t)
-{
-
- assert(returns < VCL_RET_MAX);
- p->ret_bitmap |= (1U << returns);
- /* Record the first instance of this return */
- if (p->return_tok[returns] == NULL)
- p->return_tok[returns] = t;
-}
-
-static int
-vcc_CheckActionRecurse(struct vcc *tl, struct proc *p, unsigned bitmap)
-{
- unsigned u;
- struct proccall *pc;
-
- if (!p->exists) {
- VSB_printf(tl->sb, "Function %.*s does not exist\n",
- PF(p->name));
- return (1);
- }
- if (p->active) {
- VSB_printf(tl->sb, "Function recurses on\n");
- vcc_ErrWhere(tl, p->name);
- return (1);
- }
- u = p->ret_bitmap & ~bitmap;
- if (u) {
-
-#define VCL_RET_MAC(l, U, B) \
- if (u & (1 << (VCL_RET_##U))) { \
- VSB_printf(tl->sb, "Invalid return \"" #l "\"\n");\
- vcc_ErrWhere(tl, p->return_tok[VCL_RET_##U]); \
- }
-#include "tbl/vcl_returns.h"
-#undef VCL_RET_MAC
-
- VSB_printf(tl->sb, "\n...in subroutine \"%.*s\"\n",
- PF(p->name));
- vcc_ErrWhere(tl, p->name);
- return (1);
- }
- p->active = 1;
- VTAILQ_FOREACH(pc, &p->calls, list) {
- if (vcc_CheckActionRecurse(tl, pc->p, bitmap)) {
- VSB_printf(tl->sb, "\n...called from \"%.*s\"\n",
- PF(p->name));
- vcc_ErrWhere(tl, pc->t);
- return (1);
- }
- }
- p->active = 0;
- p->called++;
- return (0);
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-vcc_checkaction1(struct vcc *tl, const struct symbol *sym)
-{
- struct proc *p;
- struct method *m;
- int i;
-
- p = sym->proc;
- AN(p);
- i = IsMethod(p->name);
- if (i < 0)
- return;
- m = method_tab + i;
- if (vcc_CheckActionRecurse(tl, p, m->ret_bitmap)) {
- VSB_printf(tl->sb,
- "\n...which is the \"%s\" method\n", m->name);
- VSB_printf(tl->sb, "Legal returns are:");
-#define VCL_RET_MAC(l, U, B) \
- if (m->ret_bitmap & ((1 << VCL_RET_##U))) \
- VSB_printf(tl->sb, " \"%s\"", #l);
-
-#include "tbl/vcl_returns.h"
-#undef VCL_RET_MAC
- VSB_printf(tl->sb, "\n");
- tl->err = 1;
- }
-
-}
-
-static void
-vcc_checkaction2(struct vcc *tl, const struct symbol *sym)
-{
- struct proc *p;
-
- p = sym->proc;
- AN(p);
-
- if (p->called)
- return;
- VSB_printf(tl->sb, "Function unused\n");
- vcc_ErrWhere(tl, p->name);
- if (!tl->err_unref) {
- VSB_printf(tl->sb, "(That was just a warning)\n");
- tl->err = 0;
- }
-}
-
-int
-vcc_CheckAction(struct vcc *tl)
-{
-
- VCC_WalkSymbols(tl, vcc_checkaction1, SYM_SUB);
- if (tl->err)
- return (tl->err);
- VCC_WalkSymbols(tl, vcc_checkaction2, SYM_SUB);
- return (tl->err);
-}
-
-/*--------------------------------------------------------------------*/
-
-static struct procuse *
-vcc_FindIllegalUse(const struct proc *p, const struct method *m)
-{
- struct procuse *pu;
-
- VTAILQ_FOREACH(pu, &p->uses, list)
- if (!(pu->mask & m->bitval))
- return (pu);
- return (NULL);
-}
-
-static int
-vcc_CheckUseRecurse(struct vcc *tl, const struct proc *p,
- struct method *m)
-{
- struct proccall *pc;
- struct procuse *pu;
-
- pu = vcc_FindIllegalUse(p, m);
- if (pu != NULL) {
- VSB_printf(tl->sb,
- "'%.*s': %s from method '%.*s'.\n",
- PF(pu->t), pu->use, PF(p->name));
- vcc_ErrWhere(tl, pu->t);
- VSB_printf(tl->sb, "\n...in subroutine \"%.*s\"\n",
- PF(p->name));
- vcc_ErrWhere(tl, p->name);
- return (1);
- }
- VTAILQ_FOREACH(pc, &p->calls, list) {
- if (vcc_CheckUseRecurse(tl, pc->p, m)) {
- VSB_printf(tl->sb, "\n...called from \"%.*s\"\n",
- PF(p->name));
- vcc_ErrWhere(tl, pc->t);
- return (1);
- }
- }
- return (0);
-}
-
-static void
-vcc_checkuses(struct vcc *tl, const struct symbol *sym)
-{
- struct proc *p;
- struct method *m;
- struct procuse *pu;
- int i;
-
- p = sym->proc;
- AN(p);
-
- i = IsMethod(p->name);
- if (i < 0)
- return;
- m = method_tab + i;
- pu = vcc_FindIllegalUse(p, m);
- if (pu != NULL) {
- VSB_printf(tl->sb,
- "'%.*s': %s in method '%.*s'.",
- PF(pu->t), pu->use, PF(p->name));
- VSB_cat(tl->sb, "\nAt: ");
- vcc_ErrWhere(tl, pu->t);
- return;
- }
- if (vcc_CheckUseRecurse(tl, p, m)) {
- VSB_printf(tl->sb,
- "\n...which is the \"%s\" method\n", m->name);
- return;
- }
-}
-
-int
-vcc_CheckUses(struct vcc *tl)
-{
-
- VCC_WalkSymbols(tl, vcc_checkuses, SYM_SUB);
- return (tl->err);
-}
diff --git a/lib/libvcl/vmodtool.py b/lib/libvcl/vmodtool.py
deleted file mode 100755
index 2b6db42..0000000
--- a/lib/libvcl/vmodtool.py
+++ /dev/null
@@ -1,553 +0,0 @@
-#!/usr/bin/env python
-#-
-# Copyright (c) 2010-2013 Varnish Software AS
-# All rights reserved.
-#
-# Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
-# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-# SUCH DAMAGE.
-#
-# Read the vmod.spec file and produce the vmod.h and vmod.c files.
-#
-# vmod.h contains the prototypes for the published functions, the module
-# C-code should include this file to ensure type-consistency.
-#
-# vmod.c contains the symbols which VCC and varnishd will use to access
-# the module: A structure of properly typed function pointers, the
-# size of this structure in bytes, and the definition of the structure
-# as a string, suitable for inclusion in the C-source of the compile VCL
-# program.
-
-import sys
-import re
-
-if len(sys.argv) == 2:
- specfile = sys.argv[1]
-else:
- specfile = "vmod.vcc"
-
-ctypes = {
- 'BACKEND': "VCL_BACKEND",
- 'BOOL': "VCL_BOOL",
- 'DURATION': "VCL_DURATION",
- 'ENUM': "VCL_ENUM",
- 'HEADER': "const struct gethdr_s *",
- 'INT': "VCL_INT",
- 'IP': "VCL_IP",
- 'PRIV_CALL': "struct vmod_priv *",
- 'PRIV_VCL': "struct vmod_priv *",
- 'REAL': "VCL_REAL",
- 'STRING': "VCL_STRING",
- 'STRING_LIST': "const char *, ...",
- 'TIME': "VCL_TIME",
- 'VOID': "VCL_VOID",
-}
-
-#######################################################################
-
-def file_header(fo):
- fo.write("""/*
- * NB: This file is machine generated, DO NOT EDIT!
- *
- * Edit vmod.vcc and run vmod.py instead
- */
-
-""")
-
-#######################################################################
-
-def is_c_name(s):
- return None != re.match("^[a-z][a-z0-9_]*$", s)
-
-#######################################################################
-
-class token(object):
- def __init__(self, ln, ch, str):
- self.ln = ln
- self.ch = ch
- self.str = str
-
- def __repr__(self):
- return "<@%d \"%s\">" % (self.ln, self.str)
-
-#######################################################################
-
-class vmod(object):
- def __init__(self, nam):
- if not is_c_name(nam):
- raise Exception("Module name '%s' is illegal" % nam)
- self.nam = nam
- self.init = None
- self.funcs = list()
- self.objs = list()
-
- def set_init(self, nam):
- if self.init != None:
- raise Exception("Module %s already has Init" % self.nam)
- if not is_c_name(nam):
- raise Exception("Init name '%s' is illegal" % nam)
- self.init = nam
-
- def add_func(self, fn):
- self.funcs.append(fn)
-
- def add_obj(self, obj):
- self.objs.append(obj)
- obj.set_modnam(self.nam)
-
- def c_proto(self, fo):
- for o in self.objs:
- o.c_proto(fo)
- fo.write("\n")
- for f in self.funcs:
- f.c_proto(fo)
- if self.init != None:
- fo.write("\n")
- fo.write("int " + self.init)
- fo.write(
- "(struct vmod_priv *, const struct VCL_conf *);\n")
- #fo.write("\n")
- #fo.write("extern const void * const Vmod_" + self.nam + "_Id;\n")
-
- def c_typedefs_(self):
- l = list()
- for o in self.objs:
- for t in o.c_typedefs(self.nam):
- l.append(t)
- l.append("")
- l.append("/* Functions */")
- for f in self.funcs:
- l.append(f.c_typedef(self.nam))
- l.append("")
- return l
-
- def c_typedefs(self, fo):
- for i in self.c_typedefs_():
- fo.write(i + "\n")
-
- def c_vmod(self, fo):
- fo.write('const char Vmod_' + self.nam + '_Name[] =')
- fo.write(' \"' + self.nam + '";\n')
- fo.write("\n")
-
- cs = self.c_struct()
- fo.write("const " + cs + ' Vmod_' + self.nam + '_Func = ')
- fo.write(self.c_initializer())
- fo.write("\n")
-
- fo.write("\n")
- fo.write("const int Vmod_" + self.nam + '_Len =')
- fo.write(" sizeof(Vmod_" + self.nam + "_Func);\n")
- fo.write("\n")
-
- fo.write("const char Vmod_" + self.nam + "_Proto[] =\n")
- for t in self.c_typedefs_():
- fo.write('\t"' + t + '\\n"\n')
- fo.write('\t"\\n"\n')
- for i in (cs + " Vmod_" + self.nam + '_Func;').split("\n"):
- fo.write('\n\t"' + i + '\\n"')
- fo.write(";\n\n")
-
- fo.write(self.c_strspec())
-
- fo.write("\n")
- fo.write('const char Vmod_' + self.nam + '_ABI[] =')
- fo.write(' VMOD_ABI_Version;\n')
- #fo.write("\n")
- #fo.write('const void * const Vmod_' + self.nam + '_Id =')
- #fo.write(' &Vmod_' + self.nam + '_Id;\n')
-
- def c_initializer(self):
- s = '{\n'
- for o in self.objs:
- s += o.c_initializer()
-
- s += "\n\t/* Functions */\n"
- for f in self.funcs:
- s += f.c_initializer()
-
- s += "\n\t/* Init/Fini */\n"
- if self.init != None:
- s += "\t" + self.init + ",\n"
- s += "};"
-
- return s
-
- def c_struct(self):
- s = 'struct Vmod_' + self.nam + '_Func {\n'
- for o in self.objs:
- s += o.c_struct(self.nam)
-
- s += "\n\t/* Functions */\n"
- for f in self.funcs:
- s += f.c_struct(self.nam)
-
- s += "\n\t/* Init/Fini */\n"
- if self.init != None:
- s += "\tvmod_init_f\t*_init;\n"
- s += '}'
- return s
-
- def c_strspec(self):
- s = "const char * const Vmod_" + self.nam + "_Spec[] = {\n"
-
- for o in self.objs:
- s += o.c_strspec(self.nam)
-
- s += "\n\t/* Functions */\n"
- for f in self.funcs:
- s += '\t"' + f.c_strspec(self.nam) + '",\n'
-
- s += "\n\t/* Init/Fini */\n"
- if self.init != None:
- s += '\t"INIT\\0Vmod_' + self.nam + '_Func._init",\n'
-
- s += "\t0\n"
- s += "};\n"
- return s
-
-#######################################################################
-
-class func(object):
- def __init__(self, nam, retval, al):
- #if not is_c_name(nam):
- # raise Exception("Func name '%s' is illegal" % nam)
- if retval not in ctypes:
- raise Exception(
- "Return type '%s' not a valid type" % retval)
- self.nam = nam
- self.cnam = nam.replace(".", "_")
- self.al = al
- self.retval = retval
- self.pfx = None
-
- def __repr__(self):
- return "<FUNC %s %s>" % (self.retval, self.nam)
-
- def set_pfx(self, s):
- self.pfx = s
-
- def c_proto(self, fo, fini=False):
- fo.write(ctypes[self.retval])
- fo.write(" vmod_" + self.cnam + "(")
- p = ""
- if not fini:
- fo.write("const struct vrt_ctx *")
- p = ", "
- if self.pfx != None:
- fo.write(p + self.pfx)
- p = ", "
- for a in self.al:
- fo.write(p + ctypes[a.typ])
- p = ", "
- if a.nam != None:
- fo.write(" " + a.nam)
- fo.write(");\n")
-
- def c_typedef(self, modname, fini=False):
- s = "typedef "
- s += ctypes[self.retval]
- s += " td_" + modname + "_" + self.cnam + "("
- p = ""
- if not fini:
- s += "const struct vrt_ctx *"
- p = ", "
- if self.pfx != None:
- s += p + self.pfx
- p = ", "
- for a in self.al:
- s += p + ctypes[a.typ]
- p = ", "
- s += ");"
- return s
-
- def c_struct(self, modname):
- s = '\ttd_' + modname + "_" + self.cnam
- while len(s.expandtabs()) < 40:
- s += "\t"
- s += "*" + self.cnam + ";\n"
- return s
-
- def c_initializer(self):
- return "\tvmod_" + self.cnam + ",\n"
-
- def c_strspec(self, modnam):
- s = modnam + "." + self.nam
- s += "\\0"
- s += "Vmod_" + modnam + "_Func." + self.cnam + "\\0"
- s += self.retval + "\\0"
- for a in self.al:
- s += a.c_strspec()
- return s
-
-#######################################################################
-
-class obj(object):
- def __init__(self, nam):
- self.nam = nam
- self.init = None
- self.fini = None
- self.methods = list()
-
- def set_modnam(self, modnam):
- self.st = "struct vmod_" + modnam + "_" + self.nam
- self.init.set_pfx(self.st + " **, const char *")
- self.fini.set_pfx(self.st + " **")
- for m in self.methods:
- m.set_pfx(self.st + " *")
-
- def set_init(self, f):
- self.init = f
- self.fini = func(f.nam, "VOID", [])
- self.init.cnam += "__init"
- self.fini.cnam += "__fini"
-
- def add_method(self, m):
- self.methods.append(m)
-
- def c_typedefs(self, modnam):
- l = list()
- l.append("/* Object " + self.nam + " */")
- l.append(self.st + ";")
- l.append(self.init.c_typedef(modnam) + "")
- l.append(self.fini.c_typedef(modnam, fini=True) + "")
- for m in self.methods:
- l.append(m.c_typedef(modnam) + "")
- return l
-
- def c_proto(self, fo):
- fo.write(self.st + ";\n")
- self.init.c_proto(fo)
- self.fini.c_proto(fo, fini = True)
- for m in self.methods:
- m.c_proto(fo)
-
- def c_struct(self, modnam):
- s = "\t/* Object " + self.nam + " */\n"
- s += self.init.c_struct(modnam)
- s += self.fini.c_struct(modnam)
- for m in self.methods:
- s += m.c_struct(modnam)
- return s
-
- def c_initializer(self):
- s = "\t/* Object " + self.nam + " */\n"
- s += self.init.c_initializer()
- s += self.fini.c_initializer()
- for m in self.methods:
- s += m.c_initializer()
- return s
-
- def c_strspec(self, modnam):
- s = "\t/* Object " + self.nam + " */\n"
- s += '\t"OBJ\\0"\n'
- s += '\t\t"' + self.init.c_strspec(modnam) + '\\0"\n'
- s += '\t\t"' + self.st + '\\0"\n'
- s += '\t\t"' + self.fini.c_strspec(modnam) + '\\0"\n'
- for m in self.methods:
- s += '\t\t"' + m.c_strspec(modnam) + '\\0"\n'
- s += '\t\t"\\0",\n'
- return s
-
-#######################################################################
-
-class arg(object):
- def __init__(self, typ, nam = None, det = None):
- self.nam = nam
- self.typ = typ
- self.det = det
-
- def __repr__(self):
- return "<ARG %s %s %s>" % (self.nam, self.typ, str(self.det))
-
- def c_strspec(self):
- if self.det == None:
- return self.typ + "\\0"
- else:
- return self.det
- return "??"
-
-#######################################################################
-
-f = open(specfile, "r")
-tl = list()
-lines = list()
-ln = 0
-for l in f:
- ln += 1
- lines.append(l)
- if l == "":
- continue
- l = re.sub("[ \t]*#.*$", "", l)
- l = re.sub("[ \t]*\n", "", l)
- l = re.sub("([(){},])", r' \1 ', l)
- if l == "":
- continue
- for j in l.split():
- tl.append(token(ln, 0, j))
-f.close()
-
-#######################################################################
-#
-#
-def parse_enum2(tl):
- t = tl.pop(0)
- if t.str != "{":
- raise Exception("expected \"{\"")
- s = "ENUM\\0"
- while True:
- t = tl.pop(0)
- if t.str == "}":
- break
- s += t.str + "\\0"
- if tl[0].str == ",":
- tl.pop(0)
- elif tl[0].str != "}":
- raise Exception("Expceted \"}\" or \",\"")
- s += "\\0"
- return arg("ENUM", det=s)
-
-#######################################################################
-#
-#
-
-def parse_func(tl, rt_type = None, obj=None):
- al = list()
- if rt_type == None:
- t = tl.pop(0)
- rt_type = t.str
- if rt_type not in ctypes:
- raise Exception(
- "Return type '%s' not a valid type" % rt_type)
-
- t = tl.pop(0)
- fname = t.str
- if obj != None and fname[0] == "." and is_c_name(fname[1:]):
- fname = obj + fname
- elif not is_c_name(fname):
- raise Exception("Function name '%s' is illegal" % fname)
-
- t = tl.pop(0)
- if t.str != "(":
- raise Exception("Expected \"(\" got \"%s\"", t.str)
-
- while True:
- t = tl.pop(0)
- if t.str == ")":
- break
- if t.str == "ENUM":
- al.append(parse_enum2(tl))
- elif t.str in ctypes:
- al.append(arg(t.str))
- else:
- raise Exception("ARG? %s" % t.str)
- if is_c_name(tl[0].str):
- al[-1].nam = tl[0].str
- t = tl.pop(0)
- if tl[0].str == ",":
- tl.pop(0)
- elif tl[0].str != ")":
- raise Exception("Expceted \")\" or \",\"")
- if t.str != ")":
- raise Exception("End Of Input looking for ')'")
- f = func(fname, rt_type, al)
- return f
-
-#######################################################################
-#
-#
-
-def parse_obj(tl):
- o = obj(tl[0].str)
- f = parse_func(tl, "VOID")
- o.set_init(f)
- t = tl.pop(0)
- assert t.str == "{"
- while True:
- t = tl.pop(0)
- if t.str == "}":
- break
- assert t.str == "Method"
- f = parse_func(tl, obj=o.nam)
- o.add_method(f)
- return o
-
-#######################################################################
-# The first thing in the file must be the Module declaration
-#
-
-t = tl.pop(0)
-if t.str != "Module":
- raise Exception("\"Module\" must be first in file")
-t = tl.pop(0)
-vmod = vmod(t.str)
-
-#######################################################################
-# Parse the rest of the file
-#
-
-while len(tl) > 0:
- t = tl.pop(0)
-
- if t.str == "Init":
- t = tl.pop(0)
- vmod.set_init(t.str)
- elif t.str == "Function":
- f = parse_func(tl)
- vmod.add_func(f)
- elif t.str == "Object":
- o = parse_obj(tl)
- vmod.add_obj(o)
- else:
- raise Exception("Expected \"Init\", \"Fini\" or \"Function\"")
-
-#######################################################################
-# Parsing done, now process
-#
-
-fc = open("vcc_if.c", "w")
-fh = open("vcc_if.h", "w")
-
-file_header(fc)
-file_header(fh)
-
-fh.write('struct vrt_ctx;\n')
-fh.write('struct VCL_conf;\n')
-fh.write('struct vmod_priv;\n')
-fh.write("\n");
-
-vmod.c_proto(fh)
-
-fc.write("""#include "config.h"
-
-#include "vrt.h"
-#include "vcc_if.h"
-#include "vmod_abi.h"
-
-
-""")
-
-vmod.c_typedefs(fc)
-vmod.c_vmod(fc)
-
-fc.close()
-fh.close()
diff --git a/lib/libvmod_debug/Makefile.am b/lib/libvmod_debug/Makefile.am
index 7e2c849..f73720c 100644
--- a/lib/libvmod_debug/Makefile.am
+++ b/lib/libvmod_debug/Makefile.am
@@ -8,7 +8,7 @@ AM_CPPFLAGS = \
vmoddir = $(pkglibdir)/vmods
vmod_srcdir = $(top_srcdir)/lib/libvmod_debug
-vmodtool = $(top_srcdir)/lib/libvcl/vmodtool.py
+vmodtool = $(top_srcdir)/lib/libvcc/vmodtool.py
noinst_LTLIBRARIES = libvmod_debug.la
libvmod_debug_la_LDFLAGS = $(AM_LDFLAGS) -module -export-dynamic -avoid-version -shared -rpath /nowhere
diff --git a/lib/libvmod_directors/Makefile.am b/lib/libvmod_directors/Makefile.am
index e49a285..7e2e2f3 100644
--- a/lib/libvmod_directors/Makefile.am
+++ b/lib/libvmod_directors/Makefile.am
@@ -8,7 +8,7 @@ AM_CPPFLAGS = \
vmoddir = $(pkglibdir)/vmods
vmod_srcdir = $(top_srcdir)/lib/libvmod_directors
-vmodtool = $(top_srcdir)/lib/libvcl/vmodtool.py
+vmodtool = $(top_srcdir)/lib/libvcc/vmodtool.py
noinst_LTLIBRARIES = libvmod_directors.la
libvmod_directors_la_LDFLAGS = $(AM_LDFLAGS) -module -export-dynamic -avoid-version -shared -rpath /nowhere
diff --git a/lib/libvmod_std/Makefile.am b/lib/libvmod_std/Makefile.am
index acc0842..cd55e5b 100644
--- a/lib/libvmod_std/Makefile.am
+++ b/lib/libvmod_std/Makefile.am
@@ -11,7 +11,7 @@ dist_man_MANS = vmod_std.3
vmoddir = $(pkglibdir)/vmods
vmod_srcdir = $(top_srcdir)/lib/libvmod_std
-vmodtool = $(top_srcdir)/lib/libvcl/vmodtool.py
+vmodtool = $(top_srcdir)/lib/libvcc/vmodtool.py
vmod_LTLIBRARIES = libvmod_std.la
libvmod_std_la_LDFLAGS = $(AM_LDFLAGS) -module -export-dynamic -avoid-version -shared
diff --git a/redhat/varnish.spec b/redhat/varnish.spec
index ea0fc24..df56f62 100644
--- a/redhat/varnish.spec
+++ b/redhat/varnish.spec
@@ -150,7 +150,7 @@ rm -rf doc/sphinx/\=build
%endif
%endif
-make check LD_LIBRARY_PATH="../../lib/libvarnish/.libs:../../lib/libvarnishcompat/.libs:../../lib/libvarnishapi/.libs:../../lib/libvcl/.libs:../../lib/libvgz/.libs"
+make check LD_LIBRARY_PATH="../../lib/libvarnish/.libs:../../lib/libvarnishcompat/.libs:../../lib/libvarnishapi/.libs:../../lib/libvcc/.libs:../../lib/libvgz/.libs"
%install
rm -rf %{buildroot}
@@ -247,7 +247,7 @@ rm -rf %{buildroot}
#%{_libdir}/libvarnish.a
#%{_libdir}/libvarnishapi.a
#%{_libdir}/libvarnishcompat.a
-#%{_libdir}/libvcl.a
+#%{_libdir}/libvcc.a
#%doc LICENSE
%pre
More information about the varnish-commit
mailing list