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