169 lines
5.2 KiB
Python
169 lines
5.2 KiB
Python
#!/bin/python3
|
|
"""
|
|
A python script to generate to_string functions for all enumerations in a cpp file.
|
|
Copyright © 2022 Matthias Quintern.
|
|
This software comes with no warranty.
|
|
This software is licensed under the GPL3
|
|
"""
|
|
from os import path, listdir, chdir
|
|
from sys import argv, exit
|
|
import re
|
|
|
|
|
|
filetypes = [".hpp", ".cpp", ".tpp"]
|
|
|
|
def error(s):
|
|
print(s)
|
|
exit(1)
|
|
|
|
|
|
def getEnumStrF(name: str, enum: dict, spaces: int):
|
|
s = " " * spaces
|
|
s += f"const std::map<{name}, std::string> {name}ToStringMap" + " { // generated by gen_enum_str.py\n"
|
|
for name_, val in enum.items():
|
|
s += " " * (spaces + 4)
|
|
s += "{ " + name_ + ", \"" + name_ + "\" },\n"
|
|
s += " " * spaces + "};\n"
|
|
s += " " * spaces + "const std::string& to_string(" + name + " v) { return " + f"{name}ToStringMap.at(v);" + " }; // generated by gen_enum_str.py\n\n"
|
|
return s
|
|
|
|
|
|
def process_file(inputfile: str, outputfile: str):
|
|
print("process_file:", inputfile)
|
|
if not path.isfile(inputfile): error("File does not exist:" + inputfile)
|
|
|
|
with open(inputfile, "r") as file:
|
|
lines = file.readlines()
|
|
|
|
# FIND ENUMS
|
|
enums_start = []
|
|
enums_stop = []
|
|
in_enum = False
|
|
for i in range(len(lines)):
|
|
if re.match(r" *enum [a-zA-Z0-9_-]+ {.*", lines[i]) and not "gen_enum_str.py" in lines[i]:
|
|
if in_enum: error("process_file: could not find end of enum starting at line " + str(enums_start.pop()))
|
|
in_enum = True
|
|
enums_start.append(i)
|
|
|
|
if in_enum:
|
|
if re.match(r" *[^/*]?.*}.*", lines[i]):
|
|
enums_stop.append(i)
|
|
in_enum = False
|
|
if len(enums_start) != len(enums_stop): error("process_file: could not find end of enum starting at line " + str(enums_start.pop()))
|
|
|
|
# create a single string with the enum
|
|
enums = []
|
|
for i in range(len(enums_start)):
|
|
enums.append("")
|
|
j = enums_start[i]
|
|
while j <= enums_stop[i]:
|
|
enums[i] += lines[j]
|
|
j += 1
|
|
|
|
# get name and vars
|
|
enum_names = []
|
|
enum_dicts = []
|
|
spaces = []
|
|
var = "[a-zA-Z0-9_-]+"
|
|
enumvar = "(" + var + r"(=*-?\d+)?)"
|
|
restring = "enum (" + var + "){(" + enumvar + ",)*" + enumvar + ",?}"
|
|
for i in range(len(enums)):
|
|
enums[i] = enums[i].replace("\n", "").replace("enum ", "enumü").replace(" ", "").replace("enumü", "enum ")
|
|
match = re.match(restring, enums[i])
|
|
if not match: error("Invalid enum at line " + str(enums_start[i]))
|
|
|
|
spaces.append(lines[enums_start[i]].find("e"))
|
|
enum_names.append(match.groups()[0])
|
|
enum_val = 0
|
|
enum = {}
|
|
for m in re.finditer(enumvar, enums[i][len("enum " + enum_names[i]):]):
|
|
if "=" in m.group():
|
|
enum_val = int(m.group()[m.group().find("=")+1:])
|
|
var_end = m.group().find("=")
|
|
else:
|
|
var_end = len(m.group())
|
|
enum[m.group()[0:var_end]] = enum_val
|
|
enum_val += 1
|
|
print("enum:", enum_names[i], enum)
|
|
enum_dicts.append(enum)
|
|
|
|
for i in reversed(range(len(enum_names))):
|
|
lines.insert(enums_stop[i] + 1, getEnumStrF(enum_names[i], enum_dicts[i], spaces[i]))
|
|
lines[enums_start[i]] = lines[enums_start[i]].strip("\n") + " // processed by gen_enum_str.py\n"
|
|
|
|
with open(outputfile, "w") as file:
|
|
file.writelines(lines)
|
|
|
|
|
|
def process_path(path_):
|
|
if path.isfile(path_) and path.splitext(path_)[-1] in filetypes:
|
|
process_file(path_, path_)
|
|
|
|
elif path.isdir(path_):
|
|
for p in listdir(path_):
|
|
if path.isfile(p) and path.splitext(p)[-1] in filetypes:
|
|
process_file(p, p)
|
|
elif path.isdir(p):
|
|
chdir(p)
|
|
process_path(p)
|
|
chdir("..")
|
|
else:
|
|
print("Invalid path:", path_)
|
|
|
|
|
|
|
|
|
|
def print_help():
|
|
"""
|
|
Synposis: get_enum_str.py <Options>... <file>...
|
|
-o <path> output: file to path. Only when 1 input file.
|
|
-h --help help
|
|
-r recurse: Recurse through the directory and process all cpp/hpp files. Implies -i
|
|
-i in place: Edit the file in place
|
|
"""
|
|
|
|
def missing_arg(arg):
|
|
print("Missing argument for", arg)
|
|
exit(1)
|
|
|
|
if __name__ == "__main__":
|
|
output_file = None
|
|
input_files = []
|
|
in_place = False
|
|
recurse = False
|
|
i = 1
|
|
while i in range(1, len(argv)):
|
|
if argv[i] == "--help" or argv[i] == "-h":
|
|
print_help()
|
|
exit(0)
|
|
if argv[i] == "-o":
|
|
if len(argv) > i + 1: output_file = argv[i+1]
|
|
else: missing_arg(argv[i])
|
|
i += 1
|
|
elif argv[i] == "-r":
|
|
recurse = True
|
|
elif argv[i] == "-i":
|
|
in_place = True
|
|
else:
|
|
input_files.append(argv[i])
|
|
i += 1
|
|
|
|
if output_file is None and not in_place and not recurse:
|
|
error("Missing output path or -i")
|
|
if output_file and (recurse or in_place or len(input_files) > 1):
|
|
error("Error: -o does not work with -r, -i or multiple input paths.")
|
|
if len(input_files) == 0:
|
|
error("Missing input files.")
|
|
if in_place:
|
|
output_file = input_files[0]
|
|
|
|
if (recurse):
|
|
for f in input_files:
|
|
process_path(f)
|
|
else:
|
|
process_file(input_files[0], output_file)
|
|
|
|
|
|
|
|
|