1#!/usr/bin/env python
2
3from __future__ import print_function
4import re
5import sys
6
7re_identifier = re.compile(r'^[a-zA-Z_]')
8re_compat_handle = re.compile(r'^COMPAT_HANDLE\((.*)\)$')
9re_pad = re.compile(r'^_pad\d*$')
10re_compat = re.compile(r'^compat_.*_t$')
11
12def removeprefix(s, prefix):
13    if s.startswith(prefix):
14        return s[len(prefix):]
15    return s
16
17def removesuffix(s, suffix):
18    if s.endswith(suffix):
19        return s[:-len(suffix)]
20    return s
21
22def get_fields(looking_for, header_tokens):
23    level = 1
24    aggr = 0
25    fields = []
26    name = ''
27
28    for token in header_tokens:
29        if token in ('struct', 'union'):
30            if level == 1:
31                aggr = 1
32                fields = []
33                name = ''
34        elif token == '{':
35            level += 1
36        elif token == '}':
37            level -= 1
38            if level == 1 and name == looking_for:
39                fields.append(token)
40                return fields
41        elif re_identifier.match(token):
42            if not (aggr == 0 or name != ''):
43                name = token
44
45        if aggr != 0:
46            fields.append(token)
47
48    return []
49
50def build_enums(name, tokens):
51    level = 1
52    kind = ''
53    named = ''
54    fields = []
55    members = []
56    id = ''
57
58    for token in tokens:
59        if token in ('struct', 'union'):
60            if not level != 2:
61                fields = ['']
62            kind = "%s;%s" % (token, kind)
63        elif token == '{':
64            level += 1
65        elif token == '}':
66            level -= 1
67            if level == 1:
68                subkind = kind
69                (subkind, _, _) = subkind.partition(';')
70                if subkind == 'union':
71                    print("\nenum XLAT_%s {" % (name,))
72                    for m in members:
73                        print("    XLAT_%s_%s," % (name, m))
74                    print("};")
75                return
76            elif level == 2:
77                named = '?'
78        elif re_identifier.match(token):
79            id = token
80            k = kind
81            (_, _, k) = k.partition(';')
82            if named != '' and k != '':
83                if len(fields) > 0 and fields[0] == '':
84                    fields.pop(0)
85                build_enums("%s_%s" % (name, token), fields)
86                named = '!'
87        elif token == ',':
88            if level == 2:
89                members.append(id)
90        elif token == ';':
91            if level == 2:
92                members.append(id)
93            if named != '':
94                (_, _, kind) = kind.partition(';')
95            named = ''
96        if len(fields) != 0:
97            fields.append(token)
98
99def handle_field(prefix, name, id, type, fields):
100    if len(fields) == 0:
101        print(" \\")
102        if type == '':
103            print("%s(_d_)->%s = (_s_)->%s;" % (prefix, id, id), end='')
104        else:
105            k = id.replace('.', '_')
106            print("%sXLAT_%s_HNDL_%s(_d_, _s_);" % (prefix, name, k), end='')
107    elif not '{' in fields:
108        tag = ' '.join(fields)
109        tag = re.sub(r'\s*(struct|union)\s+(compat_)?(\w+)\s.*', '\\3', tag)
110        print(" \\")
111        print("%sXLAT_%s(&(_d_)->%s, &(_s_)->%s);" % (prefix, tag, id, id), end='')
112    else:
113        func_id = id
114        func_tokens = fields
115        kind = ''
116        array = ""
117        level = 1
118        arrlvl = 1
119        array_type = ''
120        id = ''
121        type = ''
122        fields = []
123        for token in func_tokens:
124            if token in ('struct', 'union'):
125                if level == 2:
126                    fields = ['']
127                if level == 1:
128                    kind = token
129                    if kind == 'union':
130                        tmp = func_id.replace('.', '_')
131                        print(" \\")
132                        print("%sswitch (%s) {" % (prefix, tmp), end='')
133            elif token == '{':
134                level += 1
135                id = ''
136            elif token == '}':
137                level -= 1
138                id = ''
139                if level == 1 and kind == 'union':
140                    print(" \\")
141                    print("%s}" % (prefix,), end='')
142            elif token == '[':
143                if level != 2 or arrlvl != 1:
144                    pass
145                elif array == '':
146                    array = ' '
147                else:
148                    array = "%s;" % (array,)
149                arrlvl += 1
150            elif token == ']':
151                arrlvl -= 1
152            elif re_compat_handle.match(token):
153                if level == 2 and id == '':
154                    m = re_compat_handle.match(token)
155                    type = m.groups()[0]
156                    type = removeprefix(type, 'compat_')
157            elif token == "compat_domain_handle_t":
158                if level == 2 and id == '':
159                    array_type = token
160            elif re_identifier.match(token):
161                id = token
162            elif token in (',', ';'):
163                if level == 2 and not re_pad.match(id):
164                    if kind == 'union':
165                        tmp = "%s.%s" % (func_id, id)
166                        tmp = tmp.replace('.', '_')
167                        print(" \\")
168                        print("%scase XLAT_%s_%s:" % (prefix, name, tmp), end='')
169                        if len(fields) > 0 and fields[0] == '':
170                            fields.pop(0)
171                        handle_field("%s    " % (prefix,), name, "%s.%s" % (func_id, id), type, fields)
172                    elif array == '' and array_type == '':
173                        if len(fields) > 0 and fields[0] == '':
174                            fields.pop(0)
175                        handle_field(prefix, name, "%s.%s" % (func_id, id), type, fields)
176                    elif array == '':
177                        copy_array("    ", "%s.%s" % (func_id, id))
178                    else:
179                        (_, _, array) = array.partition(';')
180                        if len(fields) > 0 and fields[0] == '':
181                            fields.pop(0)
182                        handle_array(prefix, name, "{func_id}.{id}", array, type, fields)
183                    if token == ';':
184                        fields = []
185                        id = ''
186                        type = ''
187                    array = ''
188                    if kind == 'union':
189                        print(" \\")
190                        print("%s    break;" % (prefix,), end='')
191            else:
192                if array != '':
193                    array = "%s %s" % (array, token)
194            if len(fields) > 0:
195                fields.append(token)
196
197def copy_array(prefix, id):
198    print(" \\")
199    print("%sif ((_d_)->%s != (_s_)->%s) \\" % (prefix, id, id))
200    print("%s    memcpy((_d_)->%s, (_s_)->%s, sizeof((_d_)->%s));" % (prefix, id, id, id), end='')
201
202def handle_array(prefix, name, id, array, type, fields):
203    i = re.sub(r'[^;]', '', array)
204    i = "i%s" % (len(i),)
205
206    print(" \\")
207    print("%s{ \\" % (prefix,))
208    print("%s    unsigned int %s; \\" % (prefix, i))
209    (head, _, tail) = array.partition(';')
210    head = head.strip()
211    print("%s    for (%s = 0; %s < %s; ++%s) {" % (prefix, i, i, head, i), end='')
212    if not ';' in array:
213        handle_field("%s        " % (prefix,), name, "%s[%s]" % (id, i), type, fields)
214    else:
215        handle_array("%s        " % (prefix,) , name, "%s[%s]" % (id, i), tail, type, fields)
216    print(" \\")
217    print("%s    } \\" % (prefix,))
218    print("%s}" % (prefix,), end='')
219
220def build_body(name, tokens):
221    level = 1
222    id = ''
223    array = ''
224    arrlvl = 1
225    array_type = ''
226    type = ''
227    fields = []
228
229    print("\n#define XLAT_%s(_d_, _s_) do {" % (name,), end='')
230
231    for token in tokens:
232        if token in ('struct', 'union'):
233            if level == 2:
234                fields = ['']
235        elif token == '{':
236            level += 1
237            id = ''
238        elif token == '}':
239            level -= 1
240            id = ''
241        elif token == '[':
242            if level != 2 or arrlvl != 1:
243                pass
244            elif array == '':
245                array = ' '
246            else:
247                array = "%s;" % (array,)
248            arrlvl += 1
249        elif token == ']':
250            arrlvl -= 1
251        elif re_compat_handle.match(token):
252            if level == 2 and id == '':
253                m = re_compat_handle.match(token)
254                type = m.groups()[0]
255                type = removeprefix(type, 'compat_')
256        elif token == "compat_domain_handle_t":
257            if level == 2 and id == '':
258                array_type = token
259        elif re_identifier.match(token):
260            if array != '':
261                array = "%s %s" % (array, token)
262            else:
263                id = token
264        elif token in (',', ';'):
265            if level == 2 and not re_pad.match(id):
266                if array == '' and array_type == '':
267                    if len(fields) > 0 and fields[0] == '':
268                        fields.pop(0)
269                    handle_field("    ", name, id, type, fields)
270                elif array == '':
271                    copy_array("    ", id)
272                else:
273                    (head, sep, tmp) = array.partition(';')
274                    if sep == '':
275                        tmp = head
276                    if len(fields) > 0 and fields[0] == '':
277                        fields.pop(0)
278                    handle_array("    ", name, id, tmp, type, fields)
279                if token == ';':
280                    fields = []
281                    id = ''
282                    type = ''
283                array = ''
284        else:
285            if array != '':
286                array = "%s %s" % (array, token)
287        if len(fields) > 0:
288            fields.append(token)
289    print(" \\\n} while (0)")
290
291def check_field(kind, name, field, extrafields):
292    if not '{' in extrafields:
293        print("; \\")
294        if len(extrafields) != 0:
295            for token in extrafields:
296                if token in ('struct', 'union'):
297                    pass
298                elif re_identifier.match(token):
299                    print("    CHECK_%s" % (removeprefix(token, 'xen_'),), end='')
300                    break
301                else:
302                    raise Exception("Malformed compound declaration: '%s'" % (token,))
303        elif not '.' in field:
304            print("    CHECK_FIELD_(%s, %s, %s)" % (kind, name, field), end='')
305        else:
306            n = field.count('.')
307            field = field.replace('.', ', ')
308            print("    CHECK_SUBFIELD_%s_(%s, %s, %s)" % (n, kind, name, field), end='')
309    else:
310        level = 1
311        fields = []
312        id = ''
313
314        for token in extrafields:
315            if token in ('struct', 'union'):
316                if level == 2:
317                    fields = ['']
318            elif token == '{':
319                level += 1
320                id = ''
321            elif token == '}':
322                level -= 1
323                id = ''
324            elif re_compat.match(token):
325                if level == 2:
326                    fields = ['']
327                    token = removesuffix(token, '_t')
328                    token = removeprefix(token, 'compat_')
329            elif re.match(r'^evtchn_.*_compat_t$', token):
330                if level == 2 and token != "evtchn_port_compat_t":
331                    fields = ['']
332                    token = removesuffix(token, '_compat_t')
333            elif re_identifier.match(token):
334                id = token
335            elif token in (',', ';'):
336                if level == 2 and not re_pad.match(id):
337                    if len(fields) > 0 and fields[0] == '':
338                        fields.pop(0)
339                    check_field(kind, name, "%s.%s" % (field, id), fields)
340                    if token == ";":
341                        fields = []
342                        id = ''
343            if len(fields) > 0:
344                fields.append(token)
345
346def build_check(name, tokens):
347    level = 1
348    fields = []
349    kind = ''
350    id = ''
351    arrlvl = 1
352
353    print("")
354    print("#define CHECK_%s \\" % (name,))
355
356    for token in tokens:
357        if token in ('struct', 'union'):
358            if level == 1:
359                kind = token
360                print("    CHECK_SIZE_(%s, %s)" % (kind, name), end='')
361            elif level == 2:
362                fields = ['']
363        elif token == '{':
364            level += 1
365            id = ''
366        elif token == '}':
367            level -= 1
368            id = ''
369        elif token == '[':
370            arrlvl += 1
371        elif token == ']':
372            arrlvl -= 1
373        elif re_compat.match(token):
374            if level == 2 and token != "compat_argo_port_t":
375                fields = ['']
376                token = removesuffix(token, '_t')
377                token = removeprefix(token, 'compat_')
378        elif re_identifier.match(token):
379            if not (level != 2 or arrlvl != 1):
380                id = token
381        elif token in (',', ';'):
382            if level == 2 and not re_pad.match(id):
383                if len(fields) > 0 and fields[0] == '':
384                    fields.pop(0)
385                check_field(kind, name, id, fields)
386                if token == ";":
387                    fields = []
388                    id = ''
389
390        if len(fields) > 0:
391            fields.append(token)
392    print("")
393
394
395def main():
396    header_tokens = []
397    re_tokenazier = re.compile(r'\s+')
398    re_skip_line = re.compile(r'^\s*(#|$)')
399    re_spacer = re.compile(r'([\]\[,;:{}])')
400
401    with open(sys.argv[1]) as header:
402        for line in header:
403            if re_skip_line.match(line):
404                continue
405            line = re_spacer.sub(' \\1 ', line)
406            line = line.strip()
407            header_tokens += re_tokenazier.split(line)
408
409    with open(sys.argv[2]) as compat_list:
410        for line in compat_list:
411            words = re_tokenazier.split(line, maxsplit=1)
412            what = words[0]
413            name = words[1]
414
415            name = removeprefix(name, 'xen')
416            name = name.strip()
417
418            fields = get_fields("compat_%s" % (name,), header_tokens)
419            if len(fields) == 0:
420                raise Exception("Fields of 'compat_%s' not found in '%s'" % (name, sys.argv[1]))
421
422            if what == "!":
423                build_enums(name, fields)
424                build_body(name, fields)
425            elif what == "?":
426                build_check(name, fields)
427            else:
428                raise Exception("Invalid translation indicator: '%s'" % (what,))
429
430if __name__ == '__main__':
431    main()
432