summaryrefslogtreecommitdiff
path: root/envytools/rnn/xml2text
blob: b65929d0d072acbecca5594ad899c45a42e76dca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
#!/usr/bin/python
import sys
from lxml import etree as ET

# this does not recognize octal unlike int(s, 0)
def intdh(s):
	if s.startswith("0x"):
		return int(s[2:], 16)
	else:
		return int(s)

if sys.argv[1:2]:
	xml = sys.argv[1]
	tree = ET.parse(xml)
else:
	tree = ET.parse(sys.stdin)

root = tree.getroot();

# TODO: make this configurable and autoselect the most frequent
reg_default = "reg32"
type_defaults = set(("enum", "bitfield", "hexa"))
attr_defaults = {"prefix" : "none"}
true_strings = ("1", "yes", "true")

ns = "{http://nouveau.freedesktop.org/}"

out = sys.stdout

indent = ""

comments = {}
empty_line = False

def process(container):
	global indent
	indent += "\t"
	_process(container)
	indent = indent[:-1]

def get_pos(elem, which):
	pos = elem.attrib.get(which, None)
	if pos is not None:
		return intdh(pos)
	else:
		return intdh(elem.attrib.get("pos", "-1"))

def _process(container):
	global empty_line
	maxvalue = max([-1] + [max(intdh(elem.attrib.get("offset", "-1")), intdh(elem.attrib.get("value", "-1"))) for elem in container.iterchildren(tag=ET.Element)])
	maxlow = max([-1] + [get_pos(elem, "low") for elem in container.iterchildren(tag=ET.Element)])
	maxhigh = max([-1] + [get_pos(elem, "high") for elem in container.iterchildren(tag=ET.Element)])

	any_multibit = False
	for elem in container.iterchildren(tag=ET.Element):
		if "low" in elem.attrib and "high" in elem.attrib and elem.attrib["low"] != elem.attrib["high"]:
			any_multibit = True
			break
	value_hexdigits = len(hex(maxvalue)) - 2 if maxvalue >= 0 else -1

	offset_format = "%0" + str(value_hexdigits) + "x" if maxvalue >= 0 else None
	if maxvalue >= 16:
		value_len = value_hexdigits + 2
		# TODO: smart pretty print value instead of this
		value_format = "0x%0" + str(value_hexdigits) + "x"
	elif maxvalue >= 0:
		value_len = len(str(maxvalue))
		# TODO: smart pretty print value instead of this
		value_format = "%" + str(value_len) + "d"
	else:
		value_len = -1
		value_format = None

	low_format = "%0" + str(len(str(maxlow))) + "d" if maxlow >= 0 else None
	high_format = "%0" + str(len(str(maxhigh))) + "d" if maxhigh >= 0 else None

	for elem in container.iterchildren(tag=ET.Element):
		tag = elem.tag
		assert tag.startswith(ns)
		tag = tag[len(ns):]
		if tag == "brief" or tag == "doc":
			continue

		is_reglike = False
		line = ""
		if ((tag[:3] == "reg" and tag[3:].isdigit()) or tag == "array" or tag == "stripe") and "offset" in elem.attrib:
			line = offset_format % (intdh(elem.attrib.get("offset", -1)),)
			del elem.attrib["offset"]
			if "stride" in elem.attrib:
				line += " {" + elem.attrib["stride"] + "}"
				del elem.attrib["stride"]
			if "length" in elem.attrib:
				line += " [" + elem.attrib["length"] + "]"
				del elem.attrib["length"]
			if "name" in elem.attrib:
				line += " " + elem.attrib["name"]
				del elem.attrib["name"]
			is_reglike = True
		elif tag == "bitfield":
			if "low" not in elem.attrib and "pos" not in elem.attrib:
				print >> sys.stderr, "Bitfield " + elem.attrib.get("name", "<unnamed>") + " has no low bit!"
			low = get_pos(elem, "low")
			high = get_pos(elem, "high")
			if high < 0:
				high = low
			if low != high:
				line = low_format % (low,) + "-" + high_format % (high,)
			elif any_multibit:
