1#!/usr/bin/env python3
2#
3# SPDX-FileCopyrightText: 2014 Weng Xuetian <wengxt@gmail.com>
4#
5# SPDX-License-Identifier: LGPL-2.1-only
6#
7
8"""
9This is a ugly code generate script, which is intended to be used
10against i18nIMProto.c in IMdkit
11it will generate all serialization code against xim protocol frame
12"""
13import fileinput
14import collections
15import sys
16funcs = collections.OrderedDict()
17static_size = dict()
18
19funcname = None
20for line in fileinput.input(sys.argv[1]):
21    if "XimFrameRec" in line:
22        tokens = line.strip().split()
23        token = None
24        for token in tokens:
25            if "[]" in token:
26                break
27        if token is not None:
28            funcname = "xcb_im_" + token[:-2]
29            funcs[funcname] = []
30            fieldidx = 0
31    elif "FRAME(EOL)" in line:
32        funcname = None
33    elif funcname is not None:
34        line = line.strip()
35
36        try:
37            tp = line[:line.rindex("),")+1]
38            if tp == "_FRAME(POINTER)":
39                continue
40            if line.find("/*") != -1:
41                name = line[line.find("/*")+2:line.find("*/")]
42                name = name.strip().replace(" ", "_").replace(".", "_").replace("-", "_")
43            else:
44                name = "field{0}".format(fieldidx)
45                fieldidx += 1
46            funcs[funcname].append((tp,name))
47        except Exception as e:
48            pass
49
50def gettypename(attr):
51    if "BIT8" in attr:
52        return ("uint8_t")
53    elif "BIT16" in attr:
54        return ("uint16_t")
55    elif "BIT32" in attr:
56        return ("uint32_t")
57    elif attr == "_FRAME(BARRAY)":
58        return ("xcb_im_bytearray_t")
59    elif "_PTR" in attr:
60        return "xcb_im_" + attr[attr.find("(") + 1:attr.find(")")]
61    else:
62        print(attr)
63        assert(False)
64
65for funcname, attrs in funcs.items():
66    size = 0
67    for attr, name in attrs:
68        if "BIT8" in attr:
69            size += 1
70        elif "BIT16" in attr:
71            size += 2
72        elif "BIT32" in attr:
73            size += 4
74        elif "PAD" in attr:
75            pad = int(attr[4])
76            size += 0 if size % pad == 0 else (pad - size % pad)
77        elif "PTR" in attr:
78            if static_size[gettypename(attr)] < 0:
79                size = -1
80                break
81            else:
82                size += static_size[gettypename(attr)]
83        else:
84            size = -1
85            break
86    static_size[funcname] = size
87
88
89
90def getsize(attr, name):
91    if "BIT8" in attr:
92        return "1"
93    elif "BIT16" in attr:
94        return "2"
95    elif "BIT32" in attr:
96        return "4"
97    elif "_PTR" in attr:
98        return "{1}_size(&frame->{0})".format(name, gettypename(attr))
99
100
101def search_barray_length(attrs, i):
102    for attr, name in reversed(attrs[0:i]):
103        if "length" in name:
104            return (attr, name)
105
106    return attrs[i - 1]
107
108if len(sys.argv) > 2:
109    for funcname, attrs in funcs.items():
110        print("typedef struct _{0}_t".format(funcname))
111        print("{")
112        skip = False
113        for i, (attr, name) in enumerate(attrs):
114            if skip:
115                skip = False
116                continue
117            if "_FRAME(B" in attr:
118                print("    {1} {0};".format(name, gettypename(attr)))
119            if "_PTR" in attr:
120                print("    {1}_t {0};".format(name, gettypename(attr)))
121            elif "_PAD" in attr:
122                pass
123            elif "_BYTE_COUNTER" in attr:
124                pass
125            elif attr == "_FRAME(ITER)":
126                (iterattr, itername) = attrs[i + 1]
127                print("    struct {")
128                print("        uint32_t size;")
129                if "_FRAME(B" in iterattr:
130                    print("        {0}* items;".format(gettypename(iterattr)))
131                if "_PTR" in iterattr:
132                    print("        {0}_t* items;".format(gettypename(iterattr)))
133                print("    }} {0};".format(name))
134                skip = True
135
136        print("}} {0}_t;".format(funcname))
137        print("")
138    def print_generic(cat):
139        print("#define frame_{0}_func(FRAME) _Generic((FRAME), \\".format(cat))
140        first = True
141        for funcname, attrs in funcs.items():
142            if first:
143                first=False
144            else:
145                print(",\\")
146            if cat == "size":
147                if static_size[funcname] >= 0:
148                    print("    {0}_t : {1}".format(funcname, static_size[funcname]), end='')
149                else:
150                    print("    {0}_t : {0}_{1}(({0}_t*) &(FRAME))".format(funcname, cat), end='')
151            else:
152                print("    {0}_t : {0}_{1}".format(funcname, cat), end='')
153        print(")")
154        print("")
155    for cat in ["read", "write", "size", "free"]:
156        print_generic(cat)
157    def print_generic_size():
158        print("#define frame_has_static_size(FRAME) _Generic((FRAME), \\".format(cat))
159        first = True
160        for funcname, attrs in funcs.items():
161            if first:
162                first=False
163            else:
164                print(",\\")
165            print("    {0}_t : {1}".format(funcname, "true" if static_size[funcname] >= 0 else "false"), end='')
166        print(")")
167        print("")
168    print_generic_size()
169
170    for funcname, attrs in funcs.items():
171        usecounter = any("_BYTE_COUNTER" in attr for attr, name in attrs)
172        usecounter8 = any("_BYTE_COUNTER(BIT8" in attr for attr, name in attrs)
173        usecounter16 = any("_BYTE_COUNTER(BIT16" in attr for attr, name in attrs)
174        usecounter32 = any("_BYTE_COUNTER(BIT32" in attr for attr, name in attrs)
175        print(("""void {0}_read({0}_t *frame, uint8_t **data, size_t *len, bool swap);\n"""
176               """uint8_t* {0}_write({0}_t *frame, uint8_t *data, bool swap);\n"""
177               """void {0}_free({0}_t *frame);""").format(funcname))
178        if static_size[funcname] >= 0:
179            print("""#define {0}_size(ARG...) (((void)(ARG)), ({1}))""".format(funcname, static_size[funcname]))
180        else:
181            print("""size_t {0}_size({0}_t *frame);""".format(funcname))
182        print("")
183else:
184    print("#include <string.h>")
185    print("#include \"parser.h\"")
186    print("#include \"ximproto.h\"")
187    print("")
188
189    for funcname, attrs in funcs.items():
190        usecounter = any("_BYTE_COUNTER" in attr for attr, name in attrs)
191        usecounter8 = any("_BYTE_COUNTER(BIT8" in attr for attr, name in attrs)
192        usecounter16 = any("_BYTE_COUNTER(BIT16" in attr for attr, name in attrs)
193        usecounter32 = any("_BYTE_COUNTER(BIT32" in attr for attr, name in attrs)
194        usepad = any("_PAD" in attr for attr, name in attrs)
195        print("void {0}_read({0}_t *frame, uint8_t **data, size_t *len, bool swap)".format(funcname))
196        print("{")
197        if len(attrs) > 0:
198            print("    memset(frame, 0, sizeof(*frame));")
199        if usepad:
200            print("    uint8_t* start = *data;")
201        if usecounter:
202            if usecounter8:
203                print("    uint8_t counter8 = 0;")
204            if usecounter16:
205                print("    uint16_t counter16 = 0;")
206            if usecounter32:
207                print("    uint32_t counter32 = 0;")
208            print("    size_t counter = 0;")
209        skip = False
210        for i, (attr, name) in enumerate(attrs):
211            if skip:
212                skip = False
213                continue
214            if "_FRAME(BIT" in attr or "_PTR" in attr:
215                print("    {1}_read(&frame->{0}, data, len, swap);".format(name, gettypename(attr)))
216                print("    if (!*data) { return; }")
217            elif "_FRAME(BARRAY" in attr:
218                (lenattr, lenname) = search_barray_length(attrs, i)
219                print("    {1}_read(&frame->{0}, frame->{2}, data, len, swap);".format(name, gettypename(attr), lenname))
220                print("    if (!*data) { return; }")
221            elif "_PAD" in attr:
222                print("    *data = (uint8_t*) align_to_{0}((uintptr_t) *data, *data - start, len);".format(attr[4]))
223                print("    if (!*data) { return; }")
224            elif "_BYTE_COUNTER" in attr:
225                if "BIT8" in attr:
226                    countername = "counter8"
227                elif "BIT16" in attr:
228                    countername = "counter16"
229                elif "BIT32" in attr:
230                    countername = "counter32"
231                print("    {1}_read(&{0}, data, len, swap);".format(countername, gettypename(attr)))
232                print("    if (!*data) { return; }")
233                if countername != "counter":
234                    print("    counter = {0};".format(countername))
235            elif attr == "_FRAME(ITER)":
236                (iterattr, itername) = attrs[i + 1]
237                print("    if (counter > *len) { *data = NULL; return; } else { *len -= counter; } ")
238                print("    frame->{0}.items = NULL;".format(name, gettypename(iterattr)))
239                print("    frame->{0}.size = 0;".format(name))
240                print("    while (counter != 0) {")
241                if "_PTR" in iterattr:
242                    print("        void* temp = realloc(frame->{0}.items, (frame->{0}.size + 1) * sizeof({1}_t));".format(name, gettypename(iterattr)))
243                else:
244                    print("        void* temp = realloc(frame->{0}.items, (frame->{0}.size + 1) * sizeof({1}));".format(name, gettypename(iterattr)))
245                print("        if (!temp) {")
246                print("            *data = NULL;")
247                print("            return;")
248                print("        }")
249                print("        frame->{0}.items = temp;".format(name))
250                print("        {1}_read(&frame->{0}.items[frame->{0}.size], data, &counter, swap);".format(name, gettypename(iterattr)))
251                print("        if (!*data) { return; }")
252                print("        frame->{0}.size++;".format(name))
253                print("    }")
254                skip = True
255
256        print("}")
257        print("")
258        print("uint8_t* {0}_write({0}_t *frame, uint8_t *data, bool swap)".format(funcname))
259        print("{")
260        if usepad:
261            print("    uint8_t* start = data;")
262        if usecounter:
263            if usecounter8:
264                print("    uint8_t counter8 = 0;")
265            if usecounter16:
266                print("    uint16_t counter16 = 0;")
267            if usecounter32:
268                print("    uint32_t counter = 0;")
269        skip = False
270        for i, (attr, name) in enumerate(attrs):
271            if skip:
272                skip = False
273                continue
274            if "_FRAME(BIT" in attr or "_PTR" in attr:
275                print("    data = {1}_write(&frame->{0}, data, swap);".format(name, gettypename(attr)))
276            elif "_FRAME(BARRAY" in attr:
277                (lenattr, lenname) = search_barray_length(attrs, i)
278                print("    data = {1}_write(&frame->{0}, frame->{2}, data, swap);".format(name, gettypename(attr), lenname))
279            elif "_PAD" in attr:
280                print("    data = (uint8_t*) align_to_{0}((uintptr_t) data, data - start, NULL);".format(attr[4]))
281            elif "_BYTE_COUNTER" in attr:
282                for j, (targetattr, targetname) in enumerate(attrs):
283                    if j < i + 1:
284                        continue
285                    if targetattr == "_FRAME(ITER)":
286                        (iterattr, itername) = attrs[j + 1]
287                        break
288                if "BIT8" in attr:
289                    countername = "counter8"
290                elif "BIT16" in attr:
291                    countername = "counter16"
292                elif "BIT32" in attr:
293                    countername = "counter"
294                if "_PTR" in iterattr:
295                    print("    {0} = 0;".format(countername));
296                    print("    for (uint32_t i = 0; i < frame->{0}.size; i++) {{".format(targetname))
297                    print("        {2} += {1}_size(&frame->{0}.items[i]);".format(targetname, gettypename(iterattr), countername))
298                    print("    }")
299                else:
300                    print("    {0} = frame->{1}.size * {2};".format(countername, targetname, getsize(iterattr, itername)))
301                print("    data = {1}_write(&{0}, data, swap);".format(countername, gettypename(attr)))
302            elif attr == "_FRAME(ITER)":
303                (iterattr, itername) = attrs[i + 1]
304                print("    for (uint32_t i = 0; i < frame->{0}.size; i++) {{".format(name))
305                print("        data = {1}_write(&frame->{0}.items[i], data, swap);".format(name, gettypename(iterattr)))
306                print("    }")
307                skip = True
308
309        print("    return data;");
310
311        print("}")
312        print("")
313
314        if static_size[funcname] < 0:
315            print("size_t {0}_size({0}_t *frame)".format(funcname))
316            print("{")
317            print("    size_t size = 0;")
318            skip = False
319            for i, (attr, name) in enumerate(attrs):
320                if skip:
321                    skip = False
322                    continue
323                if "_FRAME(BIT" in attr or "_BYTE_COUNTER" in attr:
324                    print("    size += {0};".format(getsize(attr, name)))
325                elif "_PTR" in attr:
326                    print("    size += {1}_size(&frame->{0});".format(name, gettypename(attr)))
327                elif "_FRAME(BARRAY" in attr:
328                    (lenattr, lenname) = search_barray_length(attrs, i)
329                    print("    size += frame->{0};".format(lenname))
330                elif "_PAD" in attr:
331                    print("    size = align_to_{0}(size, size, NULL);".format(attr[4]))
332                elif attr == "_FRAME(ITER)":
333                    (iterattr, itername) = attrs[i + 1]
334                    if "_PTR" in iterattr:
335                        print("    for (uint32_t i = 0; i < frame->{0}.size; i++) {{".format(name))
336                        print("        size += {1}_size(&frame->{0}.items[i]);".format(name, gettypename(iterattr)))
337                        print("    }")
338
339                    else:
340                        print("    size += frame->{0}.size * {1};".format(name, getsize(iterattr, itername)))
341                    skip = True
342            print("    return size;")
343
344
345            print("}")
346            print("")
347
348        print("void {0}_free({0}_t *frame)".format(funcname))
349        print("{")
350        for i, (attr, name) in enumerate(attrs):
351            if skip:
352                skip = False
353                continue
354            if "_PTR" in attr:
355                print("    {1}_free(&frame->{0});".format(name, gettypename(attr)))
356            elif "_FRAME(BARRAY" in attr:
357                pass
358            elif attr == "_FRAME(ITER)":
359                (iterattr, itername) = attrs[i + 1]
360                if "_PTR" in iterattr:
361                    print("    if (frame->{0}.items) {{".format(name))
362                    print("        for (uint32_t i = 0; i < frame->{0}.size; i++) {{".format(name))
363                    print("            {1}_free(&frame->{0}.items[i]);".format(name, gettypename(iterattr)))
364                    print("        }")
365                    print("    }")
366                print("    free(frame->{0}.items);".format(name))
367                skip = True
368
369
370        print("}")
371        print("")
372