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