#!/usr/bin/python3 # _*_ coding=utf-8 _*_ import argparse import code import fileinput import json import readline from shutil import copy import signal import sys from text import text import datetime import xml.etree.ElementTree from misc import * import datetime # TODO-doesnt support non-byte-sized reads def type_resolver(elem, elem_list): type_str = elem.attrib["type"] type_name = elem.attrib["name"] if type_str == "int8": return "int8_t" elif type_str == "uint8": return "uint8_t" elif type_str == "int16": return "int16_t" elif type_str == "uint16": return "uint16_t" elif type_str == "int32": return "int32_t" elif type_str == "uint32": return "uint32_t" elif type_str == "int64": return "int64_t" elif type_str == "uint64": return "uint64_t" elif type_str == "int128": return "int128_t" elif type_str == "uint128": return "uint128_t" elif type_str == "float": return "float" elif type_str == "double": return "double" elif type_str == "bool": return "uint8_t" elif type_str == "uchar": return "int8_t" elif type_str == "schar": return "schar_t" elif type_str == "string": return "char*" elif type_str == "FT::conditional": return "void*" elif type_str.find("self::") == 0: for node in elem_list: if elem.attrib["type"][6:] == node.tag: return node.attrib["name"] else: return type_str def get_def_node(type_str, elem_list): for node in elem_list: if type_str == node.attrib["name"]: return node def pointer_remover(name:str): if name[-1] == '*': return name[0:-1] + '_p' else: return name def reader_generator(elem, elem_list): pass def SigHandler_SIGINT(signum, frame): print() sys.exit(0) def get_full_path(path, name): if path[-1] == "/": return path + name else: return path + "/" + name def get_elem_count(elem, elems): if "count" in elem.attrib: try: if str(int(elem.attrib["count"])) == elem.attrib["count"]: return int(elem.attrib["count"]) except ValueError: return -1 else: return 1 def get_elem_size(elem, elems): if "size" in elem.attrib: try: if str(int(elem.attrib["size"])) == elem.attrib["size"]: return int(elem.attrib["size"]) except ValueError: return -1 else: return 0 class Argparser(object): def __init__(self): parser = argparse.ArgumentParser() parser.add_argument("--targetname", type=str, help="main target name") parser.add_argument("--outdir", type=str, help="path to output dir") parser.add_argument("--structs", type=str, help="the structs json file") parser.add_argument("--structsinclude", type=str, help="the path to the header that's going to be included by structs.h before structure declarations.") parser.add_argument("--xml", type=str, help="paht to the xml file") parser.add_argument("--dbg", action="store_true", help="debug", default=False) parser.add_argument("--datetime", action="store_true", help="print date and time in autogen files", default=False) parser.add_argument("--inline", action="store_true", help="inlines reader funcs", default=False) parser.add_argument("--static", action="store_true", help="statics reader funcs", default=False) parser.add_argument("--verbose", action="store_true", help="verbose", default=False) self.args = parser.parse_args() def dupemake(path, main_name): copy("./resources/makefile", path) makefile_path = get_full_path(path, "makefile") for line in fileinput.input(makefile_path, inplace=True): if "XXX" in line: line = line.replace("XXX", main_name) sys.stdout.write(line) class CodeGen(object): def __init__(self, argparser): self.argparser = argparser self.struct_json = json.load(open(self.argparser.args.structs)) self.dnt = datetime.datetime.now().isoformat() self.elems = [] self.def_elems = [] self.read_elems = [] self.read_iter = [] self.def_iter = [] def init_hook(self): pass def init(self): dupemake(self.argparser.args.outdir, self.argparser.args.targetname) def dump_elems(self): for elem in self.elems: print("XXXX " + elem.tag) print(elem.attrib) def dump_def_elems(self): for elem in self.def_elems: print("XXXX " + elem.tag) print(elem.attrib) def dump_read_elems(self): for elem in self.read_elems: print("XXXX " + elem.tag) print(elem.attrib) def gen_reader_funcs(self): read_source = open(self.argparser.args.outdir + "/read.c", "w") read_source.write("\n// automatically generated by faultrieber\n") read_source.write("// " + self.dnt + "\n") read_source.write(text.header_list) read_source.write('#include "./structs.h"\n') inline = "inline " if self.argparser.args.inline else "" static = "static " if self.argparser.args.static else "" for elem in self.def_elems+ self.read_elems: dummy_list = [] pointer = str() access = "." if "isaggregate" in elem.attrib: pointer = "*" access = "->" read_source.write(static + inline + text.c_read_elem_sig.replace("YYY", elem.attrib["name"]).replace("XXX", elem.attrib["name"]+pointer)) read_source.write(text.c_function_dummy_dec.replace("XXX", elem.attrib["name"] + pointer)) if "isaggregate" in elem.attrib: count = get_elem_count(elem, self.read_elems+self.def_elems) if count == 1: for child in elem: child_count = get_elem_count(child, self.def_elems + self.read_elems) ref_node_name = type_resolver(child, self.def_elems) ref_node = get_def_node(ref_node_name, self.def_elems) size = get_elem_size(child, self.def_elems + self.read_elems) read_size_replacement = str() if size > 0: read_size_replacement = str(size) if size == -1: ref_size = child.attrib["size"][6:] for child2 in elem: if child2.tag == ref_size : read_size_replacement = "dummy" + access + child2.attrib["name"] if ref_node: ref_node_name = pointer_remover(ref_node.attrib["name"]) for_dummy_declare = ref_node.attrib["name"] + "* " + ref_node_name + "_ins" + "=" for_read = text.c_read_elem_sig_1.replace("XXX", ref_node_name) + ";\n" if child_count == 1: for_dummy_assign = "dummy" + access + child.attrib["name"] + "=" +ref_node_name+"_ins" + ";\n" read_source.write(for_dummy_declare+for_read+for_dummy_assign) else: if child_count > 1: for_dummy_assign = "dummy" + access + child.attrib["name"] + "[i]" + "=" +ref_node_name+"_ins" + ";\n" read_source.write(text.simple_loop.replace("YYY", for_dummy_declare+for_read+for_dummy_assign)) if child_count == -1: replacement = str() count_name_str = child.attrib["count"][6:] for child2 in elem: if child2.tag == count_name_str: replacement = "dummy" + access + child2.attrib["name"] for_dummy_assign = "dummy" + access + child.attrib["name"] + "[i]" + "=" +ref_node_name+"_ins" + ";\n" read_source.write(text.simple_loop.replace("YYY", for_dummy_declare+for_read+for_dummy_assign).replace("XXX", replacement)) else: for_dummy_declare = ref_node_name + " " + pointer_remover(ref_node_name)+"_ins" + ";\n" for item in dummy_list: if item == for_dummy_declare: for_dummy_declare = "" if for_dummy_declare: dummy_list.append(for_dummy_declare) for_read = str() if "size" in child.attrib: for_read = text.c_read_gen_2.replace("XXX", pointer_remover(ref_node_name)+"_ins").replace("YYY", read_size_replacement) else: for_read = text.c_read_gen.replace("XXX", pointer_remover(ref_node_name)+"_ins").replace("YYY", pointer_remover(ref_node_name)) if child_count == 1: for_dummy_assign = "dummy" + access + child.attrib["name"] + "=" +pointer_remover(ref_node_name)+"_ins" + ";\n" read_source.write(for_dummy_declare+for_read+for_dummy_assign) else: if child_count > 1: for_dummy_assign = "dummy" + access + child.attrib["name"] + "[i]" + "=" +pointer_remover(ref_node_name)+"_ins" + ";\n" read_source.write(text.simple_loop.replace("YYY", for_dummy_declare+for_read+for_dummy_assign)) if child_count == -1: replacement = str() count_name_str = child.attrib["count"][6:] for child2 in elem: if child2.tag == count_name_str: replacement = "dummy" + access + child2.attrib["name"] for_dummy_assign = "dummy" + access + child.attrib["name"] + "[i]" + "=" +pointer_remover(ref_node_name)+"_ins" + ";\n" read_source.write(text.simple_loop.replace("YYY", for_dummy_declare+for_read+for_dummy_assign).replace("XXX", replacement)) else: pass else: read_source.write(type_resolver(elem, self.elems) + " " + elem.attrib["name"] + ";\n") read_source.write(text.c_function_return_type) read_source.write(text.c_function_close + "\n") def read_xml(self): if self.argparser.args.xml: def_header = open(self.argparser.args.outdir + "/defines.h", "w") def_header.write("\n// automatically generated by faultreiber\n") def_header.write("// " + self.dnt + "\n") def_header.write(text.header_inttype + "\n") tree = xml.etree.ElementTree.parse(self.argparser.args.xml) root = tree.getroot() read_tree = xml.etree.ElementTree.Element("read") def_tree = xml.etree.ElementTree.Element("def") for child in root: if child.tag == "Read": read_tree = child if child.tag == "Definition": def_tree = child for child in read_tree: self.read_elems.append(child) for child in def_tree: self.def_elems.append(child) read_iter = read_tree.iter(tag=None) def_iter = def_tree.iter(tag=None) self.read_iter = read_iter self.def_iter = def_iter for child in def_iter: self.elems.append(child) if "isaggregate" in child.attrib: def_header.write("typedef struct {\n") for childerer in child: c_type = type_resolver(childerer, self.elems) def_header.write("\t" + c_type + " " + childerer.attrib["name"] + ";\n") def_header.write("}" + child.attrib["name"] + ";\n\n") for child in read_iter: self.elems.append(child) if "isaggregate" in child.attrib: def_header.write("typedef struct {\n") for childerer in child: c_type = type_resolver(childerer, self.elems) def_header.write("\t" + c_type + " " + childerer.attrib["name"] + ";\n") def_header.write("}" + child.attrib["name"] + ";\n\n") def gen_struct_header_xml(self): struct_source = open(get_full_path(self.argparser.args.outdir, "structs.h"), "w") struct_source_c = open(get_full_path(self.argparser.args.outdir, "structs.c"), "w") struct_source_c.write('#include "structs.h"') struct_source.write(text.pre_header_guard) struct_source.write(text.autogen_warning) if self.argparser.args.datetime: struct_source.write("// " + self.dnt + "\n") struct_source.write(text.header_guard_begin.replace("XXX", "structs".upper())) struct_source.write(text.header_inttype) if self.argparser.args.structsinclude: copy(self.argparser.args.structsinclude, self.argparser.args.outdir) pos = self.argparser.args.structsinclude.rfind("/") sub = self.argparser.args.structsinclude[pos+1:] struct_source.write('#include "' + sub + '"\n') for child in self.def_elems + self.read_elems: struct_source.write("typedef struct {\n") for childer in child: ref_type = type_resolver(childer, self.def_elems + self.read_elems) def_node = get_def_node(ref_type, self.def_elems + self.read_elems) pointer = str() if "count" in childer.attrib: if childer.attrib["count"] != "1": pointer = "*" if def_node: struct_source.write(ref_type + pointer + "* " + childer.attrib["name"] + ";\n") else: struct_source.write(ref_type + pointer + " " + childer.attrib["name"] + ";\n") struct_source.write("}" + child.attrib["name"] + ";\n\n") struct_source.write(text.pragma_endif) struct_source.write(text.last_comment) def gen_struct_header(self): struct_source = open(get_full_path(self.argparser.args.outdir, "structs.h"), "w") struct_source_c = open(get_full_path(self.argparser.args.outdir, "structs.c"), "w") struct_source_c.write('#include "structs.h"') struct_source.write(text.pre_header_guard) struct_source.write(text.autogen_warning) if self.argparser.args.datetime: struct_source.write("// " + self.dnt + "\n") struct_source.write(text.header_guard_begin.replace("XXX", "structs".upper())) struct_source.write(text.header_inttype) if self.argparser.args.structsinclude: copy(self.argparser.args.structsinclude, self.argparser.args.outdir) pos = self.argparser.args.structsinclude.rfind("/") sub = self.argparser.args.structsinclude[pos+1:] struct_source.write('#include "' + sub + '"\n') for k,v in self.struct_json.items(): struct_name = k field_names = v["field_name"] field_typess = v["field_type"] struct_source.write("typedef struct {\n") for i, j in zip(field_names, field_typess): struct_source.write("\t" + j + " " + i + ";\n") struct_source.write("}" + struct_name + ";\n\n") struct_source.write(text.pragma_endif) struct_source.write(text.last_comment) def run(self): self.init() self.init_hook() #self.gen_struct_header() self.read_xml() self.gen_reader_funcs() self.gen_struct_header_xml() #self.dump_def_elems() #print("") #self.dump_read_elems() # write code here def premain(argparser): signal.signal(signal.SIGINT, SigHandler_SIGINT) #here codegen = CodeGen(argparser) codegen.run() def main(): argparser = Argparser() if argparser.args.dbg: try: premain(argparser) except Exception as e: print(e.__doc__) if e.message: print(e.message) variables = globals().copy() variables.update(locals()) shell = code.InteractiveConsole(variables) shell.interact(banner="DEBUG REPL") else: premain(argparser) if __name__ == "__main__": main()