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