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