Rewrite make-dissector-reg.py in C

The output compares equal to make-dissector-reg.py and the regex
should be more robust (multiline, complete start of function definition).

The primary motivation is to clean up the python script. This small
binary results in much cleaner code. The python script is used only
to generate plugin code, therefore it is renamed.

Also in my casual measurements the C code is much faster (without cache)
than the python script with the cache.

Change-Id: Id4e8cac3c836d56775aba4819357a95ef19bcb85
Reviewed-on: https://code.wireshark.org/review/24497
Petri-Dish: Anders Broman <a.broman58@gmail.com>
Tested-by: Petri Dish Buildbot
Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
João Valverde 2017-11-19 00:20:20 +00:00 committed by Anders Broman
parent 129cb60f56
commit fe0c2b0485
14 changed files with 1767 additions and 1741 deletions

2
.gitignore vendored
View File

@ -32,8 +32,8 @@ epan/dissectors/dcerpc/*/packet-dcerpc-*.[hc]
epan/dissectors/mesa
epan/dissectors/xcbproto
epan/dissectors/packet-ncp2222.c
epan/dissectors/dissectors-cache.pkl
epan/dissectors/dissectors.c
epan/dissectors/make-dissectors
epan/dtd_parse.c
epan/dtd_preparse.c
epan/packet-ncp2222.c

View File

@ -1,32 +1,21 @@
#
MACRO(REGISTER_DISSECTOR_FILES _outputfile _registertype )
include(LocatePythonModule)
locate_python_module(make-dissector-reg REQUIRED PATHS ${CMAKE_SOURCE_DIR}/tools)
locate_python_module(make-plugin-reg REQUIRED PATHS ${CMAKE_SOURCE_DIR}/tools)
if(${_registertype} STREQUAL "dissectors" )
set( _makeregistertype "dissectorsinfile" )
set( _ftmp "${CMAKE_CURRENT_BINARY_DIR}/_regc.tmp" )
set( _depends ${ARGN} )
file(REMOVE ${_ftmp})
foreach(f ${_depends})
file(APPEND ${_ftmp} "${f}\n")
endforeach()
set( _sources ${_ftmp} )
else()
set( _makeregistertype ${_registertype} )
set( _sources ${ARGN} )
set( _depends ${_sources} )
endif()
set( _makeregistertype ${_registertype} )
set( _sources ${ARGN} )
set( _depends ${_sources} )
ADD_CUSTOM_COMMAND(
OUTPUT
${_outputfile}
COMMAND ${PYTHON_EXECUTABLE}
${PY_MAKE-DISSECTOR-REG}
${PY_MAKE-PLUGIN-REG}
${CMAKE_CURRENT_SOURCE_DIR}
${_makeregistertype}
${_sources}
DEPENDS
${_depends}
${PY_MAKE-DISSECTOR-REG}
${PY_MAKE-PLUGIN-REG}
)
ENDMACRO(REGISTER_DISSECTOR_FILES)

2
debian/rules vendored
View File

@ -58,7 +58,7 @@ override_dh_install:
override_dh_fixperms:
dh_fixperms
chmod 644 debian/wireshark-dev/usr/share/pyshared/make-dissector-reg.py \
chmod 644 debian/wireshark-dev/usr/share/pyshared/make-plugin-reg.py \
debian/wireshark-dev/usr/share/pyshared/wireshark_be.py \
debian/wireshark-dev/usr/share/pyshared/wireshark_gen.py

View File

@ -1,7 +1,7 @@
tools/idl2wrs usr/bin
tools/idl2deb usr/bin
tools/asn2deb usr/bin
tools/make-dissector-reg.py usr/share/pyshared
tools/make-plugin-reg.py usr/share/pyshared
tools/wireshark_be.py usr/share/pyshared
tools/wireshark_gen.py usr/share/pyshared
tools/asn2wrs.py usr/share/pyshared

File diff suppressed because it is too large Load Diff

View File

@ -1900,6 +1900,12 @@ subpkginclude_HEADERS = \
noinst_HEADERS = \
$(FILE_DISSECTOR_INCLUDES)
noinst_PROGRAMS = make-dissectors
make_dissectors_CFLAGS = $(WS_CPPFLAGS) $(GLIB_CFLAGS)
make_dissectors_LDADD = $(GLIB_LIBS)
# include asn1 in the source tarball. But nothing to build...
DIST_SUBDIRS = asn1 dcerpc
@ -1929,31 +1935,13 @@ x11-dissector: $(top_srcdir)/tools/process-x11-fields.pl $(srcdir)/x11-fields $(
# with the register routines for all protocols and a function pointer array
# with the handoff registration routines for all protocols.
#
# We do this by scanning through sources. If that turns out to be too slow,
# maybe we could just require every .o file to have an register routine
# of a given name (packet-aarp.o -> proto_register_aarp, etc.).
#
# Formatting conventions: The name of the proto_register_* routines an
# proto_reg_handoff_* routines must start in column zero, or must be
# preceded only by "void " starting in column zero, and must not be
# inside #if.
#
# ALL_DISSECTORS_SRC is assumed to have all the files that need to be scanned.
#
# We use a script to generate the dissectors.c file.
# The first argument is the directory in which the source files live.
# The second argument is "dissectors", to indicate that we should build
# a dissectors.c file for libwireshark.
# All subsequent arguments are the files to scan.
#
dissectors.c: $(ALL_DISSECTORS_SRC) Custom.common \
$(top_srcdir)/tools/make-dissector-reg.py
@echo Making dissectors.c ; \
$(PYTHON) $(top_srcdir)/tools/make-dissector-reg.py $(srcdir) \
dissectors $(ALL_DISSECTORS_SRC) ;
CLEANFILES = \
dissectors-cache.pkl
dissectors.c: make-dissectors $(ALL_DISSECTORS_SRC)
@echo Making dissectors.c
$(file >$@.in,$(filter %.c,$^))
$(builddir)/make-dissectors @$@.in > $@
@rm $@.in
DISTCLEANFILES = \
$(NODIST_GENERATED_FILES)

View File

@ -27,9 +27,8 @@ typedef struct _dissector_reg {
WS_DLL_PUBLIC dissector_reg_t dissector_reg_proto[];
WS_DLL_PUBLIC dissector_reg_t dissector_reg_handoff[];
WS_DLL_PUBLIC gulong dissector_reg_proto_count(void);
WS_DLL_PUBLIC gulong dissector_reg_handoff_count(void);
WS_DLL_PUBLIC const gulong dissector_reg_proto_count;
WS_DLL_PUBLIC const gulong dissector_reg_handoff_count;
#ifdef __cplusplus
}

View File

@ -0,0 +1,157 @@
/* make-dissectors.c
* Tool to build the dissector registration arrays.
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <glib.h>
#define ARRAY_RESERVED_SIZE 2048
GRegex *protos_regex, *handoffs_regex;
static int
compare_symbols(gconstpointer a, gconstpointer b)
{
return g_strcmp0(*(const char **)a, *(const char **)b);
}
static void
scan_matches(GRegex *regex, const char *string, GPtrArray *dst)
{
GMatchInfo *match_info;
char *match;
g_regex_match(regex, string, G_REGEX_MATCH_NOTEMPTY, &match_info);
while (g_match_info_matches(match_info)) {
match = g_match_info_fetch(match_info, 1);
g_ptr_array_add(dst, match);
g_match_info_next(match_info, NULL);
}
g_match_info_free(match_info);
}
static void
scan_file(const char *file, GPtrArray *protos, GPtrArray *handoffs)
{
char *contents;
if (!g_file_get_contents(file, &contents, NULL, NULL))
return;
scan_matches(protos_regex, contents, protos);
scan_matches(handoffs_regex, contents, handoffs);
g_free(contents);
}
static void
scan_list(const char *list, GPtrArray *protos, GPtrArray *handoffs)
{
char *contents, *arg;
if (!g_file_get_contents(list, &contents, NULL, NULL))
return;
for (arg = strtok(contents, " \n"); arg != NULL; arg = strtok(NULL, " \n")) {
scan_file(arg, protos, handoffs);
}
g_free(contents);
}
int main(int argc, char **argv)
{
GPtrArray *protos = NULL, *handoffs = NULL;
GError *err = NULL;
guint i;
protos = g_ptr_array_new_full(ARRAY_RESERVED_SIZE, g_free);
handoffs = g_ptr_array_new_full(ARRAY_RESERVED_SIZE, g_free);
protos_regex = g_regex_new("void\\s+(proto_register_[[:alnum:]_]+)\\s*\\(\\s*void\\s*\\)\\s*{",
G_REGEX_OPTIMIZE, G_REGEX_MATCH_NOTEMPTY, &err);
if (err) {
fprintf(stderr, "GRegex: %s\n", err->message);
exit(1);
}
handoffs_regex = g_regex_new("void\\s+(proto_reg_handoff_[[:alnum:]_]+)\\s*\\(\\s*void\\s*\\)\\s*{",
G_REGEX_OPTIMIZE, G_REGEX_MATCH_NOTEMPTY, &err);
if (err) {
fprintf(stderr, "GRegex: %s\n", err->message);
exit(1);
}
for (int arg = 1; arg < argc; arg++) {
if (argv[arg][0] == '@') {
scan_list(&argv[arg][1], protos, handoffs);
}
else {
scan_file(argv[arg], protos, handoffs);
}
}
g_ptr_array_sort(protos, compare_symbols);
g_ptr_array_sort(handoffs, compare_symbols);
printf("/*\n"
" * Do not modify this file. Changes will be overwritten.\n"
" *\n"
" * Generated automatically by the \"dissectors.c\" target using\n"
" * \"make-dissectors\".\n"
" */\n"
"\n"
"#include <ws_symbol_export.h>\n"
"#include <dissectors.h>\n"
"\n");
printf("const gulong dissector_reg_proto_count = %d;\n"
"const gulong dissector_reg_handoff_count = %d;\n"
"\n",
protos->len, handoffs->len);
for (i = 0; i < protos->len; i++) {
printf("void %s(void);\n", (char *)protos->pdata[i]);
}
printf("\n"
"dissector_reg_t dissector_reg_proto[] = {\n");
for (i = 0; i < protos->len; i++) {
printf(" { \"%s\", %s },\n", (char *)protos->pdata[i], (char *)protos->pdata[i]);
}
printf(" { NULL, NULL }\n"
"};\n"
"\n");
for (i = 0; i < handoffs->len; i++) {
printf("void %s(void);\n", (char *)handoffs->pdata[i]);
}
printf("\n"
"dissector_reg_t dissector_reg_handoff[] = {\n");
for (i = 0; i < handoffs->len; i++) {
printf(" { \"%s\", %s },\n", (char *)handoffs->pdata[i], (char *)handoffs->pdata[i]);
}
printf(" { NULL, NULL }\n"
"};\n");
g_regex_unref(protos_regex);
g_regex_unref(handoffs_regex);
g_ptr_array_free(protos, TRUE);
g_ptr_array_free(handoffs, TRUE);
}
/*
* Editor modelines
*
* Local Variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* ex: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -19,6 +19,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# TODO fix srvsvc wkssvc
set(PIDL_DISSECTOR_NAMES
atsvc
clusapi
@ -111,12 +112,6 @@ set(PIDL_DISSECTOR_wkssvc_EXTRA_DEPS
)
set(PIDL_DISSECTOR_TARGETS)
set(PIDL_DISSECTOR_SRC)
# TODO fix these dissectors, remove this and update PIDL_DISSECTOR_NAMES above.
list(APPEND PIDL_DISSECTOR_SRC
packet-dcerpc-srvsvc.c
packet-dcerpc-wkssvc.c
)
foreach(PROTOCOL_NAME IN LISTS PIDL_DISSECTOR_NAMES)
add_custom_command(
@ -148,13 +143,8 @@ foreach(PROTOCOL_NAME IN LISTS PIDL_DISSECTOR_NAMES)
list(APPEND PIDL_DISSECTOR_TARGETS
generate_dissector-dcerpc-${PROTOCOL_NAME}
)
list(APPEND PIDL_DISSECTOR_SRC
packet-dcerpc-${PROTOCOL_NAME}.c
)
endforeach()
set(PIDL_DISSECTOR_SRC ${PIDL_DISSECTOR_SRC} PARENT_SCOPE)
add_custom_target(pidl-dissectors ALL DEPENDS ${PIDL_DISSECTOR_TARGETS})
set_target_properties(pidl-dissectors
PROPERTIES FOLDER "Generated Dissectors/PIDL"

View File

@ -174,9 +174,9 @@ CPP_FILES = \
# a plugin.c file for a plugin.
# All subsequent arguments are the files to scan.
#
plugin.c: $(REGISTER_SRC_FILES) $(top_srcdir)/tools/make-dissector-reg.py
plugin.c: $(REGISTER_SRC_FILES) $(top_srcdir)/tools/make-plugin-reg.py
@echo Making plugin.c
@$(PYTHON) $(top_srcdir)/tools/make-dissector-reg.py $(srcdir) \
@$(PYTHON) $(top_srcdir)/tools/make-plugin-reg.py $(srcdir) \
plugin $(REGISTER_SRC_FILES)
checkapi:

View File

@ -29,7 +29,7 @@ static void set_cb_name(const char *proto) {
static void *
register_all_protocols_worker(void *arg _U_)
{
for (gulong i = 0; i < dissector_reg_proto_count(); i++) {
for (gulong i = 0; i < dissector_reg_proto_count; i++) {
set_cb_name(dissector_reg_proto[i].cb_name);
dissector_reg_proto[i].cb_func();
}
@ -67,7 +67,7 @@ register_all_protocols(register_cb cb, gpointer cb_data)
static void *
register_all_protocol_handoffs_worker(void *arg _U_)
{
for (gulong i = 0; i < dissector_reg_handoff_count(); i++) {
for (gulong i = 0; i < dissector_reg_handoff_count; i++) {
set_cb_name(dissector_reg_handoff[i].cb_name);
dissector_reg_handoff[i].cb_func();
}
@ -106,7 +106,7 @@ register_all_protocol_handoffs(register_cb cb, gpointer cb_data)
gulong register_count(void)
{
return dissector_reg_proto_count() + dissector_reg_handoff_count();
return dissector_reg_proto_count + dissector_reg_handoff_count;
}
/*

View File

@ -62,8 +62,8 @@ EXTRA_DIST = \
list_protos_in_cap.sh \
macos-setup.sh \
macos-setup-brew.sh \
make-dissector-reg.py \
make-manuf \
make-plugin-reg.py \
make-sminmpec.pl \
make-services.py \
make-tap-reg.py \

View File

@ -1,330 +0,0 @@
#!/usr/bin/env python
#
# Looks for registration routines in the protocol dissectors,
# and assembles C code to call all the routines.
#
# This is a Python version of the make-reg-dotc shell script.
# Running the shell script on Win32 is very very slow because of
# all the process-launching that goes on --- multiple greps and
# seds for each input file. I wrote this python version so that
# less processes would have to be started.
import os
import sys
import re
import pickle
import hashlib
from stat import *
VERSION_KEY = '_VERSION'
CUR_VERSION = 'this_is_useless_with_git'
#
# The first argument is the directory in which the source files live.
#
srcdir = sys.argv[1]
#
# The second argument is either "plugin" or "dissectors"; if it's
# "plugin", we build a plugin.c for a plugin, and if it's
# "dissectors", we build a register.c for libwireshark.
#
registertype = sys.argv[2]
if registertype in ("plugin", "plugin_wtap"):
final_filename = "plugin.c"
cache_filename = None
preamble = """\
/*
* Do not modify this file. Changes will be overwritten.
*
* Generated automatically from %s.
*/
""" % (sys.argv[0])
elif registertype in ("dissectors", "dissectorsinfile"):
final_filename = "dissectors.c"
cache_filename = "dissectors-cache.pkl"
preamble = """\
/*
* Do not modify this file. Changes will be overwritten.
*
* Generated automatically by the "register.c" target in
* epan/dissectors/Makefile using %s
* and information in epan/dissectors/register-cache.pkl.
*
* You can force this file to be regenerated completely by deleting
* it along with epan/dissectors/register-cache.pkl.
*/
""" % (sys.argv[0])
else:
print(("Unknown output type '%s'" % registertype))
sys.exit(1)
#
# All subsequent arguments are the files to scan
# or the name of a file containing the files to scan
#
if registertype == "dissectorsinfile":
try:
dissector_f = open(sys.argv[3])
except IOError:
print(("Unable to open input file '%s'" % sys.argv[3]))
sys.exit(1)
files = [line.rstrip() for line in dissector_f]
else:
files = sys.argv[3:]
# Create the proper list of filenames
filenames = []
for file in files:
if os.path.isfile(file):
filenames.append(file)
else:
filenames.append(os.path.join(srcdir, file))
if len(filenames) < 1:
print("No files found")
sys.exit(1)
# Look through all files, applying the regex to each line.
# If the pattern matches, save the "symbol" section to the
# appropriate set.
regs = {
'proto_reg': set(),
'handoff_reg': set(),
'wtap_register': set(),
}
# For those that don't know Python, r"" indicates a raw string,
# devoid of Python escapes.
proto_regex = r"(?P<symbol>\bproto_register_[_A-Za-z0-9]+)\s*\(\s*void\s*\)[^;]*$"
handoff_regex = r"(?P<symbol>\bproto_reg_handoff_[_A-Za-z0-9]+)\s*\(\s*void\s*\)[^;]*$"
wtap_reg_regex = r"(?P<symbol>\bwtap_register_[_A-Za-z0-9]+)\s*\([^;]+$"
# This table drives the pattern-matching and symbol-harvesting
patterns = [
( 'proto_reg', re.compile(proto_regex, re.MULTILINE) ),
( 'handoff_reg', re.compile(handoff_regex, re.MULTILINE) ),
( 'wtap_register', re.compile(wtap_reg_regex, re.MULTILINE) ),
]
# Open our registration symbol cache
cache = None
if cache_filename:
try:
cache_file = open(cache_filename, 'rb')
cache = pickle.load(cache_file)
cache_file.close()
if VERSION_KEY not in cache or cache[VERSION_KEY] != CUR_VERSION:
cache = {VERSION_KEY: CUR_VERSION}
except:
cache = {VERSION_KEY: CUR_VERSION}
print(("Registering %d files, %d cached" % (len(filenames), len(list(cache.keys()))-1)))
# Grep
cache_hits = 0
cache_misses = 0
for filename in filenames:
file = open(filename)
cur_mtime = os.fstat(file.fileno())[ST_MTIME]
if cache and filename in cache:
cdict = cache[filename]
if cur_mtime == cdict['mtime']:
cache_hits += 1
# print "Pulling %s from cache" % (filename)
regs['proto_reg'] |= set(cdict['proto_reg'])
regs['handoff_reg'] |= set(cdict['handoff_reg'])
regs['wtap_register'] |= set(cdict['wtap_register'])
file.close()
continue
# We don't have a cache entry
if cache is not None:
cache_misses += 1
cache[filename] = {
'mtime': cur_mtime,
'proto_reg': [],
'handoff_reg': [],
'wtap_register': [],
}
# print "Searching %s" % (filename)
# Read the whole file into memory
contents = file.read()
for action in patterns:
regex = action[1]
for match in regex.finditer(contents):
symbol = match.group("symbol")
sym_type = action[0]
regs[sym_type].add(symbol)
if cache is not None:
# print "Caching %s for %s: %s" % (sym_type, filename, symbol)
cache[filename][sym_type].append(symbol)
# We're done with the file contents
del contents
file.close()
if cache is not None and cache_filename is not None:
cache_file = open(cache_filename, 'wb')
pickle.dump(cache, cache_file)
cache_file.close()
print(("Cache hits: %d, misses: %d" % (cache_hits, cache_misses)))
# Make sure we actually processed something
if len(regs['proto_reg']) < 1:
print("No protocol registrations found")
sys.exit(1)
# Convert the sets into sorted lists to make the output pretty
regs['proto_reg'] = sorted(regs['proto_reg'])
regs['handoff_reg'] = sorted(regs['handoff_reg'])
regs['wtap_register'] = sorted(regs['wtap_register'])
reg_code = ""
reg_code += preamble
# Make the routine to register all protocols
if registertype == "plugin" or registertype == "plugin_wtap":
reg_code += """
#include "config.h"
#include <gmodule.h>
#include "moduleinfo.h"
/* plugins are DLLs */
#define WS_BUILD_DLL
#include "ws_symbol_export.h"
WS_DLL_PUBLIC_DEF void plugin_register (void);
WS_DLL_PUBLIC_DEF const gchar plugin_version[] = VERSION;
WS_DLL_PUBLIC_DEF const gchar plugin_release[] = VERSION_RELEASE;
"""
for symbol in regs['proto_reg']:
reg_code += "extern void %s(void);\n" % (symbol)
reg_code += """
WS_DLL_PUBLIC_DEF void
plugin_register (void)
{
"""
for symbol in regs['proto_reg']:
reg_code += " %s();\n" % (symbol)
reg_code += "}\n\n"
for symbol in regs['handoff_reg']:
reg_code += "extern void %s(void);\n" % (symbol)
reg_code += """
WS_DLL_PUBLIC_DEF void plugin_reg_handoff(void);
WS_DLL_PUBLIC_DEF void
plugin_reg_handoff(void)
{
"""
for symbol in regs['handoff_reg']:
reg_code += " %s();\n" % (symbol)
reg_code += "}\n"
if registertype == "plugin_wtap":
reg_code += """
WS_DLL_PUBLIC_DEF void
register_wtap_module(void)
{
"""
for symbol in regs['wtap_register']:
reg_code += " {extern void %s (void); %s ();}\n" % (symbol, symbol)
reg_code += """
}
"""
else:
reg_code += "\n#include <ws_symbol_export.h>"
reg_code += "\n#include <dissectors.h>"
reg_code += "\n"
for i in range(len(regs['proto_reg'])):
reg_code += "\nvoid %s(void);" % regs['proto_reg'][i]
reg_code += "\n\ndissector_reg_t dissector_reg_proto[] = {\n"
reg_code += " { \"%s\", %s }" % (regs['proto_reg'][0], regs['proto_reg'][0])
for i in range(1, len(regs['proto_reg'])):
reg_code += ",\n { \"%s\", %s }" % (regs['proto_reg'][i], regs['proto_reg'][i])
reg_code += "\n};\n"
for i in range(len(regs['handoff_reg'])):
reg_code += "\nvoid %s(void);" % regs['handoff_reg'][i]
reg_code += "\n\n\ndissector_reg_t dissector_reg_handoff[] = {\n"
reg_code += " { \"%s\", %s }" % (regs['handoff_reg'][0], regs['handoff_reg'][0])
for i in range(1, len(regs['handoff_reg'])):
reg_code += ",\n { \"%s\", %s }" % (regs['handoff_reg'][i], regs['handoff_reg'][i])
reg_code += "\n};\n"
reg_code += """
gulong dissector_reg_proto_count(void)
{
return %(proto_reg_len)d;
}
gulong dissector_reg_handoff_count(void)
{
return %(handoff_reg_len)d;
}
""" % {
'proto_reg_len': len(regs['proto_reg']),
'handoff_reg_len': len(regs['handoff_reg'])
}
# Compare current and new content and update the file if anything has changed.
try: # Python >= 2.6, >= 3.0
reg_code_bytes = bytes(reg_code.encode('utf-8'))
except:
reg_code_bytes = reg_code
new_hash = hashlib.sha1(reg_code_bytes).hexdigest()
try:
fh = open(final_filename, 'rb')
cur_hash = hashlib.sha1(fh.read()).hexdigest()
fh.close()
except:
cur_hash = ''
try:
if new_hash != cur_hash:
print(('Updating ' + final_filename))
fh = open(final_filename, 'w')
fh.write(reg_code)
fh.close()
else:
print((final_filename + ' unchanged.'))
except OSError:
sys.exit('Unable to write ' + final_filename + '.\n')
#
# Editor modelines - http://www.wireshark.org/tools/modelines.html
#
# Local variables:
# c-basic-offset: 4
# indent-tabs-mode: nil
# End:
#
# vi: set shiftwidth=4 expandtab:
# :indentSize=4:noTabs=true:
#

197
tools/make-plugin-reg.py Executable file
View File

@ -0,0 +1,197 @@
#!/usr/bin/env python
#
# Looks for registration routines in the plugin dissectors,
# and assembles C code to call all the routines.
#
import os
import sys
import re
import hashlib
from stat import *
#
# The first argument is the directory in which the source files live.
#
srcdir = sys.argv[1]
#
# The second argument is either "plugin" or "plugin_wtap".
#
registertype = sys.argv[2]
#
# All subsequent arguments are the files to scan.
#
files = sys.argv[3:]
final_filename = "plugin.c"
preamble = """\
/*
* Do not modify this file. Changes will be overwritten.
*
* Generated automatically from %s.
*/
""" % (sys.argv[0])
# Create the proper list of filenames
filenames = []
for file in files:
if os.path.isfile(file):
filenames.append(file)
else:
filenames.append(os.path.join(srcdir, file))
if len(filenames) < 1:
print("No files found")
sys.exit(1)
# Look through all files, applying the regex to each line.
# If the pattern matches, save the "symbol" section to the
# appropriate set.
regs = {
'proto_reg': set(),
'handoff_reg': set(),
'wtap_register': set(),
}
# For those that don't know Python, r"" indicates a raw string,
# devoid of Python escapes.
proto_regex = r"(?P<symbol>\bproto_register_[_A-Za-z0-9]+)\s*\(\s*void\s*\)[^;]*$"
handoff_regex = r"(?P<symbol>\bproto_reg_handoff_[_A-Za-z0-9]+)\s*\(\s*void\s*\)[^;]*$"
wtap_reg_regex = r"(?P<symbol>\bwtap_register_[_A-Za-z0-9]+)\s*\([^;]+$"
# This table drives the pattern-matching and symbol-harvesting
patterns = [
( 'proto_reg', re.compile(proto_regex, re.MULTILINE) ),
( 'handoff_reg', re.compile(handoff_regex, re.MULTILINE) ),
( 'wtap_register', re.compile(wtap_reg_regex, re.MULTILINE) ),
]
# Grep
for filename in filenames:
file = open(filename)
cur_mtime = os.fstat(file.fileno())[ST_MTIME]
# Read the whole file into memory
contents = file.read()
for action in patterns:
regex = action[1]
for match in regex.finditer(contents):
symbol = match.group("symbol")
sym_type = action[0]
regs[sym_type].add(symbol)
# We're done with the file contents
del contents
file.close()
# Make sure we actually processed something
if len(regs['proto_reg']) < 1:
print("No protocol registrations found")
sys.exit(1)
# Convert the sets into sorted lists to make the output pretty
regs['proto_reg'] = sorted(regs['proto_reg'])
regs['handoff_reg'] = sorted(regs['handoff_reg'])
regs['wtap_register'] = sorted(regs['wtap_register'])
reg_code = ""
reg_code += preamble
reg_code += """
#include "config.h"
#include <gmodule.h>
#include "moduleinfo.h"
/* plugins are DLLs */
#define WS_BUILD_DLL
#include "ws_symbol_export.h"
WS_DLL_PUBLIC_DEF void plugin_register (void);
WS_DLL_PUBLIC_DEF const gchar plugin_version[] = VERSION;
WS_DLL_PUBLIC_DEF const gchar plugin_release[] = VERSION_RELEASE;
"""
for symbol in regs['proto_reg']:
reg_code += "extern void %s(void);\n" % (symbol)
reg_code += """
WS_DLL_PUBLIC_DEF void
plugin_register (void)
{
"""
for symbol in regs['proto_reg']:
reg_code += " %s();\n" % (symbol)
reg_code += "}\n\n"
for symbol in regs['handoff_reg']:
reg_code += "extern void %s(void);\n" % (symbol)
reg_code += """
WS_DLL_PUBLIC_DEF void plugin_reg_handoff(void);
WS_DLL_PUBLIC_DEF void
plugin_reg_handoff(void)
{
"""
for symbol in regs['handoff_reg']:
reg_code += " %s();\n" % (symbol)
reg_code += "}\n"
if registertype == "plugin_wtap":
reg_code += """
WS_DLL_PUBLIC_DEF void
register_wtap_module(void)
{
"""
for symbol in regs['wtap_register']:
reg_code += " {extern void %s (void); %s ();}\n" % (symbol, symbol)
reg_code += "}"
# Compare current and new content and update the file if anything has changed.
try: # Python >= 2.6, >= 3.0
reg_code_bytes = bytes(reg_code.encode('utf-8'))
except:
reg_code_bytes = reg_code
new_hash = hashlib.sha1(reg_code_bytes).hexdigest()
try:
fh = open(final_filename, 'rb')
cur_hash = hashlib.sha1(fh.read()).hexdigest()
fh.close()
except:
cur_hash = ''
try:
if new_hash != cur_hash:
print(('Updating ' + final_filename))
fh = open(final_filename, 'w')
fh.write(reg_code)
fh.close()
else:
print((final_filename + ' unchanged.'))
except OSError:
sys.exit('Unable to write ' + final_filename + '.\n')
#
# Editor modelines - http://www.wireshark.org/tools/modelines.html
#
# Local variables:
# c-basic-offset: 4
# indent-tabs-mode: nil
# End:
#
# vi: set shiftwidth=4 expandtab:
# :indentSize=4:noTabs=true:
#