1#!/usr/bin/python
2
3from __future__ import print_function
4
5import sys
6import re
7
8import idl
9
10def libxl_C_instance_of(ty, instancename):
11    if isinstance(ty, idl.Aggregate) and ty.typename is None:
12        if instancename is None:
13            return libxl_C_type_define(ty)
14        else:
15            return libxl_C_type_define(ty) + " " + instancename
16
17    s = ""
18    if isinstance(ty, idl.Array):
19        s += libxl_C_instance_of(ty.lenvar.type, ty.lenvar.name) + ";\n"
20
21    return s + ty.typename + " " + instancename
22
23def libxl_C_type_define(ty, indent = ""):
24    s = ""
25    if isinstance(ty, idl.Enumeration):
26        if ty.typename is None:
27            s += "enum {\n"
28        else:
29            s += "typedef enum %s {\n" % ty.typename
30
31        for v in ty.values:
32            x = "%s = %d" % (v.name, v.value)
33            x = x.replace("\n", "\n    ")
34            s += "    " + x + ",\n"
35        if ty.typename is None:
36            s += "}"
37        else:
38            s += "} %s" % ty.typename
39
40    elif isinstance(ty, idl.Aggregate):
41        if isinstance(ty, idl.KeyedUnion):
42            s += libxl_C_instance_of(ty.keyvar.type, ty.keyvar.name) + ";\n"
43
44        if ty.typename is None:
45            s += "%s {\n" % ty.kind
46        else:
47            s += "typedef %s %s {\n" % (ty.kind, ty.typename)
48
49        for f in ty.fields:
50            if isinstance(ty, idl.KeyedUnion) and f.type is None: continue
51
52            x = libxl_C_instance_of(f.type, f.name)
53            if f.const:
54                x = "const " + x
55            x = x.replace("\n", "\n    ")
56            s += "    " + x + ";\n"
57        if ty.typename is None:
58            s += "}"
59        else:
60            s += "} %s" % ty.typename
61    else:
62        raise NotImplementedError("%s" % type(ty))
63    return s.replace("\n", "\n%s" % indent)
64
65def libxl_C_type_dispose(ty, v, indent = "    ", parent = None):
66    s = ""
67    if isinstance(ty, idl.KeyedUnion):
68        if parent is None:
69            raise Exception("KeyedUnion type must have a parent")
70        s += "switch (%s) {\n" % (parent + ty.keyvar.name)
71        for f in ty.fields:
72            (nparent,fexpr) = ty.member(v, f, parent is None)
73            s += "case %s:\n" % f.enumname
74            if f.type is not None:
75                s += libxl_C_type_dispose(f.type, fexpr, indent + "    ", nparent)
76            s += "    break;\n"
77        s += "}\n"
78    elif isinstance(ty, idl.Array):
79        if parent is None:
80            raise Exception("Array type must have a parent")
81        if ty.elem_type.dispose_fn is not None:
82            s += "{\n"
83            s += "    int i;\n"
84            s += "    for (i=0; i<%s; i++)\n" % (parent + ty.lenvar.name)
85            s += libxl_C_type_dispose(ty.elem_type, v+"[i]",
86                                      indent + "        ", parent)
87        if ty.dispose_fn is not None:
88            if ty.elem_type.dispose_fn is not None:
89                s += "    "
90            s += "%s(%s);\n" % (ty.dispose_fn, ty.pass_arg(v, parent is None))
91        if ty.elem_type.dispose_fn is not None:
92            s += "}\n"
93    elif isinstance(ty, idl.Struct) and (parent is None or ty.dispose_fn is None):
94        for f in [f for f in ty.fields if not f.const]:
95            (nparent,fexpr) = ty.member(v, f, parent is None)
96            s += libxl_C_type_dispose(f.type, fexpr, "", nparent)
97    else:
98        if ty.dispose_fn is not None:
99            s += "%s(%s);\n" % (ty.dispose_fn, ty.pass_arg(v, parent is None))
100
101    if s != "":
102        s = indent + s
103    return s.replace("\n", "\n%s" % indent).rstrip(indent)
104
105def libxl_C_type_copy(ty, v, w, indent = "    ", vparent = None, wparent = None):
106    s = ""
107
108    if vparent is None:
109        s += "GC_INIT(ctx);\n";
110
111    if isinstance(ty, idl.KeyedUnion):
112        if vparent is None or wparent is None:
113            raise Exception("KeyedUnion type must have a parent")
114        s += "%s = %s;\n" % ((vparent + ty.keyvar.name), (wparent + ty.keyvar.name))
115        s += "switch (%s) {\n" % (wparent + ty.keyvar.name)
116        for f in ty.fields:
117            (vnparent,vfexpr) = ty.member(v, f, vparent is None)
118            (wnparent,wfexpr) = ty.member(w, f, wparent is None)
119            s += "case %s:\n" % f.enumname
120            if f.type is not None:
121                s += libxl_C_type_copy(f.type, vfexpr, wfexpr, indent + "    ",
122                                       vnparent, wnparent)
123            s += "    break;\n"
124        s += "}\n"
125    elif isinstance(ty, idl.Array):
126        if vparent is None or wparent is None:
127            raise Exception("Array type must have a parent")
128        s += "%s = libxl__calloc(NOGC, %s, sizeof(*%s));\n" % (ty.pass_arg(v, vparent is None),
129                                                               (wparent + ty.lenvar.name),
130                                                               ty.pass_arg(w, wparent is None))
131        s += "%s = %s;\n" % ((vparent + ty.lenvar.name), (wparent + ty.lenvar.name))
132        s += "{\n"
133        s += "    int i;\n"
134        s += "    for (i=0; i<%s; i++)\n" % (wparent + ty.lenvar.name)
135        s += libxl_C_type_copy(ty.elem_type, v+"[i]", w+"[i]",
136                               indent + "        ", vparent, wparent)
137        s += "}\n"
138    elif isinstance(ty, idl.Struct) and ((vparent is None and wparent is None) or ty.copy_fn is None):
139        for f in [f for f in ty.fields if not f.const and not f.type.private]:
140            (vnparent,vfexpr) = ty.member(v, f, vparent is None)
141            (wnparent,wfexpr) = ty.member(w, f, wparent is None)
142            s += libxl_C_type_copy(f.type, vfexpr, wfexpr, "", vnparent, wnparent)
143    else:
144        if ty.copy_fn is not None:
145            s += "%s(ctx, %s, %s);\n" % (ty.copy_fn,
146                                         ty.pass_arg(v, vparent is None, passby=idl.PASS_BY_REFERENCE),
147                                         ty.pass_arg(w, wparent is None, passby=idl.PASS_BY_REFERENCE))
148
149        else:
150            s += "%s = %s;\n" % (ty.pass_arg(v, vparent is None, passby=idl.PASS_BY_VALUE),
151                                 ty.pass_arg(w, wparent is None, passby=idl.PASS_BY_VALUE))
152
153    if vparent is None:
154        s += "GC_FREE;\n"
155
156    if s != "":
157        s = indent + s
158    return s.replace("\n", "\n%s" % indent).rstrip(indent)
159
160def libxl_init_members(ty, nesting = 0):
161    """Returns a list of members of ty which require a separate init"""
162
163    if isinstance(ty, idl.Aggregate):
164        return [f for f in ty.fields if not f.const and isinstance(f.type,idl.KeyedUnion)]
165    else:
166        return []
167
168def libxl_C_type_do_init(ty, pass_arg, need_zero=True, indent="    "):
169    s=indent
170    if ty.init_val is not None:
171        s+= "%s = %s;\n" % (pass_arg(idl.PASS_BY_VALUE), ty.init_val)
172    elif ty.init_fn is not None:
173        s+= "%s(%s);\n" % (ty.init_fn, pass_arg(idl.PASS_BY_REFERENCE))
174    elif need_zero:
175        ptr = pass_arg(idl.PASS_BY_REFERENCE)
176        s+= "memset(%s, 0, sizeof(*%s));\n" % (ptr, ptr)
177    else:
178        s=""
179    return s
180
181def _libxl_C_type_init(ty, v, indent = "    ", parent = None, subinit=False):
182    s = ""
183    if isinstance(ty, idl.KeyedUnion):
184        if parent is None:
185            raise Exception("KeyedUnion type must have a parent")
186        if subinit:
187            s += "switch (%s) {\n" % (parent + ty.keyvar.name)
188            for f in ty.fields:
189                (nparent,fexpr) = ty.member(v, f, parent is None)
190                s += "case %s:\n" % f.enumname
191                if f.type is not None:
192                    s += _libxl_C_type_init(f.type, fexpr, "    ", nparent)
193                s += "    break;\n"
194            s += "}\n"
195        else:
196            if ty.keyvar.init_val:
197                s += "%s = %s;\n" % (parent + ty.keyvar.name, ty.keyvar.init_val)
198            elif ty.keyvar.type.init_val:
199                s += "%s = %s;\n" % (parent + ty.keyvar.name, ty.keyvar.type.init_val)
200    elif isinstance(ty, idl.Struct) and (parent is None or ty.init_fn is None):
201        for f in [f for f in ty.fields if not f.const]:
202            (nparent,fexpr) = ty.member(v, f, parent is None)
203            if f.init_val is not None:
204                s += "%s = %s;\n" % (fexpr, f.init_val)
205            else:
206                s += _libxl_C_type_init(f.type, fexpr, "", nparent)
207    else:
208        if ty.init_val is not None:
209            s += "%s = %s;\n" % (ty.pass_arg(v, parent is None), ty.init_val)
210        elif ty.init_fn is not None:
211            s += "%s(%s);\n" % (ty.init_fn, ty.pass_arg(v, parent is None))
212
213    if s != "":
214        s = indent + s
215    return s.replace("\n", "\n%s" % indent).rstrip(indent)
216
217def libxl_C_type_init(ty):
218    s = ""
219    s += "void %s(%s)\n" % (ty.init_fn, ty.make_arg("p", passby=idl.PASS_BY_REFERENCE))
220    s += "{\n"
221    s += "    memset(p, '\\0', sizeof(*p));\n"
222    s += _libxl_C_type_init(ty, "p")
223    s += "}\n"
224    s += "\n"
225    return s
226
227def libxl_C_type_member_init(ty, field):
228    if not isinstance(field.type, idl.KeyedUnion):
229        raise Exception("Only KeyedUnion is supported for member init")
230
231    ku = field.type
232
233    s = ""
234    s += "void %s(%s, %s)\n" % (ty.init_fn + "_" + ku.keyvar.name,
235                                ty.make_arg("p", passby=idl.PASS_BY_REFERENCE),
236                                ku.keyvar.type.make_arg(ku.keyvar.name))
237    s += "{\n"
238
239    if ku.keyvar.init_val is not None:
240        init_val = ku.keyvar.init_val
241    elif ku.keyvar.type.init_val is not None:
242        init_val = ku.keyvar.type.init_val
243    else:
244        init_val = None
245
246    (nparent,fexpr) = ty.member(ty.pass_arg("p"), ku.keyvar, isref=True)
247    if init_val is not None:
248        s += "    assert(%s == %s);\n" % (fexpr, init_val)
249    else:
250        s += "    assert(!%s);\n" % (fexpr)
251    s += "    %s = %s;\n" % (fexpr, ku.keyvar.name)
252
253    (nparent,fexpr) = ty.member(ty.pass_arg("p"), field, isref=True)
254    s += _libxl_C_type_init(ku, fexpr, parent=nparent, subinit=True)
255    s += "}\n"
256    s += "\n"
257    return s
258
259def libxl_C_type_gen_map_key(f, parent, indent = ""):
260    s = ""
261    if isinstance(f.type, idl.KeyedUnion):
262        s += "switch (%s) {\n" % (parent + f.type.keyvar.name)
263        for x in f.type.fields:
264            v = f.type.keyvar.name + "." + x.name
265            s += "case %s:\n" % x.enumname
266            s += "    s = yajl_gen_string(hand, (const unsigned char *)\"%s\", sizeof(\"%s\")-1);\n" % (v, v)
267            s += "    if (s != yajl_gen_status_ok)\n"
268            s += "        goto out;\n"
269            s += "    break;\n"
270        s += "}\n"
271    else:
272        s += "s = yajl_gen_string(hand, (const unsigned char *)\"%s\", sizeof(\"%s\")-1);\n" % (f.name, f.name)
273        s += "if (s != yajl_gen_status_ok)\n"
274        s += "    goto out;\n"
275    if s != "":
276        s = indent + s
277    return s.replace("\n", "\n%s" % indent).rstrip(indent)
278
279def libxl_C_type_copy_deprecated(field, v, indent = "    ", vparent = None):
280    s = ""
281
282    if isinstance(field.type, idl.KeyedUnion):
283        if vparent is None:
284            raise Exception("KeyedUnion type must have a parent")
285        s += "switch (%s) {\n" % (vparent + field.type.keyvar.name)
286        for f in [f for f in field.type.fields if not f.const]:
287            (vnparent,vfexpr) = ty.member(v, f, vparent is None)
288            s += "case %s:\n" % f.enumname
289            if f.type is not None:
290                s += libxl_C_type_copy_deprecated(f, vfexpr, indent, vnparent)
291            s+= "    break;\n"
292        s+="}\n";
293    elif isinstance(field.type, idl.Array) and field.deprecated_by:
294        raise Exception("Array type is not supported for deprecation")
295    elif isinstance(field.type, idl.Struct) and field.type.copy_fn is None:
296        for f in [f for f in field.type.fields if not f.const]:
297            (vnparent,vfexpr) = ty.member(v, f, vparent is None)
298            s += libxl_C_type_copy_deprecated(f, vfexpr, "", vnparent)
299    elif field.deprecated_by is not None:
300        if field.type.check_default_fn is None:
301            raise Exception(
302"Deprecated field %s type doesn't have a default value checker" % field.name)
303        field_pass = lambda by: field.type.pass_arg(v, vparent is None,
304                                                    passby=by)
305        field_val = field_pass(idl.PASS_BY_VALUE)
306        field_ptr = field_pass(idl.PASS_BY_REFERENCE)
307        s+= "if (!%s(&p->%s) && !%s(%s))\n" % (field.type.check_default_fn,
308                                               field.deprecated_by,
309                                               field.type.check_default_fn,
310                                               field_ptr)
311        s+= "    return -EINVAL;\n"
312        s+="(void) (&p->%s == %s);\n" % (field.deprecated_by, field_ptr)
313        s+= "if (%s(&p->%s)) {\n" % (field.type.check_default_fn,
314                                     field.deprecated_by)
315        s+= "    "
316        if field.type.copy_fn is not None:
317            s+= "%s(ctx, &p->%s, %s);\n" % (field.type.copy_fn,
318                                            field.deprecated_by, field_ptr)
319        else:
320            s+= "p->%s = %s;\n" % (field.deprecated_by, field_val)
321
322        if field.type.dispose_fn is not None:
323            s+= "    %s(%s);\n" % (field.type.dispose_fn,
324                                   field.type.pass_arg(v, vparent is None))
325        s+=libxl_C_type_do_init(field.type, field_pass)
326        s+= "}\n"
327
328    if s != "":
329        s = indent + s
330    return s.replace("\n", "\n%s" % indent).rstrip(indent)
331
332def get_init_val(f):
333    if f.init_val is not None:
334        return f.init_val
335    elif f.type.init_val is not None:
336        return f.type.init_val
337    return None
338
339def get_default_expr(f, nparent, fexpr):
340    if isinstance(f.type, idl.Aggregate):
341        return "1 /* always generate JSON output for aggregate type */"
342
343    if isinstance(f.type, idl.Array):
344        return "%s && %s" % (fexpr, nparent + f.type.lenvar.name)
345
346    init_val = get_init_val(f)
347    if init_val is not None:
348        return "%s != %s" % (fexpr, init_val)
349
350    if f.type.check_default_fn:
351        return "!%s(&%s)" % (f.type.check_default_fn, fexpr)
352
353    return "%s" % fexpr
354
355def libxl_C_type_gen_json(ty, v, indent = "    ", parent = None):
356    s = ""
357    if parent is None:
358        s += "yajl_gen_status s;\n"
359
360    if isinstance(ty, idl.Array):
361        if parent is None:
362            raise Exception("Array type must have a parent")
363        s += "{\n"
364        s += "    int i;\n"
365        s += "    s = yajl_gen_array_open(hand);\n"
366        s += "    if (s != yajl_gen_status_ok)\n"
367        s += "        goto out;\n"
368        s += "    for (i=0; i<%s; i++) {\n" % (parent + ty.lenvar.name)
369        s += libxl_C_type_gen_json(ty.elem_type, v+"[i]",
370                                   indent + "        ", parent)
371        s += "    }\n"
372        s += "    s = yajl_gen_array_close(hand);\n"
373        s += "    if (s != yajl_gen_status_ok)\n"
374        s += "        goto out;\n"
375        s += "}\n"
376    elif isinstance(ty, idl.Enumeration):
377        s += "s = libxl__yajl_gen_enum(hand, %s_to_string(%s));\n" % (ty.typename, ty.pass_arg(v, parent is None))
378        s += "if (s != yajl_gen_status_ok)\n"
379        s += "    goto out;\n"
380    elif isinstance(ty, idl.KeyedUnion):
381        if parent is None:
382            raise Exception("KeyedUnion type must have a parent")
383        s += "switch (%s) {\n" % (parent + ty.keyvar.name)
384        for f in ty.fields:
385            (nparent,fexpr) = ty.member(v, f, parent is None)
386            s += "case %s:\n" % f.enumname
387            if f.type is not None:
388                s += libxl_C_type_gen_json(f.type, fexpr, indent + "    ", nparent)
389            else:
390                s += "    s = yajl_gen_map_open(hand);\n"
391                s += "    if (s != yajl_gen_status_ok)\n"
392                s += "        goto out;\n"
393                s += "    s = yajl_gen_map_close(hand);\n"
394                s += "    if (s != yajl_gen_status_ok)\n"
395                s += "        goto out;\n"
396            s += "    break;\n"
397        s += "}\n"
398    elif isinstance(ty, idl.Struct) and (parent is None or ty.json_gen_fn is None):
399        s += "s = yajl_gen_map_open(hand);\n"
400        s += "if (s != yajl_gen_status_ok)\n"
401        s += "    goto out;\n"
402        for f in [f for f in ty.fields if not f.const and not f.type.private]:
403            (nparent,fexpr) = ty.member(v, f, parent is None)
404            default_expr = get_default_expr(f, nparent, fexpr)
405            s += "if (%s) {\n" % default_expr
406
407            s += libxl_C_type_gen_map_key(f, nparent, "    ")
408            s += libxl_C_type_gen_json(f.type, fexpr, "    ", nparent)
409
410            s += "}\n"
411
412        s += "s = yajl_gen_map_close(hand);\n"
413        s += "if (s != yajl_gen_status_ok)\n"
414        s += "    goto out;\n"
415    else:
416        if ty.json_gen_fn is not None:
417            s += "s = %s(hand, %s);\n" % (ty.json_gen_fn, ty.pass_arg(v, parent is None))
418            s += "if (s != yajl_gen_status_ok)\n"
419            s += "    goto out;\n"
420
421    if parent is None:
422        s += "out:\n"
423        s += "return s;\n"
424
425    if s != "":
426        s = indent + s
427    return s.replace("\n", "\n%s" % indent).rstrip(indent)
428
429def libxl_C_type_to_json(ty, v, indent = "    "):
430    s = ""
431    gen = "(libxl__gen_json_callback)&%s_gen_json" % ty.typename
432    s += "return libxl__object_to_json(ctx, \"%s\", %s, (void *)%s);\n" % (ty.typename, gen, ty.pass_arg(v, passby=idl.PASS_BY_REFERENCE))
433
434    if s != "":
435        s = indent + s
436    return s.replace("\n", "\n%s" % indent).rstrip(indent)
437
438def libxl_C_type_parse_json(ty, w, v, indent = "    ", parent = None, discriminator = None):
439    s = ""
440    if parent is None:
441        s += "int rc = 0;\n"
442        s += "const libxl__json_object *x __attribute__((__unused__)) = o;\n"
443
444    if isinstance(ty, idl.Array):
445        if parent is None:
446            raise Exception("Array type must have a parent")
447        if discriminator is not None:
448            raise Exception("Only KeyedUnion can have discriminator")
449        lenvar = parent + ty.lenvar.name
450        s += "{\n"
451        s += "    libxl__json_object *t;\n"
452        s += "    int i;\n"
453        s += "    if (!libxl__json_object_is_array(x)) {\n"
454        s += "        rc = -1;\n"
455        s += "        goto out;\n"
456        s += "    }\n"
457        s += "    %s = x->u.array->count;\n" % lenvar
458        s += "    %s = libxl__calloc(NOGC, %s, sizeof(*%s));\n" % (v, lenvar, v)
459        s += "    if (!%s && %s != 0) {\n" % (v, lenvar)
460        s += "        rc = -1;\n"
461        s += "        goto out;\n"
462        s += "    }\n"
463        s += "    for (i=0; (t=libxl__json_array_get(x,i)); i++) {\n"
464        s += libxl_C_type_do_init(ty.elem_type,
465                    lambda by: ("&" if by == idl.PASS_BY_REFERENCE else "")+
466                               ("%s[i]" % v),
467                                  need_zero=False, indent=indent+"    ")
468        s += libxl_C_type_parse_json(ty.elem_type, "t", v+"[i]",
469                                     indent + "    ", parent)
470        s += "    }\n"
471        s += "    if (i != %s) {\n" % lenvar
472        s += "        rc = -1;\n"
473        s += "        goto out;\n"
474        s += "    }\n"
475        s += "}\n"
476    elif isinstance(ty, idl.Enumeration):
477        if discriminator is not None:
478            raise Exception("Only KeyedUnion can have discriminator")
479        s += "{\n"
480        s += "    const char *enum_str;\n"
481        s += "    if (!libxl__json_object_is_string(%s)) {\n" % w
482        s += "        rc = -1;\n"
483        s += "        goto out;\n"
484        s += "    }\n"
485        s += "    enum_str = libxl__json_object_get_string(%s);\n" % w
486        s += "    rc = %s_from_string(enum_str, %s);\n" % (ty.typename, ty.pass_arg(v, parent is None, idl.PASS_BY_REFERENCE))
487        s += "    if (rc)\n"
488        s += "        goto out;\n"
489        s += "}\n"
490    elif isinstance(ty, idl.KeyedUnion):
491        if parent is None:
492            raise Exception("KeyedUnion type must have a parent")
493        if discriminator is None:
494            raise Excpetion("KeyedUnion type must have a discriminator")
495        for f in ty.fields:
496            if f.enumname != discriminator:
497                continue
498            (nparent,fexpr) = ty.member(v, f, parent is None)
499            if f.type is not None:
500                s += libxl_C_type_parse_json(f.type, w, fexpr, indent + "    ", nparent)
501    elif isinstance(ty, idl.Struct) and (parent is None or ty.json_parse_fn is None):
502        if discriminator is not None:
503            raise Exception("Only KeyedUnion can have discriminator")
504        for f in [f for f in ty.fields if not f.const and not f.type.private]:
505            saved_var_name = "saved_%s" % f.name
506            s += "{\n"
507            s += "    const libxl__json_object *%s = x;\n" % saved_var_name
508            if isinstance(f.type, idl.KeyedUnion):
509                for x in f.type.fields:
510                    s += "    x = libxl__json_map_get(\"%s\", %s, JSON_MAP);\n" % \
511                         (f.type.keyvar.name + "." + x.name, w)
512                    s += "    if (x) {\n"
513                    (nparent, fexpr) = ty.member(v, f.type.keyvar, parent is None)
514                    s += "        %s_init_%s(%s, %s);\n" % (ty.typename, f.type.keyvar.name, v, x.enumname)
515                    (nparent,fexpr) = ty.member(v, f, parent is None)
516                    s += libxl_C_type_parse_json(f.type, "x", fexpr, "  ", nparent, x.enumname)
517                    s += "    }\n"
518            else:
519                s += "    x = libxl__json_map_get(\"%s\", %s, %s);\n" % (f.name, w, f.type.json_parse_type)
520                s += "    if (x) {\n"
521                (nparent,fexpr) = ty.member(v, f, parent is None)
522                s += libxl_C_type_parse_json(f.type, "x", fexpr, "        ", nparent)
523                s += "    }\n"
524            s += "    x = %s;\n" % saved_var_name
525            s += "}\n"
526    else:
527        if discriminator is not None:
528            raise Exception("Only KeyedUnion can have discriminator")
529        if ty.json_parse_fn is not None:
530            s += "rc = %s(gc, %s, &%s);\n" % (ty.json_parse_fn, w, v)
531            s += "if (rc)\n"
532            s += "    goto out;\n"
533
534    if parent is None:
535        s += "out:\n"
536        s += "return rc;\n"
537
538    if s != "":
539        s = indent +s
540    return s.replace("\n", "\n%s" % indent).rstrip(indent)
541
542def libxl_C_type_from_json(ty, v, w, indent = "    "):
543    s = ""
544    parse = "(libxl__json_parse_callback)&%s_parse_json" % (ty.namespace + "_" + ty.rawname)
545    s += "return libxl__object_from_json(ctx, \"%s\", %s, %s, %s);\n" % (ty.typename, parse, v, w)
546
547    if s != "":
548        s = indent + s
549    return s.replace("\n", "\n%s" % indent).rstrip(indent)
550
551def libxl_C_enum_to_string(ty, e, indent = "    "):
552    s = ""
553    s += "switch(%s) {\n" % e
554    for v in ty.values:
555        s += "    case %s:\n" % (v.name)
556        s += "        return \"%s\";\n" % (v.valuename.lower())
557    s += "    default:\n "
558    s += "        return NULL;\n"
559    s += "}\n"
560
561    if s != "":
562        s = indent + s
563    return s.replace("\n", "\n%s" % indent).rstrip(indent)
564
565def libxl_C_enum_strings(ty, indent=""):
566    s = ""
567    s += "libxl_enum_string_table %s_string_table[] = {\n" % (ty.typename)
568    for v in ty.values:
569        s += "    { .s = \"%s\", .v = %s },\n" % (v.valuename.lower(), v.name)
570    s += "    { NULL, -1 },\n"
571    s += "};\n"
572    s += "\n"
573
574    if s != "":
575        s = indent + s
576    return s.replace("\n", "\n%s" % indent).rstrip(indent)
577
578def libxl_C_enum_from_string(ty, str, e, indent = "    "):
579    s = ""
580    s += "return libxl__enum_from_string(%s_string_table,\n" % ty.typename
581    s += "                               %s, (int *)%s);\n" % (str, e)
582
583    if s != "":
584        s = indent + s
585    return s.replace("\n", "\n%s" % indent).rstrip(indent)
586
587
588if __name__ == '__main__':
589    if len(sys.argv) != 6:
590        print("Usage: gentypes.py <idl> <header> <header-private> <header-json> <implementation>", file=sys.stderr)
591        sys.exit(1)
592
593    (_, idlname, header, header_private, header_json, impl) = sys.argv
594
595    (builtins,types) = idl.parse(idlname)
596
597    print("outputting libxl type definitions to %s" % header)
598
599    f = open(header, "w")
600
601    header_define = header.upper().replace('.','_')
602    f.write("""#ifndef %s
603#define %s
604
605/*
606 * DO NOT EDIT.
607 *
608 * This file is autogenerated by
609 * "%s"
610 */
611
612""" % (header_define, header_define, " ".join(sys.argv)))
613
614    for ty in types:
615        f.write(libxl_C_type_define(ty) + ";\n")
616        if ty.dispose_fn is not None:
617            f.write("%svoid %s(%s);\n" % (ty.hidden(), ty.dispose_fn, ty.make_arg("p")))
618        if ty.copy_deprecated_fn is not None:
619            f.write("%sint %s(libxl_ctx *ctx, %s);\n" % (ty.hidden(),
620                                                         ty.copy_deprecated_fn,
621                                                         ty.make_arg("p")))
622        if ty.copy_fn is not None:
623            f.write("%svoid %s(libxl_ctx *ctx, %s, const %s);\n" % (ty.hidden(), ty.copy_fn,
624                                              ty.make_arg("dst"), ty.make_arg("src")))
625        if ty.init_fn is not None:
626            f.write("%svoid %s(%s);\n" % (ty.hidden(), ty.init_fn, ty.make_arg("p")))
627            for field in libxl_init_members(ty):
628                if not isinstance(field.type, idl.KeyedUnion):
629                    raise Exception("Only KeyedUnion is supported for member init")
630                ku = field.type
631                f.write("%svoid %s(%s, %s);\n" % (ty.hidden(), ty.init_fn + "_" + ku.keyvar.name,
632                                               ty.make_arg("p"),
633                                               ku.keyvar.type.make_arg(ku.keyvar.name)))
634        if ty.json_gen_fn is not None:
635            f.write("%schar *%s_to_json(libxl_ctx *ctx, %s);\n" % (ty.hidden(), ty.typename, ty.make_arg("p")))
636        if ty.json_parse_fn is not None:
637            f.write("%sint %s_from_json(libxl_ctx *ctx, %s, const char *s);\n" % (ty.hidden(), ty.typename, ty.make_arg("p", passby=idl.PASS_BY_REFERENCE)))
638        if isinstance(ty, idl.Enumeration):
639            f.write("%sconst char *%s_to_string(%s);\n" % (ty.hidden(), ty.typename, ty.make_arg("p")))
640            f.write("%sint %s_from_string(const char *s, %s);\n" % (ty.hidden(), ty.typename, ty.make_arg("e", passby=idl.PASS_BY_REFERENCE)))
641            f.write("%sextern libxl_enum_string_table %s_string_table[];\n" % (ty.hidden(), ty.typename))
642        f.write("\n")
643
644    f.write("""#endif /* %s */\n""" % (header_define))
645    f.close()
646
647    print("outputting libxl JSON definitions to %s" % header_json)
648
649    f = open(header_json, "w")
650
651    header_json_define = header_json.upper().replace('.','_')
652    f.write("""#ifndef %s
653#define %s
654
655/*
656 * DO NOT EDIT.
657 *
658 * This file is autogenerated by
659 * "%s"
660 */
661
662""" % (header_json_define, header_json_define, " ".join(sys.argv)))
663
664    for ty in [ty for ty in types if ty.json_gen_fn is not None]:
665        f.write("%syajl_gen_status %s_gen_json(yajl_gen hand, %s);\n" % (ty.hidden(), ty.typename, ty.make_arg("p", passby=idl.PASS_BY_REFERENCE)))
666
667    f.write("\n")
668    f.write("""#endif /* %s */\n""" % header_json_define)
669    f.close()
670
671    print("outputting libxl type internal definitions to %s" % header_private)
672
673    f = open(header_private, "w")
674
675    header_private_define = header_private.upper().replace('.','_')
676    f.write("""#ifndef %s
677#define %s
678
679/*
680 * DO NOT EDIT.
681 *
682 * This file is autogenerated by
683 * "%s"
684 */
685
686""" % (header_private_define, header_private_define, " ".join(sys.argv)))
687
688    for ty in [ty for ty in types if ty.json_parse_fn is not None]:
689        f.write("%sint %s_parse_json(libxl__gc *gc, const libxl__json_object *o, %s);\n" % \
690                (ty.hidden(), ty.namespace + "_" + ty.rawname,
691                 ty.make_arg("p", passby=idl.PASS_BY_REFERENCE)))
692
693    f.write("\n")
694    f.write("""#endif /* %s */\n""" % header_json_define)
695    f.close()
696
697    print("outputting libxl type implementations to %s" % impl)
698
699    f = open(impl, "w")
700    f.write("""
701/* DO NOT EDIT.
702 *
703 * This file is autogenerated by
704 * "%s"
705 */
706
707#include "libxl_osdeps.h"
708
709#include <stdint.h>
710#include <stdlib.h>
711#include <string.h>
712
713#include "libxl_internal.h"
714
715
716""" % " ".join(sys.argv))
717
718    for ty in [t for t in types if t.dispose_fn is not None and t.autogenerate_dispose_fn]:
719        f.write("void %s(%s)\n" % (ty.dispose_fn, ty.make_arg("p")))
720        f.write("{\n")
721        f.write("    if (!p) return;\n")
722        f.write(libxl_C_type_dispose(ty, "p"))
723        f.write("    memset(p, 0, sizeof(*p));\n")
724        f.write("}\n")
725        f.write("\n")
726
727    for ty in [t for t in types if t.copy_fn and t.autogenerate_copy_fn]:
728        f.write("void %s(libxl_ctx *ctx, %s, const %s)\n" % (ty.copy_fn,
729                                       ty.make_arg("dst", passby=idl.PASS_BY_REFERENCE),
730                                       ty.make_arg("src", passby=idl.PASS_BY_REFERENCE)))
731        f.write("{\n")
732        f.write(libxl_C_type_copy(ty, "dst", "src"))
733        f.write("}\n")
734        f.write("\n")
735
736    for ty in [t for t in types if t.copy_deprecated_fn]:
737        f.write("int %s(libxl_ctx *ctx, %s)\n" % (ty.copy_deprecated_fn,
738            ty.make_arg("p", passby=idl.PASS_BY_REFERENCE)))
739        f.write("{\n")
740        for field in [field for field in ty.fields if not field.const]:
741            (vnparent,vfexpr) = ty.member("p", field, True)
742            f.write(libxl_C_type_copy_deprecated(field, vfexpr,
743                                                 vparent = vnparent))
744        f.write("    return 0;\n")
745        f.write("}\n")
746        f.write("\n")
747
748    for ty in [t for t in types if t.init_fn is not None and t.autogenerate_init_fn]:
749        f.write(libxl_C_type_init(ty))
750        for field in libxl_init_members(ty):
751            f.write(libxl_C_type_member_init(ty, field))
752
753    for ty in [t for t in types if isinstance(t,idl.Enumeration)]:
754        f.write("const char *%s_to_string(%s e)\n" % (ty.typename, ty.typename))
755        f.write("{\n")
756        f.write(libxl_C_enum_to_string(ty, "e"))
757        f.write("}\n")
758        f.write("\n")
759
760        f.write(libxl_C_enum_strings(ty))
761
762        f.write("int %s_from_string(const char *s, %s *e)\n" % (ty.typename, ty.typename))
763        f.write("{\n")
764        f.write(libxl_C_enum_from_string(ty, "s", "e"))
765        f.write("}\n")
766        f.write("\n")
767
768    for ty in [t for t in types if t.json_gen_fn is not None]:
769        f.write("yajl_gen_status %s_gen_json(yajl_gen hand, %s)\n" % (ty.typename, ty.make_arg("p", passby=idl.PASS_BY_REFERENCE)))
770        f.write("{\n")
771        f.write(libxl_C_type_gen_json(ty, "p"))
772        f.write("}\n")
773        f.write("\n")
774
775        f.write("char *%s_to_json(libxl_ctx *ctx, %s)\n" % (ty.typename, ty.make_arg("p")))
776        f.write("{\n")
777        f.write(libxl_C_type_to_json(ty, "p"))
778        f.write("}\n")
779        f.write("\n")
780
781    for ty in [t for t in types if t.json_parse_fn is not None]:
782        f.write("int %s_parse_json(libxl__gc *gc, const libxl__json_object *%s, %s)\n" % \
783                (ty.namespace + "_" + ty.rawname,"o",ty.make_arg("p", passby=idl.PASS_BY_REFERENCE)))
784        f.write("{\n")
785        f.write(libxl_C_type_parse_json(ty, "o", "p"))
786        f.write("}\n")
787        f.write("\n")
788
789        f.write("int %s_from_json(libxl_ctx *ctx, %s, const char *s)\n" % (ty.typename, ty.make_arg("p", passby=idl.PASS_BY_REFERENCE)))
790        f.write("{\n")
791        if not isinstance(ty, idl.Enumeration):
792            f.write("    %s_init(p);\n" % ty.typename)
793        f.write(libxl_C_type_from_json(ty, "p", "s"))
794        f.write("}\n")
795        f.write("\n")
796
797    f.close()
798