This implements a C code generator that emits code that is
(almost) identical to the classic 'rpcgen' program. The
key differences are:
- Skip inlining of calls for struct fields
- Skip K&R style function prototypes in headers
- Use int64_t instead of quad_t for OS portability
- Saner whitespace / indentation
The tests/demo.c and tests/demo.h files were created using
the traditional 'rpcgen' program, and then editted to cut
out the leading boilerplate, and the differences mentioned
above.
Signed-off-by: Daniel P. Berrangé <berrange(a)redhat.com>
---
build-aux/syntax-check.mk | 4 +-
scripts/rpcgen/rpcgen/generator.py | 467 +++++++++++++++++++++++++
scripts/rpcgen/tests/demo.c | 351 +++++++++++++++++++
scripts/rpcgen/tests/demo.h | 216 ++++++++++++
scripts/rpcgen/tests/demo.x | 128 +++++++
scripts/rpcgen/tests/meson.build | 1 +
scripts/rpcgen/tests/test_generator.py | 55 +++
7 files changed, 1221 insertions(+), 1 deletion(-)
create mode 100644 scripts/rpcgen/rpcgen/generator.py
create mode 100644 scripts/rpcgen/tests/demo.c
create mode 100644 scripts/rpcgen/tests/demo.h
create mode 100644 scripts/rpcgen/tests/demo.x
create mode 100644 scripts/rpcgen/tests/test_generator.py
diff --git a/build-aux/syntax-check.mk b/build-aux/syntax-check.mk
index 6d82a4301a..375fad188b 100644
--- a/build-aux/syntax-check.mk
+++ b/build-aux/syntax-check.mk
@@ -1429,7 +1429,7 @@ exclude_file_name_regexp--sc_prohibit_xmlURI =
^src/util/viruri\.c$$
exclude_file_name_regexp--sc_prohibit_return_as_function = \.py$$
exclude_file_name_regexp--sc_require_config_h = \
- ^(examples/|tools/virsh-edit\.c$$|tests/virmockstathelpers.c)
+ ^(examples/c/.*/.*\.c|tools/virsh-edit\.c|tests/virmockstathelpers\.c|scripts/rpcgen/tests/demo\.c)$$
exclude_file_name_regexp--sc_require_config_h_first = \
^(examples/|tools/virsh-edit\.c$$|tests/virmockstathelpers.c)
@@ -1493,6 +1493,8 @@ exclude_file_name_regexp--sc_prohibit_strcmp = \
exclude_file_name_regexp--sc_prohibit_select = \
^build-aux/syntax-check\.mk|src/util/vireventglibwatch\.c|tests/meson\.build$$
+exclude_file_name_regexp--sc_header-ifdef = \
+ ^scripts/rpcgen/tests/demo\.[ch]$$
exclude_file_name_regexp--sc_black = \
^tools/|src/|tests/|ci/|run\.in|scripts/[^/]*\.py
diff --git a/scripts/rpcgen/rpcgen/generator.py b/scripts/rpcgen/rpcgen/generator.py
new file mode 100644
index 0000000000..110cd12c5e
--- /dev/null
+++ b/scripts/rpcgen/rpcgen/generator.py
@@ -0,0 +1,467 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+from .visitor import XDRVisitor
+from .parser import (
+ XDRTypeString,
+ XDRTypeVoid,
+ XDRTypeOpaque,
+ XDRTypeCustom,
+ XDRDefinitionTypedef,
+ XDRDeclarationFixedArray,
+ XDRDeclarationVariableArray,
+ XDRDeclarationPointer,
+)
+
+
+class XDRTypeDeclarationGenerator(XDRVisitor):
+ def visit_definition_cescape(self, obj, indent, context):
+ return obj.code + "\n"
+
+ def visit_definition_constant(self, obj, indent, context):
+ return "#%sdefine %s %s\n" % (indent, obj.name, obj.value)
+
+ def visit_definition_enum(self, obj, indent, context):
+ code = "%senum %s %s;\n" % (
+ indent,
+ obj.name,
+ self.visit_object(obj.body, indent),
+ ) + "%stypedef enum %s %s;\n" % (indent, obj.name, obj.name)
+ return code
+
+ def visit_definition_struct(self, obj, indent, context):
+ code = "%sstruct %s %s;\n" % (
+ indent,
+ obj.name,
+ self.visit_object(obj.body, indent),
+ ) + "%stypedef struct %s %s;\n" % (indent, obj.name, obj.name)
+ return code
+
+ def visit_definition_union(self, obj, indent, context):
+ code = "%sstruct %s %s;\n" % (
+ indent,
+ obj.name,
+ self.visit_object(obj.body, indent, obj.name),
+ ) + "%stypedef struct %s %s;\n" % (indent, obj.name, obj.name)
+ return code
+
+ def visit_definition_typedef(self, obj, indent, context):
+ return "%stypedef %s;\n" % (indent, self.visit_object(obj.decl,
indent))
+
+ def visit_declaration_scalar(self, obj, indent, context):
+ return "%s %s" % (self.visit_object(obj.typ, indent), obj.identifier)
+
+ def visit_declaration_pointer(self, obj, indent, context):
+ return "%s *%s" % (self.visit_object(obj.typ, indent), obj.identifier)
+
+ def visit_declaration_fixedarray(self, obj, indent, context):
+ return "%s %s[%s]" % (
+ self.visit_object(obj.typ, indent),
+ obj.identifier,
+ obj.length,
+ )
+
+ def visit_declaration_variablearray(self, obj, indent, context):
+ if type(obj.typ) == XDRTypeString:
+ return "%schar *%s" % (indent, obj.identifier)
+ else:
+ code = (
+ "%sstruct {\n" % indent
+ + "%s u_int %s_len;\n" % (indent, obj.identifier)
+ + "%s %s *%s_val;\n"
+ % (indent, self.visit_object(obj.typ, ""), obj.identifier)
+ + "%s} %s" % (indent, obj.identifier)
+ )
+ return code
+
+ def visit_type_custom(self, obj, indent, context):
+ return "%s%s" % (indent, obj.identifier)
+
+ def visit_type_opaque(self, obj, indent, context):
+ return "%schar" % indent
+
+ def visit_type_string(self, obj, indent, context):
+ return "%sstring" % indent
+
+ def visit_type_void(self, obj, indent, context):
+ return "%svoid" % indent
+
+ def visit_type_char(self, obj, indent, context):
+ return "%schar" % indent
+
+ def visit_type_unsignedchar(self, obj, indent, context):
+ return "%su_char" % indent
+
+ def visit_type_short(self, obj, indent, context):
+ return "%sshort" % indent
+
+ def visit_type_unsignedshort(self, obj, indent, context):
+ return "%su_short" % indent
+
+ def visit_type_int(self, obj, indent, context):
+ return "%sint" % indent
+
+ def visit_type_unsignedint(self, obj, indent, context):
+ return "%su_int" % indent
+
+ def visit_type_hyper(self, obj, indent, context):
+ return "%sint64_t" % indent
+
+ def visit_type_unsignedhyper(self, obj, indent, context):
+ return "%suint64_t" % indent
+
+ def visit_type_bool(self, obj, indent, context):
+ return "%sbool_t" % indent
+
+ def visit_type_float(self, obj, indent, context):
+ return "%sfloat" % indent
+
+ def visit_type_double(self, obj, indent, context):
+ return "%sdouble" % indent
+
+ def visit_type_enum(self, obj, indent, context):
+ return "%senum %s" % (indent, self.visit_object(obj.body.body,
indent))
+
+ def visit_type_struct(self, obj, indent, context):
+ return "%sstruct %s" % (indent, self.visit_object(obj.body, indent))
+
+ def visit_type_union(self, obj, indent, context):
+ return "%sstruct %s" % (indent, self.visit_object(obj.body, indent))
+
+ def visit_enum_value(self, obj, indent, context):
+ return "%s%s = %s" % (indent, obj.name, obj.value)
+
+ def visit_enum_body(self, obj, indent, context):
+ code = "{\n"
+ for value in obj.values:
+ code = code + self.visit_object(value, indent + " ") +
",\n"
+ code = code + "%s}" % indent
+ return code
+
+ def visit_struct_body(self, obj, indent, context):
+ code = "{\n"
+ for value in obj.fields:
+ code = code + self.visit_object(value, indent + " ") +
";\n"
+ code = code + "%s}" % indent
+ return code
+
+ def visit_union_case(self, obj, indent, context):
+ return self.visit_object(obj.decl, indent)
+
+ def visit_union_body(self, obj, indent, context):
+ prefix = context
+ if prefix != "":
+ prefix = prefix + "_"
+
+ code = (
+ "%s{\n" % indent
+ + "%s %s;\n" % (indent, self.visit_object(obj.discriminator))
+ + "%s union {\n" % indent
+ )
+ for value in obj.cases:
+ if type(value.decl.typ) == XDRTypeVoid:
+ continue
+ code = code + self.visit_object(value, indent + " ") +
";\n"
+ if obj.default is not None and type(obj.default.typ) != XDRTypeVoid:
+ code = code + self.visit_object(obj.default, indent + " ") +
";\n"
+ code = code + "%s } %su;\n" % (indent, prefix) + "%s}" %
indent
+ return code
+
+
+class XDRMarshallDeclarationGenerator(XDRVisitor):
+ def visit_definition_enum(self, obj, indent, context):
+ return "%sextern bool_t xdr_%s(XDR *, %s*);\n" % (indent, obj.name,
obj.name)
+
+ def visit_definition_union(self, obj, indent, context):
+ return "%sextern bool_t xdr_%s(XDR *, %s*);\n" % (indent, obj.name,
obj.name)
+
+ def visit_definition_struct(self, obj, indent, context):
+ return "%sextern bool_t xdr_%s(XDR *, %s*);\n" % (indent, obj.name,
obj.name)
+
+ def visit_definition_typedef(self, obj, indent, context):
+ if isinstance(obj.decl, XDRDeclarationFixedArray):
+ return "%sextern bool_t xdr_%s(XDR *, %s);\n" % (
+ indent,
+ obj.decl.identifier,
+ obj.decl.identifier,
+ )
+ else:
+ return "%sextern bool_t xdr_%s(XDR *, %s*);\n" % (
+ indent,
+ obj.decl.identifier,
+ obj.decl.identifier,
+ )
+
+
+class XDRMarshallImplementationGenerator(XDRVisitor):
+ def visit_definition_enum(self, obj, indent, context):
+ code = (
+ "%sbool_t\n" % indent
+ + "%sxdr_%s(XDR *xdrs, %s *objp)\n" % (indent, obj.name, obj.name)
+ + "%s{\n" % indent
+ + "%s if (!xdr_enum(xdrs, (enum_t *)objp))\n" % indent
+ + "%s return FALSE;\n" % indent
+ + "%s return TRUE;\n" % indent
+ + "%s}\n" % indent
+ )
+ return code
+
+ def generate_type_call(self, decl, field, typename, embedded=False,
indent=""):
+ if type(decl.typ) == XDRTypeVoid:
+ return ""
+ if type(decl) == XDRDeclarationFixedArray:
+ if type(decl.typ) == XDRTypeOpaque:
+ code = "%s if (!xdr_%s(xdrs, %s, %s))\n" % (
+ indent,
+ self.visit_object(decl.typ, context="func"),
+ field,
+ decl.length,
+ )
+ else:
+ code = "%s if (!xdr_vector(xdrs, (char *)%s, %s,\n" % (
+ indent,
+ field,
+ decl.length,
+ ) + "%s sizeof(%s), (xdrproc_t)xdr_%s))\n" % (
+ indent,
+ self.visit_object(decl.typ),
+ self.visit_object(decl.typ, context="func"),
+ )
+ elif type(decl) == XDRDeclarationVariableArray:
+ fieldRef = "."
+ pointerStr = ""
+ if embedded:
+ pointerStr = "&"
+ else:
+ fieldRef = "->"
+
+ if type(decl.typ) == XDRTypeString:
+ code = "%s if (!xdr_%s(xdrs, %s%s, %s))\n" % (
+ indent,
+ self.visit_object(decl.typ, context="func"),
+ pointerStr,
+ field,
+ decl.maxlength,
+ )
+ elif type(decl.typ) == XDRTypeOpaque:
+ code = "%s if (!xdr_bytes(xdrs, (char **)&%s%s%s_val, "
% (
+ indent,
+ field,
+ fieldRef,
+ typename,
+ ) + "(u_int *) &%s%s%s_len, %s))\n" % (
+ field,
+ fieldRef,
+ typename,
+ decl.maxlength,
+ )
+ else:
+ code = (
+ "%s if (!xdr_array(xdrs, (char **)&%s%s%s_val, "
+ % (indent, field, fieldRef, typename)
+ + "(u_int *) &%s%s%s_len, %s,\n"
+ % (field, fieldRef, typename, decl.maxlength)
+ + "%s sizeof(%s), (xdrproc_t)xdr_%s))\n"
+ % (
+ indent,
+ self.visit_object(decl.typ),
+ self.visit_object(decl.typ, context="func"),
+ )
+ )
+ elif type(decl) == XDRDeclarationPointer:
+ pointerStr = ""
+ if embedded:
+ pointerStr = "&"
+
+ code = "%s if (!xdr_pointer(xdrs, (char **)%s%s, " % (
+ indent,
+ pointerStr,
+ field,
+ ) + "sizeof(%s), (xdrproc_t)xdr_%s))\n" % (
+ self.visit_object(decl.typ, context="func"),
+ self.visit_object(decl.typ, context="func"),
+ )
+ else:
+ pointerStr = ""
+ isFixedArray = (
+ type(decl.typ) == XDRTypeCustom
+ and type(decl.typ.definition) == XDRDefinitionTypedef
+ and type(decl.typ.definition.decl) == XDRDeclarationFixedArray
+ )
+
+ if embedded and not isFixedArray:
+ pointerStr = "&"
+
+ code = "%s if (!xdr_%s(xdrs, %s%s))\n" % (
+ indent,
+ self.visit_object(decl.typ, context="func"),
+ pointerStr,
+ field,
+ )
+
+ code = code + "%s return FALSE;\n" % indent
+ return code
+
+ def visit_definition_union(self, obj, indent, context):
+ code = (
+ "%sbool_t\n" % indent
+ + "%sxdr_%s(XDR *xdrs, %s *objp)\n" % (indent, obj.name, obj.name)
+ + "%s{\n" % indent
+ + self.generate_type_call(
+ obj.body.discriminator,
+ "objp->%s" % obj.body.discriminator.identifier,
+ obj.body.discriminator.identifier,
+ embedded=True,
+ indent=indent,
+ )
+ + "%s switch (objp->%s) {\n"
+ % (indent, obj.body.discriminator.identifier)
+ )
+
+ for case in obj.body.cases:
+ code = (
+ code
+ + "%s case %s:\n" % (indent, case.value)
+ + self.generate_type_call(
+ case.decl,
+ "objp->%s_u.%s" % (obj.name, case.decl.identifier),
+ obj.name,
+ embedded=True,
+ indent=indent + " ",
+ )
+ + "%s break;\n" % indent
+ )
+
+ code = code + "%s default:\n" % indent
+
+ if obj.body.default is not None:
+ code = (
+ code
+ + self.generate_type_call(
+ obj.body.default,
+ "objp->%s_u.%s" % (obj.name,
obj.body.default.identifier),
+ obj.name,
+ embedded=True,
+ indent=indent + " ",
+ )
+ + "%s break;\n" % indent
+ )
+ else:
+ code = code + "%s return FALSE;\n" % indent
+
+ code = (
+ code
+ + "%s }\n" % indent
+ + "%s return TRUE;\n" % indent
+ + "%s}\n" % indent
+ )
+ return code
+
+ def visit_definition_struct(self, obj, indent, context):
+ code = (
+ "%sbool_t\n" % indent
+ + "%sxdr_%s(XDR *xdrs, %s *objp)\n" % (indent, obj.name, obj.name)
+ + "%s{\n" % indent
+ )
+ for field in obj.body.fields:
+ code = code + self.generate_type_call(
+ field,
+ "objp->%s" % field.identifier,
+ field.identifier,
+ embedded=True,
+ indent=indent,
+ )
+ code = code + "%s return TRUE;\n" % indent + "%s}\n" %
indent
+ return code
+
+ def visit_definition_typedef(self, obj, indent, context):
+ code = "%sbool_t\n" % indent
+ if isinstance(obj.decl, XDRDeclarationFixedArray):
+ code = code + "%sxdr_%s(XDR *xdrs, %s objp)\n" % (
+ indent,
+ obj.decl.identifier,
+ obj.decl.identifier,
+ )
+ else:
+ code = code + "%sxdr_%s(XDR *xdrs, %s *objp)\n" % (
+ indent,
+ obj.decl.identifier,
+ obj.decl.identifier,
+ )
+ code = (
+ code
+ + "%s{\n" % indent
+ + self.generate_type_call(
+ obj.decl, "objp", obj.decl.identifier, embedded=False,
indent=indent
+ )
+ + "%s return TRUE;\n" % indent
+ + "%s}\n" % indent
+ )
+ return code
+
+ def visit_declaration_pointer(self, obj, indent, context):
+ return "%s%s *%s" % (indent, self.visit_object(obj.typ),
obj.identifier)
+
+ def visit_declaration_fixedarray(self, obj, indent, context):
+ return "%s%s %s[%s]" % (
+ indent,
+ self.visit_object(obj.typ),
+ obj.identifier,
+ obj.length,
+ )
+
+ def visit_declaration_variablearray(self, obj, indent, context):
+ return "%s%s *%s" % (indent, self.visit_object(obj.typ),
obj.identifier)
+
+ def visit_type_custom(self, obj, indent, context):
+ return "%s%s" % (indent, obj.identifier)
+
+ def visit_type_opaque(self, obj, indent, context):
+ return "%sopaque" % indent
+
+ def visit_type_string(self, obj, indent, context):
+ return "%sstring" % indent
+
+ def visit_type_char(self, obj, indent, context):
+ return "%schar" % indent
+
+ def visit_type_unsignedchar(self, obj, indent, context):
+ return "%su_char" % indent
+
+ def visit_type_short(self, obj, indent, context):
+ return "%sshort" % indent
+
+ def visit_type_unsignedshort(self, obj, indent, context):
+ return "%su_short" % indent
+
+ def visit_type_int(self, obj, indent, context):
+ return "%sint" % indent
+
+ def visit_type_unsignedint(self, obj, indent, context):
+ return "%su_int" % indent
+
+ def visit_type_hyper(self, obj, indent, context):
+ return "%sint64_t" % indent
+
+ def visit_type_unsignedhyper(self, obj, indent, context):
+ if context == "func":
+ return "%su_int64_t" % indent
+ else:
+ return "%suint64_t" % indent
+
+ def visit_type_bool(self, obj, indent, context):
+ if context == "func":
+ return "%sbool" % indent
+ else:
+ return "%sbool_t" % indent
+
+ def visit_type_float(self, obj, indent, context):
+ return "%sfloat" % indent
+
+ def visit_type_double(self, obj, indent, context):
+ return "%sdouble" % indent
+
+ def visit_enum_value(self, obj, indent, context):
+ return "%s%s = %s" % (indent, obj.name, obj.value)
+
+ def visit_union_case(self, obj, indent, context):
+ return self.visit_object(obj.value, indent)
diff --git a/scripts/rpcgen/tests/demo.c b/scripts/rpcgen/tests/demo.c
new file mode 100644
index 0000000000..a261b4fe22
--- /dev/null
+++ b/scripts/rpcgen/tests/demo.c
@@ -0,0 +1,351 @@
+bool_t
+xdr_TestEnum(XDR *xdrs, TestEnum *objp)
+{
+ if (!xdr_enum(xdrs, (enum_t *)objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_TestStruct(XDR *xdrs, TestStruct *objp)
+{
+ if (!xdr_char(xdrs, &objp->c1))
+ return FALSE;
+ if (!xdr_char(xdrs, &objp->c2))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_TestUnion(XDR *xdrs, TestUnion *objp)
+{
+ if (!xdr_int(xdrs, &objp->type))
+ return FALSE;
+ switch (objp->type) {
+ case 20:
+ if (!xdr_int(xdrs, &objp->TestUnion_u.i1))
+ return FALSE;
+ break;
+ case 30:
+ if (!xdr_int(xdrs, &objp->TestUnion_u.i2))
+ return FALSE;
+ break;
+ default:
+ if (!xdr_int(xdrs, &objp->TestUnion_u.i3))
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+bool_t
+xdr_TestUnionVoidDefault(XDR *xdrs, TestUnionVoidDefault *objp)
+{
+ if (!xdr_int(xdrs, &objp->type))
+ return FALSE;
+ switch (objp->type) {
+ case 21:
+ if (!xdr_int(xdrs, &objp->TestUnionVoidDefault_u.i1))
+ return FALSE;
+ break;
+ case 31:
+ if (!xdr_int(xdrs, &objp->TestUnionVoidDefault_u.i2))
+ return FALSE;
+ break;
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+bool_t
+xdr_TestUnionNoDefault(XDR *xdrs, TestUnionNoDefault *objp)
+{
+ if (!xdr_int(xdrs, &objp->type))
+ return FALSE;
+ switch (objp->type) {
+ case 22:
+ if (!xdr_int(xdrs, &objp->TestUnionNoDefault_u.i1))
+ return FALSE;
+ break;
+ case 32:
+ if (!xdr_int(xdrs, &objp->TestUnionNoDefault_u.i2))
+ return FALSE;
+ break;
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+bool_t
+xdr_TestIntScalar(XDR *xdrs, TestIntScalar *objp)
+{
+ if (!xdr_int(xdrs, objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_TestIntPointer(XDR *xdrs, TestIntPointer *objp)
+{
+ if (!xdr_pointer(xdrs, (char **)objp, sizeof(int), (xdrproc_t)xdr_int))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_TestIntFixedArray(XDR *xdrs, TestIntFixedArray objp)
+{
+ if (!xdr_vector(xdrs, (char *)objp, 3,
+ sizeof(int), (xdrproc_t)xdr_int))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_TestIntVariableArray(XDR *xdrs, TestIntVariableArray *objp)
+{
+ if (!xdr_array(xdrs, (char **)&objp->TestIntVariableArray_val, (u_int *)
&objp->TestIntVariableArray_len, 5,
+ sizeof(int), (xdrproc_t)xdr_int))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_TestStringVariableArray(XDR *xdrs, TestStringVariableArray *objp)
+{
+ if (!xdr_string(xdrs, objp, 7))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_TestOpaqueFixedArray(XDR *xdrs, TestOpaqueFixedArray objp)
+{
+ if (!xdr_opaque(xdrs, objp, 9))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_TestOpaqueVariableArray(XDR *xdrs, TestOpaqueVariableArray *objp)
+{
+ if (!xdr_bytes(xdrs, (char **)&objp->TestOpaqueVariableArray_val, (u_int *)
&objp->TestOpaqueVariableArray_len, 11))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_TestEnumScalar(XDR *xdrs, TestEnumScalar *objp)
+{
+ if (!xdr_TestEnum(xdrs, objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_TestEnumPointer(XDR *xdrs, TestEnumPointer *objp)
+{
+ if (!xdr_pointer(xdrs, (char **)objp, sizeof(TestEnum), (xdrproc_t)xdr_TestEnum))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_TestEnumFixedArray(XDR *xdrs, TestEnumFixedArray objp)
+{
+ if (!xdr_vector(xdrs, (char *)objp, 13,
+ sizeof(TestEnum), (xdrproc_t)xdr_TestEnum))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_TestEnumVariableArray(XDR *xdrs, TestEnumVariableArray *objp)
+{
+ if (!xdr_array(xdrs, (char **)&objp->TestEnumVariableArray_val, (u_int *)
&objp->TestEnumVariableArray_len, 15,
+ sizeof(TestEnum), (xdrproc_t)xdr_TestEnum))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_TestStructScalar(XDR *xdrs, TestStructScalar *objp)
+{
+ if (!xdr_TestStruct(xdrs, objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_TestStructPointer(XDR *xdrs, TestStructPointer *objp)
+{
+ if (!xdr_pointer(xdrs, (char **)objp, sizeof(TestStruct),
(xdrproc_t)xdr_TestStruct))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_TestStructFixedArray(XDR *xdrs, TestStructFixedArray objp)
+{
+ if (!xdr_vector(xdrs, (char *)objp, 17,
+ sizeof(TestStruct), (xdrproc_t)xdr_TestStruct))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_TestStructVariableArray(XDR *xdrs, TestStructVariableArray *objp)
+{
+ if (!xdr_array(xdrs, (char **)&objp->TestStructVariableArray_val, (u_int *)
&objp->TestStructVariableArray_len, 19,
+ sizeof(TestStruct), (xdrproc_t)xdr_TestStruct))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_TestUnionScalar(XDR *xdrs, TestUnionScalar *objp)
+{
+ if (!xdr_TestUnion(xdrs, objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_TestUnionPointer(XDR *xdrs, TestUnionPointer *objp)
+{
+ if (!xdr_pointer(xdrs, (char **)objp, sizeof(TestUnion), (xdrproc_t)xdr_TestUnion))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_TestUnionFixedArray(XDR *xdrs, TestUnionFixedArray objp)
+{
+ if (!xdr_vector(xdrs, (char *)objp, 21,
+ sizeof(TestUnion), (xdrproc_t)xdr_TestUnion))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_TestUnionVariableArray(XDR *xdrs, TestUnionVariableArray *objp)
+{
+ if (!xdr_array(xdrs, (char **)&objp->TestUnionVariableArray_val, (u_int *)
&objp->TestUnionVariableArray_len, 23,
+ sizeof(TestUnion), (xdrproc_t)xdr_TestUnion))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_TestStructAllTypes(XDR *xdrs, TestStructAllTypes *objp)
+{
+ if (!xdr_char(xdrs, &objp->sc))
+ return FALSE;
+ if (!xdr_u_char(xdrs, &objp->suc))
+ return FALSE;
+ if (!xdr_short(xdrs, &objp->ss))
+ return FALSE;
+ if (!xdr_u_short(xdrs, &objp->sus))
+ return FALSE;
+ if (!xdr_int(xdrs, &objp->si))
+ return FALSE;
+ if (!xdr_u_int(xdrs, &objp->sui))
+ return FALSE;
+ if (!xdr_int64_t(xdrs, &objp->sh))
+ return FALSE;
+ if (!xdr_u_int64_t(xdrs, &objp->suh))
+ return FALSE;
+ if (!xdr_bool(xdrs, &objp->sb))
+ return FALSE;
+ if (!xdr_float(xdrs, &objp->sf))
+ return FALSE;
+ if (!xdr_double(xdrs, &objp->sd))
+ return FALSE;
+ if (!xdr_pointer(xdrs, (char **)&objp->ip, sizeof(int), (xdrproc_t)xdr_int))
+ return FALSE;
+ if (!xdr_vector(xdrs, (char *)objp->ifa, TestConstDec,
+ sizeof(int), (xdrproc_t)xdr_int))
+ return FALSE;
+ if (!xdr_array(xdrs, (char **)&objp->iva.iva_val, (u_int *)
&objp->iva.iva_len, TestConstHex,
+ sizeof(int), (xdrproc_t)xdr_int))
+ return FALSE;
+ if (!xdr_string(xdrs, &objp->stva, TestConstOct))
+ return FALSE;
+ if (!xdr_opaque(xdrs, objp->ofa, 33))
+ return FALSE;
+ if (!xdr_bytes(xdrs, (char **)&objp->ova.ova_val, (u_int *)
&objp->ova.ova_len, 35))
+ return FALSE;
+ if (!xdr_TestEnum(xdrs, &objp->e1))
+ return FALSE;
+ if (!xdr_TestEnum(xdrs, &objp->e2))
+ return FALSE;
+ if (!xdr_pointer(xdrs, (char **)&objp->ep, sizeof(TestEnum),
(xdrproc_t)xdr_TestEnum))
+ return FALSE;
+ if (!xdr_vector(xdrs, (char *)objp->efa, 37,
+ sizeof(TestEnum), (xdrproc_t)xdr_TestEnum))
+ return FALSE;
+ if (!xdr_array(xdrs, (char **)&objp->eva.eva_val, (u_int *)
&objp->eva.eva_len, 39,
+ sizeof(TestEnum), (xdrproc_t)xdr_TestEnum))
+ return FALSE;
+ if (!xdr_TestStruct(xdrs, &objp->s))
+ return FALSE;
+ if (!xdr_pointer(xdrs, (char **)&objp->sp, sizeof(TestStruct),
(xdrproc_t)xdr_TestStruct))
+ return FALSE;
+ if (!xdr_vector(xdrs, (char *)objp->sfa, 41,
+ sizeof(TestStruct), (xdrproc_t)xdr_TestStruct))
+ return FALSE;
+ if (!xdr_array(xdrs, (char **)&objp->sva.sva_val, (u_int *)
&objp->sva.sva_len, 43,
+ sizeof(TestStruct), (xdrproc_t)xdr_TestStruct))
+ return FALSE;
+ if (!xdr_TestUnion(xdrs, &objp->u))
+ return FALSE;
+ if (!xdr_pointer(xdrs, (char **)&objp->up, sizeof(TestUnion),
(xdrproc_t)xdr_TestUnion))
+ return FALSE;
+ if (!xdr_vector(xdrs, (char *)objp->ufa, 45,
+ sizeof(TestUnion), (xdrproc_t)xdr_TestUnion))
+ return FALSE;
+ if (!xdr_array(xdrs, (char **)&objp->uva.uva_val, (u_int *)
&objp->uva.uva_len, 47,
+ sizeof(TestUnion), (xdrproc_t)xdr_TestUnion))
+ return FALSE;
+ if (!xdr_TestIntScalar(xdrs, &objp->tis))
+ return FALSE;
+ if (!xdr_TestIntPointer(xdrs, &objp->tip))
+ return FALSE;
+ if (!xdr_TestIntFixedArray(xdrs, objp->tifa))
+ return FALSE;
+ if (!xdr_TestIntVariableArray(xdrs, &objp->tiva))
+ return FALSE;
+ if (!xdr_TestStringVariableArray(xdrs, &objp->tstva))
+ return FALSE;
+ if (!xdr_TestOpaqueFixedArray(xdrs, objp->tofa))
+ return FALSE;
+ if (!xdr_TestOpaqueVariableArray(xdrs, &objp->tova))
+ return FALSE;
+ if (!xdr_TestEnumScalar(xdrs, &objp->tes))
+ return FALSE;
+ if (!xdr_TestEnumPointer(xdrs, &objp->tep))
+ return FALSE;
+ if (!xdr_TestEnumFixedArray(xdrs, objp->tefa))
+ return FALSE;
+ if (!xdr_TestEnumVariableArray(xdrs, &objp->teva))
+ return FALSE;
+ if (!xdr_TestStructScalar(xdrs, &objp->tss))
+ return FALSE;
+ if (!xdr_TestStructPointer(xdrs, &objp->tsp))
+ return FALSE;
+ if (!xdr_TestStructFixedArray(xdrs, objp->tsfa))
+ return FALSE;
+ if (!xdr_TestStructVariableArray(xdrs, &objp->tsva))
+ return FALSE;
+ if (!xdr_TestUnionScalar(xdrs, &objp->tu))
+ return FALSE;
+ if (!xdr_TestUnionPointer(xdrs, &objp->tup))
+ return FALSE;
+ if (!xdr_TestUnionFixedArray(xdrs, objp->tufa))
+ return FALSE;
+ if (!xdr_TestUnionVariableArray(xdrs, &objp->tuva))
+ return FALSE;
+ return TRUE;
+}
diff --git a/scripts/rpcgen/tests/demo.h b/scripts/rpcgen/tests/demo.h
new file mode 100644
index 0000000000..6fac61e7e9
--- /dev/null
+++ b/scripts/rpcgen/tests/demo.h
@@ -0,0 +1,216 @@
+enum TestEnum {
+ TEST_ENUM_ONE = 1,
+ TEST_ENUM_TWO = 2,
+};
+typedef enum TestEnum TestEnum;
+
+struct TestStruct {
+ char c1;
+ char c2;
+};
+typedef struct TestStruct TestStruct;
+
+struct TestUnion {
+ int type;
+ union {
+ int i1;
+ int i2;
+ int i3;
+ } TestUnion_u;
+};
+typedef struct TestUnion TestUnion;
+
+struct TestUnionVoidDefault {
+ int type;
+ union {
+ int i1;
+ int i2;
+ } TestUnionVoidDefault_u;
+};
+typedef struct TestUnionVoidDefault TestUnionVoidDefault;
+
+struct TestUnionNoDefault {
+ int type;
+ union {
+ int i1;
+ int i2;
+ } TestUnionNoDefault_u;
+};
+typedef struct TestUnionNoDefault TestUnionNoDefault;
+
+typedef int TestIntScalar;
+
+typedef int *TestIntPointer;
+
+typedef int TestIntFixedArray[3];
+
+typedef struct {
+ u_int TestIntVariableArray_len;
+ int *TestIntVariableArray_val;
+} TestIntVariableArray;
+
+typedef char *TestStringVariableArray;
+
+typedef char TestOpaqueFixedArray[9];
+
+typedef struct {
+ u_int TestOpaqueVariableArray_len;
+ char *TestOpaqueVariableArray_val;
+} TestOpaqueVariableArray;
+
+typedef TestEnum TestEnumScalar;
+
+typedef TestEnum *TestEnumPointer;
+
+typedef TestEnum TestEnumFixedArray[13];
+
+typedef struct {
+ u_int TestEnumVariableArray_len;
+ TestEnum *TestEnumVariableArray_val;
+} TestEnumVariableArray;
+
+typedef TestStruct TestStructScalar;
+
+typedef TestStruct *TestStructPointer;
+
+typedef TestStruct TestStructFixedArray[17];
+
+typedef struct {
+ u_int TestStructVariableArray_len;
+ TestStruct *TestStructVariableArray_val;
+} TestStructVariableArray;
+
+typedef TestUnion TestUnionScalar;
+
+typedef TestUnion *TestUnionPointer;
+
+typedef TestUnion TestUnionFixedArray[21];
+
+typedef struct {
+ u_int TestUnionVariableArray_len;
+ TestUnion *TestUnionVariableArray_val;
+} TestUnionVariableArray;
+
+#define TestConstDec 25
+
+#define TestConstHex 0x27
+
+#define TestConstOct 031
+
+struct TestStructAllTypes {
+ char sc;
+ u_char suc;
+ short ss;
+ u_short sus;
+ int si;
+ u_int sui;
+ int64_t sh;
+ uint64_t suh;
+ bool_t sb;
+ float sf;
+ double sd;
+ int *ip;
+ int ifa[TestConstDec];
+ struct {
+ u_int iva_len;
+ int *iva_val;
+ } iva;
+ char *stva;
+ char ofa[33];
+ struct {
+ u_int ova_len;
+ char *ova_val;
+ } ova;
+ TestEnum e1;
+ TestEnum e2;
+ TestEnum *ep;
+ TestEnum efa[37];
+ struct {
+ u_int eva_len;
+ TestEnum *eva_val;
+ } eva;
+ TestStruct s;
+ TestStruct *sp;
+ TestStruct sfa[41];
+ struct {
+ u_int sva_len;
+ TestStruct *sva_val;
+ } sva;
+ TestUnion u;
+ TestUnion *up;
+ TestUnion ufa[45];
+ struct {
+ u_int uva_len;
+ TestUnion *uva_val;
+ } uva;
+ TestIntScalar tis;
+ TestIntPointer tip;
+ TestIntFixedArray tifa;
+ TestIntVariableArray tiva;
+ TestStringVariableArray tstva;
+ TestOpaqueFixedArray tofa;
+ TestOpaqueVariableArray tova;
+ TestEnumScalar tes;
+ TestEnumPointer tep;
+ TestEnumFixedArray tefa;
+ TestEnumVariableArray teva;
+ TestStructScalar tss;
+ TestStructPointer tsp;
+ TestStructFixedArray tsfa;
+ TestStructVariableArray tsva;
+ TestUnionScalar tu;
+ TestUnionPointer tup;
+ TestUnionFixedArray tufa;
+ TestUnionVariableArray tuva;
+};
+typedef struct TestStructAllTypes TestStructAllTypes;
+
+extern bool_t xdr_TestEnum(XDR *, TestEnum*);
+
+extern bool_t xdr_TestStruct(XDR *, TestStruct*);
+
+extern bool_t xdr_TestUnion(XDR *, TestUnion*);
+
+extern bool_t xdr_TestUnionVoidDefault(XDR *, TestUnionVoidDefault*);
+
+extern bool_t xdr_TestUnionNoDefault(XDR *, TestUnionNoDefault*);
+
+extern bool_t xdr_TestIntScalar(XDR *, TestIntScalar*);
+
+extern bool_t xdr_TestIntPointer(XDR *, TestIntPointer*);
+
+extern bool_t xdr_TestIntFixedArray(XDR *, TestIntFixedArray);
+
+extern bool_t xdr_TestIntVariableArray(XDR *, TestIntVariableArray*);
+
+extern bool_t xdr_TestStringVariableArray(XDR *, TestStringVariableArray*);
+
+extern bool_t xdr_TestOpaqueFixedArray(XDR *, TestOpaqueFixedArray);
+
+extern bool_t xdr_TestOpaqueVariableArray(XDR *, TestOpaqueVariableArray*);
+
+extern bool_t xdr_TestEnumScalar(XDR *, TestEnumScalar*);
+
+extern bool_t xdr_TestEnumPointer(XDR *, TestEnumPointer*);
+
+extern bool_t xdr_TestEnumFixedArray(XDR *, TestEnumFixedArray);
+
+extern bool_t xdr_TestEnumVariableArray(XDR *, TestEnumVariableArray*);
+
+extern bool_t xdr_TestStructScalar(XDR *, TestStructScalar*);
+
+extern bool_t xdr_TestStructPointer(XDR *, TestStructPointer*);
+
+extern bool_t xdr_TestStructFixedArray(XDR *, TestStructFixedArray);
+
+extern bool_t xdr_TestStructVariableArray(XDR *, TestStructVariableArray*);
+
+extern bool_t xdr_TestUnionScalar(XDR *, TestUnionScalar*);
+
+extern bool_t xdr_TestUnionPointer(XDR *, TestUnionPointer*);
+
+extern bool_t xdr_TestUnionFixedArray(XDR *, TestUnionFixedArray);
+
+extern bool_t xdr_TestUnionVariableArray(XDR *, TestUnionVariableArray*);
+
+extern bool_t xdr_TestStructAllTypes(XDR *, TestStructAllTypes*);
diff --git a/scripts/rpcgen/tests/demo.x b/scripts/rpcgen/tests/demo.x
new file mode 100644
index 0000000000..ec69913f3d
--- /dev/null
+++ b/scripts/rpcgen/tests/demo.x
@@ -0,0 +1,128 @@
+enum TestEnum {
+ TEST_ENUM_ONE = 1,
+ TEST_ENUM_TWO = 2
+};
+
+struct TestStruct {
+ char c1;
+ char c2;
+};
+
+union TestUnion switch (int type) {
+ case 20:
+ int i1;
+ case 30:
+ int i2;
+ default:
+ int i3;
+};
+
+union TestUnionVoidDefault switch (int type) {
+ case 21:
+ int i1;
+ case 31:
+ int i2;
+ default:
+ void;
+};
+
+union TestUnionNoDefault switch (int type) {
+ case 22:
+ int i1;
+ case 32:
+ int i2;
+};
+
+typedef int TestIntScalar;
+typedef int *TestIntPointer;
+typedef int TestIntFixedArray[3];
+typedef int TestIntVariableArray<5>;
+
+typedef string TestStringVariableArray<7>;
+
+typedef opaque TestOpaqueFixedArray[9];
+typedef opaque TestOpaqueVariableArray<11>;
+
+typedef TestEnum TestEnumScalar;
+typedef TestEnum *TestEnumPointer;
+typedef TestEnum TestEnumFixedArray[13];
+typedef TestEnum TestEnumVariableArray<15>;
+
+typedef TestStruct TestStructScalar;
+typedef TestStruct *TestStructPointer;
+typedef TestStruct TestStructFixedArray[17];
+typedef TestStruct TestStructVariableArray<19>;
+
+typedef TestUnion TestUnionScalar;
+typedef TestUnion *TestUnionPointer;
+typedef TestUnion TestUnionFixedArray[21];
+typedef TestUnion TestUnionVariableArray<23>;
+
+const TestConstDec = 25;
+const TestConstHex = 0x27;
+const TestConstOct = 031;
+
+struct TestStructAllTypes {
+ char sc;
+ unsigned char suc;
+ short ss;
+ unsigned short sus;
+ int si;
+ unsigned int sui;
+ hyper sh;
+ unsigned hyper suh;
+ bool sb;
+ float sf;
+ double sd;
+/* quadruple sq; */
+
+ int *ip;
+ int ifa[TestConstDec];
+ int iva<TestConstHex>;
+
+ string stva<TestConstOct>;
+
+ opaque ofa[33];
+ opaque ova<35>;
+
+ TestEnum e1;
+ TestEnum e2;
+ TestEnum *ep;
+ TestEnum efa[37];
+ TestEnum eva<39>;
+
+ TestStruct s;
+ TestStruct *sp;
+ TestStruct sfa[41];
+ TestStruct sva<43>;
+
+ TestUnion u;
+ TestUnion *up;
+ TestUnion ufa[45];
+ TestUnion uva<47>;
+
+ TestIntScalar tis;
+ TestIntPointer tip;
+ TestIntFixedArray tifa;
+ TestIntVariableArray tiva;
+
+ TestStringVariableArray tstva;
+
+ TestOpaqueFixedArray tofa;
+ TestOpaqueVariableArray tova;
+
+ TestEnumScalar tes;
+ TestEnumPointer tep;
+ TestEnumFixedArray tefa;
+ TestEnumVariableArray teva;
+
+ TestStructScalar tss;
+ TestStructPointer tsp;
+ TestStructFixedArray tsfa;
+ TestStructVariableArray tsva;
+
+ TestUnionScalar tu;
+ TestUnionPointer tup;
+ TestUnionFixedArray tufa;
+ TestUnionVariableArray tuva;
+};
diff --git a/scripts/rpcgen/tests/meson.build b/scripts/rpcgen/tests/meson.build
index 4b1ea308ce..953a3dbede 100644
--- a/scripts/rpcgen/tests/meson.build
+++ b/scripts/rpcgen/tests/meson.build
@@ -1,4 +1,5 @@
rpcgen_tests = files([
+ 'test_generator.py',
'test_lexer.py',
'test_parser.py',
])
diff --git a/scripts/rpcgen/tests/test_generator.py
b/scripts/rpcgen/tests/test_generator.py
new file mode 100644
index 0000000000..bc7660a6fc
--- /dev/null
+++ b/scripts/rpcgen/tests/test_generator.py
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+import os
+from pathlib import Path
+
+from rpcgen.parser import XDRParser
+from rpcgen.generator import (
+ XDRTypeDeclarationGenerator,
+ XDRMarshallDeclarationGenerator,
+ XDRMarshallImplementationGenerator,
+)
+
+
+def test_generate_header():
+ x = Path(Path(__file__).parent, "demo.x")
+ h = Path(Path(__file__).parent, "demo.h")
+ with x.open("r") as fp:
+ parser = XDRParser(fp)
+ spec = parser.parse()
+
+ got = (
+ XDRTypeDeclarationGenerator(spec).visit()
+ + "\n"
+ + XDRMarshallDeclarationGenerator(spec).visit()
+ )
+
+ with h.open("r") as fp:
+ want = fp.read()
+
+ if "VIR_TEST_REGENERATE_OUTPUT" in os.environ:
+ want = got
+ with h.open("w") as fp:
+ fp.write(want)
+
+ assert got == want
+
+
+def test_generate_source():
+ x = Path(Path(__file__).parent, "demo.x")
+ h = Path(Path(__file__).parent, "demo.c")
+ with x.open("r") as fp:
+ parser = XDRParser(fp)
+ spec = parser.parse()
+
+ got = XDRMarshallImplementationGenerator(spec).visit()
+
+ with h.open("r") as fp:
+ want = fp.read()
+
+ if "VIR_TEST_REGENERATE_OUTPUT" in os.environ:
+ want = got
+ with h.open("w") as fp:
+ fp.write(want)
+
+ assert got == want
--
2.39.1