util: Helper to create sets and hashes with pointer keys
[mesa.git] / src / util / merge_driinfo.py
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 """
24 usage: merge_driinfo.py <list of input files>
25
26 Generates a source file which contains the DRI_CONF_xxx macros for generating
27 the driinfo XML that describes the available DriConf options for a driver and
28 its supported state trackers, based on the merged information from the input
29 files.
30 """
31
32 from __future__ import print_function
33
34 import mako.template
35 import re
36 import sys
37
38
39 # Some regexps used during input parsing
40 RE_section_begin = re.compile(r'DRI_CONF_SECTION_(.*)')
41 RE_option = re.compile(r'DRI_CONF_(.*)\((.*)\)')
42
43
44 class 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
55 class 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
66 def 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
136 def 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
157 def 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
182 def 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 /*
193 Use as:
194
195 #include "xmlpool.h"
196
197 static const char driinfo_xml[] =
198 #include "this_file"
199 ;
200 */
201
202 DRI_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
210 DRI_CONF_END""")
211
212 print(driinfo_h_template.render(sections=merged_sections_list))
213 return True
214
215
216 if __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)