mirror of https://github.com/nirenjan/libx52.git
198 lines
7.4 KiB
Python
Executable File
198 lines
7.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Read the default configuration file, and create ID enums for sections
|
|
and options.
|
|
"""
|
|
|
|
import argparse
|
|
import configparser
|
|
import json
|
|
import os.path
|
|
|
|
from collections import defaultdict
|
|
from itertools import count
|
|
from pprint import pprint
|
|
|
|
class ConfigToEnum:
|
|
"""ConfigToEnum scans a configuration file, and dumps the secions and
|
|
options within a section as Python Enums"""
|
|
|
|
REGISTRY_COMMENT = """The configuration registry is a historic record of
|
|
all configuration identifiers. Do NOT edit this file manually, or else, the
|
|
communication protocol may break."""
|
|
|
|
def __init__(self, cfg_file, config_ids):
|
|
"""Initialize the object"""
|
|
self.config = configparser.ConfigParser(default_section=None, interpolation=None)
|
|
self.config.optionxform = str
|
|
self.config.read(cfg_file)
|
|
|
|
self.registry_file = config_ids
|
|
|
|
try:
|
|
with open(self.registry_file, encoding='utf-8') as regfd:
|
|
self.config_ids = json.load(regfd)
|
|
except Exception:
|
|
# On any error, ignore it and start with a clean slate
|
|
self.config_ids = {}
|
|
|
|
self.sections = {}
|
|
self.options = {}
|
|
|
|
def parse(self):
|
|
"""Parse the config object and assign IDs"""
|
|
self._parse_sections()
|
|
for section in self.config.sections():
|
|
self._parse_options(section)
|
|
|
|
def _parse_sections(self):
|
|
"""Assign IDs to each section"""
|
|
sections = {}
|
|
unassigned = []
|
|
for section in self.config.sections():
|
|
section = section.upper()
|
|
section_id = self.config_ids.get('sections', {}).get(section)
|
|
if section_id is None:
|
|
unassigned.append(section)
|
|
else:
|
|
sections[section] = section_id
|
|
|
|
if not sections:
|
|
counter = count(1)
|
|
else:
|
|
counter = count(max(sections.values()) + 1)
|
|
|
|
sections.update({k:v for k, v in zip(unassigned, counter)})
|
|
|
|
orig_sections = self.config_ids.get('sections', {})
|
|
sections.update({k:v for k, v in orig_sections.items() if k not in sections})
|
|
|
|
self.sections = sections
|
|
|
|
def _parse_options(self, section):
|
|
options = {}
|
|
unassigned = []
|
|
for option in self.config.options(section):
|
|
option = option.upper()
|
|
section = section.upper()
|
|
option_id = self.config_ids.get('options', {}).get(section, {}).get(option)
|
|
if option_id is None:
|
|
unassigned.append(option)
|
|
else:
|
|
options[option] = option_id
|
|
|
|
if not options:
|
|
counter = count(1)
|
|
else:
|
|
counter = count(max(options.values()) + 1)
|
|
|
|
options.update({k:v for k, v in zip(unassigned, counter)})
|
|
orig_options = self.config_ids.get('options', {}).get(section, {})
|
|
|
|
# Make sure that we have all the entries already
|
|
options.update({k:v for k, v in orig_options.items() if k not in options})
|
|
|
|
self.options[section] = options
|
|
|
|
def save_registry(self):
|
|
"""Save the generated registry"""
|
|
registry = {
|
|
"_comment": self.REGISTRY_COMMENT,
|
|
"sections": self.sections,
|
|
"options": self.options,
|
|
}
|
|
|
|
with open(self.registry_file, 'w', encoding='utf-8') as regfd:
|
|
json.dump(registry, regfd, indent=4)
|
|
|
|
def generate_c_definitions(self, output_header, output_source):
|
|
"""Generate the C definitions"""
|
|
with open(output_header, 'w', encoding='utf-8') as out_fd:
|
|
include_guard = os.path.basename(output_header).replace('-', '_').replace('.', '_').upper()
|
|
|
|
print("// Autogenerated config identifiers - DO NOT EDIT\n", file=out_fd)
|
|
print(f"#ifndef {include_guard}", file=out_fd)
|
|
print(f"#define {include_guard}", file=out_fd)
|
|
print(file=out_fd)
|
|
|
|
max_sec_val = max(self.sections.values()) + 1
|
|
max_opt_val_global = 0
|
|
for section, value in self.sections.items():
|
|
print(f"#define CFG_SECTION_{section} {value}", file=out_fd)
|
|
max_opt_val = max(self.options[section].values()) + 1
|
|
max_opt_val_global = max(max_opt_val, max_opt_val_global)
|
|
|
|
for option, value in self.options[section].items():
|
|
print(f"#define CFG_OPTION_{section}_{option} {value}", file=out_fd)
|
|
|
|
print(f"#define CFG_OPTION_{section}_MAX_OPTIONS {max_opt_val}\n", file=out_fd)
|
|
|
|
print(f"#define CFG_SECTION_MAX {max_sec_val}\n", file=out_fd)
|
|
print(f"#define CFG_SECTION_MAX_OPT_VAL {max_opt_val_global}\n", file=out_fd)
|
|
|
|
print("extern const char * section_names[CFG_SECTION_MAX];", file=out_fd)
|
|
print("extern const char * option_names[CFG_SECTION_MAX][CFG_SECTION_MAX_OPT_VAL];", file=out_fd)
|
|
|
|
print(f"#endif // !defined {include_guard}", file=out_fd)
|
|
|
|
with open(output_source, 'w', encoding='utf-8') as out_fd:
|
|
print("// Autogenerated config string table - DO NOT EDIT\n", file=out_fd)
|
|
print(f'#include "{os.path.basename(output_header)}"', file=out_fd)
|
|
|
|
print("const char * section_names[CFG_SECTION_MAX] = {", file=out_fd)
|
|
for section, value in self.sections.items():
|
|
print(f' [{value}] = "{section.lower()}",', file=out_fd)
|
|
print("};\n", file=out_fd)
|
|
|
|
print("const char * options_names[CFG_SECTION_MAX][CFG_SECTION_MAX_OPT_VAL] = {", file=out_fd)
|
|
for section, value in self.sections.items():
|
|
print(f' [{value}] =', '{', file=out_fd)
|
|
for option, value in self.options[section].items():
|
|
print(f' [{value}] = "{option.lower()}",', file=out_fd)
|
|
print(' },', file=out_fd)
|
|
print("};\n", file=out_fd)
|
|
|
|
|
|
def generate_py_definitions(self, output_file):
|
|
"""Generate the Python definitions"""
|
|
try:
|
|
out_fd = open(output_file, 'w', encoding='utf-8')
|
|
|
|
print("'''Autogenerated config identifiers from x52d.conf'''", file=out_fd)
|
|
print("# DO NOT EDIT\n", file=out_fd)
|
|
print("from enum import Enum", file=out_fd)
|
|
|
|
print("\nclass Section(Enum):", file=out_fd)
|
|
print(" '''Section identifiers'''", file=out_fd)
|
|
for section, value in self.sections.items():
|
|
print(f" {section} = {value}", file=out_fd)
|
|
|
|
for section in self.sections.keys():
|
|
print(f"\nclass {section}(Enum):", file=out_fd)
|
|
print(f" '''Section {section} identifiers'''", file=out_fd)
|
|
for option, value in self.options[section].items():
|
|
print(f" {option} = {value}", file=out_fd)
|
|
|
|
finally:
|
|
out_fd.close()
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Generate C enum and python enum for config")
|
|
parser.add_argument('input_file')
|
|
parser.add_argument('registry')
|
|
parser.add_argument('output_c_header')
|
|
parser.add_argument('output_c_strings')
|
|
parser.add_argument('output_py_defs')
|
|
|
|
args = parser.parse_args()
|
|
|
|
c2e = ConfigToEnum(args.input_file, args.registry)
|
|
c2e.parse()
|
|
c2e.save_registry()
|
|
|
|
c2e.generate_c_definitions(args.output_c_header, args.output_c_strings)
|
|
c2e.generate_py_definitions(args.output_py_defs)
|
|
|
|
if __name__ == '__main__':
|
|
main()
|