mirror of https://github.com/OISF/suricata
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
229 lines
6.6 KiB
Python
229 lines
6.6 KiB
Python
#! /usr/bin/env python2
|
|
|
|
# This script will scan Rust source files looking for extern "C"
|
|
# functions and generate C header files from them with a filename
|
|
# based on the Rust filename.
|
|
#
|
|
# Usage: From the top suricata source directory:
|
|
#
|
|
# ./rust/gen-c-headers.py
|
|
#
|
|
|
|
from __future__ import print_function
|
|
|
|
import sys
|
|
import os
|
|
import re
|
|
from io import StringIO
|
|
|
|
template = """/* Copyright (C) 2017 Open Information Security Foundation
|
|
*
|
|
* You can copy, redistribute or modify this Program under the terms of
|
|
* the GNU General Public License version 2 as published by the Free
|
|
* Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* version 2 along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
* 02110-1301, USA.
|
|
*/
|
|
|
|
/*
|
|
* DO NOT EDIT. This file is automatically generated.
|
|
*/
|
|
|
|
#ifndef __%(name)s__
|
|
#define __%(name)s__
|
|
|
|
%(prototypes)s
|
|
#endif /* ! __%(name)s__ */
|
|
"""
|
|
|
|
# Map of Rust types to C types.
|
|
type_map = {
|
|
"bool": "bool",
|
|
"i8": "int8_t",
|
|
"i16" :"int16_t",
|
|
"i32" :"int32_t",
|
|
"i64" :"int64_t",
|
|
|
|
"u8": "uint8_t",
|
|
"u16" :"uint16_t",
|
|
"u32" :"uint32_t",
|
|
"u64" :"uint64_t",
|
|
|
|
"libc::c_void": "void",
|
|
|
|
"libc::c_char": "char",
|
|
"libc::c_int": "int",
|
|
"c_int": "int",
|
|
"libc::int8_t": "int8_t",
|
|
|
|
"libc::uint8_t": "uint8_t",
|
|
"libc::uint16_t": "uint16_t",
|
|
"libc::uint32_t": "uint32_t",
|
|
"libc::uint64_t": "uint64_t",
|
|
|
|
"SuricataContext": "SuricataContext",
|
|
"SuricataFileContext": "SuricataFileContext",
|
|
"FileContainer": "FileContainer",
|
|
"core::Flow": "Flow",
|
|
"Flow": "Flow",
|
|
"DNSState": "RSDNSState",
|
|
"DNSTransaction": "RSDNSTransaction",
|
|
"NFSState": "NFSState",
|
|
"NFSTransaction": "NFSTransaction",
|
|
"NTPState": "NTPState",
|
|
"NTPTransaction": "NTPTransaction",
|
|
"TFTPTransaction": "TFTPTransaction",
|
|
"TFTPState": "TFTPState",
|
|
"SMBState": "SMBState",
|
|
"SMBTransaction": "SMBTransaction",
|
|
"IKEV2State": "IKEV2State",
|
|
"IKEV2Transaction": "IKEV2Transaction",
|
|
"JsonT": "json_t",
|
|
"DetectEngineState": "DetectEngineState",
|
|
"core::DetectEngineState": "DetectEngineState",
|
|
"core::AppLayerDecoderEvents": "AppLayerDecoderEvents",
|
|
"AppLayerDecoderEvents": "AppLayerDecoderEvents",
|
|
"core::AppLayerEventType": "AppLayerEventType",
|
|
"applayer::AppLayerGetTxIterTuple": "AppLayerGetTxIterTuple",
|
|
"AppLayerGetTxIterTuple": "AppLayerGetTxIterTuple",
|
|
"AppLayerEventType": "AppLayerEventType",
|
|
"CLuaState": "lua_State",
|
|
"Store": "Store",
|
|
"AppProto": "AppProto",
|
|
}
|
|
|
|
def convert_type(rs_type):
|
|
m = re.match("^[^\s]+$", rs_type)
|
|
if m:
|
|
if rs_type in type_map:
|
|
return type_map[rs_type]
|
|
|
|
m = re.match("^(.*)(\s[^\s]+)$", rs_type)
|
|
if m:
|
|
mod = m.group(1).strip()
|
|
rtype = m.group(2).strip()
|
|
if rtype in type_map:
|
|
if mod in [
|
|
"*mut",
|
|
"* mut",
|
|
"&mut",
|
|
"&'static mut",
|
|
]:
|
|
return "%s *" % (type_map[rtype])
|
|
elif mod in [
|
|
"*const",
|
|
"* const"]:
|
|
return "const %s *" % (type_map[rtype])
|
|
elif mod in [
|
|
"*mut *const",
|
|
"*mut*const"]:
|
|
return "%s **" % (type_map[rtype])
|
|
else:
|
|
raise Exception("Unknown modifier '%s' in '%s'." % (
|
|
mod, rs_type))
|
|
else:
|
|
raise Exception("Unknown type: %s" % (rtype))
|
|
|
|
raise Exception("Failed to parse Rust type: %s" % (rs_type))
|
|
|
|
def make_output_filename(filename):
|
|
parts = filename.split(os.path.sep)[2:]
|
|
last = os.path.splitext(parts.pop())[0]
|
|
outpath = "./gen/c-headers/rust-%s-%s-gen.h" % (
|
|
"-".join(parts), last)
|
|
return outpath.replace("--", "-")
|
|
|
|
def write_header(fileobj, filename):
|
|
filename = os.path.basename(filename).replace(
|
|
"-", "_").replace(".", "_").upper()
|
|
fileobj.write(file_header % {"name": filename})
|
|
|
|
def should_regen(input_filename, output_filename):
|
|
"""Check if a file should be regenerated. If the output doesn't exist,
|
|
or the input is newer than the output return True. Otherwise
|
|
return False.
|
|
|
|
"""
|
|
if not os.path.exists(output_filename):
|
|
return True
|
|
if os.stat(input_filename).st_mtime > os.stat(output_filename).st_mtime:
|
|
return True
|
|
return False
|
|
|
|
def gen_headers(filename):
|
|
|
|
output_filename = make_output_filename(filename)
|
|
|
|
if not should_regen(filename, output_filename):
|
|
return
|
|
|
|
buf = open(filename).read()
|
|
writer = StringIO()
|
|
|
|
for fn in re.findall(
|
|
r"^pub (unsafe )?extern \"C\" fn ([A_Za-z0-9_]+)\(([^{]+)?\)"
|
|
r"(\s+-> ([^{]+))?",
|
|
buf,
|
|
re.M | re.DOTALL):
|
|
|
|
args = []
|
|
|
|
fnName = fn[1]
|
|
|
|
for arg in fn[2].split(","):
|
|
if not arg:
|
|
continue
|
|
arg_name, rs_type = arg.split(":", 1)
|
|
arg_name = arg_name.strip()
|
|
rs_type = rs_type.strip()
|
|
c_type = convert_type(rs_type)
|
|
|
|
if arg_name != "_":
|
|
args.append("%s %s" % (c_type, arg_name))
|
|
else:
|
|
args.append(c_type)
|
|
|
|
if not args:
|
|
args.append("void")
|
|
|
|
retType = fn[4].strip()
|
|
if retType == "":
|
|
returns = "void"
|
|
else:
|
|
returns = convert_type(retType)
|
|
|
|
writer.write(u"%s %s(%s);\n" % (returns, fnName, ", ".join(args)))
|
|
|
|
if writer.tell() > 0:
|
|
print("Writing %s" % (output_filename))
|
|
if not os.path.exists(os.path.dirname(output_filename)):
|
|
os.makedirs(os.path.dirname(output_filename))
|
|
with open(output_filename, "w") as output:
|
|
output.write(template % {
|
|
"prototypes": writer.getvalue(),
|
|
"name": os.path.basename(output_filename).replace(
|
|
"-", "_").replace(".", "_").upper()
|
|
})
|
|
|
|
def main():
|
|
|
|
rust_top = os.path.dirname(sys.argv[0])
|
|
os.chdir(rust_top)
|
|
|
|
for dirpath, dirnames, filenames in os.walk("./src"):
|
|
for filename in filenames:
|
|
if filename.endswith(".rs"):
|
|
path = os.path.join(dirpath, filename)
|
|
gen_headers(path)
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|