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@xxxxxxxxxx> --- 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