mirror of https://github.com/OISF/suricata
rust: c header generator
parent
e739fa1477
commit
d0880d75ff
@ -0,0 +1,194 @@
|
|||||||
|
#! /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 = {
|
||||||
|
"i8": "int8_t",
|
||||||
|
"i32" :"int32_t",
|
||||||
|
|
||||||
|
"u8": "uint8_t",
|
||||||
|
|
||||||
|
"libc::c_void": "void",
|
||||||
|
|
||||||
|
"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",
|
||||||
|
"core::Flow": "Flow",
|
||||||
|
"DNSState": "RSDNSState",
|
||||||
|
"DNSTransaction": "RSDNSTransaction",
|
||||||
|
"JsonT": "json_t",
|
||||||
|
"DetectEngineState": "DetectEngineState",
|
||||||
|
"core::DetectEngineState": "DetectEngineState",
|
||||||
|
"core::AppLayerDecoderEvents": "AppLayerDecoderEvents",
|
||||||
|
"CLuaState": "lua_State",
|
||||||
|
}
|
||||||
|
|
||||||
|
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",
|
||||||
|
"*const",
|
||||||
|
"&mut",
|
||||||
|
"&'static mut",
|
||||||
|
]:
|
||||||
|
return "%s *" % (type_map[rtype])
|
||||||
|
elif mod in [
|
||||||
|
"*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 = "../src/rust-%s-%s.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 extern \"C\" fn ([A_Za-z0-9_]+)\(([^{]+)?\)"
|
||||||
|
r"(\s+-> ([^{]+))?",
|
||||||
|
buf,
|
||||||
|
re.M | re.DOTALL):
|
||||||
|
|
||||||
|
args = []
|
||||||
|
|
||||||
|
fnName = fn[0]
|
||||||
|
|
||||||
|
for arg in fn[1].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[3].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))
|
||||||
|
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())
|
Loading…
Reference in New Issue