You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
216 lines
6.9 KiB
216 lines
6.9 KiB
#!/usr/bin/env python
|
|
|
|
import argparse
|
|
import io
|
|
import os
|
|
import re
|
|
|
|
re_enum_decl = re.compile(r'enum class (\w+)( *// *<(\w+)>)?')
|
|
re_enum_value = re.compile(r'(\w+)(?= *([,=]|//|$))')
|
|
re_values = re.compile(r'UNC_OPTVALS\((\w+)\)')
|
|
re_aliases = re.compile(r'UNC_OPTVAL_ALIAS\(([^)]+)\)')
|
|
enums = {}
|
|
values = {}
|
|
|
|
root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
script = os.path.relpath(__file__, root)
|
|
|
|
|
|
# =============================================================================
|
|
class Enumeration(object):
|
|
# -------------------------------------------------------------------------
|
|
def __init__(self, name, prefix, f):
|
|
self.name = name
|
|
self.prefix = prefix
|
|
|
|
self.values = []
|
|
self.value_aliases = {}
|
|
|
|
self.convert_internal = False
|
|
|
|
for line in iter(f.readline, ''):
|
|
line = line.strip()
|
|
|
|
if line.startswith('{'):
|
|
for line in iter(f.readline, ''):
|
|
line = line.strip()
|
|
if line.startswith('};'):
|
|
return
|
|
|
|
if 'UNC_INTERNAL' in line:
|
|
return
|
|
|
|
if 'UNC_CONVERT_INTERNAL' in line:
|
|
self.convert_internal = True
|
|
continue
|
|
|
|
mv = re_enum_value.match(line)
|
|
if mv is not None:
|
|
v = mv.group(1)
|
|
self.values.append(v)
|
|
self.value_aliases[v] = [v.lower()]
|
|
|
|
# -------------------------------------------------------------------------
|
|
def add_aliases(self, value, *args):
|
|
aliases = [x[1:-1] for x in args] # strip quotes
|
|
self.value_aliases[value] += aliases
|
|
|
|
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
def enum_value(enum, value):
|
|
if enum.prefix is not None:
|
|
return u'{}_{}'.format(enum.prefix, value)
|
|
return value
|
|
|
|
# -----------------------------------------------------------------------------
|
|
def write_banner(out, args):
|
|
out.write(
|
|
u'/**\n'
|
|
u' * @file {out_name}\n'
|
|
u' * Helpers for option enumerators.\n'
|
|
u' * Automatically generated by <code>{script}</code>\n'
|
|
u' * from {in_name}.\n'
|
|
u' */\n'
|
|
u'\n'.format(
|
|
in_name=os.path.basename(args.header),
|
|
out_name=os.path.basename(args.output),
|
|
script=script))
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
def write_value_strings(out, args):
|
|
for vn, vs in values.items():
|
|
out.write(u'const char *const {}_values[] = {{\n'.format(vn))
|
|
out.write(u'{}\n nullptr\n}};\n\n'.format(
|
|
u'\n'.join([u' "{}",'.format(x.lower()) for x in vs])))
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
def write_aliases(out, args):
|
|
for enum in enums.values():
|
|
if enum.prefix is None:
|
|
continue
|
|
|
|
for v in enum.values:
|
|
out.write(u'constexpr auto {p}_{v} = {n}::{v};\n'.format(
|
|
p=enum.prefix, n=enum.name, v=v))
|
|
|
|
out.write(u'\n')
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
def write_conversions(out, args):
|
|
header = u'\n//{}\n'.format('-' * 77)
|
|
|
|
for enum in enums.values():
|
|
if enum.convert_internal:
|
|
continue
|
|
|
|
out.write(header)
|
|
out.write(
|
|
u'bool convert_string(const char *in, {} &out)\n'.format(
|
|
enum.name))
|
|
out.write(
|
|
u'{\n'
|
|
u' if (false)\n'
|
|
u' {\n'
|
|
u' }\n')
|
|
|
|
for v in enum.values:
|
|
for a in enum.value_aliases[v]:
|
|
out.write(
|
|
u' else if (strcasecmp(in, "{}") == 0)\n'
|
|
u' {{\n'
|
|
u' out = {};\n'
|
|
u' return(true);\n'
|
|
u' }}\n'.format(a, enum_value(enum, v)))
|
|
|
|
out.write(
|
|
u' else\n'
|
|
u' {\n'
|
|
u' return(false);\n'
|
|
u' }\n'
|
|
u'}\n\n')
|
|
|
|
for enum in enums.values():
|
|
out.write(header)
|
|
out.write(u'const char *to_string({} val)\n'.format(enum.name))
|
|
out.write(u'{\n'
|
|
u' switch (val)\n'
|
|
u' {\n')
|
|
|
|
for v in enum.values:
|
|
vs = v if enum.convert_internal else v.lower()
|
|
out.write(
|
|
u' case {}:\n'
|
|
u' return "{}";\n\n'.format(
|
|
enum_value(enum, v), vs))
|
|
|
|
out.write(
|
|
u' default:\n'
|
|
u' fprintf(stderr, "%s: Unknown {} \'%d\'\\n",\n'
|
|
u' __func__, static_cast<int>(val));\n'
|
|
u' log_flush(true);\n'
|
|
u' exit(EX_SOFTWARE);\n'
|
|
u' }}\n'
|
|
u'}}\n\n'.format(enum.name))
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
def main():
|
|
parser = argparse.ArgumentParser(description='Generate options.cpp')
|
|
parser.add_argument('output', type=str,
|
|
help='location of options.cpp to write')
|
|
parser.add_argument('header', type=str,
|
|
help='location of options.h to read')
|
|
parser.add_argument('template', type=str,
|
|
help='location of option_enum.cpp.in '
|
|
'to use as template')
|
|
args = parser.parse_args()
|
|
|
|
with io.open(args.header, 'rt', encoding='utf-8') as f:
|
|
for line in iter(f.readline, ''):
|
|
line = line.strip()
|
|
|
|
me = re_enum_decl.match(line)
|
|
if me is not None:
|
|
e = Enumeration(me.group(1), me.group(3), f)
|
|
enums[e.name] = e
|
|
continue
|
|
|
|
mv = re_values.match(line)
|
|
if mv is not None:
|
|
enum_name = mv.group(1)
|
|
enum = enums['{}_e'.format(enum_name)]
|
|
values[enum_name] = enum.values
|
|
|
|
ma = re_aliases.match(line)
|
|
if ma is not None:
|
|
alias_args = [x.strip() for x in ma.group(1).split(',')]
|
|
enum = enums[alias_args[0]]
|
|
enum.add_aliases(*alias_args[1:])
|
|
|
|
replacements = {
|
|
u'##BANNER##': write_banner,
|
|
u'##VALUE_STRINGS##': write_value_strings,
|
|
u'##ALIASES##': write_aliases,
|
|
u'##CONVERSIONS##': write_conversions,
|
|
}
|
|
|
|
with io.open(args.output, 'wt', encoding='utf-8') as out:
|
|
with io.open(args.template, 'rt', encoding='utf-8') as t:
|
|
for line in t:
|
|
directive = line.strip()
|
|
if directive in replacements:
|
|
replacements[directive](out, args)
|
|
else:
|
|
out.write(line)
|
|
|
|
|
|
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
if __name__ == '__main__':
|
|
main()
|