1# 2# Copyright 2017 Advanced Micro Devices, Inc. 3# 4# Permission is hereby granted, free of charge, to any person obtaining a 5# copy of this software and associated documentation files (the "Software"), 6# to deal in the Software without restriction, including without limitation 7# on the rights to use, copy, modify, merge, publish, distribute, sub 8# license, and/or sell copies of the Software, and to permit persons to whom 9# the Software is furnished to do so, subject to the following conditions: 10# 11# The above copyright notice and this permission notice (including the next 12# paragraph) shall be included in all copies or substantial portions of the 13# Software. 14# 15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18# THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 19# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21# USE OR OTHER DEALINGS IN THE SOFTWARE. 22 23""" 24usage: merge_driinfo.py <list of input files> 25 26Generates a source file which contains the DRI_CONF_xxx macros for generating 27the driinfo XML that describes the available DriConf options for a driver and 28its supported state trackers, based on the merged information from the input 29files. 30""" 31 32from __future__ import print_function 33 34import mako.template 35import re 36import sys 37 38 39# Some regexps used during input parsing 40RE_section_begin = re.compile(r'DRI_CONF_SECTION_(.*)') 41RE_option = re.compile(r'DRI_CONF_(.*)\((.*)\)') 42 43 44class Option(object): 45 """ 46 Represent a config option as: 47 * name: the xxx part of the DRI_CONF_xxx macro 48 * defaults: the defaults parameters that are passed into the macro 49 """ 50 def __init__(self, name, defaults): 51 self.name = name 52 self.defaults = defaults 53 54 55class Section(object): 56 """ 57 Represent a config section description as: 58 * name: the xxx part of the DRI_CONF_SECTION_xxx macro 59 * options: list of options 60 """ 61 def __init__(self, name): 62 self.name = name 63 self.options = [] 64 65 66def parse_inputs(input_filenames): 67 success = True 68 sections_lists = [] 69 70 for input_filename in input_filenames: 71 with open(input_filename, 'r') as infile: 72 sections = [] 73 sections_lists.append(sections) 74 75 section = None 76 77 linenum = 0 78 for line in infile: 79 linenum += 1 80 line = line.strip() 81 if not line: 82 continue 83 84 if line.startswith('//'): 85 continue 86 87 if line == 'DRI_CONF_SECTION_END': 88 if section is None: 89 print('{}:{}: no open section' 90 .format(input_filename, linenum)) 91 success = False 92 continue 93 section = None 94 continue 95 96 m = RE_section_begin.match(line) 97 if m: 98 if section is not None: 99 print('{}:{}: nested sections are not supported' 100 .format(input_filename, linenum)) 101 success = False 102 continue 103 if sections is None: 104 print('{}:{}: missing DRIINFO line' 105 .format(input_filename, linenum)) 106 success = False 107 break # parsing the rest really makes no sense 108 section = Section(m.group(1)) 109 sections.append(section) 110 continue 111 112 m = RE_option.match(line) 113 if m: 114 if section is None: 115 print('{}:{}: no open section' 116 .format(input_filename, linenum)) 117 success = False 118 break 119 section.options.append(Option(m.group(1), m.group(2))) 120 continue 121 122 print('{}:{}: do not understand this line' 123 .format(input_filename, linenum)) 124 success = False 125 126 if section is not None: 127 print('{}:end-of-file: missing end of section' 128 .format(input_filename)) 129 success = False 130 131 if success: 132 return sections_lists 133 return None 134 135 136def merge_sections(section_list): 137 """ 138 section_list: list of Section objects to be merged, all of the same name 139 Return a merged Section object (everything is deeply copied) 140 """ 141 merged_section = Section(section_list[0].name) 142 143 for section in section_list: 144 assert section.name == merged_section.name 145 146 for orig_option in section.options: 147 for merged_option in merged_section.options: 148 if orig_option.name == merged_option.name: 149 merged_option.defaults = orig_option.defaults 150 break 151 else: 152 merged_section.options.append(Option(orig_option.name, orig_option.defaults)) 153 154 return merged_section 155 156 157def merge_sections_lists(sections_lists): 158 """ 159 sections_lists: list of lists of Section objects to be merged 160 Return a merged list of merged Section objects; everything is deeply copied. 161 Default values for options in later lists override earlier default values. 162 """ 163 merged_sections = [] 164 165 for idx,sections in enumerate(sections_lists): 166 for base_section in sections: 167 original_sections = [base_section] 168 for next_sections in sections_lists[idx+1:]: 169 for j,section in enumerate(next_sections): 170 if section.name == base_section.name: 171 original_sections.append(section) 172 del next_sections[j] 173 break 174 175 merged_section = merge_sections(original_sections) 176 177 merged_sections.append(merged_section) 178 179 return merged_sections 180 181 182def main(input_filenames): 183 sections_lists = parse_inputs(input_filenames) 184 if sections_lists is None: 185 return False 186 187 merged_sections_list = merge_sections_lists(sections_lists) 188 189 driinfo_h_template = mako.template.Template("""\ 190// DO NOT EDIT - this file is automatically generated by merge_driinfo.py 191 192/* 193Use as: 194 195#include "xmlpool.h" 196 197static const char driinfo_xml[] = 198#include "this_file" 199; 200*/ 201 202DRI_CONF_BEGIN 203% for section in sections: 204 DRI_CONF_SECTION_${section.name} 205% for option in section.options: 206 DRI_CONF_${option.name}(${option.defaults}) 207% endfor 208 DRI_CONF_SECTION_END 209% endfor 210DRI_CONF_END""") 211 212 print(driinfo_h_template.render(sections=merged_sections_list)) 213 return True 214 215 216if __name__ == '__main__': 217 if len(sys.argv) <= 1: 218 print('Missing arguments') 219 sys.exit(1) 220 221 if not main(sys.argv[1:]): 222 sys.exit(1) 223