source: lib/libvmod_std/vmod.py @ 3a08c3

Revision 3a08c3, 8.0 KB checked in by Poul-Henning Kamp <phk@…>, 3 years ago (diff)

Add Vmod_Id handle which VMOD can identify themselves to VRT with.

  • Property mode set to 100755
Line 
1#!/usr/local/bin/python
2#-
3# Copyright (c) 2010-2011 Varnish Software AS
4# All rights reserved.
5#
6# Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions
10# are met:
11# 1. Redistributions of source code must retain the above copyright
12#    notice, this list of conditions and the following disclaimer.
13# 2. Redistributions in binary form must reproduce the above copyright
14#    notice, this list of conditions and the following disclaimer in the
15#    documentation and/or other materials provided with the distribution.
16#
17# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20# ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27# SUCH DAMAGE.
28#
29# Read the vmod.spec file and produce the vmod.h and vmod.c files.
30#
31# vmod.h contains the prototypes for the published functions, the module
32# C-code should include this file to ensure type-consistency.
33#
34# vmod.c contains the symbols which VCC and varnishd will use to access
35# the module:  A structure of properly typed function pointers, the
36# size of this structure in bytes, and the definition of the structure
37# as a string, suitable for inclusion in the C-source of the compile VCL
38# program.
39
40import sys
41import re
42
43if len(sys.argv) == 2:
44        specfile = sys.argv[1]
45else:
46        specfile = "vmod.vcc"
47
48ctypes = {
49        'IP':           "struct sockaddr_storage *",
50        'STRING':       "const char *",
51        'STRING_LIST':  "const char *, ...",
52        'BOOL':         "unsigned",
53        'BACKEND':      "struct director *",
54        'ENUM':         "const char *",
55        'TIME':         "double",
56        'REAL':         "double",
57        'DURATION':     "double",
58        'INT':          "int",
59        'HEADER':       "enum gethdr_e, const char *",
60        'PRIV_VCL':     "struct vmod_priv *",
61        'PRIV_CALL':    "struct vmod_priv *",
62        'VOID':         "void",
63}
64
65#######################################################################
66
67initname = ""
68modname = "???"
69pstruct = ""
70pinit = ""
71tdl = ""
72plist = ""
73slist = ""
74
75def do_func(fname, rval, args, vargs):
76        global pstruct
77        global pinit
78        global plist
79        global slist
80        global tdl
81        #print(fname, rval, args)
82
83        # C argument list
84        cargs = "(struct sess *"
85        for i in args:
86                cargs += ", " + i
87        cargs += ")"
88
89        # Prototypes for vmod implementation and interface typedef
90        proto = ctypes[rval] + " vmod_" + fname + cargs
91        sproto = ctypes[rval] + " td_" + modname + "_" + fname + cargs
92
93        # append to lists of prototypes
94        plist += proto + ";\n"
95        tdl += "typedef " + sproto + ";\n"
96
97        # Append to struct members
98        pstruct += "\ttd_" + modname + "_" + fname + "\t*" + fname + ";\n"
99
100        # Append to struct initializer
101        pinit += "\tvmod_" + fname + ",\n"
102
103        # Compose the vmod spec-string
104        s = modname + '.' + fname + "\\0"
105        s += "Vmod_Func_" + modname + "." + fname + "\\0"
106        s += rval + '\\0'
107        for i in vargs:
108                s +=  i + '\\0'
109        slist += '\t"' + s + '",\n'
110
111#######################################################################
112
113def partition(string, separator):
114        if (hasattr(string,"partition")):
115                return string.partition(separator)
116        i = string.find(separator)
117        if i >= 0:
118                return (string[:i],separator,string[i+len(separator):])
119        return (string, '', '')
120
121#######################################################################
122
123def is_c_name(s):
124        return None != re.match("^[a-z][a-z0-9_]*$", s)
125
126#######################################################################
127
128def parse_enum(tq):
129        assert tq[0] == '{'
130        assert tq[-1] == '}'
131        f = tq[1:-1].split(',')
132        s="ENUM\\0"
133        b=dict()
134        for i in f:
135                i = i.strip()
136                if not is_c_name(i):
137                        raise Exception("Enum value '%s' is illegal" % i)
138                if i in b:
139                        raise Exception("Duplicate Enum value '%s'" % i)
140                b[i] = True
141                s = s + i.strip() + '\\0'
142        return s
143
144#######################################################################
145
146f = open(specfile, "r")
147
148def nextline():
149        while True:
150                l0 = f.readline()
151                if l0 == "":
152                        return l0
153                l0 = re.sub("#.*$", "", l0)
154                l0 = re.sub("\s\s*", " ", l0.strip())
155                if l0 != "":
156                        return l0
157
158while True:
159        l0 = nextline()
160        if l0 == "":
161                break;
162        l = partition(l0, " ")
163
164        if l[0] == "Module":
165                modname = l[2].strip();
166                if not is_c_name(modname):
167                        raise Exception("Module name '%s' is illegal" % modname)
168                continue
169
170        if l[0] == "Init":
171                initname = l[2].strip();
172                if not is_c_name(initname):
173                        raise Exception("Init name '%s' is illegal" % initname)
174                continue
175
176        if l[0] != "Function":
177                raise Exception("Expected 'Function' line, got '%s'" % l[0])
178
179        # Find the return type of the function
180        l = partition(l[2].strip(), " ")
181        rt_type = l[0]
182        if rt_type not in ctypes:
183                raise Exception("Return type '%s' not a valid type" % rt_type)
184
185        # Find the function name
186        l = partition(l[2].strip(), "(")
187
188        fname = l[0].strip()
189        if not is_c_name(fname):
190                raise Exception("Function name '%s' is illegal" % fname)
191
192        if l[1] != '(':
193                raise Exception("Missing '('")
194
195        l = l[2]
196
197        while -1 == l.find(")"):
198                l1 = nextline()
199                if l1 == "":
200                        raise Exception("End Of Input looking for ')'")
201                l = l + l1
202
203        if -1 != l.find("("):
204                raise Exception("Nesting trouble with '(...)' ")
205
206        if l[-1:] != ')':
207                raise Exception("Junk after ')'")
208
209        l = l[:-1]
210
211        args = list()
212        vargs = list()
213
214        for i in re.finditer("([A-Z_]+)\s*({[^}]+})?(,|$)", l):
215                at = i.group(1)
216                tq = i.group(2)
217                if at not in ctypes:
218                        raise Exception(
219                            "Argument type '%s' not a valid type" % at)
220
221                args.append(ctypes[at])
222
223                if at == "ENUM":
224                        if tq == None:
225                                raise Exception(
226                                    "Argument type '%s' needs qualifier {...}" % at)
227                        at=parse_enum(tq)
228
229                elif tq != None:
230                        raise Exception(
231                            "Argument type '%s' cannot be qualified with {...}" % at)
232
233                vargs.append(at)
234
235        do_func(fname, rt_type, args, vargs)
236
237#######################################################################
238def dumps(s):
239        while True:
240                l = partition(s, "\n")
241                if len(l[0]) == 0:
242                        break
243                fc.write('\t"' + l[0] + '\\n"\n')
244                s = l[2]
245
246#######################################################################
247
248if initname != "":
249        plist += "int " + initname + "(struct vmod_priv *, const struct VCL_conf *);\n"
250        pstruct += "\tvmod_init_f\t*_init;\n"
251        pinit += "\t" + initname + ",\n"
252        slist += '\t"INIT\\0Vmod_Func_' + modname + '._init",\n'
253
254#######################################################################
255
256def file_header(fo):
257        fo.write("""/*
258 * NB:  This file is machine generated, DO NOT EDIT!
259 *
260 * Edit vmod.vcc and run vmod.py instead
261 */
262
263""")
264
265#######################################################################
266
267fc = open("vcc_if.c", "w")
268fh = open("vcc_if.h", "w")
269
270file_header(fc)
271file_header(fh)
272
273fh.write('struct sess;\n')
274fh.write('struct VCL_conf;\n')
275fh.write('struct vmod_priv;\n')
276fh.write("\n");
277
278fh.write(plist)
279
280
281fc.write('#include "vrt.h"\n')
282fc.write('#include "vcc_if.h"\n')
283fc.write('#include "vmod_abi.h"\n')
284fc.write("\n");
285
286fc.write("\n");
287
288fc.write(tdl);
289fc.write("\n");
290
291fc.write('const char Vmod_Name[] = "' + modname + '";\n')
292
293fc.write("const struct Vmod_Func_" + modname + " {\n")
294fc.write(pstruct + "} Vmod_Func = {\n" + pinit + "};\n")
295fc.write("\n");
296
297fc.write("const int Vmod_Len = sizeof(Vmod_Func);\n")
298fc.write("\n");
299
300fc.write('const char Vmod_Proto[] =\n')
301dumps(tdl);
302fc.write('\t"\\n"\n')
303dumps("struct Vmod_Func_" + modname + " {\n")
304dumps(pstruct + "} Vmod_Func_" + modname + ";\n")
305fc.write('\t;\n')
306fc.write("\n");
307
308fc.write('const char * const Vmod_Spec[] = {\n' + slist + '\t0\n};\n')
309
310fc.write('const char Vmod_Varnish_ABI[] = VMOD_ABI_Version;\n')
311
312fh.write('extern const void * const Vmod_Id;\n')
313fc.write('const void * const Vmod_Id = &Vmod_Id;\n')
314
315fc.write("\n")
316
Note: See TracBrowser for help on using the repository browser.