The Doxygen documentation for enumerators prefixes the enumerator name with the enumeration name. For unscoped enumerations, this is incorrect. Drop the scope. This fixes warnings produced by Doxygen when multiple enumerators with identical names are defined in different scopes. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Tested-by: Jacopo Mondi <jacopo@jmondi.org> Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
226 lines
6.7 KiB
Python
Executable file
226 lines
6.7 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
# Copyright (C) 2019, Google Inc.
|
|
#
|
|
# Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
#
|
|
# gen-controls.py - Generate control definitions from YAML
|
|
|
|
import argparse
|
|
import string
|
|
import sys
|
|
import yaml
|
|
|
|
|
|
def snake_case(s):
|
|
return ''.join([c.isupper() and ('_' + c) or c for c in s]).strip('_')
|
|
|
|
|
|
def format_description(description):
|
|
description = description.strip('\n').split('\n')
|
|
description[0] = '\\brief ' + description[0]
|
|
return '\n'.join([(line and ' * ' or ' *') + line for line in description])
|
|
|
|
|
|
def generate_cpp(controls):
|
|
enum_doc_start_template = string.Template('''/**
|
|
* \\enum ${name}Enum
|
|
* \\brief Supported ${name} values''')
|
|
enum_doc_value_template = string.Template(''' * \\var ${value}
|
|
${description}''')
|
|
doc_template = string.Template('''/**
|
|
* \\var ${name}
|
|
${description}
|
|
*/''')
|
|
def_template = string.Template('extern const Control<${type}> ${name}(${id_name}, "${name}");')
|
|
enum_values_doc = string.Template('''/**
|
|
* \\var ${name}Values
|
|
* \\brief List of all $name supported values
|
|
*/''')
|
|
enum_values_start = string.Template('''extern const std::array<const ControlValue, ${size}> ${name}Values = {''')
|
|
enum_values_values = string.Template('''\tstatic_cast<int32_t>(${name}),''')
|
|
|
|
ctrls_doc = []
|
|
ctrls_def = []
|
|
draft_ctrls_doc = []
|
|
draft_ctrls_def = []
|
|
ctrls_map = []
|
|
|
|
for ctrl in controls:
|
|
name, ctrl = ctrl.popitem()
|
|
id_name = snake_case(name).upper()
|
|
|
|
ctrl_type = ctrl['type']
|
|
if ctrl_type == 'string':
|
|
ctrl_type = 'std::string'
|
|
elif ctrl.get('size'):
|
|
ctrl_type = 'Span<const %s>' % ctrl_type
|
|
|
|
info = {
|
|
'name': name,
|
|
'type': ctrl_type,
|
|
'description': format_description(ctrl['description']),
|
|
'id_name': id_name,
|
|
}
|
|
|
|
target_doc = ctrls_doc
|
|
target_def = ctrls_def
|
|
if ctrl.get('draft'):
|
|
target_doc = draft_ctrls_doc
|
|
target_def = draft_ctrls_def
|
|
|
|
enum = ctrl.get('enum')
|
|
if enum:
|
|
enum_doc = []
|
|
enum_doc.append(enum_doc_start_template.substitute(info))
|
|
|
|
num_entries = 0
|
|
for entry in enum:
|
|
value_info = {
|
|
'name': name,
|
|
'value': entry['name'],
|
|
'description': format_description(entry['description']),
|
|
}
|
|
enum_doc.append(enum_doc_value_template.substitute(value_info))
|
|
num_entries += 1
|
|
|
|
enum_doc = '\n *\n'.join(enum_doc)
|
|
enum_doc += '\n */'
|
|
target_doc.append(enum_doc)
|
|
|
|
values_info = {
|
|
'name': info['name'],
|
|
'size': num_entries,
|
|
}
|
|
target_doc.append(enum_values_doc.substitute(values_info))
|
|
target_def.append(enum_values_start.substitute(values_info))
|
|
for entry in enum:
|
|
value_info = {
|
|
'name': entry['name']
|
|
}
|
|
target_def.append(enum_values_values.substitute(value_info))
|
|
target_def.append("};")
|
|
|
|
target_doc.append(doc_template.substitute(info))
|
|
target_def.append(def_template.substitute(info))
|
|
|
|
if ctrl.get('draft'):
|
|
name = 'draft::' + name
|
|
|
|
ctrls_map.append('\t{ ' + id_name + ', &' + name + ' },')
|
|
|
|
return {
|
|
'controls_doc': '\n\n'.join(ctrls_doc),
|
|
'controls_def': '\n'.join(ctrls_def),
|
|
'draft_controls_doc': '\n\n'.join(draft_ctrls_doc),
|
|
'draft_controls_def': '\n\n'.join(draft_ctrls_def),
|
|
'controls_map': '\n'.join(ctrls_map),
|
|
}
|
|
|
|
|
|
def generate_h(controls):
|
|
enum_template_start = string.Template('''enum ${name}Enum {''')
|
|
enum_value_template = string.Template('''\t${name} = ${value},''')
|
|
enum_values_template = string.Template('''extern const std::array<const ControlValue, ${size}> ${name}Values;''')
|
|
template = string.Template('''extern const Control<${type}> ${name};''')
|
|
|
|
ctrls = []
|
|
draft_ctrls = []
|
|
ids = []
|
|
id_value = 1
|
|
|
|
for ctrl in controls:
|
|
name, ctrl = ctrl.popitem()
|
|
id_name = snake_case(name).upper()
|
|
|
|
ids.append('\t' + id_name + ' = ' + str(id_value) + ',')
|
|
|
|
ctrl_type = ctrl['type']
|
|
if ctrl_type == 'string':
|
|
ctrl_type = 'std::string'
|
|
elif ctrl.get('size'):
|
|
ctrl_type = 'Span<const %s>' % ctrl_type
|
|
|
|
info = {
|
|
'name': name,
|
|
'type': ctrl_type,
|
|
}
|
|
|
|
target_ctrls = ctrls
|
|
if ctrl.get('draft'):
|
|
target_ctrls = draft_ctrls
|
|
|
|
enum = ctrl.get('enum')
|
|
if enum:
|
|
target_ctrls.append(enum_template_start.substitute(info))
|
|
|
|
num_entries = 0
|
|
for entry in enum:
|
|
value_info = {
|
|
'name': entry['name'],
|
|
'value': entry['value'],
|
|
}
|
|
target_ctrls.append(enum_value_template.substitute(value_info))
|
|
num_entries += 1
|
|
target_ctrls.append("};")
|
|
|
|
values_info = {
|
|
'name': info['name'],
|
|
'size': num_entries,
|
|
}
|
|
target_ctrls.append(enum_values_template.substitute(values_info))
|
|
|
|
target_ctrls.append(template.substitute(info))
|
|
id_value += 1
|
|
|
|
return {
|
|
'ids': '\n'.join(ids),
|
|
'controls': '\n'.join(ctrls),
|
|
'draft_controls': '\n'.join(draft_ctrls)
|
|
}
|
|
|
|
|
|
def fill_template(template, data):
|
|
|
|
template = open(template, 'rb').read()
|
|
template = template.decode('utf-8')
|
|
template = string.Template(template)
|
|
return template.substitute(data)
|
|
|
|
|
|
def main(argv):
|
|
|
|
# Parse command line arguments
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('-o', dest='output', metavar='file', type=str,
|
|
help='Output file name. Defaults to standard output if not specified.')
|
|
parser.add_argument('input', type=str,
|
|
help='Input file name.')
|
|
parser.add_argument('template', type=str,
|
|
help='Template file name.')
|
|
args = parser.parse_args(argv[1:])
|
|
|
|
data = open(args.input, 'rb').read()
|
|
controls = yaml.safe_load(data)['controls']
|
|
|
|
if args.template.endswith('.cpp.in'):
|
|
data = generate_cpp(controls)
|
|
elif args.template.endswith('.h.in'):
|
|
data = generate_h(controls)
|
|
else:
|
|
raise RuntimeError('Unknown template type')
|
|
|
|
data = fill_template(args.template, data)
|
|
|
|
if args.output:
|
|
output = open(args.output, 'wb')
|
|
output.write(data.encode('utf-8'))
|
|
output.close()
|
|
else:
|
|
sys.stdout.write(data)
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main(sys.argv))
|