rpcgen: add a C code generator for XDR protocol specs

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.

Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrangé 2022-12-19 14:08:09 -05:00
parent 518af85344
commit 8ec79e5e14
7 changed files with 1223 additions and 1 deletions

View File

@ -1436,7 +1436,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)
@ -1500,6 +1500,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

View File

@ -0,0 +1,469 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
import platform
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" and platform.system() == "Darwin":
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)

351
scripts/rpcgen/tests/demo.c Normal file
View File

@ -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_uint64_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;
}

216
scripts/rpcgen/tests/demo.h Normal file
View File

@ -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*);

128
scripts/rpcgen/tests/demo.x Normal file
View File

@ -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;
};

View File

@ -1,4 +1,5 @@
rpcgen_tests = files([
'test_generator.py',
'test_lexer.py',
'test_parser.py',
])

View File

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