#				line = (" " * (len(str(maxlow)))) + low_format % (low,) + (" " * (len(str(maxhigh)) - len(str(maxlow)) + 1))
				line = low_format % (low,) + (" " * (len(str(maxhigh)) + 1))
			else:
				line = low_format % (low,)
                        if "pos" in elem.attrib:
                                del elem.attrib["pos"]
			if "low" in elem.attrib:
				del elem.attrib["low"]
			if "high" in elem.attrib:
				del elem.attrib["high"]
		elif tag == "value":
			if "value" in elem.attrib:
				line = (value_format % (intdh(elem.attrib["value"]),))
				if "name" in elem.attrib:
					line += " = "
				del elem.attrib["value"]
			else:
				if "name" not in elem.attrib:
					print >> sys.stderr, "Value has no value and no name attributes!"
				if value_len >= 0:
					line += " " * (value_len + 3)

			if "name" in elem.attrib:
				line += elem.attrib["name"]
				del elem.attrib["name"]
		elif tag == "import":
			line = "#import"
			if "file" in elem.attrib:
				file = elem.attrib["file"]
				line += " \"" + file + "\""
			else:
				print >> sys.stderr, "Import with no file attribute!"
			del elem.attrib["file"]
		elif tag[:4] == "use-":
			line = "use " + tag[4:]
		else:
			line = tag
		if "name" in elem.attrib:
			line += " " + elem.attrib["name"]
			del elem.attrib["name"]
		if is_reglike or tag == "bitfield":
			need_regwidth = tag[:3] == "reg" and tag != reg_default
			if ("type" in elem.attrib and elem.attrib["type"] not in type_defaults) or need_regwidth:
				line += " " + elem.attrib.get("type", "reg").replace(" ", ",") + (":" + tag[3:] if need_regwidth else "")
			if "type" in elem.attrib:
				del elem.attrib["type"]
		brief = "\n".join([elem2.text for elem2 in elem.iterchildren(tag=ET.Element) if elem2.tag == ns + "brief"])
		if brief:
			line += " \"" + brief + "\""

		if "varset" in elem.attrib and "variants" in elem.attrib:
			elem.attrib["variants"] = elem.attrib["varset"] + "=" + elem.attrib["variants"]
			del elem.attrib["varset"]

		for keyword in ("inline", "bare"):
			if keyword in elem.attrib:
				if elem.attrib[keyword].lower() in true_strings:
					line = keyword + " " + line
				del elem.attrib[keyword]

		for attr in elem.attrib.keys():
			value = elem.attrib[attr]
			if value != attr_defaults.get(attr):
				line += " " + (attr if attr != "variants" else "") + "(" + value + ")"
		if is_reglike:
			if tag == "array":
				line += " ="
			elif tag == "stripe":
				line += " :="
		elif tag == "bitfield" or tag == "value" or tag == "import" or tag[:4] == "use-":
			pass
		else:
			line += ":"
		our_comments = comments.get(elem, [])
		if our_comments:
			line += " // " + our_comments[0]
		if empty_line:
			print
			empty_line = False
		print indent + line
		if len(our_comments) > 1:
			for comment in our_comments[1:]:
				print indent + "\t// " + comment

		doc = "\n".join([elem2.text for elem2 in elem.iterchildren(tag=ET.Element) if elem2.tag == ns + "doc"])
		if doc:
			lines = [line.strip() for line in doc.split("\n")]
			while lines and not lines[0]:
				lines = lines[1:]
			while lines and not lines[-1]:
				lines = lines[:-1]
			for line in lines:
				print indent + "\t: " + line
		process(elem)
		if elem.tail and elem.tail.count("\n") > 1:
			empty_line = True

last_non_comment = None
for node in root.iter():
	if isinstance(node, ET._Comment) and last_non_comment is not None:
# reattach whitespace following comment to previous node
		prev = node.getprevious()
		if prev is not None:
			prev.tail = (prev.tail if prev.tail else "") + node.tail
		else:
			prev = node.getparent()
			if prev is not None:
				prev.text = (prev.text if prev.text else "") + node.tail

		node.getparent().remove(node)
		lines = node.text.split("\n")
		queue = []
		got_anything = comments.get(last_non_comment) is not None
		for line in lines:
			line = line.strip()
			if line or got_anything:
				queue.append(line)
			if line:
				comments.setdefault(last_non_comment, []).extend(queue)
				queue = []
				got_anything = True
	else:
		last_non_comment = node
_process(root)