#!/usr/bin/env python import xml.etree.ElementTree as ET import os import re import codecs class Scope(object): """ Single parameter group """ re_deep_lines = re.compile(r'.*\/.*\/') def __init__(self, ): self.scope = set() def __str__(self): return self.scope.__str__() def Add(self, scope): """ Add Scope to set """ self.scope.add(scope) def Has(self, scope): """ Check for existance """ if len(self.scope) == 0: return True # Anything in the form xxxxx/yyyyy/zzzzz.... # is treated as xxxxx/yyyyy while (self.re_deep_lines.match(scope)): scope = os.path.dirname(scope) return scope in self.scope class CMakeParser(object): """ Parses provided data and stores all found paths in scope. """ re_split_lines = re.compile(r'[\r\n]+') re_comment = re.compile(r'^\#') re_start = re.compile(r'set\s*\(\s*config_module_list') re_end = re.compile(r'\)\s*') def Parse(self, scope, contents): """ Incrementally parse cmake file contents and append all found path scope to scope. """ # This code is essentially a comment-parsing grammar. "state" # represents parser state. It contains human-readable state # names. state = None for line in self.re_split_lines.split(contents): line = line.strip() # Ignore empty lines if line == "": continue if self.re_comment.match(line): continue elif self.re_start.match(line): state = "gather" continue elif state is not None and state == "gather": if self.re_end.match(line): return True scope.Add(line) return False if len(os.sys.argv) < 2: print("Error in %s" % os.sys.argv[0]) print("Usage: %s [cmake-file-scoping] " % os.sys.argv[0]) raise SystemExit scope = Scope() if len(os.sys.argv) == 3: with codecs.open(os.sys.argv[2], 'r', 'utf-8') as f: try: contents = f.read() f.close() parser = CMakeParser() parser.Parse(scope, contents) except: contents = '' print('Failed reading file: %s, skipping scoping.' % os.sys.argv[2]) pass fp_header = open("px4_parameters.h", "w") fp_src = open("px4_parameters.c", "w") tree = ET.parse(os.sys.argv[1]) root = tree.getroot() # Generate the header file content header = """ #include #include // DO NOT EDIT // This file is autogenerated from parameters.xml __BEGIN_DECLS struct px4_parameters_t { """ start_name = "" end_name = "" for group in root: if group.tag == "group" and "no_code_generation" not in group.attrib: section = """ /***************************************************************** * %s ****************************************************************/""" % group.attrib["name"] for param in group: scope_ = param.find('scope').text if not scope.Has(scope_): continue if not start_name: start_name = param.attrib["name"] end_name = param.attrib["name"] header += section section ="" header += """ const struct param_info_s __param__%s;""" % param.attrib["name"] header += """ const unsigned int param_count; }; extern const struct px4_parameters_t px4_parameters; """ # Generate the C file content src = """ #include // DO NOT EDIT // This file is autogenerated from paramaters.xml const #ifndef __PX4_DARWIN __attribute__((used, section("__param"))) #endif struct px4_parameters_t px4_parameters = { """ i=0 for group in root: if group.tag == "group" and "no_code_generation" not in group.attrib: section = """ /***************************************************************** * %s ****************************************************************/""" % group.attrib["name"] for param in group: scope_ = param.find('scope').text if not scope.Has(scope_): continue if not start_name: start_name = param.attrib["name"] end_name = param.attrib["name"] val_str = "#error UNKNOWN PARAM TYPE, FIX px_generate_params.py" if (param.attrib["type"] == "FLOAT"): val_str = ".val.f = " elif (param.attrib["type"] == "INT32"): val_str = ".val.i = " i+=1 src += section section ="" src += """ { "%s", PARAM_TYPE_%s, %s%s }, """ % (param.attrib["name"], param.attrib["type"], val_str, param.attrib["default"]) src += """ %d }; //extern const struct px4_parameters_t px4_parameters; __END_DECLS """ % i fp_header.write(header) fp_src.write(src) fp_header.close() fp_src.close()