# XF Template Generator __author__ = "Louis Heredero" __copyright__ = "Copyright 2023, Louis Heredero" __license__ = "GPL3.0" __version__ = "1.1.0" import json import locale import os import re import time def ucfirst(s): return s[0].upper() + s[1:] def get_input(title, default=None, non_null=False): """Prompts user for an input Args: title (str): Name of value default (Any, optional): Default value. Defaults to None. non_null (bool, optional): Whether the can be null. Defaults to False. Returns: str|None: The value """ while True: txt = title if default is not None: txt += f" [{default}]" txt += ": " value = input(txt).strip() if value: return value elif default: return default elif not non_null: return "" def fill_template(dir_, variables, filename): """Replaces values in a template file Args: dir_ (str): Path of src directory variables (dict): Dictionary of values to replace filename (str): Template file name Returns: str: Template content with replaced values """ with open(os.path.join(dir_, "templates", filename), "r") as f: content = f.read() def replace(m): indent = m.group(1) key = m.group(2) txt = variables[key] if indent: lines = txt.split("\n") lines = [indent+line for line in lines] txt = "\n".join(lines) return txt return re.sub("([ \t]*)\$\{(.+?)\}", replace, content) def output_file(dir_, filename, content): """Writes content to a given file. Checks before overwriting Args: dir_ (str): Path of src directory filename (str): Output file name content (str): Content to write """ outdir = os.path.join(dir_, "out") if not os.path.isdir(outdir): os.mkdir(outdir) outpath = os.path.join(outdir, filename) if os.path.exists(outpath): replace = input(f"The file {filename} already exists. Overwrite it ? y/N: ") if replace.lower() != "y": return with open(outpath, "w") as f: f.write(content) def main(): locale.setlocale(locale.LC_TIME, "en_GB.utf8") dir_ = os.path.dirname(__file__) # Load config if it exists conf_path = os.path.join(dir_, "config.json") if os.path.exists(conf_path): with open(conf_path, "r") as f: variables = json.load(f) else: variables = {} variables["date"] = time.strftime("%B %Y") variables["author"] = get_input("Author", variables.get("author", ""), True) variables["filename"] = get_input("Filename", None, True).upper() variables["filename_lc"] = variables["filename"].lower() variables["fn"] = get_input("Filename (short)", None, True).upper() ########## # States # ########## states = [] print("States (leave empty to end):") print("> INIT") while True: state = input("> ").upper() if state: states.append(state) else: break states = ["ST"+variables["fn"]+"_"+s for s in states] variables["STATES_ENUM"] = ",\n".join(states) states_cases = [] for state in states: case_ = f"case {state}:\n" case_ += " break;" states_cases.append(case_) variables["STATES_CASES"] = "\n\n".join(states_cases) ########## # Events # ########## events = ["init = 100"] print("Events (leave empty to end):") print("> init") while True: event = input("> ").lower() if event: events.append(event) else: break events_enum = ["ev"+variables["fn"]+e for e in events] events_enum = ",\n".join(events_enum).split("\n") events_enum[0] += " // TODO change this number (< 256)" variables["EVENTS_ENUM"] = "\n".join(events_enum) events_emits_def = [] emit_def = "" emit_def += "void {filename}_emit{Event}({filename}* me, uint16_t t) {\n" emit_def += " POST(me, &{filename}_processEvent, ev{fn}{event}, t, 0);\n" emit_def += "}" emit_def = emit_def.replace("{filename}", variables["filename"]).replace("{fn}", variables["fn"]) for event in events[1:]: events_emits_def.append( emit_def.replace("{event}", event).replace("{Event}", event.capitalize()) ) variables["EVENTS_EMITS_DEF"] = "\n\n".join(events_emits_def) events_emits_dec = [] emit_dec = "" emit_dec += "/**\n" emit_dec += " * Emit the {event} event\n" emit_dec += " * @param me the {filename} itself\n" emit_dec += " * @param t time to wait in ms before triggering event\n" emit_dec += " */" emit_dec += "void {filename}_emit{Event}({filename}* me, uint16_t t);" emit_dec = emit_dec.replace("{filename}", variables["filename"]) for event in events[1:]: events_emits_dec.append( emit_dec.replace("{event}", event).replace("{Event}", event.capitalize()) ) variables["EVENTS_EMITS_DEC"] = "\n\n".join(events_emits_dec) ############# # Variables # ############# vars_init = [] vars_struct = [] vars_setters_def = [] vars_setters_dec = [] setter_def = "" setter_def += "void {filename}_set{Name}({filename}* me, {type} v) {\n" setter_def += " me->{name} = v;\n" setter_def += "}" setter_def = setter_def.replace("{filename}", variables["filename"]) setter_dec = "void {filename}_set{Name}({filename}* me, {type} v);" setter_dec = setter_dec.replace("{filename}", variables["filename"]) print("Variables:") print("(leave name empty to end)") while True: name = input("Name: ").strip() if not name: break type_ = input("Type: ").strip() default = input("Default value: ").strip() print() vars_struct.append(f"{type_} {name};") if default: vars_init.append(f"me->{name} = {default};") vars_setters_def.append( setter_def.replace("{type}", type_) .replace("{name}", name) .replace("{Name}", ucfirst(name)) ) vars_setters_dec.append( setter_dec.replace("{type}", type_) .replace("{Name}", ucfirst(name)) ) variables["VARS_INIT"] = "\n".join(vars_init) variables["VARS_STRUCT"] = "\n".join(vars_struct) variables["VARS_SETTERS_DEF"] = "\n\n".join(vars_setters_def) variables["VARS_SETTERS_DEC"] = "\n\n".join(vars_setters_dec) ################## # Fill templates # ################## file_c = fill_template(dir_, variables, "file.c") file_h = fill_template(dir_, variables, "file.h") output_file(dir_, variables["filename_lc"]+".c", file_c) output_file(dir_, variables["filename_lc"]+".h", file_h) # Save config with open(conf_path, "w") as f: conf = { "author": variables["author"] } json.dump(conf, f) if __name__ == "__main__": main()