MIT krb5-1.6 HACK patch
[metze/wireshark/wip.git] / tools / make-dissector-reg.py
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$
13
14 import os
15 import sys
16 import re
17 import pickle
18 import hashlib
19 from stat import *
20
21 VERSION_KEY = '_VERSION'
22 CUR_VERSION = '$Id$'
23
24 #
25 # The first argument is the directory in which the source files live.
26 #
27 srcdir = sys.argv[1]
28
29 #
30 # The second argument is either "plugin" or "dissectors"; if it's
31 # "plugin", we build a plugin.c for a plugin, and if it's
32 # "dissectors", we build a register.c for libwireshark.
33 #
34 registertype = sys.argv[2]
35 if registertype in ("plugin", "plugin_wtap"):
36     final_filename = "plugin.c"
37     cache_filename = None
38     preamble = """\
39 /*
40  * Do not modify this file. Changes will be overwritten.
41  *
42  * Generated automatically from %s.
43  */
44 """ % (sys.argv[0])
45 elif registertype in ("dissectors", "dissectorsinfile"):
46     final_filename = "register.c"
47     cache_filename = "register-cache.pkl"
48     preamble = """\
49 /*
50  * Do not modify this file. Changes will be overwritten.
51  *
52  * Generated automatically by the "register.c" target in
53  * epan/dissectors/Makefile or Makefile.nmake using
54  * %s
55  * and information in 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 """ % (sys.argv[0])
61 else:
62     print(("Unknown output type '%s'" % registertype))
63     sys.exit(1)
64
65
66 #
67 # All subsequent arguments are the files to scan
68 # or the name of a file containing the files to scan
69 #
70 if registertype == "dissectorsinfile":
71     try:
72         dissector_f = open(sys.argv[3])
73     except IOError:
74         print(("Unable to open input file '%s'" % sys.argv[3]))
75         sys.exit(1)
76
77     files = [line.rstrip() for line in dissector_f]
78 else:
79     files = sys.argv[3:]
80
81 # Create the proper list of filenames
82 filenames = []
83 for file in files:
84     if os.path.isfile(file):
85         filenames.append(file)
86     else:
87         filenames.append(os.path.join(srcdir, file))
88
89 if len(filenames) < 1:
90     print("No files found")
91     sys.exit(1)
92
93
94 # Look through all files, applying the regex to each line.
95 # If the pattern matches, save the "symbol" section to the
96 # appropriate set.
97 regs = {
98         'proto_reg': set(),
99         'handoff_reg': set(),
100         'wtap_register': set(),
101         }
102
103 # For those that don't know Python, r"" indicates a raw string,
104 # devoid of Python escapes.
105 proto_regex = r"(?P<symbol>proto_register_[_A-Za-z0-9]+)\s*\(\s*void\s*\)[^;]*$"
106
107 handoff_regex = r"(?P<symbol>proto_reg_handoff_[_A-Za-z0-9]+)\s*\(\s*void\s*\)[^;]*$"
108
109 wtap_reg_regex = r"(?P<symbol>wtap_register_[_A-Za-z0-9]+)\s*\([^;]+$"
110
111 # This table drives the pattern-matching and symbol-harvesting
112 patterns = [
113         ( 'proto_reg', re.compile(proto_regex, re.MULTILINE) ),
114         ( 'handoff_reg', re.compile(handoff_regex, re.MULTILINE) ),
115         ( 'wtap_register', re.compile(wtap_reg_regex, re.MULTILINE) ),
116         ]
117
118 # Open our registration symbol cache
119 cache = None
120 if cache_filename:
121     try:
122         cache_file = open(cache_filename, 'rb')
123         cache = pickle.load(cache_file)
124         cache_file.close()
125         if VERSION_KEY not in cache or cache[VERSION_KEY] != CUR_VERSION:
126             cache = {VERSION_KEY: CUR_VERSION}
127     except:
128         cache = {VERSION_KEY: CUR_VERSION}
129
130     print(("Registering %d files, %d cached" % (len(filenames), len(list(cache.keys()))-1)))
131
132 # Grep
133 cache_hits = 0
134 cache_misses = 0
135 for filename in filenames:
136     file = open(filename)
137     cur_mtime = os.fstat(file.fileno())[ST_MTIME]
138     if cache and filename in cache:
139         cdict = cache[filename]
140         if cur_mtime == cdict['mtime']:
141             cache_hits += 1
142 #                       print "Pulling %s from cache" % (filename)
143             regs['proto_reg'] |= set(cdict['proto_reg'])
144             regs['handoff_reg'] |= set(cdict['handoff_reg'])
145             regs['wtap_register'] |= set(cdict['wtap_register'])
146             file.close()
147             continue
148     # We don't have a cache entry
149     if cache is not None:
150         cache_misses += 1
151         cache[filename] = {
152                 'mtime': cur_mtime,
153                 'proto_reg': [],
154                 'handoff_reg': [],
155                 'wtap_register': [],
156                 }
157 #       print "Searching %s" % (filename)
158     # Read the whole file into memory
159     contents = file.read()
160     for action in patterns:
161         regex = action[1]
162         for match in regex.finditer(contents):
163             symbol = match.group("symbol")
164             sym_type = action[0]
165             regs[sym_type].add(symbol)
166             if cache is not None:
167 #                               print "Caching %s for %s: %s" % (sym_type, filename, symbol)
168                 cache[filename][sym_type].append(symbol)
169     # We're done with the file contents
170     contets = ""
171     file.close()
172
173
174 if cache is not None and cache_filename is not None:
175     cache_file = open(cache_filename, 'wb')
176     pickle.dump(cache, cache_file)
177     cache_file.close()
178     print(("Cache hits: %d, misses: %d" % (cache_hits, cache_misses)))
179
180 # Make sure we actually processed something
181 if len(regs['proto_reg']) < 1:
182     print("No protocol registrations found")
183     sys.exit(1)
184
185 # Convert the sets into sorted lists to make the output pretty
186 regs['proto_reg'] = sorted(regs['proto_reg'])
187 regs['handoff_reg'] = sorted(regs['handoff_reg'])
188 regs['wtap_register'] = sorted(regs['wtap_register'])
189
190 reg_code = ""
191
192 reg_code += preamble
193
194 # Make the routine to register all protocols
195 if registertype == "plugin" or registertype == "plugin_wtap":
196     reg_code += """
197 #include "config.h"
198
199 #include <gmodule.h>
200
201 #include "moduleinfo.h"
202
203 /* plugins are DLLs */
204 #define WS_BUILD_DLL
205 #include "ws_symbol_export.h"
206
207 #ifndef ENABLE_STATIC
208 WS_DLL_PUBLIC_DEF void plugin_register (void);
209 WS_DLL_PUBLIC_DEF const gchar version[] = VERSION;
210
211 /* Start the functions we need for the plugin stuff */
212
213 WS_DLL_PUBLIC_DEF void
214 plugin_register (void)
215 {
216 """
217 else:
218     reg_code += """
219 #include "register.h"
220 void
221 register_all_protocols(register_cb cb, gpointer client_data)
222 {
223 """
224
225 for symbol in regs['proto_reg']:
226     if registertype == "plugin" or registertype == "plugin_wtap":
227         reg_code += "    {extern void %s (void); %s ();}\n" % (symbol, symbol)
228     else:
229         reg_code += "    {extern void %s (void); if(cb) (*cb)(RA_REGISTER, \"%s\", client_data); %s ();}\n" % (symbol, symbol, symbol)
230
231 reg_code += "}\n"
232
233
234 # Make the routine to register all protocol handoffs
235 if registertype == "plugin" or registertype == "plugin_wtap":
236     reg_code += """
237 WS_DLL_PUBLIC_DEF void plugin_reg_handoff(void);
238
239 WS_DLL_PUBLIC_DEF void
240 plugin_reg_handoff(void)
241 {
242 """
243 else:
244     reg_code += """
245 void
246 register_all_protocol_handoffs(register_cb cb, gpointer client_data)
247 {
248 """
249
250 for symbol in regs['handoff_reg']:
251     if registertype == "plugin" or registertype == "plugin_wtap":
252         reg_code += "    {extern void %s (void); %s ();}\n" % (symbol, symbol)
253     else:
254         reg_code += "    {extern void %s (void); if(cb) (*cb)(RA_HANDOFF, \"%s\", client_data); %s ();}\n" % (symbol, symbol, symbol)
255
256 reg_code += "}\n"
257
258 if registertype == "plugin":
259     reg_code += "#endif\n"
260 elif registertype == "plugin_wtap":
261     reg_code += """
262 WS_DLL_PUBLIC_DEF void
263 register_wtap_module(void)
264 {
265 """
266
267     for symbol in regs['wtap_register']:
268         line = "    {extern void %s (void); %s ();}\n" % (symbol, symbol)
269         reg_code += line
270
271     reg_code += """
272 }
273 #endif
274 """
275
276 else:
277     reg_code += """
278 static gulong proto_reg_count(void)
279 {
280     return %(proto_reg_len)d;
281 }
282
283 static gulong handoff_reg_count(void)
284 {
285     return %(handoff_reg_len)d;
286 }
287
288 gulong register_count(void)
289 {
290     return proto_reg_count() + handoff_reg_count();
291 }
292
293 """ % {
294     'proto_reg_len': len(regs['proto_reg']),
295     'handoff_reg_len': len(regs['handoff_reg'])
296   }
297
298
299 # Compare current and new content and update the file if anything has changed.
300
301 try:    # Python >= 2.6, >= 3.0
302     reg_code_bytes = bytes(reg_code.encode('utf-8'))
303 except:
304     reg_code_bytes = reg_code
305
306 new_hash = hashlib.sha1(reg_code_bytes).hexdigest()
307
308 try:
309     fh = open(final_filename, 'rb')
310     cur_hash = hashlib.sha1(fh.read()).hexdigest()
311     fh.close()
312 except:
313     cur_hash = ''
314
315 try:
316     if new_hash != cur_hash:
317         print(('Updating ' + final_filename))
318         fh = open(final_filename, 'w')
319         fh.write(reg_code)
320         fh.close()
321     else:
322         print((final_filename + ' unchanged.'))
323         os.utime(final_filename, None)
324 except OSError:
325     sys.exit('Unable to write ' + final_filename + '.\n')
326
327 #
328 # Editor modelines  -  http://www.wireshark.org/tools/modelines.html
329 #
330 # Local variables:
331 # c-basic-offset: 4
332 # indent-tabs-mode: nil
333 # End:
334 #
335 # vi: set shiftwidth=4 expandtab:
336 # :indentSize=4:noTabs=true:
337 #