regen pidl all: rm epan/dissectors/pidl/*-stamp; pushd epan/dissectors/pidl/ && make...
[wireshark-sm.git] / epan / wslua / make-taps.py
blob1cc3cfc4a47a45a0b810d0ab4f13942a2f25e788
1 #!/usr/bin/env python3
3 # make-taps.py
5 # By Gerald Combs <gerald@wireshark.org>
6 # Based on make-taps.pl by Luis E. Garcia Onatnon <luis.ontanon@gmail.com>
8 # Wireshark - Network traffic analyzer
9 # By Gerald Combs <gerald@wireshark.org>
10 # Copyright 1998 Gerald Combs
12 # SPDX-License-Identifier: GPL-2.0-or-later
13 '''\
14 Extract structs from C headers to generate a function that pushes a lua table
15 into the stack containing the elements of the struct.
16 '''
18 import argparse
19 import configparser
20 import os
21 import re
22 import sys
25 this_dir = os.path.dirname(__file__)
28 def get_tap_info(tap_name, header_file, struct_name, enum_types):
29 code = f'#include "{header_file}"\n'
30 doc = f'Tap: {tap_name}\n'
31 enums = {}
32 buf = ''
34 types = {
35 'gchar[]': 'lua_pushstring(L,(const char*)v->STR);',
36 'gchar*': 'lua_pushstring(L,(const char*)v->STR);',
37 'guint': 'lua_pushinteger(L,(lua_Integer)v->STR);',
38 'guint8': 'lua_pushinteger(L,(lua_Integer)v->STR);',
39 'guint16': 'lua_pushinteger(L,(lua_Integer)v->STR);',
40 'guint32': 'lua_pushinteger(L,(lua_Integer)v->STR);',
41 'gint': 'lua_pushinteger(L,(lua_Integer)v->STR);',
42 'gint8': 'lua_pushinteger(L,(lua_Integer)v->STR);',
43 'gint16': 'lua_pushinteger(L,(lua_Integer)v->STR);',
44 'gint32': 'lua_pushinteger(L,(lua_Integer)v->STR);',
45 'gboolean': 'lua_pushboolean(L,(int)v->STR);',
46 'char[]': 'lua_pushstring(L,(const char*)v->STR);',
47 'char*': 'lua_pushstring(L,(const char*)v->STR);',
48 'unsigned': 'lua_pushinteger(L,(lua_Integer)v->STR);',
49 'uint8_t': 'lua_pushinteger(L,(lua_Integer)v->STR);',
50 'uint16_t': 'lua_pushinteger(L,(lua_Integer)v->STR);',
51 'uint32_t': 'lua_pushinteger(L,(lua_Integer)v->STR);',
52 'int': 'lua_pushinteger(L,(lua_Integer)v->STR);',
53 'int8_t': 'lua_pushinteger(L,(lua_Integer)v->STR);',
54 'int16_t': 'lua_pushinteger(L,(lua_Integer)v->STR);',
55 'int32': 'lua_pushinteger(L,(lua_Integer)v->STR);',
56 'bool': 'lua_pushboolean(L,(int)v->STR);',
57 'address': '{ Address a = (Address)g_malloc(sizeof(address)); copy_address(a, &(v->STR)); pushAddress(L,a); }',
58 'address*': '{ Address a = (Address)g_malloc(sizeof(address)); copy_address(a, v->STR); pushAddress(L,a); }',
59 'nstime_t': 'lua_pushnumber(L,(lua_Number)nstime_to_sec(&(v->STR)));',
60 'nstime_t*': 'lua_pushnumber(L,(lua_Number)nstime_to_sec(v->STR));',
63 comments = {
64 'gchar[]': 'string',
65 'gchar*': 'string',
66 'guint': 'number',
67 'guint8': 'number',
68 'guint16': 'number',
69 'guint32': 'number',
70 'gint': 'number',
71 'gint8': 'number',
72 'gint16': 'number',
73 'gint32': 'number',
74 'gboolean': 'boolean',
75 'char[]': 'string',
76 'char*': 'string',
77 'unsigned': 'number',
78 'uint8_t': 'number',
79 'uint16_t': 'number',
80 'uint32_t': 'number',
81 'int': 'number',
82 'int8_t': 'number',
83 'int16_t': 'number',
84 'int32_t': 'number',
85 'bool': 'boolean',
86 'address': 'Address',
87 'address*': 'Address',
88 'nstime_t': 'number (seconds, since 1-1-1970 if absolute)',
89 'nstime_t*': 'number (seconds, since 1-1-1970 if absolute)',
92 with open(os.path.join(this_dir, header_file), encoding='utf-8') as header_f:
93 for line in header_f:
94 # Remove comments
95 line = re.sub(r'\/\*.*?\*/', '', line)
96 line = re.sub(r'//.*', '', line)
97 buf += line
99 for enum in enum_types:
100 m = re.search(fr'typedef\s+enum[^{{]*{{([^}}]*)}}[\s\n]*{enum}[\s\n]*;', buf, flags=re.DOTALL)
101 if m:
102 types[enum] = f'lua_pushinteger(L,(lua_Integer)v->STR); /* {enum} */'
103 econsts = m.group(1).splitlines()
104 econsts = [re.sub(r'\s+', '', item) for item in econsts]
105 econsts = [re.sub(',', '', item) for item in econsts]
106 econsts = [item for item in econsts if item]
107 enums[enum] = econsts
108 ebody = '|'.join(econsts)
109 comments[enum] = f'{enum}: {{ {ebody} }}'
111 m = re.search(fr'typedef\s+struct.*?{{([^}}]*)}}[\s\n]*({struct_name})[\s\n]*;', buf, flags=re.DOTALL)
112 if not m:
113 sys.stderr.write(f'could not find typedef {struct_name} in {header_file}')
114 sys.exit(1)
116 body = m.group(1)
118 elems = {}
120 for line in body.splitlines():
121 k = None
122 v = None
124 m = re.search(r'\s*(.*?)([\w\d_]+)\s*\[\s*\d+\s*\]\s*;', line)
125 if m:
126 k = m.group(2)
127 v = m.group(1)
128 v += '[]'
130 m = re.search(r'\s*(.*?)([\w\d_]+)\s*;', line)
131 if m:
132 k = m.group(2)
133 v = m.group(1)
135 if v and k:
136 v = re.sub(r'const ', '', v)
137 v = re.sub(r'\s+', '', v)
138 elems[k] = v
140 code += f'static void wslua_{tap_name}_to_table(lua_State* L, const void* p) {{\n\tconst {struct_name}* v;\n\n\tv = (const {struct_name}*)p;\n\tlua_newtable(L);\n\n'
142 for el in sorted(elems):
143 try:
144 fmt = types[elems[el]]
145 code += f'\tlua_pushstring(L,\"{el}\");\n\t'
146 lua_type = re.sub(r'\bSTR\b', el, fmt)
147 code += lua_type
148 code += '\n\tlua_settable(L,-3);\n'
149 doc += f'\t{el}: {comments[elems[el]]}\n'
150 except KeyError:
151 pass
153 code += "}\n\n"
154 doc += "\n"
156 return (code, doc, enums)
159 def main():
160 parser = argparse.ArgumentParser(description="Generate bindings required for Lua taps.")
161 parser.add_argument("out_c", metavar='C file', help="output C file")
162 parser.add_argument("out_doc", metavar='documentation file', help="output text file")
163 args = parser.parse_args()
165 tap_config = configparser.ConfigParser()
166 tap_config.read(os.path.join(this_dir, 'taps.ini'))
168 enums = {}
169 c_body = '''\
170 /* This file is autogenerated from ./taps by ./make-taps.py */
171 /* DO NOT EDIT! */
173 #include "config.h"
175 #include "wslua.h"
177 #include <wsutil/nstime.h>
180 doc_body = '\n'
182 for tap_name in tap_config.sections():
183 tap_d = tap_config[tap_name]
184 enum_types = []
185 if 'enum_types' in tap_d.keys():
186 enum_types = tap_d['enum_types'].split(' ')
187 (code, doc, file_enums) = get_tap_info(tap_name, tap_d['header_file'], tap_d['struct_name'], enum_types)
188 c_body += code
189 doc_body += doc
190 enums.update(file_enums)
192 c_body += 'static tappable_t tappables[] = {\n'
193 for tap_name in sorted(tap_config.sections()):
194 c_body += f'\t{{"{tap_name}", wslua_{tap_name}_to_table }},\n'
195 c_body += '''\
196 {"frame",NULL},
197 {NULL,NULL}
201 c_body += '\nint wslua_set_tap_enums(lua_State* L) {\n'
202 for enum in sorted(enums):
203 c_body += f'\n\t/*\n\t * {enum}\n\t */\n\tlua_newtable(L);\n'
204 for econst in enums[enum]:
205 c_body += f'''\
206 lua_pushinteger(L,(lua_Integer){econst});
207 lua_setglobal(L,"{econst}");
208 lua_pushinteger(L,(lua_Integer){econst});
209 lua_pushstring(L,"{econst}");
210 lua_settable(L,-3);
212 c_body += f'\tlua_setglobal(L,\"{enum}\");\n'
213 c_body += '\treturn 0;\n}\n'
215 c_body += '''\
218 tap_extractor_t wslua_get_tap_extractor(const gchar* name) {
219 tappable_t* t;
220 for(t = tappables; t->name; t++ ) {
221 if (g_str_equal(t->name,name)) return t->extractor;
224 return NULL;
228 with open(args.out_c, mode='w', encoding='utf-8') as out_c_f:
229 out_c_f.write(c_body)
231 with open(args.out_doc, mode='w', encoding='utf-8') as out_doc_f:
232 out_doc_f.write(doc_body)
234 if __name__ == '__main__':
235 main()