--- /dev/null
+#
+# Copyright 2017 Advanced Micro Devices, Inc.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# on the rights to use, copy, modify, merge, publish, distribute, sub
+# license, and/or sell copies of the Software, and to permit persons to whom
+# the Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+"""
+usage: merge_driinfo.py <list of input files>
+
+Generates a source file which contains the DRI_CONF_xxx macros for generating
+the driinfo XML that describes the available DriConf options for a driver and
+its supported state trackers, based on the merged information from the input
+files.
+"""
+
+from __future__ import print_function
+
+import mako.template
+import re
+import sys
+
+
+# Some regexps used during input parsing
+RE_section_begin = re.compile(r'DRI_CONF_SECTION_(.*)')
+RE_option = re.compile(r'DRI_CONF_(.*)\((.*)\)')
+
+
+class Option(object):
+ """
+ Represent a config option as:
+ * name: the xxx part of the DRI_CONF_xxx macro
+ * defaults: the defaults parameters that are passed into the macro
+ """
+ def __init__(self, name, defaults):
+ self.name = name
+ self.defaults = defaults
+
+
+class Section(object):
+ """
+ Represent a config section description as:
+ * name: the xxx part of the DRI_CONF_SECTION_xxx macro
+ * options: list of options
+ """
+ def __init__(self, name):
+ self.name = name
+ self.options = []
+
+
+def parse_inputs(input_filenames):
+ success = True
+ sections_lists = []
+
+ for input_filename in input_filenames:
+ with open(input_filename, 'r') as infile:
+ sections = []
+ sections_lists.append(sections)
+
+ section = None
+
+ linenum = 0
+ for line in infile:
+ linenum += 1
+ line = line.strip()
+ if not line:
+ continue
+
+ if line.startswith('//'):
+ continue
+
+ if line == 'DRI_CONF_SECTION_END':
+ if section is None:
+ print('{}:{}: no open section'
+ .format(input_filename, linenum))
+ success = False
+ continue
+ section = None
+ continue
+
+ m = RE_section_begin.match(line)
+ if m:
+ if section is not None:
+ print('{}:{}: nested sections are not supported'
+ .format(input_filename, linenum))
+ success = False
+ continue
+ if sections is None:
+ print('{}:{}: missing DRIINFO line'
+ .format(input_filename, linenum))
+ success = False
+ break # parsing the rest really makes no sense
+ section = Section(m.group(1))
+ sections.append(section)
+ continue
+
+ m = RE_option.match(line)
+ if m:
+ if section is None:
+ print('{}:{}: no open section'
+ .format(input_filename, linenum))
+ success = False
+ break
+ section.options.append(Option(m.group(1), m.group(2)))
+ continue
+
+ print('{}:{}: do not understand this line'
+ .format(input_filename, linenum))
+ success = False
+
+ if section is not None:
+ print('{}:end-of-file: missing end of section'
+ .format(input_filename))
+ success = False
+
+ if success:
+ return sections_lists
+ return None
+
+
+def merge_sections(section_list):
+ """
+ section_list: list of Section objects to be merged, all of the same name
+ Return a merged Section object (everything is deeply copied)
+ """
+ merged_section = Section(section_list[0].name)
+
+ for section in section_list:
+ assert section.name == merged_section.name
+
+ for orig_option in section.options:
+ for merged_option in merged_section.options:
+ if orig_option.name == merged_option.name:
+ merged_option.defaults = orig_option.defaults
+ break
+ else:
+ merged_section.options.append(Option(orig_option.name, orig_option.defaults))
+
+ return merged_section
+
+
+def merge_sections_lists(sections_lists):
+ """
+ sections_lists: list of lists of Section objects to be merged
+ Return a merged list of merged Section objects; everything is deeply copied.
+ Default values for options in later lists override earlier default values.
+ """
+ merged_sections = []
+
+ for idx,sections in enumerate(sections_lists):
+ for base_section in sections:
+ original_sections = [base_section]
+ for next_sections in sections_lists[idx+1:]:
+ for j,section in enumerate(next_sections):
+ if section.name == base_section.name:
+ original_sections.append(section)
+ del next_sections[j]
+ break
+
+ merged_section = merge_sections(original_sections)
+
+ merged_sections.append(merged_section)
+
+ return merged_sections
+
+
+def main(input_filenames):
+ sections_lists = parse_inputs(input_filenames)
+ if sections_lists is None:
+ return False
+
+ merged_sections_list = merge_sections_lists(sections_lists)
+
+ driinfo_h_template = mako.template.Template("""\
+// DO NOT EDIT - this file is automatically generated by merge_driinfo.py
+
+/*
+Use as:
+
+#include "xmlpool.h"
+
+static const char driinfo_xml[] =
+#include "this_file"
+;
+*/
+
+DRI_CONF_BEGIN
+% for section in sections:
+ DRI_CONF_SECTION_${section.name}
+% for option in section.options:
+ DRI_CONF_${option.name}(${option.defaults})
+% endfor
+ DRI_CONF_SECTION_END
+% endfor
+DRI_CONF_END""")
+
+ print(driinfo_h_template.render(sections=merged_sections_list))
+ return True
+
+
+if __name__ == '__main__':
+ if len(sys.argv) <= 1:
+ print('Missing arguments')
+ sys.exit(1)
+
+ if not main(sys.argv[1:]):
+ sys.exit(1)