1#!/usr/bin/env python3
2#
3# Looks for registration routines in the plugins
4# and assembles C code to call all the routines.
5# A new "plugin.c" file will be written in the current directory.
6#
7
8import os
9import sys
10import re
11
12#
13# The first argument is the directory in which the source files live.
14#
15srcdir = sys.argv[1]
16#
17# The second argument is either "plugin", "plugin_wtap", "plugin_codec",
18# or "plugin_tap".
19#
20registertype = sys.argv[2]
21#
22# All subsequent arguments are the files to scan.
23#
24files = sys.argv[3:]
25
26final_filename = "plugin.c"
27preamble = """\
28/*
29 * Do not modify this file. Changes will be overwritten.
30 *
31 * Generated automatically from %s.
32 */
33""" % (os.path.basename(sys.argv[0]))
34
35# Create the proper list of filenames
36filenames = []
37for file in files:
38    if os.path.isfile(file):
39        filenames.append(file)
40    else:
41        filenames.append(os.path.join(srcdir, file))
42
43if len(filenames) < 1:
44    print("No files found")
45    sys.exit(1)
46
47
48# Look through all files, applying the regex to each line.
49# If the pattern matches, save the "symbol" section to the
50# appropriate set.
51regs = {
52        'proto_reg': set(),
53        'handoff_reg': set(),
54        'wtap_register': set(),
55        'codec_register': set(),
56        'register_tap_listener': set(),
57        }
58
59# For those that don't know Python, r"" indicates a raw string,
60# devoid of Python escapes.
61proto_regex = r"\bproto_register_(?P<symbol>[_A-Za-z0-9]+)\s*\(\s*void\s*\)[^;]*$"
62
63handoff_regex = r"\bproto_reg_handoff_(?P<symbol>[_A-Za-z0-9]+)\s*\(\s*void\s*\)[^;]*$"
64
65wtap_reg_regex = r"\bwtap_register_(?P<symbol>[_A-Za-z0-9]+)\s*\([^;]+$"
66
67codec_reg_regex = r"\bcodec_register_(?P<symbol>[_A-Za-z0-9]+)\s*\([^;]+$"
68
69tap_reg_regex = r"\bregister_tap_listener_(?P<symbol>[_A-Za-z0-9]+)\s*\([^;]+$"
70
71# This table drives the pattern-matching and symbol-harvesting
72patterns = [
73        ( 'proto_reg', re.compile(proto_regex, re.MULTILINE) ),
74        ( 'handoff_reg', re.compile(handoff_regex, re.MULTILINE) ),
75        ( 'wtap_register', re.compile(wtap_reg_regex, re.MULTILINE) ),
76        ( 'codec_register', re.compile(codec_reg_regex, re.MULTILINE) ),
77        ( 'register_tap_listener', re.compile(tap_reg_regex, re.MULTILINE) ),
78        ]
79
80# Grep
81for filename in filenames:
82    file = open(filename)
83    # Read the whole file into memory
84    contents = file.read()
85    for action in patterns:
86        regex = action[1]
87        for match in regex.finditer(contents):
88            symbol = match.group("symbol")
89            sym_type = action[0]
90            regs[sym_type].add(symbol)
91    # We're done with the file contents
92    del contents
93    file.close()
94
95# Make sure we actually processed something
96if (len(regs['proto_reg']) < 1 and len(regs['wtap_register']) < 1 and len(regs['codec_register']) < 1 and len(regs['register_tap_listener']) < 1):
97    print("No plugin registrations found")
98    sys.exit(1)
99
100# Convert the sets into sorted lists to make the output pretty
101regs['proto_reg'] = sorted(regs['proto_reg'])
102regs['handoff_reg'] = sorted(regs['handoff_reg'])
103regs['wtap_register'] = sorted(regs['wtap_register'])
104regs['codec_register'] = sorted(regs['codec_register'])
105regs['register_tap_listener'] = sorted(regs['register_tap_listener'])
106
107reg_code = ""
108
109reg_code += preamble
110
111reg_code += """
112#include "config.h"
113
114#include <gmodule.h>
115
116/* plugins are DLLs on Windows */
117#define WS_BUILD_DLL
118#include "ws_symbol_export.h"
119
120"""
121
122if registertype == "plugin":
123    reg_code += "#include \"epan/proto.h\"\n\n"
124if registertype == "plugin_wtap":
125    reg_code += "#include \"wiretap/wtap.h\"\n\n"
126if registertype == "plugin_codec":
127    reg_code += "#include \"wsutil/codecs.h\"\n\n"
128if registertype == "plugin_tap":
129    reg_code += "#include \"epan/tap.h\"\n\n"
130
131for symbol in regs['proto_reg']:
132    reg_code += "void proto_register_%s(void);\n" % (symbol)
133for symbol in regs['handoff_reg']:
134    reg_code += "void proto_reg_handoff_%s(void);\n" % (symbol)
135for symbol in regs['wtap_register']:
136    reg_code += "void wtap_register_%s(void);\n" % (symbol)
137for symbol in regs['codec_register']:
138    reg_code += "void codec_register_%s(void);\n" % (symbol)
139for symbol in regs['register_tap_listener']:
140    reg_code += "void register_tap_listener_%s(void);\n" % (symbol)
141
142reg_code += """
143WS_DLL_PUBLIC_DEF const gchar plugin_version[] = PLUGIN_VERSION;
144WS_DLL_PUBLIC_DEF const int plugin_want_major = VERSION_MAJOR;
145WS_DLL_PUBLIC_DEF const int plugin_want_minor = VERSION_MINOR;
146
147WS_DLL_PUBLIC void plugin_register(void);
148
149void plugin_register(void)
150{
151"""
152
153if registertype == "plugin":
154    for symbol in regs['proto_reg']:
155        reg_code +="    static proto_plugin plug_%s;\n\n" % (symbol)
156        reg_code +="    plug_%s.register_protoinfo = proto_register_%s;\n" % (symbol, symbol)
157        if symbol in regs['handoff_reg']:
158            reg_code +="    plug_%s.register_handoff = proto_reg_handoff_%s;\n" % (symbol, symbol)
159        else:
160            reg_code +="    plug_%s.register_handoff = NULL;\n" % (symbol)
161        reg_code += "    proto_register_plugin(&plug_%s);\n" % (symbol)
162if registertype == "plugin_wtap":
163    for symbol in regs['wtap_register']:
164        reg_code += "    static wtap_plugin plug_%s;\n\n" % (symbol)
165        reg_code += "    plug_%s.register_wtap_module = wtap_register_%s;\n" % (symbol, symbol)
166        reg_code += "    wtap_register_plugin(&plug_%s);\n" % (symbol)
167if registertype == "plugin_codec":
168    for symbol in regs['codec_register']:
169        reg_code += "    static codecs_plugin plug_%s;\n\n" % (symbol)
170        reg_code += "    plug_%s.register_codec_module = codec_register_%s;\n" % (symbol, symbol)
171        reg_code += "    codecs_register_plugin(&plug_%s);\n" % (symbol)
172if registertype == "plugin_tap":
173    for symbol in regs['register_tap_listener']:
174        reg_code += "    static tap_plugin plug_%s;\n\n" % (symbol)
175        reg_code += "    plug_%s.register_tap_listener = register_tap_listener_%s;\n" % (symbol, symbol)
176        reg_code += "    tap_register_plugin(&plug_%s);\n" % (symbol)
177
178reg_code += "}\n"
179
180try:
181    fh = open(final_filename, 'w')
182    fh.write(reg_code)
183    fh.close()
184except OSError:
185    sys.exit('Unable to write ' + final_filename + '.\n')
186
187#
188# Editor modelines  -  https://www.wireshark.org/tools/modelines.html
189#
190# Local variables:
191# c-basic-offset: 4
192# indent-tabs-mode: nil
193# End:
194#
195# vi: set shiftwidth=4 expandtab:
196# :indentSize=4:noTabs=true:
197#
198