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