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