xref: /libbtbb/wireshark/plugins/btbredr/tools/make-dissector-reg.py (revision 4cc286f39977de0d2c7d8305e14882bbf313e363)
1*4cc286f3SDominic Spill#!/usr/bin/env python
2*4cc286f3SDominic Spill#
3*4cc286f3SDominic Spill# Looks for registration routines in the protocol dissectors,
4*4cc286f3SDominic Spill# and assembles C code to call all the routines.
5*4cc286f3SDominic Spill#
6*4cc286f3SDominic Spill# This is a Python version of the make-reg-dotc shell script.
7*4cc286f3SDominic Spill# Running the shell script on Win32 is very very slow because of
8*4cc286f3SDominic Spill# all the process-launching that goes on --- multiple greps and
9*4cc286f3SDominic Spill# seds for each input file.  I wrote this python version so that
10*4cc286f3SDominic Spill# less processes would have to be started.
11*4cc286f3SDominic Spill#
12*4cc286f3SDominic Spill# $Id: make-dissector-reg.py 40736 2012-01-26 21:38:53Z gerald $
13*4cc286f3SDominic Spill
14*4cc286f3SDominic Spillimport os
15*4cc286f3SDominic Spillimport sys
16*4cc286f3SDominic Spillimport re
17*4cc286f3SDominic Spillimport pickle
18*4cc286f3SDominic Spillfrom stat import *
19*4cc286f3SDominic Spill
20*4cc286f3SDominic SpillVERSION_KEY = '_VERSION'
21*4cc286f3SDominic SpillCUR_VERSION = '$Id: make-dissector-reg.py 40736 2012-01-26 21:38:53Z gerald $'
22*4cc286f3SDominic Spill
23*4cc286f3SDominic Spill#
24*4cc286f3SDominic Spill# The first argument is the directory in which the source files live.
25*4cc286f3SDominic Spill#
26*4cc286f3SDominic Spillsrcdir = sys.argv[1]
27*4cc286f3SDominic Spill
28*4cc286f3SDominic Spill#
29*4cc286f3SDominic Spill# The second argument is either "plugin" or "dissectors"; if it's
30*4cc286f3SDominic Spill# "plugin", we build a plugin.c for a plugin, and if it's
31*4cc286f3SDominic Spill# "dissectors", we build a register.c for libwireshark.
32*4cc286f3SDominic Spill#
33*4cc286f3SDominic Spillregistertype = sys.argv[2]
34*4cc286f3SDominic Spillif registertype == "plugin" or registertype == "plugin_wtap":
35*4cc286f3SDominic Spill	tmp_filename = "plugin.c-tmp"
36*4cc286f3SDominic Spill	final_filename = "plugin.c"
37*4cc286f3SDominic Spill	cache_filename = None
38*4cc286f3SDominic Spill	preamble = """\
39*4cc286f3SDominic Spill/*
40*4cc286f3SDominic Spill * Do not modify this file.
41*4cc286f3SDominic Spill *
42*4cc286f3SDominic Spill * It is created automatically by Makefile or Makefile.nmake.
43*4cc286f3SDominic Spill */
44*4cc286f3SDominic Spill"""
45*4cc286f3SDominic Spillelif registertype == "dissectors":
46*4cc286f3SDominic Spill	tmp_filename = "register.c-tmp"
47*4cc286f3SDominic Spill	final_filename = "register.c"
48*4cc286f3SDominic Spill	cache_filename = "register-cache.pkl"
49*4cc286f3SDominic Spill	preamble = """\
50*4cc286f3SDominic Spill/*
51*4cc286f3SDominic Spill * Do not modify this file.
52*4cc286f3SDominic Spill *
53*4cc286f3SDominic Spill * It is created automatically by the "register.c" target in
54*4cc286f3SDominic Spill * epan/dissectors/Makefile or Makefile.nmake using information in
55*4cc286f3SDominic Spill * epan/dissectors/register-cache.pkl.
56*4cc286f3SDominic Spill *
57*4cc286f3SDominic Spill * You can force this file to be regenerated completely by deleting
58*4cc286f3SDominic Spill * it along with epan/dissectors/register-cache.pkl.
59*4cc286f3SDominic Spill */
60*4cc286f3SDominic Spill"""
61*4cc286f3SDominic Spillelse:
62*4cc286f3SDominic Spill	print(("Unknown output type '%s'" % registertype))
63*4cc286f3SDominic Spill	sys.exit(1)
64*4cc286f3SDominic Spill
65*4cc286f3SDominic Spill
66*4cc286f3SDominic Spill#
67*4cc286f3SDominic Spill# All subsequent arguments are the files to scan.
68*4cc286f3SDominic Spill#
69*4cc286f3SDominic Spillfiles = sys.argv[3:]
70*4cc286f3SDominic Spill
71*4cc286f3SDominic Spill# Create the proper list of filenames
72*4cc286f3SDominic Spillfilenames = []
73*4cc286f3SDominic Spillfor file in files:
74*4cc286f3SDominic Spill	if os.path.isfile(file):
75*4cc286f3SDominic Spill		filenames.append(file)
76*4cc286f3SDominic Spill	else:
77*4cc286f3SDominic Spill		filenames.append(os.path.join(srcdir, file))
78*4cc286f3SDominic Spill
79*4cc286f3SDominic Spillif len(filenames) < 1:
80*4cc286f3SDominic Spill	print("No files found")
81*4cc286f3SDominic Spill	sys.exit(1)
82*4cc286f3SDominic Spill
83*4cc286f3SDominic Spill
84*4cc286f3SDominic Spill# Look through all files, applying the regex to each line.
85*4cc286f3SDominic Spill# If the pattern matches, save the "symbol" section to the
86*4cc286f3SDominic Spill# appropriate array.
87*4cc286f3SDominic Spillregs = {
88*4cc286f3SDominic Spill	'proto_reg': [],
89*4cc286f3SDominic Spill	'handoff_reg': [],
90*4cc286f3SDominic Spill	'wtap_register': [],
91*4cc286f3SDominic Spill	}
92*4cc286f3SDominic Spill
93*4cc286f3SDominic Spill# For those that don't know Python, r"" indicates a raw string,
94*4cc286f3SDominic Spill# devoid of Python escapes.
95*4cc286f3SDominic Spillproto_regex0 = r"^(?P<symbol>proto_register_[_A-Za-z0-9]+)\s*\([^;]+$"
96*4cc286f3SDominic Spillproto_regex1 = r"void\s+(?P<symbol>proto_register_[_A-Za-z0-9]+)\s*\([^;]+$"
97*4cc286f3SDominic Spill
98*4cc286f3SDominic Spillhandoff_regex0 = r"^(?P<symbol>proto_reg_handoff_[_A-Za-z0-9]+)\s*\([^;]+$"
99*4cc286f3SDominic Spillhandoff_regex1 = r"void\s+(?P<symbol>proto_reg_handoff_[_A-Za-z0-9]+)\s*\([^;]+$"
100*4cc286f3SDominic Spill
101*4cc286f3SDominic Spillwtap_reg_regex0 = r"^(?P<symbol>wtap_register_[_A-Za-z0-9]+)\s*\([^;]+$"
102*4cc286f3SDominic Spillwtap_reg_regex1 = r"void\s+(?P<symbol>wtap_register_[_A-Za-z0-9]+)\s*\([^;]+$"
103*4cc286f3SDominic Spill
104*4cc286f3SDominic Spill# This table drives the pattern-matching and symbol-harvesting
105*4cc286f3SDominic Spillpatterns = [
106*4cc286f3SDominic Spill	( 'proto_reg', re.compile(proto_regex0) ),
107*4cc286f3SDominic Spill	( 'proto_reg', re.compile(proto_regex1) ),
108*4cc286f3SDominic Spill	( 'handoff_reg', re.compile(handoff_regex0) ),
109*4cc286f3SDominic Spill	( 'handoff_reg', re.compile(handoff_regex1) ),
110*4cc286f3SDominic Spill	( 'wtap_register', re.compile(wtap_reg_regex0) ),
111*4cc286f3SDominic Spill	( 'wtap_register', re.compile(wtap_reg_regex1) ),
112*4cc286f3SDominic Spill	]
113*4cc286f3SDominic Spill
114*4cc286f3SDominic Spill# Open our registration symbol cache
115*4cc286f3SDominic Spillcache = None
116*4cc286f3SDominic Spillif cache_filename:
117*4cc286f3SDominic Spill	try:
118*4cc286f3SDominic Spill		cache_file = open(cache_filename, 'rb')
119*4cc286f3SDominic Spill		cache = pickle.load(cache_file)
120*4cc286f3SDominic Spill		cache_file.close()
121*4cc286f3SDominic Spill		if VERSION_KEY not in cache or cache[VERSION_KEY] != CUR_VERSION:
122*4cc286f3SDominic Spill			cache = {VERSION_KEY: CUR_VERSION}
123*4cc286f3SDominic Spill	except:
124*4cc286f3SDominic Spill		cache = {VERSION_KEY: CUR_VERSION}
125*4cc286f3SDominic Spill
126*4cc286f3SDominic Spill	print(("Registering %d files, %d cached" % (len(filenames), len(list(cache.keys()))-1)))
127*4cc286f3SDominic Spill
128*4cc286f3SDominic Spill# Grep
129*4cc286f3SDominic Spillcache_hits = 0
130*4cc286f3SDominic Spillcache_misses = 0
131*4cc286f3SDominic Spillfor filename in filenames:
132*4cc286f3SDominic Spill	file = open(filename)
133*4cc286f3SDominic Spill	cur_mtime = os.fstat(file.fileno())[ST_MTIME]
134*4cc286f3SDominic Spill	if cache and filename in cache:
135*4cc286f3SDominic Spill		cdict = cache[filename]
136*4cc286f3SDominic Spill		if cur_mtime == cdict['mtime']:
137*4cc286f3SDominic Spill			cache_hits += 1
138*4cc286f3SDominic Spill#			print "Pulling %s from cache" % (filename)
139*4cc286f3SDominic Spill			regs['proto_reg'].extend(cdict['proto_reg'])
140*4cc286f3SDominic Spill			regs['handoff_reg'].extend(cdict['handoff_reg'])
141*4cc286f3SDominic Spill			regs['wtap_register'].extend(cdict['wtap_register'])
142*4cc286f3SDominic Spill			file.close()
143*4cc286f3SDominic Spill			continue
144*4cc286f3SDominic Spill	# We don't have a cache entry
145*4cc286f3SDominic Spill	if cache is not None:
146*4cc286f3SDominic Spill		cache_misses += 1
147*4cc286f3SDominic Spill		cache[filename] = {
148*4cc286f3SDominic Spill			'mtime': cur_mtime,
149*4cc286f3SDominic Spill			'proto_reg': [],
150*4cc286f3SDominic Spill			'handoff_reg': [],
151*4cc286f3SDominic Spill			'wtap_register': [],
152*4cc286f3SDominic Spill			}
153*4cc286f3SDominic Spill#	print "Searching %s" % (filename)
154*4cc286f3SDominic Spill	for line in file.readlines():
155*4cc286f3SDominic Spill		for action in patterns:
156*4cc286f3SDominic Spill			regex = action[1]
157*4cc286f3SDominic Spill			match = regex.search(line)
158*4cc286f3SDominic Spill			if match:
159*4cc286f3SDominic Spill				symbol = match.group("symbol")
160*4cc286f3SDominic Spill				sym_type = action[0]
161*4cc286f3SDominic Spill				regs[sym_type].append(symbol)
162*4cc286f3SDominic Spill				if cache is not None:
163*4cc286f3SDominic Spill#					print "Caching %s for %s: %s" % (sym_type, filename, symbol)
164*4cc286f3SDominic Spill					cache[filename][sym_type].append(symbol)
165*4cc286f3SDominic Spill	file.close()
166*4cc286f3SDominic Spill
167*4cc286f3SDominic Spill
168*4cc286f3SDominic Spillif cache is not None and cache_filename is not None:
169*4cc286f3SDominic Spill	cache_file = open(cache_filename, 'wb')
170*4cc286f3SDominic Spill	pickle.dump(cache, cache_file)
171*4cc286f3SDominic Spill	cache_file.close()
172*4cc286f3SDominic Spill	print(("Cache hits: %d, misses: %d" % (cache_hits, cache_misses)))
173*4cc286f3SDominic Spill
174*4cc286f3SDominic Spill# Make sure we actually processed something
175*4cc286f3SDominic Spillif len(regs['proto_reg']) < 1:
176*4cc286f3SDominic Spill	print("No protocol registrations found")
177*4cc286f3SDominic Spill	sys.exit(1)
178*4cc286f3SDominic Spill
179*4cc286f3SDominic Spill# Sort the lists to make them pretty
180*4cc286f3SDominic Spillregs['proto_reg'].sort()
181*4cc286f3SDominic Spillregs['handoff_reg'].sort()
182*4cc286f3SDominic Spillregs['wtap_register'].sort()
183*4cc286f3SDominic Spill
184*4cc286f3SDominic Spillreg_code = open(tmp_filename, "w")
185*4cc286f3SDominic Spill
186*4cc286f3SDominic Spillreg_code.write(preamble)
187*4cc286f3SDominic Spill
188*4cc286f3SDominic Spill# Make the routine to register all protocols
189*4cc286f3SDominic Spillif registertype == "plugin" or registertype == "plugin_wtap":
190*4cc286f3SDominic Spill	reg_code.write("""
191*4cc286f3SDominic Spill#ifdef HAVE_CONFIG_H
192*4cc286f3SDominic Spill# include "config.h"
193*4cc286f3SDominic Spill#endif
194*4cc286f3SDominic Spill
195*4cc286f3SDominic Spill#include <gmodule.h>
196*4cc286f3SDominic Spill
197*4cc286f3SDominic Spill#include "moduleinfo.h"
198*4cc286f3SDominic Spill
199*4cc286f3SDominic Spill#ifndef ENABLE_STATIC
200*4cc286f3SDominic SpillG_MODULE_EXPORT const gchar version[] = VERSION;
201*4cc286f3SDominic Spill
202*4cc286f3SDominic Spill/* Start the functions we need for the plugin stuff */
203*4cc286f3SDominic Spill
204*4cc286f3SDominic SpillG_MODULE_EXPORT void
205*4cc286f3SDominic Spillplugin_register (void)
206*4cc286f3SDominic Spill{
207*4cc286f3SDominic Spill""");
208*4cc286f3SDominic Spillelse:
209*4cc286f3SDominic Spill	reg_code.write("""
210*4cc286f3SDominic Spill#include "register.h"
211*4cc286f3SDominic Spillvoid
212*4cc286f3SDominic Spillregister_all_protocols(register_cb cb, gpointer client_data)
213*4cc286f3SDominic Spill{
214*4cc286f3SDominic Spill""");
215*4cc286f3SDominic Spill
216*4cc286f3SDominic Spillfor symbol in regs['proto_reg']:
217*4cc286f3SDominic Spill	if registertype == "plugin" or registertype == "plugin_wtap":
218*4cc286f3SDominic Spill		line = "  {extern void %s (void); %s ();}\n" % (symbol, symbol)
219*4cc286f3SDominic Spill	else:
220*4cc286f3SDominic Spill		line = "  {extern void %s (void); if(cb) (*cb)(RA_REGISTER, \"%s\", client_data); %s ();}\n" % (symbol, symbol, symbol)
221*4cc286f3SDominic Spill	reg_code.write(line)
222*4cc286f3SDominic Spill
223*4cc286f3SDominic Spillreg_code.write("}\n")
224*4cc286f3SDominic Spill
225*4cc286f3SDominic Spill
226*4cc286f3SDominic Spill# Make the routine to register all protocol handoffs
227*4cc286f3SDominic Spillif registertype == "plugin" or registertype == "plugin_wtap":
228*4cc286f3SDominic Spill	reg_code.write("""
229*4cc286f3SDominic SpillG_MODULE_EXPORT void
230*4cc286f3SDominic Spillplugin_reg_handoff(void)
231*4cc286f3SDominic Spill{
232*4cc286f3SDominic Spill""");
233*4cc286f3SDominic Spillelse:
234*4cc286f3SDominic Spill	reg_code.write("""
235*4cc286f3SDominic Spillvoid
236*4cc286f3SDominic Spillregister_all_protocol_handoffs(register_cb cb, gpointer client_data)
237*4cc286f3SDominic Spill{
238*4cc286f3SDominic Spill""");
239*4cc286f3SDominic Spill
240*4cc286f3SDominic Spillfor symbol in regs['handoff_reg']:
241*4cc286f3SDominic Spill	if registertype == "plugin" or registertype == "plugin_wtap":
242*4cc286f3SDominic Spill		line = "  {extern void %s (void); %s ();}\n" % (symbol, symbol)
243*4cc286f3SDominic Spill	else:
244*4cc286f3SDominic Spill		line = "  {extern void %s (void); if(cb) (*cb)(RA_HANDOFF, \"%s\", client_data); %s ();}\n" % (symbol, symbol, symbol)
245*4cc286f3SDominic Spill	reg_code.write(line)
246*4cc286f3SDominic Spill
247*4cc286f3SDominic Spillreg_code.write("}\n")
248*4cc286f3SDominic Spill
249*4cc286f3SDominic Spillif registertype == "plugin":
250*4cc286f3SDominic Spill	reg_code.write("#endif\n");
251*4cc286f3SDominic Spillelif registertype == "plugin_wtap":
252*4cc286f3SDominic Spill	reg_code.write("""
253*4cc286f3SDominic SpillG_MODULE_EXPORT void
254*4cc286f3SDominic Spillregister_wtap_module(void)
255*4cc286f3SDominic Spill{
256*4cc286f3SDominic Spill""");
257*4cc286f3SDominic Spill
258*4cc286f3SDominic Spill	for symbol in regs['wtap_register']:
259*4cc286f3SDominic Spill		line = "  {extern void %s (void); %s ();}\n" % (symbol, symbol)
260*4cc286f3SDominic Spill		reg_code.write(line)
261*4cc286f3SDominic Spill
262*4cc286f3SDominic Spill	reg_code.write("}\n");
263*4cc286f3SDominic Spill	reg_code.write("#endif\n");
264*4cc286f3SDominic Spillelse:
265*4cc286f3SDominic Spill	reg_code.write("""
266*4cc286f3SDominic Spillstatic gulong proto_reg_count(void)
267*4cc286f3SDominic Spill{
268*4cc286f3SDominic Spill""");
269*4cc286f3SDominic Spill
270*4cc286f3SDominic Spill	line = "  return %d;\n" % len(regs['proto_reg'])
271*4cc286f3SDominic Spill	reg_code.write(line)
272*4cc286f3SDominic Spill
273*4cc286f3SDominic Spill	reg_code.write("""
274*4cc286f3SDominic Spill}
275*4cc286f3SDominic Spill""");
276*4cc286f3SDominic Spill	reg_code.write("""
277*4cc286f3SDominic Spillstatic gulong handoff_reg_count(void)
278*4cc286f3SDominic Spill{
279*4cc286f3SDominic Spill""");
280*4cc286f3SDominic Spill
281*4cc286f3SDominic Spill	line = "  return %d;\n" % len(regs['handoff_reg'])
282*4cc286f3SDominic Spill	reg_code.write(line)
283*4cc286f3SDominic Spill
284*4cc286f3SDominic Spill	reg_code.write("""
285*4cc286f3SDominic Spill}
286*4cc286f3SDominic Spill""");
287*4cc286f3SDominic Spill	reg_code.write("""
288*4cc286f3SDominic Spillgulong register_count(void)
289*4cc286f3SDominic Spill{
290*4cc286f3SDominic Spill""");
291*4cc286f3SDominic Spill
292*4cc286f3SDominic Spill	line = "  return proto_reg_count() + handoff_reg_count();"
293*4cc286f3SDominic Spill	reg_code.write(line)
294*4cc286f3SDominic Spill
295*4cc286f3SDominic Spill	reg_code.write("""
296*4cc286f3SDominic Spill}\n
297*4cc286f3SDominic Spill""");
298*4cc286f3SDominic Spill
299*4cc286f3SDominic Spill
300*4cc286f3SDominic Spill# Close the file
301*4cc286f3SDominic Spillreg_code.close()
302*4cc286f3SDominic Spill
303*4cc286f3SDominic Spill# Remove the old final_file if it exists.
304*4cc286f3SDominic Spilltry:
305*4cc286f3SDominic Spill	os.stat(final_filename)
306*4cc286f3SDominic Spill	os.remove(final_filename)
307*4cc286f3SDominic Spillexcept OSError:
308*4cc286f3SDominic Spill	pass
309*4cc286f3SDominic Spill
310*4cc286f3SDominic Spill# Move from tmp file to final file
311*4cc286f3SDominic Spillos.rename(tmp_filename, final_filename)
312