Server IP : 52.91.253.208 / Your IP : 3.22.71.106 [ Web Server : Apache System : Linux ip-172-26-9-9 4.19.0-25-cloud-amd64 #1 SMP Debian 4.19.289-1 (2023-07-24) x86_64 User : daemon ( 1) PHP Version : 7.3.18 Disable Function : NONE Domains : 3 Domains MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /opt/bitnami/varnish/share/varnish/ |
Upload File : |
#!/usr/bin/env python3 # # Copyright (c) 2010-2016 Varnish Software # All rights reserved. # # Author: Poul-Henning Kamp <phk@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.vcc file (inputvcc) and produce: vmod_if.h -- Prototypes for the implementation vmod_if.c -- Magic glue & datastructures to make things a VMOD. vmod_${name}.rst -- Extracted documentation """ # This script should work with both Python 2 and Python 3. from __future__ import print_function import os import sys import re import optparse import unittest import copy import json import hashlib AMBOILERPLATE = ''' # Boilerplate generated by vmodtool.py - changes will be overwritten AM_LDFLAGS = $(AM_LT_LDFLAGS) AM_CPPFLAGS = \\ \t-I$(top_srcdir)/include \\ \t-I$(top_srcdir)/bin/varnishd \\ \t-I$(top_builddir)/include vmoddir = $(pkglibdir)/vmods vmodtool = $(top_srcdir)/lib/libvcc/vmodtool.py vmodtoolargs = --strict --boilerplate vmod_LTLIBRARIES = libvmod_XXX.la libvmod_XXX_la_CFLAGS = \\ \t@SAN_CFLAGS@ libvmod_XXX_la_LDFLAGS = \\ \t$(AM_LDFLAGS) \\ \t$(VMOD_LDFLAGS) \\ \t@SAN_LDFLAGS@ nodist_libvmod_XXX_la_SOURCES = vcc_if.c vcc_if.h $(libvmod_XXX_la_OBJECTS): vcc_if.h vcc_if.h vmod_XXX.rst vmod_XXX.man.rst: vcc_if.c vcc_if.c: $(vmodtool) $(srcdir)/vmod.vcc \t@PYTHON@ $(vmodtool) $(vmodtoolargs) $(srcdir)/vmod.vcc EXTRA_DIST = vmod.vcc automake_boilerplate.am CLEANFILES = $(builddir)/vcc_if.c $(builddir)/vcc_if.h \\ \t$(builddir)/vmod_XXX.rst \\ \t$(builddir)/vmod_XXX.man.rst ''' PRIVS = { 'PRIV_CALL': "struct vmod_priv *", 'PRIV_VCL': "struct vmod_priv *", 'PRIV_TASK': "struct vmod_priv *", 'PRIV_TOP': "struct vmod_priv *", } CTYPES = { 'ACL': "VCL_ACL", 'BACKEND': "VCL_BACKEND", 'BLOB': "VCL_BLOB", 'BODY': "VCL_BODY", 'BOOL': "VCL_BOOL", 'BYTES': "VCL_BYTES", 'DURATION': "VCL_DURATION", 'ENUM': "VCL_ENUM", 'HEADER': "VCL_HEADER", 'HTTP': "VCL_HTTP", 'INT': "VCL_INT", 'IP': "VCL_IP", 'PROBE': "VCL_PROBE", 'REAL': "VCL_REAL", 'STEVEDORE': "VCL_STEVEDORE", 'STRANDS': "VCL_STRANDS", 'STRING': "VCL_STRING", 'STRING_LIST': "const char *, ...", 'TIME': "VCL_TIME", 'VOID': "VCL_VOID", } CTYPES.update(PRIVS) ####################################################################### def is_quoted(txt): return len(txt) > 2 and txt[0] == txt[-1] and txt[0] in ('"', "'") def unquote(txt): assert is_quoted(txt) return txt[1:-1] ####################################################################### def write_file_warning(fo, a, b, c): fo.write(a + "\n") fo.write(b + " NB: This file is machine generated, DO NOT EDIT!\n") fo.write(b + "\n") fo.write(b + " Edit vmod.vcc and run make instead\n") fo.write(c + "\n\n") def write_c_file_warning(fo): write_file_warning(fo, "/*", " *", " */") def write_rst_file_warning(fo): write_file_warning(fo, "..", "..", "..") def write_rst_hdr(fo, s, below="-", above=None): if above is not None: fo.write(above * len(s) + "\n") fo.write(s + "\n") if below is not None: fo.write(below * len(s) + "\n") ####################################################################### def lwrap(s, width=64): """ Wrap a C-prototype like string into a number of lines. """ ll = [] p = "" while len(s) > width: y = s[:width].rfind(',') if y == -1: y = s[:width].rfind('(') if y == -1: break ll.append(p + s[:y + 1]) s = s[y + 1:].lstrip() p = " " if s: ll.append(p + s) return "\n".join(ll) + "\n" def fmt_cstruct(fo, mn, x): """ Align fields in C struct """ a = "\ttd_" + mn + "_" + x while len(a.expandtabs()) < 40: a += "\t" fo.write("%s*%s;\n" % (a, x)) ####################################################################### inputline = None def err(txt, warn=True): if inputline is not None: print("While parsing line:\n\t", inputline) if opts.strict or not warn: print("ERROR: " + txt, file=sys.stderr) exit(1) else: print("WARNING: " + txt, file=sys.stderr) ####################################################################### class CType(object): def __init__(self, wl, enums): self.nm = None self.defval = None self.spec = None self.opt = False self.vt = wl.pop(0) self.ct = CTYPES.get(self.vt) if self.ct is None: err("Expected type got '%s'" % self.vt, warn=False) if wl and wl[0] == "{": if self.vt != "ENUM": err("Only ENUMs take {...} specs", warn=False) self.add_spec(wl, enums) def __str__(self): s = "<" + self.vt if self.nm is not None: s += " " + self.nm if self.defval is not None: s += " VAL=" + self.defval if self.spec is not None: s += " SPEC=" + str(self.spec) return s + ">" def add_spec(self, wl, enums): assert self.vt == "ENUM" assert wl.pop(0) == "{" self.spec = [] while True: x = wl.pop(0) if is_quoted(x): x = unquote(x) assert x self.spec.append(x) enums[x] = True w = wl.pop(0) if w == "}": break assert w == "," def vcl(self): if self.vt in ("STRING_LIST", "STRANDS"): return "STRING" if self.spec is None: return self.vt return self.vt + " {" + ", ".join(self.spec) + "}" def synopsis(self): if self.vt in ("STRING_LIST", "STRANDS"): return "STRING" return self.vt def json(self, jl): jl.append([self.vt]) while jl[-1][-1] is None: jl[-1].pop(-1) ####################################################################### class arg(CType): ''' Parse front of word list into argument ''' def __init__(self, wl, argnames, enums, end): super(arg, self).__init__(wl, enums) if wl[0] == end: return x = wl.pop(0) if x in argnames: err("Duplicate argument name '%s'" % x, warn=False) argnames[x] = True self.nm = x if wl[0] == end: return x = wl.pop(0) if x != "=": err("Expected '=' got '%s'" % x, warn=False) x = wl.pop(0) if self.vt == "ENUM": if is_quoted(x): x = unquote(x) self.defval = x def json(self, jl): jl.append([self.vt, self.nm, self.defval, self.spec]) if self.opt: jl[-1].append(True) while jl[-1][-1] is None: jl[-1].pop(-1) ####################################################################### class ProtoType(object): def __init__(self, st, retval=True, prefix=""): self.st = st self.obj = None self.args = [] self.argstruct = False wl = self.st.toks[1:] if retval: self.retval = CType(wl, st.vcc.enums) else: self.retval = CType(['VOID'], st.vcc.enums) self.bname = wl.pop(0) if not re.match("^[a-zA-Z.][a-zA-Z0-9_]*$", self.bname): err("%s(): Illegal name\n" % self.bname, warn=False) self.name = prefix + self.bname if not re.match('^[a-zA-Z_][a-zA-Z0-9_]*$', self.cname()): err("%s(): Illegal C-name\n" % self.cname(), warn=False) if len(wl) == 2 and wl[0] == '(' and wl[1] == ')': return if wl[0] != "(": err("Syntax error: Expected '(', got '%s'" % wl[0], warn=False) wl[0] = ',' if wl[-1] != ")": err("Syntax error: Expected ')', got '%s'" % wl[-1], warn=False) wl[-1] = ',' names = {} n = 0 while wl: n += 1 x = wl.pop(0) if x != ',': err("Expected ',' found '%s'" % x, warn=False) if not wl: break if wl[0] == '[': wl.pop(0) t = arg(wl, names, st.vcc.enums, ']') if t.nm is None: err("Optional arguments must have names", warn=False) t.opt = True x = wl.pop(0) if x != ']': err("Expected ']' found '%s'" % x, warn=False) self.argstruct = True else: t = arg(wl, names, st.vcc.enums, ',') if t.nm is None: t.nm2 = "arg%d" % n else: t.nm2 = t.nm self.args.append(t) def vcl_proto(self, short, pfx=""): if isinstance(self.st, MethodStanza): pfx += pfx s = pfx if isinstance(self.st, ObjectStanza): s += "new " + self.obj + " = " elif self.retval is not None: s += self.retval.vcl() + " " if isinstance(self.st, ObjectStanza): s += self.st.vcc.modname + "." + self.name + "(" elif isinstance(self.st, MethodStanza): s += self.obj + self.bname + "(" else: s += self.name + "(" ll = [] for i in self.args: if short: t = i.synopsis() else: t = i.vcl() if t in PRIVS: continue if i.nm is not None: t += " " + i.nm if not short: if i.defval is not None: t += "=" + i.defval if i.opt: t = "[" + t + "]" ll.append(t) t = ",@".join(ll) if len(s + t) > 68 and not short: s += "\n" + pfx + pfx s += t.replace("@", "\n" + pfx + pfx) s += "\n" + pfx + ")" else: s += t.replace("@", " ") + ")" return s def rsthead(self, fo): s = self.vcl_proto(False) if len(s) < 60: write_rst_hdr(fo, s, '-') else: s = self.vcl_proto(True) if len(s) > 60: s = self.name + "(...)" write_rst_hdr(fo, s, '-') fo.write("\n::\n\n" + self.vcl_proto(False, pfx=" ") + "\n") def synopsis(self, fo, unused_man): fo.write(self.vcl_proto(True, pfx=" ") + "\n") fo.write(" \n") def cname(self, pfx=False): r = self.name.replace(".", "_") if pfx: return self.st.vcc.sympfx + r return r def proto(self, args, name): s = self.retval.ct + " " + name + '(' ll = args if self.argstruct: ll.append(self.argstructname() + "*") else: for i in self.args: ll.append(i.ct) s += ", ".join(ll) return s + ');' def typedef(self, args): tn = 'td_' + self.st.vcc.modname + '_' + self.cname() return "typedef " + self.proto(args, name=tn) def argstructname(self): return "struct %s_arg" % self.cname(True) def argstructure(self): s = "\n" + self.argstructname() + " {\n" for i in self.args: if i.opt: assert i.nm is not None s += "\tchar\t\t\tvalid_%s;\n" % i.nm for i in self.args: s += "\t" + i.ct if len(i.ct) < 8: s += "\t" if len(i.ct) < 16: s += "\t" s += "\t" + i.nm2 + ";\n" s += "};\n" return s def cstuff(self, args, where): s = "" if where == 'h': if self.argstruct: s += self.argstructure() s += lwrap(self.proto(args, self.cname(True))) elif where == 'c': s += lwrap(self.typedef(args)) elif where == 'o': if self.argstruct: s += self.argstructure() s += lwrap(self.typedef(args)) else: assert False return s def json(self, jl, cfunc): ll = [] self.retval.json(ll) ll.append('Vmod_%s_Func.%s' % (self.st.vcc.modname, cfunc)) if self.argstruct: ll.append(self.argstructname()) else: ll.append("") for i in self.args: i.json(ll) jl.append(ll) ####################################################################### class Stanza(object): def __init__(self, toks, l0, doc, vcc): self.toks = toks self.line = l0 while doc and doc[0] == '': doc.pop(0) while doc and doc[-1] == '': doc.pop(-1) self.doc = doc self.vcc = vcc self.rstlbl = None self.null_ok = False self.methods = None self.proto = None self.parse() def parse(self): assert "subclass should have defined" == "parse method" def dump(self): print(type(self), self.line) def syntax(self): err("Syntax error.\n" + "\tShould be: " + self.__doc__.strip() + "\n" + "\tIs: " + " ".join(self.toks) + "\n", warn=False) def rstfile(self, fo, man): if self.rstlbl is not None: fo.write(".. _" + self.rstlbl + ":\n\n") self.rsthead(fo, man) fo.write("\n") self.rstmid(fo, man) fo.write("\n") self.rsttail(fo, man) fo.write("\n") def rsthead(self, fo, unused_man): if self.proto is not None: self.proto.rsthead(fo) def rstmid(self, fo, unused_man): fo.write("\n".join(self.doc) + "\n") def rsttail(self, unused_fo, unused_man): return def synopsis(self, fo, man): if self.proto is not None: self.proto.synopsis(fo, man) def cstuff(self, unused_fo, unused_where): return def cstruct(self, unused_fo, unused_define): return def json(self, unused_jl): return ####################################################################### class ModuleStanza(Stanza): ''' $Module modname man_section description ... ''' def parse(self): if len(self.toks) < 4: self.syntax() self.vcc.modname = self.toks[1] self.vcc.mansection = self.toks[2] if len(self.toks) == 4 and is_quoted(self.toks[3]): self.vcc.moddesc = unquote(self.toks[3]) else: print("\nNOTICE: Please put $Module description in quotes.\n") self.vcc.moddesc = " ".join(self.toks[3:]) self.rstlbl = "vmod_%s(%s)" % ( self.vcc.modname, self.vcc.mansection ) self.vcc.contents.append(self) def rsthead(self, fo, man): write_rst_hdr(fo, self.vcc.sympfx + self.vcc.modname, "=", "=") fo.write("\n") write_rst_hdr(fo, self.vcc.moddesc, "-", "-") fo.write("\n") fo.write(":Manual section: " + self.vcc.mansection + "\n") if self.vcc.auto_synopsis: fo.write("\n") write_rst_hdr(fo, "SYNOPSIS", "=") fo.write("\n") fo.write("\n::\n\n") fo.write(' import %s [from "path"] ;\n' % self.vcc.modname) fo.write(" \n") for c in self.vcc.contents: c.synopsis(fo, man) fo.write("\n") def rsttail(self, fo, man): if man: return write_rst_hdr(fo, "CONTENTS", "=") fo.write("\n") ll = [] for i in self.vcc.contents[1:]: j = i.rstlbl if j is not None: ll.append([j.split("_", 1)[1], j]) if i.methods is None: continue for x in i.methods: j = x.rstlbl ll.append([j.split("_", 1)[1], j]) ll.sort() for i in ll: fo.write("* :ref:`%s`\n" % i[1]) fo.write("\n") class ABIStanza(Stanza): ''' $ABI [strict|vrt] ''' def parse(self): if len(self.toks) != 2: self.syntax() valid = { 'strict': True, 'vrt': False, } self.vcc.strict_abi = valid.get(self.toks[1]) if self.vcc.strict_abi is None: err("Valid ABI types are 'strict' or 'vrt', got '%s'\n" % self.toks[1]) self.vcc.contents.append(self) class PrefixStanza(Stanza): ''' $Prefix symbol ''' def parse(self): if len(self.toks) != 2: self.syntax() self.vcc.sympfx = self.toks[1] + "_" self.vcc.contents.append(self) class SynopsisStanza(Stanza): ''' $Synopsis [auto|manual] ''' def parse(self): if len(self.toks) != 2: self.syntax() valid = { 'auto': True, 'manual': False, } self.vcc.auto_synopsis = valid.get(self.toks[1]) if self.vcc.auto_synopsis is None: err("Valid Synopsis values are 'auto' or 'manual', got '%s'\n" % self.toks[1]) self.vcc.contents.append(self) class EventStanza(Stanza): ''' $Event function_name ''' def parse(self): if len(self.toks) != 2: self.syntax() self.event_func = self.toks[1] self.vcc.contents.append(self) def rstfile(self, fo, man): if self.doc: err("Not emitting .RST for $Event %s\n" % self.event_func) def cstuff(self, fo, where): if where == 'h': fo.write("vmod_event_f %s;\n" % self.event_func) def cstruct(self, fo, define): if define: fo.write("\tvmod_event_f\t\t\t*_event;\n") else: fo.write("\t%s,\n" % self.event_func) def json(self, jl): jl.append([ "$EVENT", "Vmod_%s_Func._event" % self.vcc.modname ]) class FunctionStanza(Stanza): def parse(self): self.proto = ProtoType(self) self.rstlbl = "func_" + self.proto.name self.vcc.contents.append(self) def cstuff(self, fo, where): fo.write(self.proto.cstuff(['VRT_CTX'], where)) def cstruct(self, fo, define): if define: fmt_cstruct(fo, self.vcc.modname, self.proto.cname()) else: fo.write("\t" + self.proto.cname(pfx=True) + ",\n") def json(self, jl): jl.append(["$FUNC", "%s" % self.proto.name]) self.proto.json(jl[-1], self.proto.cname()) class ObjectStanza(Stanza): def parse(self): if self.toks[1] == "NULL_OK": self.toks.pop(1) self.null_ok = True self.proto = ProtoType(self, retval=False) self.proto.obj = "x" + self.proto.name self.init = copy.copy(self.proto) self.init.name += '__init' self.fini = copy.copy(self.proto) self.fini.name += '__fini' self.fini.argstruct = False self.fini.args = [] self.rstlbl = "obj_" + self.proto.name self.vcc.contents.append(self) self.methods = [] def rsthead(self, fo, man): self.proto.rsthead(fo) fo.write("\n" + "\n".join(self.doc) + "\n\n") for i in self.methods: i.rstfile(fo, man) def rstmid(self, unused_fo, unused_man): return def synopsis(self, fo, man): self.proto.synopsis(fo, man) for i in self.methods: i.proto.synopsis(fo, man) def cstuff(self, fo, w): sn = self.vcc.sympfx + self.vcc.modname + "_" + self.proto.name fo.write("struct %s;\n" % sn) fo.write(self.init.cstuff( ['VRT_CTX', 'struct %s **' % sn, 'const char *'], w)) fo.write(self.fini.cstuff(['struct %s **' % sn], w)) for i in self.methods: fo.write(i.proto.cstuff(['VRT_CTX', 'struct %s *' % sn], w)) fo.write("\n") def cstruct(self, fo, define): if define: fmt_cstruct(fo, self.vcc.modname, self.init.name) fmt_cstruct(fo, self.vcc.modname, self.fini.name) else: p = "\t" + self.vcc.sympfx fo.write(p + self.init.name + ",\n") fo.write(p + self.fini.name + ",\n") for i in self.methods: i.cstruct(fo, define) fo.write("\n") def json(self, jl): ll = [ "$OBJ", self.proto.name, { "NULL_OK": self.null_ok }, "struct %s%s_%s" % (self.vcc.sympfx, self.vcc.modname, self.proto.name), ] l2 = ["$INIT"] ll.append(l2) self.init.json(l2, self.init.name) l2 = ["$FINI"] ll.append(l2) self.fini.json(l2, self.fini.name) for i in self.methods: i.json(ll) jl.append(ll) def dump(self): super(ObjectStanza, self).dump() for i in self.methods: i.dump() ####################################################################### class MethodStanza(Stanza): def parse(self): p = self.vcc.contents[-1] assert isinstance(p, ObjectStanza) self.pfx = p.proto.name self.proto = ProtoType(self, prefix=self.pfx) if not self.proto.bname.startswith("."): err("$Method %s: Method names need to start with . (dot)" % self.proto.bname, warn=False) self.proto.obj = "x" + self.pfx self.rstlbl = "func_" + self.proto.name p.methods.append(self) def cstruct(self, fo, define): if define: fmt_cstruct(fo, self.vcc.modname, self.proto.cname()) else: fo.write('\t' + self.proto.cname(pfx=True) + ",\n") def json(self, jl): jl.append(["$METHOD", self.proto.name[len(self.pfx)+1:]]) self.proto.json(jl[-1], self.proto.cname()) ####################################################################### DISPATCH = { "Module": ModuleStanza, "Prefix": PrefixStanza, "ABI": ABIStanza, "Event": EventStanza, "Function": FunctionStanza, "Object": ObjectStanza, "Method": MethodStanza, "Synopsis": SynopsisStanza, } class vcc(object): ''' Processing context for a single .vcc file ''' def __init__(self, inputvcc, rstdir, outputprefix): self.inputfile = inputvcc self.rstdir = rstdir self.pfx = outputprefix self.sympfx = "vmod_" self.contents = [] self.commit_files = [] self.copyright = "" self.enums = {} self.strict_abi = True self.auto_synopsis = True self.modname = None def openfile(self, fn): self.commit_files.append(fn) return open(fn + ".tmp", "w") def commit(self): for i in self.commit_files: os.rename(i + ".tmp", i) def parse(self): global inputline b = open(self.inputfile, "rb").read() a = "\n" + b.decode("utf-8") self.file_id = hashlib.sha256(b).hexdigest() s = a.split("\n$") self.copyright = s.pop(0).strip() while s: ss = re.split('\n([^\t ])', s.pop(0), maxsplit=1) toks = self.tokenize(ss[0]) inputline = '$' + ' '.join(toks) c = ss[0].split() d = "".join(ss[1:]) m = DISPATCH.get(toks[0]) if m is None: err("Unknown stanza $%s" % toks[0], warn=False) m(toks, [c[0], " ".join(c[1:])], d.split('\n'), self) inputline = None def tokenize(self, txt, seps=None, quotes=None): if seps is None: seps = "[](){},=" if quotes is None: quotes = '"' + "'" quote = None out = [] i = 0 inside = False while i < len(txt): c = txt[i] # print("T", [c], quote, inside, i) i += 1 if quote is not None and c == quote: inside = False quote = None out[-1] += c elif quote is not None: out[-1] += c elif c.isspace(): inside = False elif seps.find(c) >= 0: inside = False out.append(c) elif quotes.find(c) >= 0: quote = c out.append(c) elif inside: out[-1] += c else: out.append(c) inside = True #print("TOK", [str]) #for i in out: # print("\t", [i]) return out def rst_copyright(self, fo): write_rst_hdr(fo, "COPYRIGHT", "=") fo.write("\n::\n\n") a = self.copyright a = a.replace("\n#", "\n ") if a[:2] == "#\n": a = a[2:] if a[:3] == "#-\n": a = a[3:] fo.write(a + "\n") def rstfile(self, man=False): fn = os.path.join(self.rstdir, "vmod_" + self.modname) if man: fn += ".man" fn += ".rst" fo = self.openfile(fn) write_rst_file_warning(fo) fo.write(".. role:: ref(emphasis)\n\n") for i in self.contents: i.rstfile(fo, man) if self.copyright: self.rst_copyright(fo) fo.close() def amboilerplate(self): fo = self.openfile("automake_boilerplate.am") fo.write(AMBOILERPLATE.replace("XXX", self.modname)) fo.close() def hfile(self): fn = self.pfx + ".h" fo = self.openfile(fn) write_c_file_warning(fo) fo.write("#ifndef VDEF_H_INCLUDED\n") fo.write('# error "Include vdef.h first"\n') fo.write("#endif\n") fo.write("#ifndef VRT_H_INCLUDED\n") fo.write('# error "Include vrt.h first"\n') fo.write("#endif\n") fo.write("\n") for j in sorted(self.enums): fo.write("extern VCL_ENUM %senum_%s;\n" % (self.sympfx, j)) fo.write("\n") for j in self.contents: j.cstuff(fo, 'h') fo.close() def cstruct(self, fo, csn): fo.write("\n%s {\n" % csn) for j in self.contents: j.cstruct(fo, True) for j in sorted(self.enums): fo.write("\tVCL_ENUM\t\t\t*enum_%s;\n" % j) fo.write("};\n") def cstruct_init(self, fo, csn): fo.write("\nstatic const %s Vmod_Func = {\n" % csn) for j in self.contents: j.cstruct(fo, False) fo.write("\n") for j in sorted(self.enums): fo.write("\t&%senum_%s,\n" % (self.sympfx, j)) fo.write("};\n") def json(self, fo): jl = [["$VMOD", "1.0"]] for j in self.contents: j.json(jl) bz = bytearray(json.dumps(jl, separators=(",", ":")), encoding="ascii") + b"\0" fo.write("\nstatic const char Vmod_Json[%d] = {\n" % len(bz)) t = "\t" for i in bz: t += "%d," % i if len(t) >= 69: fo.write(t + "\n") t = "\t" if len(t) > 1: fo.write(t[:-1]) fo.write("\n};\n\n") for i in json.dumps(jl, indent=2, separators=(',', ': ')).split("\n"): j = "// " + i if len(j) > 72: fo.write(j[:72] + "[...]\n") else: fo.write(j + "\n") fo.write("\n") def vmod_data(self, fo): vmd = "Vmod_%s_Data" % self.modname for i in (714, 759, 765): fo.write("\n/*lint -esym(%d, %s) */\n" % (i, vmd)) fo.write("\nextern const struct vmod_data %s;\n" % vmd) fo.write("\nconst struct vmod_data %s = {\n" % vmd) if self.strict_abi: fo.write("\t.vrt_major =\t0,\n") fo.write("\t.vrt_minor =\t0,\n") else: fo.write("\t.vrt_major =\tVRT_MAJOR_VERSION,\n") fo.write("\t.vrt_minor =\tVRT_MINOR_VERSION,\n") fo.write('\t.name =\t\t"%s",\n' % self.modname) fo.write('\t.func =\t\t&Vmod_Func,\n') fo.write('\t.func_len =\tsizeof(Vmod_Func),\n') fo.write('\t.proto =\tVmod_Proto,\n') fo.write('\t.json =\t\tVmod_Json,\n') fo.write('\t.abi =\t\tVMOD_ABI_Version,\n') fo.write("\t.file_id =\t\"%s\",\n" % self.file_id) fo.write("};\n") def cfile(self): fno = self.pfx + ".c" fo = self.openfile(fno) fnx = fno + ".tmp2" fx = open(fnx, "w") write_c_file_warning(fo) fo.write('#include "config.h"\n') fo.write('#include <stdio.h>\n') for i in ["vdef", "vrt", self.pfx, "vmod_abi"]: fo.write('#include "%s.h"\n' % i) fo.write("\n") for j in sorted(self.enums): fo.write('VCL_ENUM %senum_%s = "%s";\n' % (self.sympfx, j, j)) fo.write("\n") for i in self.contents: if isinstance(i, ObjectStanza): i.cstuff(fo, 'c') i.cstuff(fx, 'o') fx.write("/* Functions */\n") for i in self.contents: if isinstance(i, FunctionStanza): i.cstuff(fo, 'c') i.cstuff(fx, 'o') csn = "Vmod_%s_Func" % self.modname scsn = "struct " + csn self.cstruct(fo, scsn) self.cstruct(fx, scsn) fo.write("\n/*lint -esym(754, " + csn + "::*) */\n") self.cstruct_init(fo, scsn) fx.close() fo.write("\nstatic const char Vmod_Proto[] =\n") for i in open(fnx): fo.write('\t"%s\\n"\n' % i.rstrip()) fo.write('\t"static struct %s %s;";\n' % (csn, csn)) os.remove(fnx) self.json(fo) self.vmod_data(fo) fo.close() ####################################################################### def runmain(inputvcc, rstdir, outputprefix): v = vcc(inputvcc, rstdir, outputprefix) v.parse() v.rstfile(man=False) v.rstfile(man=True) v.hfile() v.cfile() if opts.boilerplate: v.amboilerplate() v.commit() if __name__ == "__main__": usagetext = "Usage: %prog [options] <vmod.vcc>" oparser = optparse.OptionParser(usage=usagetext) oparser.add_option('-b', '--boilerplate', action='store_true', default=False, help="Be strict when parsing the input file") oparser.add_option('-N', '--strict', action='store_true', default=False, help="Be strict when parsing the input file") oparser.add_option('-o', '--output', metavar="prefix", default='vcc_if', help='Output file prefix (default: "vcc_if")') oparser.add_option('-w', '--rstdir', metavar="directory", default='.', help='Where to save the generated RST files ' + '(default: ".")') oparser.add_option('', '--runtests', action='store_true', default=False, dest="runtests", help=optparse.SUPPRESS_HELP) (opts, args) = oparser.parse_args() if opts.runtests: # Pop off --runtests, pass remaining to unittest. del sys.argv[1] unittest.main() exit() i_vcc = None if len(args) == 1 and os.path.exists(args[0]): i_vcc = args[0] elif os.path.exists("vmod.vcc"): if not i_vcc: i_vcc = "vmod.vcc" else: print("ERROR: No vmod.vcc file supplied or found.", file=sys.stderr) oparser.print_help() exit(-1) runmain(i_vcc, opts.rstdir, opts.output)