mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-06 05:13:18 +00:00
tools: Add xdrgen
Add a Python-based tool for translating XDR specifications into XDR encoder and decoder functions written in the Linux kernel's C coding style. The generator attempts to match the usual C coding style of the Linux kernel's SunRPC consumers. This approach is similar to the netlink code generator in tools/net/ynl . The maintainability benefits of machine-generated XDR code include: - Stronger type checking - Reduces the number of bugs introduced by human error - Makes the XDR code easier to audit and analyze - Enables rapid prototyping of new RPC-based protocols - Hardens the layering between protocol logic and marshaling - Makes it easier to add observability on demand - Unit tests might be built for both the tool and (automatically) for the generated code In addition, converting the XDR layer to use memory-safe languages such as Rust will be easier if much of the code can be converted automatically. Tested-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
parent
45bb63ed20
commit
4b132aacb0
243
include/linux/sunrpc/xdrgen/_builtins.h
Normal file
243
include/linux/sunrpc/xdrgen/_builtins.h
Normal file
@ -0,0 +1,243 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2024 Oracle and/or its affiliates.
|
||||
*
|
||||
* This header defines XDR data type primitives specified in
|
||||
* Section 4 of RFC 4506, used by RPC programs implemented
|
||||
* in the Linux kernel.
|
||||
*/
|
||||
|
||||
#ifndef _SUNRPC_XDRGEN__BUILTINS_H_
|
||||
#define _SUNRPC_XDRGEN__BUILTINS_H_
|
||||
|
||||
#include <linux/sunrpc/xdr.h>
|
||||
|
||||
static inline bool
|
||||
xdrgen_decode_void(struct xdr_stream *xdr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_encode_void(struct xdr_stream *xdr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_decode_bool(struct xdr_stream *xdr, bool *ptr)
|
||||
{
|
||||
__be32 *p = xdr_inline_decode(xdr, XDR_UNIT);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*ptr = (*p != xdr_zero);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_encode_bool(struct xdr_stream *xdr, bool val)
|
||||
{
|
||||
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*p = val ? xdr_one : xdr_zero;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_decode_int(struct xdr_stream *xdr, s32 *ptr)
|
||||
{
|
||||
__be32 *p = xdr_inline_decode(xdr, XDR_UNIT);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*ptr = be32_to_cpup(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_encode_int(struct xdr_stream *xdr, s32 val)
|
||||
{
|
||||
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*p = cpu_to_be32(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_decode_unsigned_int(struct xdr_stream *xdr, u32 *ptr)
|
||||
{
|
||||
__be32 *p = xdr_inline_decode(xdr, XDR_UNIT);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*ptr = be32_to_cpup(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_encode_unsigned_int(struct xdr_stream *xdr, u32 val)
|
||||
{
|
||||
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*p = cpu_to_be32(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_decode_long(struct xdr_stream *xdr, s32 *ptr)
|
||||
{
|
||||
__be32 *p = xdr_inline_decode(xdr, XDR_UNIT);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*ptr = be32_to_cpup(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_encode_long(struct xdr_stream *xdr, s32 val)
|
||||
{
|
||||
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*p = cpu_to_be32(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_decode_unsigned_long(struct xdr_stream *xdr, u32 *ptr)
|
||||
{
|
||||
__be32 *p = xdr_inline_decode(xdr, XDR_UNIT);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*ptr = be32_to_cpup(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_encode_unsigned_long(struct xdr_stream *xdr, u32 val)
|
||||
{
|
||||
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*p = cpu_to_be32(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_decode_hyper(struct xdr_stream *xdr, s64 *ptr)
|
||||
{
|
||||
__be32 *p = xdr_inline_decode(xdr, XDR_UNIT * 2);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*ptr = get_unaligned_be64(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_encode_hyper(struct xdr_stream *xdr, s64 val)
|
||||
{
|
||||
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT * 2);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
put_unaligned_be64(val, p);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_decode_unsigned_hyper(struct xdr_stream *xdr, u64 *ptr)
|
||||
{
|
||||
__be32 *p = xdr_inline_decode(xdr, XDR_UNIT * 2);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*ptr = get_unaligned_be64(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_encode_unsigned_hyper(struct xdr_stream *xdr, u64 val)
|
||||
{
|
||||
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT * 2);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
put_unaligned_be64(val, p);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_decode_string(struct xdr_stream *xdr, string *ptr, u32 maxlen)
|
||||
{
|
||||
__be32 *p;
|
||||
u32 len;
|
||||
|
||||
if (unlikely(xdr_stream_decode_u32(xdr, &len) != XDR_UNIT))
|
||||
return false;
|
||||
if (unlikely(maxlen && len > maxlen))
|
||||
return false;
|
||||
if (len != 0) {
|
||||
p = xdr_inline_decode(xdr, len);
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
ptr->data = (unsigned char *)p;
|
||||
}
|
||||
ptr->len = len;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_encode_string(struct xdr_stream *xdr, string val, u32 maxlen)
|
||||
{
|
||||
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT + xdr_align_size(val.len));
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
xdr_encode_opaque(p, val.data, val.len);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_decode_opaque(struct xdr_stream *xdr, opaque *ptr, u32 maxlen)
|
||||
{
|
||||
__be32 *p;
|
||||
u32 len;
|
||||
|
||||
if (unlikely(xdr_stream_decode_u32(xdr, &len) != XDR_UNIT))
|
||||
return false;
|
||||
if (unlikely(maxlen && len > maxlen))
|
||||
return false;
|
||||
if (len != 0) {
|
||||
p = xdr_inline_decode(xdr, len);
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
ptr->data = (u8 *)p;
|
||||
}
|
||||
ptr->len = len;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_encode_opaque(struct xdr_stream *xdr, opaque val)
|
||||
{
|
||||
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT + xdr_align_size(val.len));
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
xdr_encode_opaque(p, val.data, val.len);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* _SUNRPC_XDRGEN__BUILTINS_H_ */
|
26
include/linux/sunrpc/xdrgen/_defs.h
Normal file
26
include/linux/sunrpc/xdrgen/_defs.h
Normal file
@ -0,0 +1,26 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2024 Oracle and/or its affiliates.
|
||||
*
|
||||
* This header defines XDR data type primitives specified in
|
||||
* Section 4 of RFC 4506, used by RPC programs implemented
|
||||
* in the Linux kernel.
|
||||
*/
|
||||
|
||||
#ifndef _SUNRPC_XDRGEN__DEFS_H_
|
||||
#define _SUNRPC_XDRGEN__DEFS_H_
|
||||
|
||||
#define TRUE (true)
|
||||
#define FALSE (false)
|
||||
|
||||
typedef struct {
|
||||
u32 len;
|
||||
unsigned char *data;
|
||||
} string;
|
||||
|
||||
typedef struct {
|
||||
u32 len;
|
||||
u8 *data;
|
||||
} opaque;
|
||||
|
||||
#endif /* _SUNRPC_XDRGEN__DEFS_H_ */
|
2
tools/net/sunrpc/xdrgen/.gitignore
vendored
Normal file
2
tools/net/sunrpc/xdrgen/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
__pycache__
|
||||
generators/__pycache__
|
244
tools/net/sunrpc/xdrgen/README
Normal file
244
tools/net/sunrpc/xdrgen/README
Normal file
@ -0,0 +1,244 @@
|
||||
xdrgen - Linux Kernel XDR code generator
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
SunRPC programs are typically specified using a language defined by
|
||||
RFC 4506. In fact, all IETF-published NFS specifications provide a
|
||||
description of the specified protocol using this language.
|
||||
|
||||
Since the 1990's, user space consumers of SunRPC have had access to
|
||||
a tool that could read such XDR specifications and then generate C
|
||||
code that implements the RPC portions of that protocol. This tool is
|
||||
called rpcgen.
|
||||
|
||||
This RPC-level code is code that handles input directly from the
|
||||
network, and thus a high degree of memory safety and sanity checking
|
||||
is needed to help ensure proper levels of security. Bugs in this
|
||||
code can have significant impact on security and performance.
|
||||
|
||||
However, it is code that is repetitive and tedious to write by hand.
|
||||
|
||||
The C code generated by rpcgen makes extensive use of the facilities
|
||||
of the user space TI-RPC library and libc. Furthermore, the dialect
|
||||
of the generated code is very traditional K&R C.
|
||||
|
||||
The Linux kernel's implementation of SunRPC-based protocols hand-roll
|
||||
their XDR implementation. There are two main reasons for this:
|
||||
|
||||
1. libtirpc (and its predecessors) operate only in user space. The
|
||||
kernel's RPC implementation and its API are significantly
|
||||
different than libtirpc.
|
||||
|
||||
2. rpcgen-generated code is believed to be less efficient than code
|
||||
that is hand-written.
|
||||
|
||||
These days, gcc and its kin are capable of optimizing code better
|
||||
than human authors. There are only a few instances where writing
|
||||
XDR code by hand will make a measurable performance different.
|
||||
|
||||
In addition, the current hand-written code in the Linux kernel is
|
||||
difficult to audit and prove that it implements exactly what is in
|
||||
the protocol specification.
|
||||
|
||||
In order to accrue the benefits of machine-generated XDR code in the
|
||||
kernel, a tool is needed that will output C code that works against
|
||||
the kernel's SunRPC implementation rather than libtirpc.
|
||||
|
||||
Enter xdrgen.
|
||||
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
These dependencies are typically packaged by Linux distributions:
|
||||
|
||||
- python3
|
||||
- python3-lark
|
||||
- python3-jinja2
|
||||
|
||||
These dependencies are available via PyPi:
|
||||
|
||||
- pip install 'lark[interegular]'
|
||||
|
||||
|
||||
XDR Specifications
|
||||
------------------
|
||||
|
||||
When adding a new protocol implementation to the kernel, the XDR
|
||||
specification can be derived by feeding a .txt copy of the RFC to
|
||||
the script located in tools/net/sunrpc/extract.sh.
|
||||
|
||||
$ extract.sh < rfc0001.txt > new2.x
|
||||
|
||||
|
||||
Operation
|
||||
---------
|
||||
|
||||
Once a .x file is available, use xdrgen to generate source and
|
||||
header files containing an implementation of XDR encoding and
|
||||
decoding functions for the specified protocol.
|
||||
|
||||
$ ./xdrgen definitions new2.x > include/linux/sunrpc/xdrgen/new2.h
|
||||
$ ./xdrgen declarations new2.x > new2xdr_gen.h
|
||||
|
||||
and
|
||||
|
||||
$ ./xdrgen source new2.x > new2xdr_gen.c
|
||||
|
||||
The files are ready to use for a server-side protocol implementation,
|
||||
or may be used as a guide for implementing these routines by hand.
|
||||
|
||||
By default, the only comments added to this code are kdoc comments
|
||||
that appear directly in front of the public per-procedure APIs. For
|
||||
deeper introspection, specifying the "--annotate" flag will insert
|
||||
additional comments in the generated code to help readers match the
|
||||
generated code to specific parts of the XDR specification.
|
||||
|
||||
Because the generated code is targeted for the Linux kernel, it
|
||||
is tagged with a GPLv2-only license.
|
||||
|
||||
The xdrgen tool can also provide lexical and syntax checking of
|
||||
an XDR specification:
|
||||
|
||||
$ ./xdrgen lint xdr/new.x
|
||||
|
||||
|
||||
How It Works
|
||||
------------
|
||||
|
||||
xdrgen does not use machine learning to generate source code. The
|
||||
translation is entirely deterministic.
|
||||
|
||||
RFC 4506 Section 6 contains a BNF grammar of the XDR specification
|
||||
language. The grammar has been adapted for use by the Python Lark
|
||||
module.
|
||||
|
||||
The xdr.ebnf file in this directory contains the grammar used to
|
||||
parse XDR specifications. xdrgen configures Lark using the grammar
|
||||
in xdr.ebnf. Lark parses the target XDR specification using this
|
||||
grammar, creating a parse tree.
|
||||
|
||||
xdrgen then transforms the parse tree into an abstract syntax tree.
|
||||
This tree is passed to a series of code generators.
|
||||
|
||||
The generators are implemented as Python classes residing in the
|
||||
generators/ directory. Each generator emits code created from Jinja2
|
||||
templates stored in the templates/ directory.
|
||||
|
||||
The source code is generated in the same order in which they appear
|
||||
in the specification to ensure the generated code compiles. This
|
||||
conforms with the behavior of rpcgen.
|
||||
|
||||
xdrgen assumes that the generated source code is further compiled by
|
||||
a compiler that can optimize in a number of ways, including:
|
||||
|
||||
- Unused functions are discarded (ie, not added to the executable)
|
||||
|
||||
- Aggressive function inlining removes unnecessary stack frames
|
||||
|
||||
- Single-arm switch statements are replaced by a single conditional
|
||||
branch
|
||||
|
||||
And so on.
|
||||
|
||||
|
||||
Pragmas
|
||||
-------
|
||||
|
||||
Pragma directives specify exceptions to the normal generation of
|
||||
encoding and decoding functions. Currently one directive is
|
||||
implemented: "public".
|
||||
|
||||
Pragma exclude
|
||||
------ -------
|
||||
|
||||
pragma exclude <RPC procedure> ;
|
||||
|
||||
In some cases, a procedure encoder or decoder function might need
|
||||
special processing that cannot be automatically generated. The
|
||||
automatically-generated functions might conflict or interfere with
|
||||
the hand-rolled function. To avoid editing the generated source code
|
||||
by hand, a pragma can specify that the procedure's encoder and
|
||||
decoder functions are not included in the generated header and
|
||||
source.
|
||||
|
||||
For example:
|
||||
|
||||
pragma exclude NFSPROC3_READDIRPLUS;
|
||||
|
||||
Excludes the decoder function for the READDIRPLUS argument and the
|
||||
encoder function for the READDIRPLUS result.
|
||||
|
||||
Note that because data item encoder and decoder functions are
|
||||
defined "static __maybe_unused", subsequent compilation
|
||||
automatically excludes data item encoder and decoder functions that
|
||||
are used only by excluded procedure.
|
||||
|
||||
Pragma header
|
||||
------ ------
|
||||
|
||||
pragma header <string> ;
|
||||
|
||||
Provide a name to use for the header file. For example:
|
||||
|
||||
pragma header nlm4;
|
||||
|
||||
Adds
|
||||
|
||||
#include "nlm4xdr_gen.h"
|
||||
|
||||
to the generated source file.
|
||||
|
||||
Pragma public
|
||||
------ ------
|
||||
|
||||
pragma public <XDR data item> ;
|
||||
|
||||
Normally XDR encoder and decoder functions are "static". In case an
|
||||
implementer wants to call these functions from other source code,
|
||||
s/he can add a public pragma in the input .x file to indicate a set
|
||||
of functions that should get a prototype in the generated header,
|
||||
and the function definitions will not be declared static.
|
||||
|
||||
For example:
|
||||
|
||||
pragma public nfsstat3;
|
||||
|
||||
Adds these prototypes in the generated header:
|
||||
|
||||
bool xdrgen_decode_nfsstat3(struct xdr_stream *xdr, enum nfsstat3 *ptr);
|
||||
bool xdrgen_encode_nfsstat3(struct xdr_stream *xdr, enum nfsstat3 value);
|
||||
|
||||
And, in the generated source code, both of these functions appear
|
||||
without the "static __maybe_unused" modifiers.
|
||||
|
||||
|
||||
Future Work
|
||||
-----------
|
||||
|
||||
Finish implementing XDR pointer and list types.
|
||||
|
||||
Generate client-side procedure functions
|
||||
|
||||
Expand the README into a user guide similar to rpcgen(1)
|
||||
|
||||
Add more pragma directives:
|
||||
|
||||
* @pages -- use xdr_read/write_pages() for the specified opaque
|
||||
field
|
||||
* @skip -- do not decode, but rather skip, the specified argument
|
||||
field
|
||||
|
||||
Enable something like a #include to dynamically insert the content
|
||||
of other specification files
|
||||
|
||||
Properly support line-by-line pass-through via the "%" decorator
|
||||
|
||||
Build a unit test suite for verifying translation of XDR language
|
||||
into compilable code
|
||||
|
||||
Add a command-line option to insert trace_printk call sites in the
|
||||
generated source code, for improved (temporary) observability
|
||||
|
||||
Generate kernel Rust code as well as C code
|
2
tools/net/sunrpc/xdrgen/__init__.py
Normal file
2
tools/net/sunrpc/xdrgen/__init__.py
Normal file
@ -0,0 +1,2 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Just to make sphinx-apidoc document this directory
|
113
tools/net/sunrpc/xdrgen/generators/__init__.py
Normal file
113
tools/net/sunrpc/xdrgen/generators/__init__.py
Normal file
@ -0,0 +1,113 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
"""Define a base code generator class"""
|
||||
|
||||
import sys
|
||||
from jinja2 import Environment, FileSystemLoader, Template
|
||||
|
||||
from xdr_ast import _XdrAst, Specification, _RpcProgram, _XdrTypeSpecifier
|
||||
from xdr_ast import public_apis, pass_by_reference, get_header_name
|
||||
from xdr_parse import get_xdr_annotate
|
||||
|
||||
|
||||
def create_jinja2_environment(language: str, xdr_type: str) -> Environment:
|
||||
"""Open a set of templates based on output language"""
|
||||
match language:
|
||||
case "C":
|
||||
environment = Environment(
|
||||
loader=FileSystemLoader(sys.path[0] + "/templates/C/" + xdr_type + "/"),
|
||||
trim_blocks=True,
|
||||
lstrip_blocks=True,
|
||||
)
|
||||
environment.globals["annotate"] = get_xdr_annotate()
|
||||
environment.globals["public_apis"] = public_apis
|
||||
environment.globals["pass_by_reference"] = pass_by_reference
|
||||
return environment
|
||||
case _:
|
||||
raise NotImplementedError("Language not supported")
|
||||
|
||||
|
||||
def get_jinja2_template(
|
||||
environment: Environment, template_type: str, template_name: str
|
||||
) -> Template:
|
||||
"""Retrieve a Jinja2 template for emitting source code"""
|
||||
return environment.get_template(template_type + "/" + template_name + ".j2")
|
||||
|
||||
|
||||
def find_xdr_program_name(root: Specification) -> str:
|
||||
"""Retrieve the RPC program name from an abstract syntax tree"""
|
||||
raw_name = get_header_name()
|
||||
if raw_name != "none":
|
||||
return raw_name.lower()
|
||||
for definition in root.definitions:
|
||||
if isinstance(definition.value, _RpcProgram):
|
||||
raw_name = definition.value.name
|
||||
return raw_name.lower().removesuffix("_program").removesuffix("_prog")
|
||||
return "noprog"
|
||||
|
||||
|
||||
def header_guard_infix(filename: str) -> str:
|
||||
"""Extract the header guard infix from the specification filename"""
|
||||
basename = filename.split("/")[-1]
|
||||
program = basename.replace(".x", "")
|
||||
return program.upper()
|
||||
|
||||
|
||||
def kernel_c_type(spec: _XdrTypeSpecifier) -> str:
|
||||
"""Return name of C type"""
|
||||
builtin_native_c_type = {
|
||||
"bool": "bool",
|
||||
"int": "s32",
|
||||
"unsigned_int": "u32",
|
||||
"long": "s32",
|
||||
"unsigned_long": "u32",
|
||||
"hyper": "s64",
|
||||
"unsigned_hyper": "u64",
|
||||
}
|
||||
if spec.type_name in builtin_native_c_type:
|
||||
return builtin_native_c_type[spec.type_name]
|
||||
return spec.type_name
|
||||
|
||||
|
||||
class Boilerplate:
|
||||
"""Base class to generate boilerplate for source files"""
|
||||
|
||||
def __init__(self, language: str, peer: str):
|
||||
"""Initialize an instance of this class"""
|
||||
raise NotImplementedError("No language support defined")
|
||||
|
||||
def emit_declaration(self, filename: str, root: Specification) -> None:
|
||||
"""Emit declaration header boilerplate"""
|
||||
raise NotImplementedError("Header boilerplate generation not supported")
|
||||
|
||||
def emit_definition(self, filename: str, root: Specification) -> None:
|
||||
"""Emit definition header boilerplate"""
|
||||
raise NotImplementedError("Header boilerplate generation not supported")
|
||||
|
||||
def emit_source(self, filename: str, root: Specification) -> None:
|
||||
"""Emit generic source code for this XDR type"""
|
||||
raise NotImplementedError("Source boilerplate generation not supported")
|
||||
|
||||
|
||||
class SourceGenerator:
|
||||
"""Base class to generate header and source code for XDR types"""
|
||||
|
||||
def __init__(self, language: str, peer: str):
|
||||
"""Initialize an instance of this class"""
|
||||
raise NotImplementedError("No language support defined")
|
||||
|
||||
def emit_declaration(self, node: _XdrAst) -> None:
|
||||
"""Emit one function declaration for this XDR type"""
|
||||
raise NotImplementedError("Declaration generation not supported")
|
||||
|
||||
def emit_decoder(self, node: _XdrAst) -> None:
|
||||
"""Emit one decoder function for this XDR type"""
|
||||
raise NotImplementedError("Decoder generation not supported")
|
||||
|
||||
def emit_definition(self, node: _XdrAst) -> None:
|
||||
"""Emit one definition for this XDR type"""
|
||||
raise NotImplementedError("Definition generation not supported")
|
||||
|
||||
def emit_encoder(self, node: _XdrAst) -> None:
|
||||
"""Emit one encoder function for this XDR type"""
|
||||
raise NotImplementedError("Encoder generation not supported")
|
20
tools/net/sunrpc/xdrgen/generators/constant.py
Normal file
20
tools/net/sunrpc/xdrgen/generators/constant.py
Normal file
@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env python3
|
||||
# ex: set filetype=python:
|
||||
|
||||
"""Generate code to handle XDR constants"""
|
||||
|
||||
from generators import SourceGenerator, create_jinja2_environment
|
||||
from xdr_ast import _XdrConstant
|
||||
|
||||
class XdrConstantGenerator(SourceGenerator):
|
||||
"""Generate source code for XDR constants"""
|
||||
|
||||
def __init__(self, language: str, peer: str):
|
||||
"""Initialize an instance of this class"""
|
||||
self.environment = create_jinja2_environment(language, "constants")
|
||||
self.peer = peer
|
||||
|
||||
def emit_definition(self, node: _XdrConstant) -> None:
|
||||
"""Emit one definition for a constant"""
|
||||
template = self.environment.get_template("definition.j2")
|
||||
print(template.render(name=node.name, value=node.value))
|
44
tools/net/sunrpc/xdrgen/generators/enum.py
Normal file
44
tools/net/sunrpc/xdrgen/generators/enum.py
Normal file
@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env python3
|
||||
# ex: set filetype=python:
|
||||
|
||||
"""Generate code to handle XDR enum types"""
|
||||
|
||||
from generators import SourceGenerator, create_jinja2_environment
|
||||
from xdr_ast import _XdrEnum, public_apis
|
||||
|
||||
|
||||
class XdrEnumGenerator(SourceGenerator):
|
||||
"""Generate source code for XDR enum types"""
|
||||
|
||||
def __init__(self, language: str, peer: str):
|
||||
"""Initialize an instance of this class"""
|
||||
self.environment = create_jinja2_environment(language, "enum")
|
||||
self.peer = peer
|
||||
|
||||
def emit_declaration(self, node: _XdrEnum) -> None:
|
||||
"""Emit one declaration pair for an XDR enum type"""
|
||||
if node.name in public_apis:
|
||||
template = self.environment.get_template("declaration/close.j2")
|
||||
print(template.render(name=node.name))
|
||||
|
||||
def emit_definition(self, node: _XdrEnum) -> None:
|
||||
"""Emit one definition for an XDR enum type"""
|
||||
template = self.environment.get_template("definition/open.j2")
|
||||
print(template.render(name=node.name))
|
||||
|
||||
template = self.environment.get_template("definition/enumerator.j2")
|
||||
for enumerator in node.enumerators:
|
||||
print(template.render(name=enumerator.name, value=enumerator.value))
|
||||
|
||||
template = self.environment.get_template("definition/close.j2")
|
||||
print(template.render(name=node.name))
|
||||
|
||||
def emit_decoder(self, node: _XdrEnum) -> None:
|
||||
"""Emit one decoder function for an XDR enum type"""
|
||||
template = self.environment.get_template("decoder/enum.j2")
|
||||
print(template.render(name=node.name))
|
||||
|
||||
def emit_encoder(self, node: _XdrEnum) -> None:
|
||||
"""Emit one encoder function for an XDR enum type"""
|
||||
template = self.environment.get_template("encoder/enum.j2")
|
||||
print(template.render(name=node.name))
|
33
tools/net/sunrpc/xdrgen/generators/header_bottom.py
Normal file
33
tools/net/sunrpc/xdrgen/generators/header_bottom.py
Normal file
@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env python3
|
||||
# ex: set filetype=python:
|
||||
|
||||
"""Generate header bottom boilerplate"""
|
||||
|
||||
import os.path
|
||||
import time
|
||||
|
||||
from generators import Boilerplate, header_guard_infix
|
||||
from generators import create_jinja2_environment, get_jinja2_template
|
||||
from xdr_ast import Specification
|
||||
|
||||
|
||||
class XdrHeaderBottomGenerator(Boilerplate):
|
||||
"""Generate header boilerplate"""
|
||||
|
||||
def __init__(self, language: str, peer: str):
|
||||
"""Initialize an instance of this class"""
|
||||
self.environment = create_jinja2_environment(language, "header_bottom")
|
||||
self.peer = peer
|
||||
|
||||
def emit_declaration(self, filename: str, root: Specification) -> None:
|
||||
"""Emit the bottom header guard"""
|
||||
template = get_jinja2_template(self.environment, "declaration", "header")
|
||||
print(template.render(infix=header_guard_infix(filename)))
|
||||
|
||||
def emit_definition(self, filename: str, root: Specification) -> None:
|
||||
"""Emit the bottom header guard"""
|
||||
template = get_jinja2_template(self.environment, "definition", "header")
|
||||
print(template.render(infix=header_guard_infix(filename)))
|
||||
|
||||
def emit_source(self, filename: str, root: Specification) -> None:
|
||||
pass
|
45
tools/net/sunrpc/xdrgen/generators/header_top.py
Normal file
45
tools/net/sunrpc/xdrgen/generators/header_top.py
Normal file
@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python3
|
||||
# ex: set filetype=python:
|
||||
|
||||
"""Generate header top boilerplate"""
|
||||
|
||||
import os.path
|
||||
import time
|
||||
|
||||
from generators import Boilerplate, header_guard_infix
|
||||
from generators import create_jinja2_environment, get_jinja2_template
|
||||
from xdr_ast import Specification
|
||||
|
||||
|
||||
class XdrHeaderTopGenerator(Boilerplate):
|
||||
"""Generate header boilerplate"""
|
||||
|
||||
def __init__(self, language: str, peer: str):
|
||||
"""Initialize an instance of this class"""
|
||||
self.environment = create_jinja2_environment(language, "header_top")
|
||||
self.peer = peer
|
||||
|
||||
def emit_declaration(self, filename: str, root: Specification) -> None:
|
||||
"""Emit the top header guard"""
|
||||
template = get_jinja2_template(self.environment, "declaration", "header")
|
||||
print(
|
||||
template.render(
|
||||
infix=header_guard_infix(filename),
|
||||
filename=filename,
|
||||
mtime=time.ctime(os.path.getmtime(filename)),
|
||||
)
|
||||
)
|
||||
|
||||
def emit_definition(self, filename: str, root: Specification) -> None:
|
||||
"""Emit the top header guard"""
|
||||
template = get_jinja2_template(self.environment, "definition", "header")
|
||||
print(
|
||||
template.render(
|
||||
infix=header_guard_infix(filename),
|
||||
filename=filename,
|
||||
mtime=time.ctime(os.path.getmtime(filename)),
|
||||
)
|
||||
)
|
||||
|
||||
def emit_source(self, filename: str, root: Specification) -> None:
|
||||
pass
|
272
tools/net/sunrpc/xdrgen/generators/pointer.py
Normal file
272
tools/net/sunrpc/xdrgen/generators/pointer.py
Normal file
@ -0,0 +1,272 @@
|
||||
#!/usr/bin/env python3
|
||||
# ex: set filetype=python:
|
||||
|
||||
"""Generate code to handle XDR pointer types"""
|
||||
|
||||
from jinja2 import Environment
|
||||
|
||||
from generators import SourceGenerator, kernel_c_type
|
||||
from generators import create_jinja2_environment, get_jinja2_template
|
||||
|
||||
from xdr_ast import _XdrBasic, _XdrVariableLengthString
|
||||
from xdr_ast import _XdrFixedLengthOpaque, _XdrVariableLengthOpaque
|
||||
from xdr_ast import _XdrFixedLengthArray, _XdrVariableLengthArray
|
||||
from xdr_ast import _XdrOptionalData, _XdrPointer, _XdrDeclaration
|
||||
from xdr_ast import public_apis
|
||||
|
||||
|
||||
def emit_pointer_declaration(environment: Environment, node: _XdrPointer) -> None:
|
||||
"""Emit a declaration pair for an XDR pointer type"""
|
||||
if node.name in public_apis:
|
||||
template = get_jinja2_template(environment, "declaration", "close")
|
||||
print(template.render(name=node.name))
|
||||
|
||||
|
||||
def emit_pointer_member_definition(
|
||||
environment: Environment, field: _XdrDeclaration
|
||||
) -> None:
|
||||
"""Emit a definition for one field in an XDR struct"""
|
||||
if isinstance(field, _XdrBasic):
|
||||
template = get_jinja2_template(environment, "definition", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
type=kernel_c_type(field.spec),
|
||||
classifier=field.spec.c_classifier,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrFixedLengthOpaque):
|
||||
template = get_jinja2_template(environment, "definition", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
size=field.size,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrVariableLengthOpaque):
|
||||
template = get_jinja2_template(environment, "definition", field.template)
|
||||
print(template.render(name=field.name))
|
||||
elif isinstance(field, _XdrVariableLengthString):
|
||||
template = get_jinja2_template(environment, "definition", field.template)
|
||||
print(template.render(name=field.name))
|
||||
elif isinstance(field, _XdrFixedLengthArray):
|
||||
template = get_jinja2_template(environment, "definition", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
type=kernel_c_type(field.spec),
|
||||
size=field.size,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrVariableLengthArray):
|
||||
template = get_jinja2_template(environment, "definition", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
type=kernel_c_type(field.spec),
|
||||
classifier=field.spec.c_classifier,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrOptionalData):
|
||||
template = get_jinja2_template(environment, "definition", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
type=kernel_c_type(field.spec),
|
||||
classifier=field.spec.c_classifier,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def emit_pointer_definition(environment: Environment, node: _XdrPointer) -> None:
|
||||
"""Emit a definition for an XDR pointer type"""
|
||||
template = get_jinja2_template(environment, "definition", "open")
|
||||
print(template.render(name=node.name))
|
||||
|
||||
for field in node.fields[0:-1]:
|
||||
emit_pointer_member_definition(environment, field)
|
||||
|
||||
template = get_jinja2_template(environment, "definition", "close")
|
||||
print(template.render(name=node.name))
|
||||
|
||||
|
||||
def emit_pointer_member_decoder(
|
||||
environment: Environment, field: _XdrDeclaration
|
||||
) -> None:
|
||||
"""Emit a decoder for one field in an XDR pointer"""
|
||||
if isinstance(field, _XdrBasic):
|
||||
template = get_jinja2_template(environment, "decoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
type=field.spec.type_name,
|
||||
classifier=field.spec.c_classifier,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrFixedLengthOpaque):
|
||||
template = get_jinja2_template(environment, "decoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
size=field.size,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrVariableLengthOpaque):
|
||||
template = get_jinja2_template(environment, "decoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
maxsize=field.maxsize,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrVariableLengthString):
|
||||
template = get_jinja2_template(environment, "decoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
maxsize=field.maxsize,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrFixedLengthArray):
|
||||
template = get_jinja2_template(environment, "decoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
type=field.spec.type_name,
|
||||
size=field.size,
|
||||
classifier=field.spec.c_classifier,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrVariableLengthArray):
|
||||
template = get_jinja2_template(environment, "decoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
type=field.spec.type_name,
|
||||
maxsize=field.maxsize,
|
||||
classifier=field.spec.c_classifier,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrOptionalData):
|
||||
template = get_jinja2_template(environment, "decoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
type=field.spec.type_name,
|
||||
classifier=field.spec.c_classifier,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def emit_pointer_decoder(environment: Environment, node: _XdrPointer) -> None:
|
||||
"""Emit one decoder function for an XDR pointer type"""
|
||||
template = get_jinja2_template(environment, "decoder", "open")
|
||||
print(template.render(name=node.name))
|
||||
|
||||
for field in node.fields[0:-1]:
|
||||
emit_pointer_member_decoder(environment, field)
|
||||
|
||||
template = get_jinja2_template(environment, "decoder", "close")
|
||||
print(template.render())
|
||||
|
||||
|
||||
def emit_pointer_member_encoder(
|
||||
environment: Environment, field: _XdrDeclaration
|
||||
) -> None:
|
||||
"""Emit an encoder for one field in a XDR pointer"""
|
||||
if isinstance(field, _XdrBasic):
|
||||
template = get_jinja2_template(environment, "encoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
type=field.spec.type_name,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrFixedLengthOpaque):
|
||||
template = get_jinja2_template(environment, "encoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
size=field.size,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrVariableLengthOpaque):
|
||||
template = get_jinja2_template(environment, "encoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
maxsize=field.maxsize,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrVariableLengthString):
|
||||
template = get_jinja2_template(environment, "encoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
maxsize=field.maxsize,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrFixedLengthArray):
|
||||
template = get_jinja2_template(environment, "encoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
type=field.spec.type_name,
|
||||
size=field.size,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrVariableLengthArray):
|
||||
template = get_jinja2_template(environment, "encoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
type=field.spec.type_name,
|
||||
maxsize=field.maxsize,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrOptionalData):
|
||||
template = get_jinja2_template(environment, "encoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
type=field.spec.type_name,
|
||||
classifier=field.spec.c_classifier,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def emit_pointer_encoder(environment: Environment, node: _XdrPointer) -> None:
|
||||
"""Emit one encoder function for an XDR pointer type"""
|
||||
template = get_jinja2_template(environment, "encoder", "open")
|
||||
print(template.render(name=node.name))
|
||||
|
||||
for field in node.fields[0:-1]:
|
||||
emit_pointer_member_encoder(environment, field)
|
||||
|
||||
template = get_jinja2_template(environment, "encoder", "close")
|
||||
print(template.render())
|
||||
|
||||
|
||||
class XdrPointerGenerator(SourceGenerator):
|
||||
"""Generate source code for XDR pointer"""
|
||||
|
||||
def __init__(self, language: str, peer: str):
|
||||
"""Initialize an instance of this class"""
|
||||
self.environment = create_jinja2_environment(language, "pointer")
|
||||
self.peer = peer
|
||||
|
||||
def emit_declaration(self, node: _XdrPointer) -> None:
|
||||
"""Emit one declaration pair for an XDR pointer type"""
|
||||
emit_pointer_declaration(self.environment, node)
|
||||
|
||||
def emit_definition(self, node: _XdrPointer) -> None:
|
||||
"""Emit one declaration for an XDR pointer type"""
|
||||
emit_pointer_definition(self.environment, node)
|
||||
|
||||
def emit_decoder(self, node: _XdrPointer) -> None:
|
||||
"""Emit one decoder function for an XDR pointer type"""
|
||||
emit_pointer_decoder(self.environment, node)
|
||||
|
||||
def emit_encoder(self, node: _XdrPointer) -> None:
|
||||
"""Emit one encoder function for an XDR pointer type"""
|
||||
emit_pointer_encoder(self.environment, node)
|
168
tools/net/sunrpc/xdrgen/generators/program.py
Normal file
168
tools/net/sunrpc/xdrgen/generators/program.py
Normal file
@ -0,0 +1,168 @@
|
||||
#!/usr/bin/env python3
|
||||
# ex: set filetype=python:
|
||||
|
||||
"""Generate code for an RPC program's procedures"""
|
||||
|
||||
from jinja2 import Environment
|
||||
|
||||
from generators import SourceGenerator, create_jinja2_environment
|
||||
from xdr_ast import _RpcProgram, _RpcVersion, excluded_apis
|
||||
|
||||
|
||||
def emit_version_definitions(
|
||||
environment: Environment, program: str, version: _RpcVersion
|
||||
) -> None:
|
||||
"""Emit procedure numbers for each RPC version's procedures"""
|
||||
template = environment.get_template("definition/open.j2")
|
||||
print(template.render(program=program.upper()))
|
||||
|
||||
template = environment.get_template("definition/procedure.j2")
|
||||
for procedure in version.procedures:
|
||||
if procedure.name not in excluded_apis:
|
||||
print(
|
||||
template.render(
|
||||
name=procedure.name,
|
||||
value=procedure.number,
|
||||
)
|
||||
)
|
||||
|
||||
template = environment.get_template("definition/close.j2")
|
||||
print(template.render())
|
||||
|
||||
|
||||
def emit_version_declarations(
|
||||
environment: Environment, program: str, version: _RpcVersion
|
||||
) -> None:
|
||||
"""Emit declarations for each RPC version's procedures"""
|
||||
arguments = set()
|
||||
for procedure in version.procedures:
|
||||
if procedure.name not in excluded_apis:
|
||||
arguments.add(procedure.argument.type_name)
|
||||
if len(arguments) > 0:
|
||||
print("")
|
||||
template = environment.get_template("declaration/argument.j2")
|
||||
for argument in arguments:
|
||||
print(template.render(program=program, argument=argument))
|
||||
|
||||
results = set()
|
||||
for procedure in version.procedures:
|
||||
if procedure.name not in excluded_apis:
|
||||
results.add(procedure.result.type_name)
|
||||
if len(results) > 0:
|
||||
print("")
|
||||
template = environment.get_template("declaration/result.j2")
|
||||
for result in results:
|
||||
print(template.render(program=program, result=result))
|
||||
|
||||
|
||||
def emit_version_argument_decoders(
|
||||
environment: Environment, program: str, version: _RpcVersion
|
||||
) -> None:
|
||||
"""Emit server argument decoders for each RPC version's procedures"""
|
||||
arguments = set()
|
||||
for procedure in version.procedures:
|
||||
if procedure.name not in excluded_apis:
|
||||
arguments.add(procedure.argument.type_name)
|
||||
|
||||
template = environment.get_template("decoder/argument.j2")
|
||||
for argument in arguments:
|
||||
print(template.render(program=program, argument=argument))
|
||||
|
||||
|
||||
def emit_version_result_decoders(
|
||||
environment: Environment, program: str, version: _RpcVersion
|
||||
) -> None:
|
||||
"""Emit client result decoders for each RPC version's procedures"""
|
||||
results = set()
|
||||
for procedure in version.procedures:
|
||||
if procedure.name not in excluded_apis:
|
||||
results.add(procedure.result.type_name)
|
||||
|
||||
template = environment.get_template("decoder/result.j2")
|
||||
for result in results:
|
||||
print(template.render(program=program, result=result))
|
||||
|
||||
|
||||
def emit_version_argument_encoders(
|
||||
environment: Environment, program: str, version: _RpcVersion
|
||||
) -> None:
|
||||
"""Emit client argument encoders for each RPC version's procedures"""
|
||||
arguments = set()
|
||||
for procedure in version.procedures:
|
||||
if procedure.name not in excluded_apis:
|
||||
arguments.add(procedure.argument.type_name)
|
||||
|
||||
template = environment.get_template("encoder/argument.j2")
|
||||
for argument in arguments:
|
||||
print(template.render(program=program, argument=argument))
|
||||
|
||||
|
||||
def emit_version_result_encoders(
|
||||
environment: Environment, program: str, version: _RpcVersion
|
||||
) -> None:
|
||||
"""Emit server result encoders for each RPC version's procedures"""
|
||||
results = set()
|
||||
for procedure in version.procedures:
|
||||
if procedure.name not in excluded_apis:
|
||||
results.add(procedure.result.type_name)
|
||||
|
||||
template = environment.get_template("encoder/result.j2")
|
||||
for result in results:
|
||||
print(template.render(program=program, result=result))
|
||||
|
||||
|
||||
class XdrProgramGenerator(SourceGenerator):
|
||||
"""Generate source code for an RPC program's procedures"""
|
||||
|
||||
def __init__(self, language: str, peer: str):
|
||||
"""Initialize an instance of this class"""
|
||||
self.environment = create_jinja2_environment(language, "program")
|
||||
self.peer = peer
|
||||
|
||||
def emit_definition(self, node: _RpcProgram) -> None:
|
||||
"""Emit procedure numbers for each of an RPC programs's procedures"""
|
||||
raw_name = node.name
|
||||
program = raw_name.lower().removesuffix("_program").removesuffix("_prog")
|
||||
|
||||
for version in node.versions:
|
||||
emit_version_definitions(self.environment, program, version)
|
||||
|
||||
def emit_declaration(self, node: _RpcProgram) -> None:
|
||||
"""Emit a declaration pair for each of an RPC programs's procedures"""
|
||||
raw_name = node.name
|
||||
program = raw_name.lower().removesuffix("_program").removesuffix("_prog")
|
||||
|
||||
for version in node.versions:
|
||||
emit_version_declarations(self.environment, program, version)
|
||||
|
||||
def emit_decoder(self, node: _RpcProgram) -> None:
|
||||
"""Emit all decoder functions for an RPC program's procedures"""
|
||||
raw_name = node.name
|
||||
program = raw_name.lower().removesuffix("_program").removesuffix("_prog")
|
||||
match self.peer:
|
||||
case "server":
|
||||
for version in node.versions:
|
||||
emit_version_argument_decoders(
|
||||
self.environment, program, version,
|
||||
)
|
||||
case "client":
|
||||
for version in node.versions:
|
||||
emit_version_result_decoders(
|
||||
self.environment, program, version,
|
||||
)
|
||||
|
||||
def emit_encoder(self, node: _RpcProgram) -> None:
|
||||
"""Emit all encoder functions for an RPC program's procedures"""
|
||||
raw_name = node.name
|
||||
program = raw_name.lower().removesuffix("_program").removesuffix("_prog")
|
||||
match self.peer:
|
||||
case "server":
|
||||
for version in node.versions:
|
||||
emit_version_result_encoders(
|
||||
self.environment, program, version,
|
||||
)
|
||||
case "client":
|
||||
for version in node.versions:
|
||||
emit_version_argument_encoders(
|
||||
self.environment, program, version,
|
||||
)
|
32
tools/net/sunrpc/xdrgen/generators/source_top.py
Normal file
32
tools/net/sunrpc/xdrgen/generators/source_top.py
Normal file
@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env python3
|
||||
# ex: set filetype=python:
|
||||
|
||||
"""Generate source code boilerplate"""
|
||||
|
||||
import os.path
|
||||
import time
|
||||
|
||||
from generators import Boilerplate
|
||||
from generators import find_xdr_program_name, create_jinja2_environment
|
||||
from xdr_ast import _RpcProgram, Specification, get_header_name
|
||||
|
||||
|
||||
class XdrSourceTopGenerator(Boilerplate):
|
||||
"""Generate source code boilerplate"""
|
||||
|
||||
def __init__(self, language: str, peer: str):
|
||||
"""Initialize an instance of this class"""
|
||||
self.environment = create_jinja2_environment(language, "source_top")
|
||||
self.peer = peer
|
||||
|
||||
def emit_source(self, filename: str, root: Specification) -> None:
|
||||
"""Emit the top source boilerplate"""
|
||||
name = find_xdr_program_name(root)
|
||||
template = self.environment.get_template(self.peer + ".j2")
|
||||
print(
|
||||
template.render(
|
||||
program=name,
|
||||
filename=filename,
|
||||
mtime=time.ctime(os.path.getmtime(filename)),
|
||||
)
|
||||
)
|
272
tools/net/sunrpc/xdrgen/generators/struct.py
Normal file
272
tools/net/sunrpc/xdrgen/generators/struct.py
Normal file
@ -0,0 +1,272 @@
|
||||
#!/usr/bin/env python3
|
||||
# ex: set filetype=python:
|
||||
|
||||
"""Generate code to handle XDR struct types"""
|
||||
|
||||
from jinja2 import Environment
|
||||
|
||||
from generators import SourceGenerator, kernel_c_type
|
||||
from generators import create_jinja2_environment, get_jinja2_template
|
||||
|
||||
from xdr_ast import _XdrBasic, _XdrVariableLengthString
|
||||
from xdr_ast import _XdrFixedLengthOpaque, _XdrVariableLengthOpaque
|
||||
from xdr_ast import _XdrFixedLengthArray, _XdrVariableLengthArray
|
||||
from xdr_ast import _XdrOptionalData, _XdrStruct, _XdrDeclaration
|
||||
from xdr_ast import public_apis
|
||||
|
||||
|
||||
def emit_struct_declaration(environment: Environment, node: _XdrStruct) -> None:
|
||||
"""Emit one declaration pair for an XDR struct type"""
|
||||
if node.name in public_apis:
|
||||
template = get_jinja2_template(environment, "declaration", "close")
|
||||
print(template.render(name=node.name))
|
||||
|
||||
|
||||
def emit_struct_member_definition(
|
||||
environment: Environment, field: _XdrDeclaration
|
||||
) -> None:
|
||||
"""Emit a definition for one field in an XDR struct"""
|
||||
if isinstance(field, _XdrBasic):
|
||||
template = get_jinja2_template(environment, "definition", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
type=kernel_c_type(field.spec),
|
||||
classifier=field.spec.c_classifier,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrFixedLengthOpaque):
|
||||
template = get_jinja2_template(environment, "definition", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
size=field.size,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrVariableLengthOpaque):
|
||||
template = get_jinja2_template(environment, "definition", field.template)
|
||||
print(template.render(name=field.name))
|
||||
elif isinstance(field, _XdrVariableLengthString):
|
||||
template = get_jinja2_template(environment, "definition", field.template)
|
||||
print(template.render(name=field.name))
|
||||
elif isinstance(field, _XdrFixedLengthArray):
|
||||
template = get_jinja2_template(environment, "definition", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
type=kernel_c_type(field.spec),
|
||||
size=field.size,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrVariableLengthArray):
|
||||
template = get_jinja2_template(environment, "definition", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
type=kernel_c_type(field.spec),
|
||||
classifier=field.spec.c_classifier,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrOptionalData):
|
||||
template = get_jinja2_template(environment, "definition", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
type=kernel_c_type(field.spec),
|
||||
classifier=field.spec.c_classifier,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def emit_struct_definition(environment: Environment, node: _XdrStruct) -> None:
|
||||
"""Emit one definition for an XDR struct type"""
|
||||
template = get_jinja2_template(environment, "definition", "open")
|
||||
print(template.render(name=node.name))
|
||||
|
||||
for field in node.fields:
|
||||
emit_struct_member_definition(environment, field)
|
||||
|
||||
template = get_jinja2_template(environment, "definition", "close")
|
||||
print(template.render(name=node.name))
|
||||
|
||||
|
||||
def emit_struct_member_decoder(
|
||||
environment: Environment, field: _XdrDeclaration
|
||||
) -> None:
|
||||
"""Emit a decoder for one field in an XDR struct"""
|
||||
if isinstance(field, _XdrBasic):
|
||||
template = get_jinja2_template(environment, "decoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
type=field.spec.type_name,
|
||||
classifier=field.spec.c_classifier,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrFixedLengthOpaque):
|
||||
template = get_jinja2_template(environment, "decoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
size=field.size,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrVariableLengthOpaque):
|
||||
template = get_jinja2_template(environment, "decoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
maxsize=field.maxsize,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrVariableLengthString):
|
||||
template = get_jinja2_template(environment, "decoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
maxsize=field.maxsize,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrFixedLengthArray):
|
||||
template = get_jinja2_template(environment, "decoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
type=field.spec.type_name,
|
||||
size=field.size,
|
||||
classifier=field.spec.c_classifier,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrVariableLengthArray):
|
||||
template = get_jinja2_template(environment, "decoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
type=field.spec.type_name,
|
||||
maxsize=field.maxsize,
|
||||
classifier=field.spec.c_classifier,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrOptionalData):
|
||||
template = get_jinja2_template(environment, "decoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
type=field.spec.type_name,
|
||||
classifier=field.spec.c_classifier,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def emit_struct_decoder(environment: Environment, node: _XdrStruct) -> None:
|
||||
"""Emit one decoder function for an XDR struct type"""
|
||||
template = get_jinja2_template(environment, "decoder", "open")
|
||||
print(template.render(name=node.name))
|
||||
|
||||
for field in node.fields:
|
||||
emit_struct_member_decoder(environment, field)
|
||||
|
||||
template = get_jinja2_template(environment, "decoder", "close")
|
||||
print(template.render())
|
||||
|
||||
|
||||
def emit_struct_member_encoder(
|
||||
environment: Environment, field: _XdrDeclaration
|
||||
) -> None:
|
||||
"""Emit an encoder for one field in an XDR struct"""
|
||||
if isinstance(field, _XdrBasic):
|
||||
template = get_jinja2_template(environment, "encoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
type=field.spec.type_name,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrFixedLengthOpaque):
|
||||
template = get_jinja2_template(environment, "encoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
size=field.size,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrVariableLengthOpaque):
|
||||
template = get_jinja2_template(environment, "encoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
maxsize=field.maxsize,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrVariableLengthString):
|
||||
template = get_jinja2_template(environment, "encoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
maxsize=field.maxsize,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrFixedLengthArray):
|
||||
template = get_jinja2_template(environment, "encoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
type=field.spec.type_name,
|
||||
size=field.size,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrVariableLengthArray):
|
||||
template = get_jinja2_template(environment, "encoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
type=field.spec.type_name,
|
||||
maxsize=field.maxsize,
|
||||
)
|
||||
)
|
||||
elif isinstance(field, _XdrOptionalData):
|
||||
template = get_jinja2_template(environment, "encoder", field.template)
|
||||
print(
|
||||
template.render(
|
||||
name=field.name,
|
||||
type=field.spec.type_name,
|
||||
classifier=field.spec.c_classifier,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def emit_struct_encoder(environment: Environment, node: _XdrStruct) -> None:
|
||||
"""Emit one encoder function for an XDR struct type"""
|
||||
template = get_jinja2_template(environment, "encoder", "open")
|
||||
print(template.render(name=node.name))
|
||||
|
||||
for field in node.fields:
|
||||
emit_struct_member_encoder(environment, field)
|
||||
|
||||
template = get_jinja2_template(environment, "encoder", "close")
|
||||
print(template.render())
|
||||
|
||||
|
||||
class XdrStructGenerator(SourceGenerator):
|
||||
"""Generate source code for XDR structs"""
|
||||
|
||||
def __init__(self, language: str, peer: str):
|
||||
"""Initialize an instance of this class"""
|
||||
self.environment = create_jinja2_environment(language, "struct")
|
||||
self.peer = peer
|
||||
|
||||
def emit_declaration(self, node: _XdrStruct) -> None:
|
||||
"""Emit one declaration pair for an XDR struct type"""
|
||||
emit_struct_declaration(self.environment, node)
|
||||
|
||||
def emit_definition(self, node: _XdrStruct) -> None:
|
||||
"""Emit one definition for an XDR struct type"""
|
||||
emit_struct_definition(self.environment, node)
|
||||
|
||||
def emit_decoder(self, node: _XdrStruct) -> None:
|
||||
"""Emit one decoder function for an XDR struct type"""
|
||||
emit_struct_decoder(self.environment, node)
|
||||
|
||||
def emit_encoder(self, node: _XdrStruct) -> None:
|
||||
"""Emit one encoder function for an XDR struct type"""
|
||||
emit_struct_encoder(self.environment, node)
|
255
tools/net/sunrpc/xdrgen/generators/typedef.py
Normal file
255
tools/net/sunrpc/xdrgen/generators/typedef.py
Normal file
@ -0,0 +1,255 @@
|
||||
#!/usr/bin/env python3
|
||||
# ex: set filetype=python:
|
||||
|
||||
"""Generate code to handle XDR typedefs"""
|
||||
|
||||
from jinja2 import Environment
|
||||
|
||||
from generators import SourceGenerator, kernel_c_type
|
||||
from generators import create_jinja2_environment, get_jinja2_template
|
||||
|
||||
from xdr_ast import _XdrBasic, _XdrTypedef, _XdrVariableLengthString
|
||||
from xdr_ast import _XdrFixedLengthOpaque, _XdrVariableLengthOpaque
|
||||
from xdr_ast import _XdrFixedLengthArray, _XdrVariableLengthArray
|
||||
from xdr_ast import _XdrOptionalData, _XdrVoid, _XdrDeclaration
|
||||
from xdr_ast import public_apis
|
||||
|
||||
|
||||
def emit_typedef_declaration(environment: Environment, node: _XdrDeclaration) -> None:
|
||||
"""Emit a declaration pair for one XDR typedef"""
|
||||
if node.name not in public_apis:
|
||||
return
|
||||
if isinstance(node, _XdrBasic):
|
||||
template = get_jinja2_template(environment, "declaration", node.template)
|
||||
print(
|
||||
template.render(
|
||||
name=node.name,
|
||||
type=kernel_c_type(node.spec),
|
||||
classifier=node.spec.c_classifier,
|
||||
)
|
||||
)
|
||||
elif isinstance(node, _XdrVariableLengthString):
|
||||
template = get_jinja2_template(environment, "declaration", node.template)
|
||||
print(template.render(name=node.name))
|
||||
elif isinstance(node, _XdrFixedLengthOpaque):
|
||||
template = get_jinja2_template(environment, "declaration", node.template)
|
||||
print(template.render(name=node.name, size=node.size))
|
||||
elif isinstance(node, _XdrVariableLengthOpaque):
|
||||
template = get_jinja2_template(environment, "declaration", node.template)
|
||||
print(template.render(name=node.name))
|
||||
elif isinstance(node, _XdrFixedLengthArray):
|
||||
template = get_jinja2_template(environment, "declaration", node.template)
|
||||
print(
|
||||
template.render(
|
||||
name=node.name,
|
||||
type=node.spec.type_name,
|
||||
size=node.size,
|
||||
)
|
||||
)
|
||||
elif isinstance(node, _XdrVariableLengthArray):
|
||||
template = get_jinja2_template(environment, "declaration", node.template)
|
||||
print(
|
||||
template.render(
|
||||
name=node.name,
|
||||
type=node.spec.type_name,
|
||||
classifier=node.spec.c_classifier,
|
||||
)
|
||||
)
|
||||
elif isinstance(node, _XdrOptionalData):
|
||||
raise NotImplementedError("<optional_data> typedef not yet implemented")
|
||||
elif isinstance(node, _XdrVoid):
|
||||
raise NotImplementedError("<void> typedef not yet implemented")
|
||||
else:
|
||||
raise NotImplementedError("typedef: type not recognized")
|
||||
|
||||
|
||||
def emit_type_definition(environment: Environment, node: _XdrDeclaration) -> None:
|
||||
"""Emit a definition for one XDR typedef"""
|
||||
if isinstance(node, _XdrBasic):
|
||||
template = get_jinja2_template(environment, "definition", node.template)
|
||||
print(
|
||||
template.render(
|
||||
name=node.name,
|
||||
type=kernel_c_type(node.spec),
|
||||
classifier=node.spec.c_classifier,
|
||||
)
|
||||
)
|
||||
elif isinstance(node, _XdrVariableLengthString):
|
||||
template = get_jinja2_template(environment, "definition", node.template)
|
||||
print(template.render(name=node.name))
|
||||
elif isinstance(node, _XdrFixedLengthOpaque):
|
||||
template = get_jinja2_template(environment, "definition", node.template)
|
||||
print(template.render(name=node.name, size=node.size))
|
||||
elif isinstance(node, _XdrVariableLengthOpaque):
|
||||
template = get_jinja2_template(environment, "definition", node.template)
|
||||
print(template.render(name=node.name))
|
||||
elif isinstance(node, _XdrFixedLengthArray):
|
||||
template = get_jinja2_template(environment, "definition", node.template)
|
||||
print(
|
||||
template.render(
|
||||
name=node.name,
|
||||
type=node.spec.type_name,
|
||||
size=node.size,
|
||||
)
|
||||
)
|
||||
elif isinstance(node, _XdrVariableLengthArray):
|
||||
template = get_jinja2_template(environment, "definition", node.template)
|
||||
print(
|
||||
template.render(
|
||||
name=node.name,
|
||||
type=node.spec.type_name,
|
||||
classifier=node.spec.c_classifier,
|
||||
)
|
||||
)
|
||||
elif isinstance(node, _XdrOptionalData):
|
||||
raise NotImplementedError("<optional_data> typedef not yet implemented")
|
||||
elif isinstance(node, _XdrVoid):
|
||||
raise NotImplementedError("<void> typedef not yet implemented")
|
||||
else:
|
||||
raise NotImplementedError("typedef: type not recognized")
|
||||
|
||||
|
||||
def emit_typedef_decoder(environment: Environment, node: _XdrDeclaration) -> None:
|
||||
"""Emit a decoder function for one XDR typedef"""
|
||||
if isinstance(node, _XdrBasic):
|
||||
template = get_jinja2_template(environment, "decoder", node.template)
|
||||
print(
|
||||
template.render(
|
||||
name=node.name,
|
||||
type=node.spec.type_name,
|
||||
)
|
||||
)
|
||||
elif isinstance(node, _XdrVariableLengthString):
|
||||
template = get_jinja2_template(environment, "decoder", node.template)
|
||||
print(
|
||||
template.render(
|
||||
name=node.name,
|
||||
maxsize=node.maxsize,
|
||||
)
|
||||
)
|
||||
elif isinstance(node, _XdrFixedLengthOpaque):
|
||||
template = get_jinja2_template(environment, "decoder", node.template)
|
||||
print(
|
||||
template.render(
|
||||
name=node.name,
|
||||
size=node.size,
|
||||
)
|
||||
)
|
||||
elif isinstance(node, _XdrVariableLengthOpaque):
|
||||
template = get_jinja2_template(environment, "decoder", node.template)
|
||||
print(
|
||||
template.render(
|
||||
name=node.name,
|
||||
maxsize=node.maxsize,
|
||||
)
|
||||
)
|
||||
elif isinstance(node, _XdrFixedLengthArray):
|
||||
template = get_jinja2_template(environment, "decoder", node.template)
|
||||
print(
|
||||
template.render(
|
||||
name=node.name,
|
||||
type=node.spec.type_name,
|
||||
size=node.size,
|
||||
classifier=node.spec.c_classifier,
|
||||
)
|
||||
)
|
||||
elif isinstance(node, _XdrVariableLengthArray):
|
||||
template = get_jinja2_template(environment, "decoder", node.template)
|
||||
print(
|
||||
template.render(
|
||||
name=node.name,
|
||||
type=node.spec.type_name,
|
||||
maxsize=node.maxsize,
|
||||
)
|
||||
)
|
||||
elif isinstance(node, _XdrOptionalData):
|
||||
raise NotImplementedError("<optional_data> typedef not yet implemented")
|
||||
elif isinstance(node, _XdrVoid):
|
||||
raise NotImplementedError("<void> typedef not yet implemented")
|
||||
else:
|
||||
raise NotImplementedError("typedef: type not recognized")
|
||||
|
||||
|
||||
def emit_typedef_encoder(environment: Environment, node: _XdrDeclaration) -> None:
|
||||
"""Emit an encoder function for one XDR typedef"""
|
||||
if isinstance(node, _XdrBasic):
|
||||
template = get_jinja2_template(environment, "encoder", node.template)
|
||||
print(
|
||||
template.render(
|
||||
name=node.name,
|
||||
type=node.spec.type_name,
|
||||
)
|
||||
)
|
||||
elif isinstance(node, _XdrVariableLengthString):
|
||||
template = get_jinja2_template(environment, "encoder", node.template)
|
||||
print(
|
||||
template.render(
|
||||
name=node.name,
|
||||
maxsize=node.maxsize,
|
||||
)
|
||||
)
|
||||
elif isinstance(node, _XdrFixedLengthOpaque):
|
||||
template = get_jinja2_template(environment, "encoder", node.template)
|
||||
print(
|
||||
template.render(
|
||||
name=node.name,
|
||||
size=node.size,
|
||||
)
|
||||
)
|
||||
elif isinstance(node, _XdrVariableLengthOpaque):
|
||||
template = get_jinja2_template(environment, "encoder", node.template)
|
||||
print(
|
||||
template.render(
|
||||
name=node.name,
|
||||
maxsize=node.maxsize,
|
||||
)
|
||||
)
|
||||
elif isinstance(node, _XdrFixedLengthArray):
|
||||
template = get_jinja2_template(environment, "encoder", node.template)
|
||||
print(
|
||||
template.render(
|
||||
name=node.name,
|
||||
type=node.spec.type_name,
|
||||
size=node.size,
|
||||
)
|
||||
)
|
||||
elif isinstance(node, _XdrVariableLengthArray):
|
||||
template = get_jinja2_template(environment, "encoder", node.template)
|
||||
print(
|
||||
template.render(
|
||||
name=node.name,
|
||||
type=node.spec.type_name,
|
||||
maxsize=node.maxsize,
|
||||
)
|
||||
)
|
||||
elif isinstance(node, _XdrOptionalData):
|
||||
raise NotImplementedError("<optional_data> typedef not yet implemented")
|
||||
elif isinstance(node, _XdrVoid):
|
||||
raise NotImplementedError("<void> typedef not yet implemented")
|
||||
else:
|
||||
raise NotImplementedError("typedef: type not recognized")
|
||||
|
||||
|
||||
class XdrTypedefGenerator(SourceGenerator):
|
||||
"""Generate source code for XDR typedefs"""
|
||||
|
||||
def __init__(self, language: str, peer: str):
|
||||
"""Initialize an instance of this class"""
|
||||
self.environment = create_jinja2_environment(language, "typedef")
|
||||
self.peer = peer
|
||||
|
||||
def emit_declaration(self, node: _XdrTypedef) -> None:
|
||||
"""Emit one declaration pair for an XDR enum type"""
|
||||
emit_typedef_declaration(self.environment, node.declaration)
|
||||
|
||||
def emit_definition(self, node: _XdrTypedef) -> None:
|
||||
"""Emit one definition for an XDR typedef"""
|
||||
emit_type_definition(self.environment, node.declaration)
|
||||
|
||||
def emit_decoder(self, node: _XdrTypedef) -> None:
|
||||
"""Emit one decoder function for an XDR typedef"""
|
||||
emit_typedef_decoder(self.environment, node.declaration)
|
||||
|
||||
def emit_encoder(self, node: _XdrTypedef) -> None:
|
||||
"""Emit one encoder function for an XDR typedef"""
|
||||
emit_typedef_encoder(self.environment, node.declaration)
|
243
tools/net/sunrpc/xdrgen/generators/union.py
Normal file
243
tools/net/sunrpc/xdrgen/generators/union.py
Normal file
@ -0,0 +1,243 @@
|
||||
#!/usr/bin/env python3
|
||||
# ex: set filetype=python:
|
||||
|
||||
"""Generate code to handle XDR unions"""
|
||||
|
||||
from jinja2 import Environment
|
||||
|
||||
from generators import SourceGenerator
|
||||
from generators import create_jinja2_environment, get_jinja2_template
|
||||
|
||||
from xdr_ast import _XdrBasic, _XdrUnion, _XdrVoid
|
||||
from xdr_ast import _XdrDeclaration, _XdrCaseSpec, public_apis
|
||||
|
||||
|
||||
def emit_union_declaration(environment: Environment, node: _XdrUnion) -> None:
|
||||
"""Emit one declaration pair for an XDR union type"""
|
||||
if node.name in public_apis:
|
||||
template = get_jinja2_template(environment, "declaration", "close")
|
||||
print(template.render(name=node.name))
|
||||
|
||||
|
||||
def emit_union_switch_spec_definition(
|
||||
environment: Environment, node: _XdrDeclaration
|
||||
) -> None:
|
||||
"""Emit a definition for an XDR union's discriminant"""
|
||||
assert isinstance(node, _XdrBasic)
|
||||
template = get_jinja2_template(environment, "definition", "switch_spec")
|
||||
print(
|
||||
template.render(
|
||||
name=node.name,
|
||||
type=node.spec.type_name,
|
||||
classifier=node.spec.c_classifier,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def emit_union_case_spec_definition(
|
||||
environment: Environment, node: _XdrDeclaration
|
||||
) -> None:
|
||||
"""Emit a definition for an XDR union's case arm"""
|
||||
if isinstance(node.arm, _XdrVoid):
|
||||
return
|
||||
assert isinstance(node.arm, _XdrBasic)
|
||||
template = get_jinja2_template(environment, "definition", "case_spec")
|
||||
print(
|
||||
template.render(
|
||||
name=node.arm.name,
|
||||
type=node.arm.spec.type_name,
|
||||
classifier=node.arm.spec.c_classifier,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def emit_union_definition(environment: Environment, node: _XdrUnion) -> None:
|
||||
"""Emit one XDR union definition"""
|
||||
template = get_jinja2_template(environment, "definition", "open")
|
||||
print(template.render(name=node.name))
|
||||
|
||||
emit_union_switch_spec_definition(environment, node.discriminant)
|
||||
|
||||
for case in node.cases:
|
||||
emit_union_case_spec_definition(environment, case)
|
||||
|
||||
if node.default is not None:
|
||||
emit_union_case_spec_definition(environment, node.default)
|
||||
|
||||
template = get_jinja2_template(environment, "definition", "close")
|
||||
print(template.render(name=node.name))
|
||||
|
||||
|
||||
def emit_union_switch_spec_decoder(
|
||||
environment: Environment, node: _XdrDeclaration
|
||||
) -> None:
|
||||
"""Emit a decoder for an XDR union's discriminant"""
|
||||
assert isinstance(node, _XdrBasic)
|
||||
template = get_jinja2_template(environment, "decoder", "switch_spec")
|
||||
print(template.render(name=node.name, type=node.spec.type_name))
|
||||
|
||||
|
||||
def emit_union_case_spec_decoder(environment: Environment, node: _XdrCaseSpec) -> None:
|
||||
"""Emit decoder functions for an XDR union's case arm"""
|
||||
|
||||
if isinstance(node.arm, _XdrVoid):
|
||||
return
|
||||
|
||||
template = get_jinja2_template(environment, "decoder", "case_spec")
|
||||
for case in node.values:
|
||||
print(template.render(case=case))
|
||||
|
||||
assert isinstance(node.arm, _XdrBasic)
|
||||
template = get_jinja2_template(environment, "decoder", node.arm.template)
|
||||
print(
|
||||
template.render(
|
||||
name=node.arm.name,
|
||||
type=node.arm.spec.type_name,
|
||||
classifier=node.arm.spec.c_classifier,
|
||||
)
|
||||
)
|
||||
|
||||
template = get_jinja2_template(environment, "decoder", "break")
|
||||
print(template.render())
|
||||
|
||||
|
||||
def emit_union_default_spec_decoder(environment: Environment, node: _XdrUnion) -> None:
|
||||
"""Emit a decoder function for an XDR union's default arm"""
|
||||
default_case = node.default
|
||||
|
||||
# Avoid a gcc warning about a default case with boolean discriminant
|
||||
if default_case is None and node.discriminant.spec.type_name == "bool":
|
||||
return
|
||||
|
||||
template = get_jinja2_template(environment, "decoder", "default_spec")
|
||||
print(template.render())
|
||||
|
||||
if default_case is None or isinstance(default_case.arm, _XdrVoid):
|
||||
template = get_jinja2_template(environment, "decoder", "break")
|
||||
print(template.render())
|
||||
return
|
||||
|
||||
assert isinstance(default_case.arm, _XdrBasic)
|
||||
template = get_jinja2_template(environment, "decoder", default_case.arm.template)
|
||||
print(
|
||||
template.render(
|
||||
name=default_case.arm.name,
|
||||
type=default_case.arm.spec.type_name,
|
||||
classifier=default_case.arm.spec.c_classifier,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def emit_union_decoder(environment: Environment, node: _XdrUnion) -> None:
|
||||
"""Emit one XDR union decoder"""
|
||||
template = get_jinja2_template(environment, "decoder", "open")
|
||||
print(template.render(name=node.name))
|
||||
|
||||
emit_union_switch_spec_decoder(environment, node.discriminant)
|
||||
|
||||
for case in node.cases:
|
||||
emit_union_case_spec_decoder(environment, case)
|
||||
|
||||
emit_union_default_spec_decoder(environment, node)
|
||||
|
||||
template = get_jinja2_template(environment, "decoder", "close")
|
||||
print(template.render())
|
||||
|
||||
|
||||
def emit_union_switch_spec_encoder(
|
||||
environment: Environment, node: _XdrDeclaration
|
||||
) -> None:
|
||||
"""Emit an encoder for an XDR union's discriminant"""
|
||||
assert isinstance(node, _XdrBasic)
|
||||
template = get_jinja2_template(environment, "encoder", "switch_spec")
|
||||
print(template.render(name=node.name, type=node.spec.type_name))
|
||||
|
||||
|
||||
def emit_union_case_spec_encoder(environment: Environment, node: _XdrCaseSpec) -> None:
|
||||
"""Emit encoder functions for an XDR union's case arm"""
|
||||
|
||||
if isinstance(node.arm, _XdrVoid):
|
||||
return
|
||||
|
||||
template = get_jinja2_template(environment, "encoder", "case_spec")
|
||||
for case in node.values:
|
||||
print(template.render(case=case))
|
||||
|
||||
assert isinstance(node.arm, _XdrBasic)
|
||||
template = get_jinja2_template(environment, "encoder", node.arm.template)
|
||||
print(
|
||||
template.render(
|
||||
name=node.arm.name,
|
||||
type=node.arm.spec.type_name,
|
||||
)
|
||||
)
|
||||
|
||||
template = get_jinja2_template(environment, "encoder", "break")
|
||||
print(template.render())
|
||||
|
||||
|
||||
def emit_union_default_spec_encoder(environment: Environment, node: _XdrUnion) -> None:
|
||||
"""Emit an encoder function for an XDR union's default arm"""
|
||||
default_case = node.default
|
||||
|
||||
# Avoid a gcc warning about a default case with boolean discriminant
|
||||
if default_case is None and node.discriminant.spec.type_name == "bool":
|
||||
return
|
||||
|
||||
template = get_jinja2_template(environment, "encoder", "default_spec")
|
||||
print(template.render())
|
||||
|
||||
if default_case is None or isinstance(default_case.arm, _XdrVoid):
|
||||
template = get_jinja2_template(environment, "encoder", "break")
|
||||
print(template.render())
|
||||
return
|
||||
|
||||
assert isinstance(default_case.arm, _XdrBasic)
|
||||
template = get_jinja2_template(environment, "encoder", default_case.arm.template)
|
||||
print(
|
||||
template.render(
|
||||
name=default_case.arm.name,
|
||||
type=default_case.arm.spec.type_name,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def emit_union_encoder(environment, node: _XdrUnion) -> None:
|
||||
"""Emit one XDR union encoder"""
|
||||
template = get_jinja2_template(environment, "encoder", "open")
|
||||
print(template.render(name=node.name))
|
||||
|
||||
emit_union_switch_spec_encoder(environment, node.discriminant)
|
||||
|
||||
for case in node.cases:
|
||||
emit_union_case_spec_encoder(environment, case)
|
||||
|
||||
emit_union_default_spec_encoder(environment, node)
|
||||
|
||||
template = get_jinja2_template(environment, "encoder", "close")
|
||||
print(template.render())
|
||||
|
||||
|
||||
class XdrUnionGenerator(SourceGenerator):
|
||||
"""Generate source code for XDR unions"""
|
||||
|
||||
def __init__(self, language: str, peer: str):
|
||||
"""Initialize an instance of this class"""
|
||||
self.environment = create_jinja2_environment(language, "union")
|
||||
self.peer = peer
|
||||
|
||||
def emit_declaration(self, node: _XdrUnion) -> None:
|
||||
"""Emit one declaration pair for an XDR union"""
|
||||
emit_union_declaration(self.environment, node)
|
||||
|
||||
def emit_definition(self, node: _XdrUnion) -> None:
|
||||
"""Emit one definition for an XDR union"""
|
||||
emit_union_definition(self.environment, node)
|
||||
|
||||
def emit_decoder(self, node: _XdrUnion) -> None:
|
||||
"""Emit one decoder function for an XDR union"""
|
||||
emit_union_decoder(self.environment, node)
|
||||
|
||||
def emit_encoder(self, node: _XdrUnion) -> None:
|
||||
"""Emit one encoder function for an XDR union"""
|
||||
emit_union_encoder(self.environment, node)
|
119
tools/net/sunrpc/xdrgen/grammars/xdr.lark
Normal file
119
tools/net/sunrpc/xdrgen/grammars/xdr.lark
Normal file
@ -0,0 +1,119 @@
|
||||
// A Lark grammar for the XDR specification language based on
|
||||
// https://tools.ietf.org/html/rfc4506 Section 6.3
|
||||
|
||||
declaration : "opaque" identifier "[" value "]" -> fixed_length_opaque
|
||||
| "opaque" identifier "<" [ value ] ">" -> variable_length_opaque
|
||||
| "string" identifier "<" [ value ] ">" -> variable_length_string
|
||||
| type_specifier identifier "[" value "]" -> fixed_length_array
|
||||
| type_specifier identifier "<" [ value ] ">" -> variable_length_array
|
||||
| type_specifier "*" identifier -> optional_data
|
||||
| type_specifier identifier -> basic
|
||||
| "void" -> void
|
||||
|
||||
value : decimal_constant
|
||||
| hexadecimal_constant
|
||||
| octal_constant
|
||||
| identifier
|
||||
|
||||
constant : decimal_constant | hexadecimal_constant | octal_constant
|
||||
|
||||
type_specifier : unsigned_hyper
|
||||
| unsigned_long
|
||||
| unsigned_int
|
||||
| hyper
|
||||
| long
|
||||
| int
|
||||
| float
|
||||
| double
|
||||
| quadruple
|
||||
| bool
|
||||
| enum_type_spec
|
||||
| struct_type_spec
|
||||
| union_type_spec
|
||||
| identifier
|
||||
|
||||
unsigned_hyper : "unsigned" "hyper"
|
||||
unsigned_long : "unsigned" "long"
|
||||
unsigned_int : "unsigned" "int"
|
||||
hyper : "hyper"
|
||||
long : "long"
|
||||
int : "int"
|
||||
float : "float"
|
||||
double : "double"
|
||||
quadruple : "quadruple"
|
||||
bool : "bool"
|
||||
|
||||
enum_type_spec : "enum" enum_body
|
||||
|
||||
enum_body : "{" ( identifier "=" value ) ( "," identifier "=" value )* "}"
|
||||
|
||||
struct_type_spec : "struct" struct_body
|
||||
|
||||
struct_body : "{" ( declaration ";" )+ "}"
|
||||
|
||||
union_type_spec : "union" union_body
|
||||
|
||||
union_body : switch_spec "{" case_spec+ [ default_spec ] "}"
|
||||
|
||||
switch_spec : "switch" "(" declaration ")"
|
||||
|
||||
case_spec : ( "case" value ":" )+ declaration ";"
|
||||
|
||||
default_spec : "default" ":" declaration ";"
|
||||
|
||||
constant_def : "const" identifier "=" value ";"
|
||||
|
||||
type_def : "typedef" declaration ";" -> typedef
|
||||
| "enum" identifier enum_body ";" -> enum
|
||||
| "struct" identifier struct_body ";" -> struct
|
||||
| "union" identifier union_body ";" -> union
|
||||
|
||||
specification : definition*
|
||||
|
||||
definition : constant_def
|
||||
| type_def
|
||||
| program_def
|
||||
| pragma_def
|
||||
|
||||
//
|
||||
// RPC program definitions not specified in RFC 4506
|
||||
//
|
||||
|
||||
program_def : "program" identifier "{" version_def+ "}" "=" constant ";"
|
||||
|
||||
version_def : "version" identifier "{" procedure_def+ "}" "=" constant ";"
|
||||
|
||||
procedure_def : type_specifier identifier "(" type_specifier ")" "=" constant ";"
|
||||
|
||||
pragma_def : "pragma" directive identifier [ identifier ] ";"
|
||||
|
||||
directive : exclude_directive
|
||||
| header_directive
|
||||
| pages_directive
|
||||
| public_directive
|
||||
| skip_directive
|
||||
|
||||
exclude_directive : "exclude"
|
||||
header_directive : "header"
|
||||
pages_directive : "pages"
|
||||
public_directive : "public"
|
||||
skip_directive : "skip"
|
||||
|
||||
//
|
||||
// XDR language primitives
|
||||
//
|
||||
|
||||
identifier : /([a-z]|[A-Z])(_|[a-z]|[A-Z]|[0-9])*/
|
||||
|
||||
decimal_constant : /[\+-]?(0|[1-9][0-9]*)/
|
||||
hexadecimal_constant : /0x([a-f]|[A-F]|[0-9])+/
|
||||
octal_constant : /0[0-7]+/
|
||||
|
||||
PASSTHRU : "%" | "%" /.+/
|
||||
%ignore PASSTHRU
|
||||
|
||||
%import common.C_COMMENT
|
||||
%ignore C_COMMENT
|
||||
|
||||
%import common.WS
|
||||
%ignore WS
|
2
tools/net/sunrpc/xdrgen/subcmds/__init__.py
Normal file
2
tools/net/sunrpc/xdrgen/subcmds/__init__.py
Normal file
@ -0,0 +1,2 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Just to make sphinx-apidoc document this directory
|
76
tools/net/sunrpc/xdrgen/subcmds/declarations.py
Normal file
76
tools/net/sunrpc/xdrgen/subcmds/declarations.py
Normal file
@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env python3
|
||||
# ex: set filetype=python:
|
||||
|
||||
"""Translate an XDR specification into executable code that
|
||||
can be compiled for the Linux kernel."""
|
||||
|
||||
import logging
|
||||
|
||||
from argparse import Namespace
|
||||
from lark import logger
|
||||
from lark.exceptions import UnexpectedInput
|
||||
|
||||
from generators.constant import XdrConstantGenerator
|
||||
from generators.enum import XdrEnumGenerator
|
||||
from generators.header_bottom import XdrHeaderBottomGenerator
|
||||
from generators.header_top import XdrHeaderTopGenerator
|
||||
from generators.pointer import XdrPointerGenerator
|
||||
from generators.program import XdrProgramGenerator
|
||||
from generators.typedef import XdrTypedefGenerator
|
||||
from generators.struct import XdrStructGenerator
|
||||
from generators.union import XdrUnionGenerator
|
||||
|
||||
from xdr_ast import transform_parse_tree, _RpcProgram, Specification
|
||||
from xdr_ast import _XdrConstant, _XdrEnum, _XdrPointer
|
||||
from xdr_ast import _XdrTypedef, _XdrStruct, _XdrUnion
|
||||
from xdr_parse import xdr_parser, set_xdr_annotate
|
||||
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
|
||||
def emit_header_declarations(
|
||||
root: Specification, language: str, peer: str
|
||||
) -> None:
|
||||
"""Emit header declarations"""
|
||||
for definition in root.definitions:
|
||||
if isinstance(definition.value, _XdrEnum):
|
||||
gen = XdrEnumGenerator(language, peer)
|
||||
elif isinstance(definition.value, _XdrPointer):
|
||||
gen = XdrPointerGenerator(language, peer)
|
||||
elif isinstance(definition.value, _XdrTypedef):
|
||||
gen = XdrTypedefGenerator(language, peer)
|
||||
elif isinstance(definition.value, _XdrStruct):
|
||||
gen = XdrStructGenerator(language, peer)
|
||||
elif isinstance(definition.value, _XdrUnion):
|
||||
gen = XdrUnionGenerator(language, peer)
|
||||
elif isinstance(definition.value, _RpcProgram):
|
||||
gen = XdrProgramGenerator(language, peer)
|
||||
else:
|
||||
continue
|
||||
gen.emit_declaration(definition.value)
|
||||
|
||||
|
||||
def handle_parse_error(e: UnexpectedInput) -> bool:
|
||||
"""Simple parse error reporting, no recovery attempted"""
|
||||
print(e)
|
||||
return True
|
||||
|
||||
|
||||
def subcmd(args: Namespace) -> int:
|
||||
"""Generate definitions and declarations"""
|
||||
|
||||
set_xdr_annotate(args.annotate)
|
||||
parser = xdr_parser()
|
||||
with open(args.filename, encoding="utf-8") as f:
|
||||
parse_tree = parser.parse(f.read(), on_error=handle_parse_error)
|
||||
ast = transform_parse_tree(parse_tree)
|
||||
|
||||
gen = XdrHeaderTopGenerator(args.language, args.peer)
|
||||
gen.emit_declaration(args.filename, ast)
|
||||
|
||||
emit_header_declarations(ast, args.language, args.peer)
|
||||
|
||||
gen = XdrHeaderBottomGenerator(args.language, args.peer)
|
||||
gen.emit_declaration(args.filename, ast)
|
||||
|
||||
return 0
|
78
tools/net/sunrpc/xdrgen/subcmds/definitions.py
Normal file
78
tools/net/sunrpc/xdrgen/subcmds/definitions.py
Normal file
@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env python3
|
||||
# ex: set filetype=python:
|
||||
|
||||
"""Translate an XDR specification into executable code that
|
||||
can be compiled for the Linux kernel."""
|
||||
|
||||
import logging
|
||||
|
||||
from argparse import Namespace
|
||||
from lark import logger
|
||||
from lark.exceptions import UnexpectedInput
|
||||
|
||||
from generators.constant import XdrConstantGenerator
|
||||
from generators.enum import XdrEnumGenerator
|
||||
from generators.header_bottom import XdrHeaderBottomGenerator
|
||||
from generators.header_top import XdrHeaderTopGenerator
|
||||
from generators.pointer import XdrPointerGenerator
|
||||
from generators.program import XdrProgramGenerator
|
||||
from generators.typedef import XdrTypedefGenerator
|
||||
from generators.struct import XdrStructGenerator
|
||||
from generators.union import XdrUnionGenerator
|
||||
|
||||
from xdr_ast import transform_parse_tree, Specification
|
||||
from xdr_ast import _RpcProgram, _XdrConstant, _XdrEnum, _XdrPointer
|
||||
from xdr_ast import _XdrTypedef, _XdrStruct, _XdrUnion
|
||||
from xdr_parse import xdr_parser, set_xdr_annotate
|
||||
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
|
||||
def emit_header_definitions(
|
||||
root: Specification, language: str, peer: str
|
||||
) -> None:
|
||||
"""Emit header definitions"""
|
||||
for definition in root.definitions:
|
||||
if isinstance(definition.value, _XdrConstant):
|
||||
gen = XdrConstantGenerator(language, peer)
|
||||
elif isinstance(definition.value, _XdrEnum):
|
||||
gen = XdrEnumGenerator(language, peer)
|
||||
elif isinstance(definition.value, _XdrPointer):
|
||||
gen = XdrPointerGenerator(language, peer)
|
||||
elif isinstance(definition.value, _RpcProgram):
|
||||
gen = XdrProgramGenerator(language, peer)
|
||||
elif isinstance(definition.value, _XdrTypedef):
|
||||
gen = XdrTypedefGenerator(language, peer)
|
||||
elif isinstance(definition.value, _XdrStruct):
|
||||
gen = XdrStructGenerator(language, peer)
|
||||
elif isinstance(definition.value, _XdrUnion):
|
||||
gen = XdrUnionGenerator(language, peer)
|
||||
else:
|
||||
continue
|
||||
gen.emit_definition(definition.value)
|
||||
|
||||
|
||||
def handle_parse_error(e: UnexpectedInput) -> bool:
|
||||
"""Simple parse error reporting, no recovery attempted"""
|
||||
print(e)
|
||||
return True
|
||||
|
||||
|
||||
def subcmd(args: Namespace) -> int:
|
||||
"""Generate definitions"""
|
||||
|
||||
set_xdr_annotate(args.annotate)
|
||||
parser = xdr_parser()
|
||||
with open(args.filename, encoding="utf-8") as f:
|
||||
parse_tree = parser.parse(f.read(), on_error=handle_parse_error)
|
||||
ast = transform_parse_tree(parse_tree)
|
||||
|
||||
gen = XdrHeaderTopGenerator(args.language, args.peer)
|
||||
gen.emit_definition(args.filename, ast)
|
||||
|
||||
emit_header_definitions(ast, args.language, args.peer)
|
||||
|
||||
gen = XdrHeaderBottomGenerator(args.language, args.peer)
|
||||
gen.emit_definition(args.filename, ast)
|
||||
|
||||
return 0
|
33
tools/net/sunrpc/xdrgen/subcmds/lint.py
Normal file
33
tools/net/sunrpc/xdrgen/subcmds/lint.py
Normal file
@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env python3
|
||||
# ex: set filetype=python:
|
||||
|
||||
"""Translate an XDR specification into executable code that
|
||||
can be compiled for the Linux kernel."""
|
||||
|
||||
import logging
|
||||
|
||||
from argparse import Namespace
|
||||
from lark import logger
|
||||
from lark.exceptions import UnexpectedInput
|
||||
|
||||
from xdr_parse import xdr_parser
|
||||
from xdr_ast import transform_parse_tree
|
||||
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
|
||||
def handle_parse_error(e: UnexpectedInput) -> bool:
|
||||
"""Simple parse error reporting, no recovery attempted"""
|
||||
print(e)
|
||||
return True
|
||||
|
||||
|
||||
def subcmd(args: Namespace) -> int:
|
||||
"""Lexical and syntax check of an XDR specification"""
|
||||
|
||||
parser = xdr_parser()
|
||||
with open(args.filename, encoding="utf-8") as f:
|
||||
parse_tree = parser.parse(f.read(), on_error=handle_parse_error)
|
||||
transform_parse_tree(parse_tree)
|
||||
|
||||
return 0
|
118
tools/net/sunrpc/xdrgen/subcmds/source.py
Normal file
118
tools/net/sunrpc/xdrgen/subcmds/source.py
Normal file
@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env python3
|
||||
# ex: set filetype=python:
|
||||
|
||||
"""Translate an XDR specification into executable code that
|
||||
can be compiled for the Linux kernel."""
|
||||
|
||||
import logging
|
||||
|
||||
from argparse import Namespace
|
||||
from lark import logger
|
||||
from lark.exceptions import UnexpectedInput
|
||||
|
||||
from generators.source_top import XdrSourceTopGenerator
|
||||
from generators.enum import XdrEnumGenerator
|
||||
from generators.pointer import XdrPointerGenerator
|
||||
from generators.program import XdrProgramGenerator
|
||||
from generators.typedef import XdrTypedefGenerator
|
||||
from generators.struct import XdrStructGenerator
|
||||
from generators.union import XdrUnionGenerator
|
||||
|
||||
from xdr_ast import transform_parse_tree, _RpcProgram, Specification
|
||||
from xdr_ast import _XdrAst, _XdrEnum, _XdrPointer
|
||||
from xdr_ast import _XdrStruct, _XdrTypedef, _XdrUnion
|
||||
|
||||
from xdr_parse import xdr_parser, set_xdr_annotate
|
||||
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
|
||||
def emit_source_decoder(node: _XdrAst, language: str, peer: str) -> None:
|
||||
"""Emit one XDR decoder function for a source file"""
|
||||
if isinstance(node, _XdrEnum):
|
||||
gen = XdrEnumGenerator(language, peer)
|
||||
elif isinstance(node, _XdrPointer):
|
||||
gen = XdrPointerGenerator(language, peer)
|
||||
elif isinstance(node, _XdrTypedef):
|
||||
gen = XdrTypedefGenerator(language, peer)
|
||||
elif isinstance(node, _XdrStruct):
|
||||
gen = XdrStructGenerator(language, peer)
|
||||
elif isinstance(node, _XdrUnion):
|
||||
gen = XdrUnionGenerator(language, peer)
|
||||
elif isinstance(node, _RpcProgram):
|
||||
gen = XdrProgramGenerator(language, peer)
|
||||
else:
|
||||
return
|
||||
gen.emit_decoder(node)
|
||||
|
||||
|
||||
def emit_source_encoder(node: _XdrAst, language: str, peer: str) -> None:
|
||||
"""Emit one XDR encoder function for a source file"""
|
||||
if isinstance(node, _XdrEnum):
|
||||
gen = XdrEnumGenerator(language, peer)
|
||||
elif isinstance(node, _XdrPointer):
|
||||
gen = XdrPointerGenerator(language, peer)
|
||||
elif isinstance(node, _XdrTypedef):
|
||||
gen = XdrTypedefGenerator(language, peer)
|
||||
elif isinstance(node, _XdrStruct):
|
||||
gen = XdrStructGenerator(language, peer)
|
||||
elif isinstance(node, _XdrUnion):
|
||||
gen = XdrUnionGenerator(language, peer)
|
||||
elif isinstance(node, _RpcProgram):
|
||||
gen = XdrProgramGenerator(language, peer)
|
||||
else:
|
||||
return
|
||||
gen.emit_encoder(node)
|
||||
|
||||
|
||||
def generate_server_source(filename: str, root: Specification, language: str) -> None:
|
||||
"""Generate server-side source code"""
|
||||
|
||||
gen = XdrSourceTopGenerator(language, "server")
|
||||
gen.emit_source(filename, root)
|
||||
|
||||
for definition in root.definitions:
|
||||
emit_source_decoder(definition.value, language, "server")
|
||||
for definition in root.definitions:
|
||||
emit_source_encoder(definition.value, language, "server")
|
||||
|
||||
|
||||
def generate_client_source(filename: str, root: Specification, language: str) -> None:
|
||||
"""Generate server-side source code"""
|
||||
|
||||
gen = XdrSourceTopGenerator(language, "client")
|
||||
gen.emit_source(filename, root)
|
||||
|
||||
# cel: todo: client needs XDR size macros
|
||||
|
||||
for definition in root.definitions:
|
||||
emit_source_encoder(definition.value, language, "client")
|
||||
for definition in root.definitions:
|
||||
emit_source_decoder(definition.value, language, "client")
|
||||
|
||||
# cel: todo: client needs PROC macros
|
||||
|
||||
|
||||
def handle_parse_error(e: UnexpectedInput) -> bool:
|
||||
"""Simple parse error reporting, no recovery attempted"""
|
||||
print(e)
|
||||
return True
|
||||
|
||||
|
||||
def subcmd(args: Namespace) -> int:
|
||||
"""Generate encoder and decoder functions"""
|
||||
|
||||
set_xdr_annotate(args.annotate)
|
||||
parser = xdr_parser()
|
||||
with open(args.filename, encoding="utf-8") as f:
|
||||
parse_tree = parser.parse(f.read(), on_error=handle_parse_error)
|
||||
ast = transform_parse_tree(parse_tree)
|
||||
match args.peer:
|
||||
case "server":
|
||||
generate_server_source(args.filename, ast, args.language)
|
||||
case "client":
|
||||
generate_client_source(args.filename, ast, args.language)
|
||||
case _:
|
||||
print("Code generation for", args.peer, "is not yet supported")
|
||||
|
||||
return 0
|
@ -0,0 +1,3 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
|
||||
enum { {{ name }} = {{ value }} };
|
@ -0,0 +1,4 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
|
||||
bool xdrgen_decode_{{ name }}(struct xdr_stream *xdr, enum {{ name }} *ptr);
|
||||
bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr, enum {{ name }} value);
|
19
tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum.j2
Normal file
19
tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum.j2
Normal file
@ -0,0 +1,19 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
|
||||
{% if annotate %}
|
||||
/* enum {{ name }} */
|
||||
{% endif %}
|
||||
{% if name in public_apis %}
|
||||
bool
|
||||
{% else %}
|
||||
static bool __maybe_unused
|
||||
{% endif %}
|
||||
xdrgen_decode_{{ name }}(struct xdr_stream *xdr, enum {{ name }} *ptr)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (xdr_stream_decode_u32(xdr, &val) < 0)
|
||||
return false;
|
||||
*ptr = val;
|
||||
return true;
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
};
|
@ -0,0 +1,2 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{{ name }} = {{ value }},
|
@ -0,0 +1,3 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
|
||||
enum {{ name }} {
|
14
tools/net/sunrpc/xdrgen/templates/C/enum/encoder/enum.j2
Normal file
14
tools/net/sunrpc/xdrgen/templates/C/enum/encoder/enum.j2
Normal file
@ -0,0 +1,14 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
|
||||
{% if annotate %}
|
||||
/* enum {{ name }} */
|
||||
{% endif %}
|
||||
{% if name in public_apis %}
|
||||
bool
|
||||
{% else %}
|
||||
static bool __maybe_unused
|
||||
{% endif %}
|
||||
xdrgen_encode_{{ name }}(struct xdr_stream *xdr, enum {{ name }} value)
|
||||
{
|
||||
return xdr_stream_encode_u32(xdr, value) == XDR_UNIT;
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
|
||||
#endif /* _LINUX_XDRGEN_{{ infix }}_DECL_H */
|
@ -0,0 +1,3 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
|
||||
#endif /* _LINUX_XDRGEN_{{ infix }}_DEF_H */
|
@ -0,0 +1,14 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Generated by xdrgen. Manual edits will be lost. */
|
||||
/* XDR specification file: {{ filename }} */
|
||||
/* XDR specification modification time: {{ mtime }} */
|
||||
|
||||
#ifndef _LINUX_XDRGEN_{{ infix }}_DECL_H
|
||||
#define _LINUX_XDRGEN_{{ infix }}_DECL_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <linux/sunrpc/xdr.h>
|
||||
#include <linux/sunrpc/xdrgen/_defs.h>
|
||||
#include <linux/sunrpc/xdrgen/_builtins.h>
|
||||
#include <linux/sunrpc/xdrgen/{{ infix.lower() }}.h>
|
@ -0,0 +1,10 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Generated by xdrgen. Manual edits will be lost. */
|
||||
/* XDR specification file: {{ filename }} */
|
||||
/* XDR specification modification time: {{ mtime }} */
|
||||
|
||||
#ifndef _LINUX_XDRGEN_{{ infix }}_DEF_H
|
||||
#define _LINUX_XDRGEN_{{ infix }}_DEF_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/sunrpc/xdrgen/_defs.h>
|
@ -0,0 +1,4 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
|
||||
bool xdrgen_decode_{{ name }}(struct xdr_stream *xdr, struct {{ name }} *ptr);
|
||||
bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const struct {{ name }} *value);
|
@ -0,0 +1,6 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (basic) */
|
||||
{% endif %}
|
||||
if (!xdrgen_decode_{{ type }}(xdr, &ptr->{{ name }}))
|
||||
return false;
|
@ -0,0 +1,3 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
return true;
|
||||
};
|
@ -0,0 +1,8 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (fixed-length array) */
|
||||
{% endif %}
|
||||
for (u32 i = 0; i < {{ size }}; i++) {
|
||||
if (xdrgen_decode_{{ type }}(xdr, &ptr->{{ name }}.items[i]) < 0)
|
||||
return false;
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (fixed-length opaque) */
|
||||
{% endif %}
|
||||
if (xdr_stream_decode_opaque_fixed(xdr, ptr->{{ name }}, {{ size }}) < 0)
|
||||
return false;
|
22
tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/open.j2
Normal file
22
tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/open.j2
Normal file
@ -0,0 +1,22 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
|
||||
{% if annotate %}
|
||||
/* pointer {{ name }} */
|
||||
{% endif %}
|
||||
{% if name in public_apis %}
|
||||
bool
|
||||
{% else %}
|
||||
static bool __maybe_unused
|
||||
{% endif %}
|
||||
xdrgen_decode_{{ name }}(struct xdr_stream *xdr, struct {{ name }} *ptr)
|
||||
{
|
||||
bool opted;
|
||||
|
||||
{% if annotate %}
|
||||
/* opted */
|
||||
{% endif %}
|
||||
if (!xdrgen_decode_bool(xdr, &opted))
|
||||
return false;
|
||||
if (!opted)
|
||||
return true;
|
||||
|
@ -0,0 +1,6 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (optional data) */
|
||||
{% endif %}
|
||||
if (!xdrgen_decode_{{ type }}(xdr, ptr->{{ name }}))
|
||||
return false;
|
@ -0,0 +1,13 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (variable-length array) */
|
||||
{% endif %}
|
||||
if (xdr_stream_decode_u32(xdr, &ptr->{{ name }}.count) != XDR_UNIT)
|
||||
return false;
|
||||
{% if maxsize != "0" %}
|
||||
if (ptr->{{ name }}.count > {{ maxsize }})
|
||||
return false;
|
||||
{% endif %}
|
||||
for (u32 i = 0; i < ptr->{{ name }}.count; i++)
|
||||
if (!xdrgen_decode_{{ type }}(xdr, &ptr->{{ name }}.element[i]))
|
||||
return false;
|
@ -0,0 +1,6 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (variable-length opaque) */
|
||||
{% endif %}
|
||||
if (!xdrgen_decode_opaque(xdr, (opaque *)ptr, {{ maxsize }}))
|
||||
return false;
|
@ -0,0 +1,6 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (variable-length string) */
|
||||
{% endif %}
|
||||
if (!xdrgen_decode_string(xdr, (string *)ptr, {{ maxsize }}))
|
||||
return false;
|
@ -0,0 +1,5 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* (basic) */
|
||||
{% endif %}
|
||||
{{ classifier }}{{ type }} {{ name }};
|
@ -0,0 +1,2 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
};
|
@ -0,0 +1,5 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* (fixed-length array) */
|
||||
{% endif %}
|
||||
{{ type }} {{ name }}[{{ size }}];
|
@ -0,0 +1,5 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* (fixed-length opaque) */
|
||||
{% endif %}
|
||||
u8 {{ name }}[{{ size }}];
|
@ -0,0 +1,6 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
|
||||
{% if annotate %}
|
||||
/* pointer {{ name }} */
|
||||
{% endif %}
|
||||
struct {{ name }} {
|
@ -0,0 +1,5 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* (optional data) */
|
||||
{% endif %}
|
||||
{{ classifier }}{{ type }} *{{ name }};
|
@ -0,0 +1,8 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* (variable-length array) */
|
||||
{% endif %}
|
||||
struct {
|
||||
u32 count;
|
||||
{{ classifier }}{{ type }} *element;
|
||||
} {{ name }};
|
@ -0,0 +1,5 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* (variable-length opaque) */
|
||||
{% endif %}
|
||||
opaque {{ name }};
|
@ -0,0 +1,5 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* (variable-length string) */
|
||||
{% endif %}
|
||||
string {{ name }};
|
10
tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/basic.j2
Normal file
10
tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/basic.j2
Normal file
@ -0,0 +1,10 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (basic) */
|
||||
{% endif %}
|
||||
{% if type in pass_by_reference %}
|
||||
if (!xdrgen_encode_{{ type }}(xdr, &value->{{ name }}))
|
||||
{% else %}
|
||||
if (!xdrgen_encode_{{ type }}(xdr, value->{{ name }}))
|
||||
{% endif %}
|
||||
return false;
|
@ -0,0 +1,3 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
return true;
|
||||
};
|
@ -0,0 +1,12 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (fixed-length array) */
|
||||
{% endif %}
|
||||
for (u32 i = 0; i < {{ size }}; i++) {
|
||||
{% if type in pass_by_reference %}
|
||||
if (xdrgen_encode_{{ type }}(xdr, &value->items[i]) < 0)
|
||||
{% else %}
|
||||
if (xdrgen_encode_{{ type }}(xdr, value->items[i]) < 0)
|
||||
{% endif %}
|
||||
return false;
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (fixed-length opaque) */
|
||||
{% endif %}
|
||||
if (xdr_stream_encode_opaque_fixed(xdr, value->{{ name }}, {{ size }}) < 0)
|
||||
return false;
|
20
tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/open.j2
Normal file
20
tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/open.j2
Normal file
@ -0,0 +1,20 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
|
||||
{% if annotate %}
|
||||
/* pointer {{ name }} */
|
||||
{% endif %}
|
||||
{% if name in public_apis %}
|
||||
bool
|
||||
{% else %}
|
||||
static bool __maybe_unused
|
||||
{% endif %}
|
||||
xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const struct {{ name }} *value)
|
||||
{
|
||||
{% if annotate %}
|
||||
/* opted */
|
||||
{% endif %}
|
||||
if (!xdrgen_encode_bool(xdr, value != NULL))
|
||||
return false;
|
||||
if (!value)
|
||||
return true;
|
||||
|
@ -0,0 +1,6 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (optional data) */
|
||||
{% endif %}
|
||||
if (!xdrgen_encode_{{ type }}(xdr, value->{{ name }}))
|
||||
return false;
|
@ -0,0 +1,15 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (variable-length array) */
|
||||
{% endif %}
|
||||
if (value->{{ name }}.count > {{ maxsize }})
|
||||
return false;
|
||||
if (xdr_stream_encode_u32(xdr, value->{{ name }}.count) != XDR_UNIT)
|
||||
return false;
|
||||
for (u32 i = 0; i < value->{{ name }}.count; i++)
|
||||
{% if type in pass_by_reference %}
|
||||
if (!xdrgen_encode_{{ type }}(xdr, &value->{{ name }}.element[i]))
|
||||
{% else %}
|
||||
if (!xdrgen_encode_{{ type }}(xdr, value->{{ name }}.element[i]))
|
||||
{% endif %}
|
||||
return false;
|
@ -0,0 +1,8 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (variable-length opaque) */
|
||||
{% endif %}
|
||||
if (value->{{ name }}.len > {{ maxsize }})
|
||||
return false;
|
||||
if (xdr_stream_encode_opaque(xdr, value->{{ name }}.data, value->{{ name }}.len) < 0)
|
||||
return false;
|
@ -0,0 +1,8 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (variable-length string) */
|
||||
{% endif %}
|
||||
if (value->{{ name }}.len > {{ maxsize }})
|
||||
return false;
|
||||
if (xdr_stream_encode_opaque(xdr, value->{{ name }}.data, value->{{ name }}.len) < 0)
|
||||
return false;
|
@ -0,0 +1,2 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
bool {{ program }}_svc_decode_{{ argument }}(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
@ -0,0 +1,2 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
bool {{ program }}_svc_encode_{{ result }}(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
@ -0,0 +1,21 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
|
||||
/**
|
||||
* {{ program }}_svc_decode_{{ argument }} - Decode a {{ argument }} argument
|
||||
* @rqstp: RPC transaction context
|
||||
* @xdr: source XDR data stream
|
||||
*
|
||||
* Return values:
|
||||
* %true: procedure arguments decoded successfully
|
||||
* %false: decode failed
|
||||
*/
|
||||
bool {{ program }}_svc_decode_{{ argument }}(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
{% if argument == 'void' %}
|
||||
return xdrgen_decode_void(xdr);
|
||||
{% else %}
|
||||
struct {{ argument }} *argp = rqstp->rq_argp;
|
||||
|
||||
return xdrgen_decode_{{ argument }}(xdr, argp);
|
||||
{% endif %}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
|
||||
{% if annotate %}
|
||||
/* Decode {{ result }} results */
|
||||
{% endif %}
|
||||
static int {{ program }}_xdr_dec_{{ result }}(struct rpc_rqst *req,
|
||||
struct xdr_stream *xdr, void *data)
|
||||
{
|
||||
{% if result == 'void' %}
|
||||
xdrgen_decode_void(xdr);
|
||||
{% else %}
|
||||
struct {{ result }} *result = data;
|
||||
|
||||
if (!xdrgen_decode_{{ result }}(xdr, result))
|
||||
return -EIO;
|
||||
if (result->stat != nfs_ok) {
|
||||
trace_nfs_xdr_status(xdr, (int)result->stat);
|
||||
return {{ program }}_stat_to_errno(result->stat);
|
||||
}
|
||||
{% endif %}
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
};
|
@ -0,0 +1,6 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
|
||||
{% if annotate %}
|
||||
/* procedure numbers for {{ program }} */
|
||||
{% endif %}
|
||||
enum {
|
@ -0,0 +1,2 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{{ name }} = {{ value }},
|
@ -0,0 +1,16 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
|
||||
{%if annotate %}
|
||||
/* Encode {{ argument }} arguments */
|
||||
{% endif %}
|
||||
static void {{ program }}_xdr_enc_{{ argument }}(struct rpc_rqst *req,
|
||||
struct xdr_stream *xdr, const void *data)
|
||||
{
|
||||
{% if argument == 'void' %}
|
||||
xdrgen_encode_void(xdr);
|
||||
{% else %}
|
||||
const struct {{ argument }} *args = data;
|
||||
|
||||
xdrgen_encode_{{ argument }}(xdr, args);
|
||||
{% endif %}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
|
||||
/**
|
||||
* {{ program }}_svc_encode_{{ result }} - Encode a {{ result }} result
|
||||
* @rqstp: RPC transaction context
|
||||
* @xdr: target XDR data stream
|
||||
*
|
||||
* Return values:
|
||||
* %true: procedure results encoded successfully
|
||||
* %false: encode failed
|
||||
*/
|
||||
bool {{ program }}_svc_encode_{{ result }}(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
{% if result == 'void' %}
|
||||
return xdrgen_encode_void(xdr);
|
||||
{% else %}
|
||||
struct {{ result }} *resp = rqstp->rq_resp;
|
||||
|
||||
return xdrgen_encode_{{ result }}(xdr, resp);
|
||||
{% endif %}
|
||||
}
|
8
tools/net/sunrpc/xdrgen/templates/C/source_top/client.j2
Normal file
8
tools/net/sunrpc/xdrgen/templates/C/source_top/client.j2
Normal file
@ -0,0 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Generated by xdrgen. Manual edits will be lost.
|
||||
// XDR specification file: {{ filename }}
|
||||
// XDR specification modification time: {{ mtime }}
|
||||
|
||||
#include <linux/sunrpc/xprt.h>
|
||||
|
||||
#include "{{ program }}xdr_gen.h"
|
8
tools/net/sunrpc/xdrgen/templates/C/source_top/server.j2
Normal file
8
tools/net/sunrpc/xdrgen/templates/C/source_top/server.j2
Normal file
@ -0,0 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Generated by xdrgen. Manual edits will be lost.
|
||||
// XDR specification file: {{ filename }}
|
||||
// XDR specification modification time: {{ mtime }}
|
||||
|
||||
#include <linux/sunrpc/svc.h>
|
||||
|
||||
#include "{{ program }}xdr_gen.h"
|
@ -0,0 +1,4 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
|
||||
bool xdrgen_decode_{{ name }}(struct xdr_stream *xdr, struct {{ name }} *ptr);
|
||||
bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const struct {{ name }} *value);
|
@ -0,0 +1,6 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (basic) */
|
||||
{% endif %}
|
||||
if (!xdrgen_decode_{{ type }}(xdr, &ptr->{{ name }}))
|
||||
return false;
|
@ -0,0 +1,3 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
return true;
|
||||
};
|
@ -0,0 +1,8 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (fixed-length array) */
|
||||
{% endif %}
|
||||
for (u32 i = 0; i < {{ size }}; i++) {
|
||||
if (xdrgen_decode_{{ type }}(xdr, &ptr->{{ name }}.items[i]) < 0)
|
||||
return false;
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (fixed-length opaque) */
|
||||
{% endif %}
|
||||
if (xdr_stream_decode_opaque_fixed(xdr, ptr->{{ name }}, {{ size }}) < 0)
|
||||
return false;
|
12
tools/net/sunrpc/xdrgen/templates/C/struct/decoder/open.j2
Normal file
12
tools/net/sunrpc/xdrgen/templates/C/struct/decoder/open.j2
Normal file
@ -0,0 +1,12 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
|
||||
{% if annotate %}
|
||||
/* struct {{ name }} */
|
||||
{% endif %}
|
||||
{% if name in public_apis %}
|
||||
bool
|
||||
{% else %}
|
||||
static bool __maybe_unused
|
||||
{% endif %}
|
||||
xdrgen_decode_{{ name }}(struct xdr_stream *xdr, struct {{ name }} *ptr)
|
||||
{
|
@ -0,0 +1,6 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (optional data) */
|
||||
{% endif %}
|
||||
if (!xdrgen_decode_{{ type }}(xdr, ptr->{{ name }}))
|
||||
return false;
|
@ -0,0 +1,13 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (variable-length array) */
|
||||
{% endif %}
|
||||
if (xdr_stream_decode_u32(xdr, &ptr->{{ name }}.count) != XDR_UNIT)
|
||||
return false;
|
||||
{% if maxsize != "0" %}
|
||||
if (ptr->{{ name }}.count > {{ maxsize }})
|
||||
return false;
|
||||
{% endif %}
|
||||
for (u32 i = 0; i < ptr->{{ name }}.count; i++)
|
||||
if (!xdrgen_decode_{{ type }}(xdr, &ptr->{{ name }}.element[i]))
|
||||
return false;
|
@ -0,0 +1,6 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (variable-length opaque) */
|
||||
{% endif %}
|
||||
if (!xdrgen_decode_opaque(xdr, (opaque *)ptr, {{ maxsize }}))
|
||||
return false;
|
@ -0,0 +1,6 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (variable-length string) */
|
||||
{% endif %}
|
||||
if (!xdrgen_decode_string(xdr, (string *)ptr, {{ maxsize }}))
|
||||
return false;
|
@ -0,0 +1,5 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* (basic) */
|
||||
{% endif %}
|
||||
{{ classifier }}{{ type }} {{ name }};
|
@ -0,0 +1,2 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
};
|
@ -0,0 +1,5 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* (fixed-length array) */
|
||||
{% endif %}
|
||||
{{ type }} {{ name }}[{{ size }}];
|
@ -0,0 +1,5 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* (fixed-length opaque) */
|
||||
{% endif %}
|
||||
u8 {{ name }}[{{ size }}];
|
@ -0,0 +1,6 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
|
||||
{% if annotate %}
|
||||
/* struct {{ name }} */
|
||||
{% endif %}
|
||||
struct {{ name }} {
|
@ -0,0 +1,5 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* (optional data) */
|
||||
{% endif %}
|
||||
{{ classifier }}{{ type }} *{{ name }};
|
@ -0,0 +1,8 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* (variable-length array) */
|
||||
{% endif %}
|
||||
struct {
|
||||
u32 count;
|
||||
{{ classifier }}{{ type }} *element;
|
||||
} {{ name }};
|
@ -0,0 +1,5 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* (variable-length opaque) */
|
||||
{% endif %}
|
||||
opaque {{ name }};
|
@ -0,0 +1,5 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* (variable-length string) */
|
||||
{% endif %}
|
||||
string {{ name }};
|
10
tools/net/sunrpc/xdrgen/templates/C/struct/encoder/basic.j2
Normal file
10
tools/net/sunrpc/xdrgen/templates/C/struct/encoder/basic.j2
Normal file
@ -0,0 +1,10 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (basic) */
|
||||
{% endif %}
|
||||
{% if type in pass_by_reference %}
|
||||
if (!xdrgen_encode_{{ type }}(xdr, &value->{{ name }}))
|
||||
{% else %}
|
||||
if (!xdrgen_encode_{{ type }}(xdr, value->{{ name }}))
|
||||
{% endif %}
|
||||
return false;
|
@ -0,0 +1,3 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
return true;
|
||||
};
|
@ -0,0 +1,12 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (fixed-length array) */
|
||||
{% endif %}
|
||||
for (u32 i = 0; i < {{ size }}; i++) {
|
||||
{% if type in pass_by_reference %}
|
||||
if (xdrgen_encode_{{ type }}(xdr, &value->items[i]) < 0)
|
||||
{% else %}
|
||||
if (xdrgen_encode_{{ type }}(xdr, value->items[i]) < 0)
|
||||
{% endif %}
|
||||
return false;
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (fixed-length opaque) */
|
||||
{% endif %}
|
||||
if (xdr_stream_encode_opaque_fixed(xdr, value->{{ name }}, {{ size }}) < 0)
|
||||
return false;
|
12
tools/net/sunrpc/xdrgen/templates/C/struct/encoder/open.j2
Normal file
12
tools/net/sunrpc/xdrgen/templates/C/struct/encoder/open.j2
Normal file
@ -0,0 +1,12 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
|
||||
{% if annotate %}
|
||||
/* struct {{ name }} */
|
||||
{% endif %}
|
||||
{% if name in public_apis %}
|
||||
bool
|
||||
{% else %}
|
||||
static bool __maybe_unused
|
||||
{% endif %}
|
||||
xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const struct {{ name }} *value)
|
||||
{
|
@ -0,0 +1,6 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (optional data) */
|
||||
{% endif %}
|
||||
if (!xdrgen_encode_{{ type }}(xdr, value->{{ name }}))
|
||||
return false;
|
@ -0,0 +1,15 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (variable-length array) */
|
||||
{% endif %}
|
||||
if (value->{{ name }}.count > {{ maxsize }})
|
||||
return false;
|
||||
if (xdr_stream_encode_u32(xdr, value->{{ name }}.count) != XDR_UNIT)
|
||||
return false;
|
||||
for (u32 i = 0; i < value->{{ name }}.count; i++)
|
||||
{% if type in pass_by_reference %}
|
||||
if (!xdrgen_encode_{{ type }}(xdr, &value->{{ name }}.element[i]))
|
||||
{% else %}
|
||||
if (!xdrgen_encode_{{ type }}(xdr, value->{{ name }}.element[i]))
|
||||
{% endif %}
|
||||
return false;
|
@ -0,0 +1,8 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (variable-length opaque) */
|
||||
{% endif %}
|
||||
if (value->{{ name }}.len > {{ maxsize }})
|
||||
return false;
|
||||
if (xdr_stream_encode_opaque(xdr, value->{{ name }}.data, value->{{ name }}.len) < 0)
|
||||
return false;
|
@ -0,0 +1,8 @@
|
||||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
{% if annotate %}
|
||||
/* member {{ name }} (variable-length string) */
|
||||
{% endif %}
|
||||
if (value->{{ name }}.len > {{ maxsize }})
|
||||
return false;
|
||||
if (xdr_stream_encode_opaque(xdr, value->{{ name }}.data, value->{{ name }}.len) < 0)
|
||||
return false;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user