From 81fc9d083367ace55cbeff15db937f4de6f69dfb Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 9 Oct 2019 16:41:01 +0100 Subject: [PATCH] Implement rxgen Implement the rxgen program to process .xg interface files into C definitions. Signed-off-by: David Howells --- .gitignore | 3 + lib/Makefile | 15 +- rxgen/Makefile | 3 + rxgen/emit_c_struct.py | 366 +++++++++++++++ rxgen/emit_c_sync_funcs.py | 656 +++++++++++++++++++++++++++ rxgen/rxgen.py | 905 +++++++++++++++++++++++++++++++++++++ rxgen/rxgen_bits.py | 603 ++++++++++++++++++++++++ 7 files changed, 2549 insertions(+), 2 deletions(-) create mode 100644 rxgen/Makefile create mode 100644 rxgen/emit_c_struct.py create mode 100644 rxgen/emit_c_sync_funcs.py create mode 100755 rxgen/rxgen.py create mode 100644 rxgen/rxgen_bits.py diff --git a/.gitignore b/.gitignore index bda4893..0b36bab 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,6 @@ .*.o.d *.so lib/libkafs_utils.* +lib/afs_xg.* +rxgen/__pycache__/ +rxgen/parsetab.py diff --git a/lib/Makefile b/lib/Makefile index 6e81c71..8228645 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,6 +1,12 @@ CFLAGS := -g -Wall -Wformat -fpic -O2 -Wno-pointer-arith -LIB_SRCS := rxrpc_xdr.C af_rxrpc.C rxrpc_core.C +RXGEN := ../rxgen/rxgen.py +RPC_HEADERS := $(wildcard ../rpc-api/*.h) +RPC_DEFS := $(filter-out %test.xg, $(sort $(wildcard ../rpc-api/*.xg))) +#RPC_HEADERS := ../rpc-api/test.h +#RPC_DEFS := ../rpc-api/test.xg + +LIB_SRCS := afs_xg.C rxrpc_xdr.C af_rxrpc.C rxrpc_core.C LIB_OBJS := $(patsubst %.C,%.o,$(LIB_SRCS)) %.o: %.C @@ -11,10 +17,15 @@ all: libkafs_utils.a libkafs_utils.a: $(LIB_OBJS) $(AR) rcs -o $@ $(LIB_OBJS) +afs_xg.o: afs_xg.C afs_xg.H rxrpc.H + +afs_xg.C afs_xg.H: $(RPC_HEADERS) $(RPC_DEFS) $(wildcard ../rxgen/*.py) Makefile + $(RXGEN) $(RPC_HEADERS) $(RPC_DEFS) + DEPS := $(wildcard .*.o.d) ifneq ($(DEPS),) include $(DEPS) endif clean: - $(RM) *~ *.o *.so *.a $(DEPS) + $(RM) *~ afs_xg.[CH] *.o *.so *.a $(DEPS) diff --git a/rxgen/Makefile b/rxgen/Makefile new file mode 100644 index 0000000..642cd4e --- /dev/null +++ b/rxgen/Makefile @@ -0,0 +1,3 @@ + +clean: + $(RM) -r *~ parsetab.py __pycache__/ diff --git a/rxgen/emit_c_struct.py b/rxgen/emit_c_struct.py new file mode 100644 index 0000000..43e7251 --- /dev/null +++ b/rxgen/emit_c_struct.py @@ -0,0 +1,366 @@ +#!/usr/bin/python3 +# +# Emit C structure +# -*- coding: utf-8 -*- + +__copyright__ = """ +Copyright (C) 2020 Red Hat, Inc. All Rights Reserved. +Written by David Howells (dhowells@redhat.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public Licence version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public Licence for more details. + +You should have received a copy of the GNU General Public Licence +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +from rxgen_bits import * + +############################################################################### +# +# Emit a structure member definition list +# +############################################################################### +def emit_struct_member_list(o, struct, members): + for m in members: + o.where(struct.name + "::" + m.name) + if m.is_single(): + if m.is_string(): + o.rxhdr("\t", m.ty.c_name, "\t", m.name, ";\n") + elif m.is_opaque(): + o.rxhdr("\t", m.ty.c_name, "\t", m.name, ";\n") + else: + o.rxhdr("\t", m.ty.c_name, "\t", m.name, ";\n") + elif m.is_int_array() or m.is_struct_array(): + o.rxhdr("\t", m.ty.c_name, "\t", m.name, "[", m.ty.dim.name, "];\n") + elif m.is_bulk(): + o.rxhdr("\tstd::vector<", m.ty.c_name, "> ", m.name, ";\n") + else: + raise RuntimeError("Unsupported type '" + str(m.ty) + "'\n") + +############################################################################### +# +# Emit a C union definition for this type +# +############################################################################### +def emit_union_decl(o, struct): + selector = struct.selector_name + want_i = False + + # + # Write out a C structure definition for this type + # + o.rxhdr("struct ", struct.name, " {\n") + o.rxhdr("\t", struct.selector_type, " ", selector, ";\n") + + for case in struct.members: + for m in case.members: + if m.is_array(): + want_i = True + break + o.rxhdr("\t\t/* case ", case.tag, " */\n") + emit_struct_member_list(o, struct, case.members) + + o.rxhdr("};\n") + +############################################################################### +# +# Emit a C structure definition for this type +# +############################################################################### +def emit_struct_decl(o, struct): + o.rxhdr("\n") + if struct.is_union(): + emit_union_decl(o, struct) + else: + o.rxhdr("struct ", struct.name, " {\n") + emit_struct_member_list(o, struct, struct.members) + o.rxhdr("};\n") + +############################################################################### +# +# Emit code to calculate the size of a member list +# +############################################################################### +def emit_struct_calc_members(o, members): + for m in members: + if m.is_single_int32(): + o.rxsrc("\trxrpc::reserve(resv);\t// ", m.name, "\n") + elif m.is_single_int64(): + o.rxsrc("\trxrpc::reserve_u64(resv);\t// ", m.name, "\n") + elif m.is_single_struct(): + o.rxsrc("\treserve_", m.ty.name, "(resv, p.", m.name, ");\n") + elif m.is_single_string(): + o.rxsrc("\trxrpc::reserve_string(resv, p.", + m.name, ", ", m.what_max_obj(), ");\n"); + elif m.is_single_opaque(): + o.rxsrc("\trxrpc::reserve_opaque(resv, p.", + m.name, ", ", m.what_max_obj(), ");\n"); + elif m.is_array(): + if m.is_int32_array(): + o.rxsrc("\trxrpc::reserve_a32(resv, ", m.dim.name, ");\t// ", m.name, "[]\n") + elif m.is_int64_array(): + o.rxsrc("\trxrpc::reserve_a64(resv, ", m.dim.name, ");\t// ", m.name, "[]\n") + elif m.is_struct_array(): + o.rxsrc("\tfor (size_t i = 0; i < ", m.dim.name, "; i++)\n") + o.rxsrc("\t\treserve_", m.ty.name, "(resv, p.", m.name, "[i]);\n") + else: + raise RuntimeError("No enc-calc for array type '" + str(m.ty) + "'") + elif m.is_bulk(): + o.rxsrc("\trxrpc::reserve(resv);\t// ", m.name, "__nr\n") + if m.is_int32(): + o.rxsrc("\trxrpc::reserve_a32(resv, p.", m.name, ".size());\n") + else: + o.rxsrc("\tfor (size_t i = 0; i < p.", m.name, ".size(); i++)\n") + if m.is_string(): + o.rxsrc("\t\trxrpc::reserve_string(resv, p.", + m.name, "[i], ", m.what_max_obj(), ");\n"); + elif m.is_opaque(): + o.rxsrc("\t\trxrpc::reserve_opaque(resv, p.", + m.name, "[i], ", m.what_max_obj(), ");\n"); + else: + o.rxsrc("\t\treserve_", m.ty.name, "(resv, p.", m.name, "[i]);\n") + elif str(m.ty) == "opr_uuid": + o.rxsrc("\t\trxrpc::reserve_", m.ty.name, "(resv, p.", m.name, ");\n") + else: + raise RuntimeError("No enc-calc for type '" + str(m.ty) + "'") + +############################################################################### +# +# Emit a structure member list encoder +# +############################################################################### +def emit_struct_encode_members(o, struct, members): + for m in members: + o.where(struct.name + "::" + m.name) + if m.is_single_int32(): + o.rxsrc("\trxrpc::enc (z_buf, p.", m.name, ");\n") + elif m.is_single_int64(): + o.rxsrc("\trxrpc::enc_u64 (z_buf, p.", m.name, ");\n") + elif m.is_single_struct(): + o.rxsrc("\tencode_", m.ty.name, "(z_buf, p.", m.name, ");\n") + elif m.is_array(): + o.rxsrc("\tfor (size_t i = 0; i < ", m.dim.name, "; i++)\n") + if m.is_int32_array(): + o.rxsrc("\t\trxrpc::enc (z_buf, p.", m.name, "[i]);\n") + elif m.is_int64_array(): + o.rxsrc("\t\trxrpc::enc_u64 (z_buf, p.", m.name, "[i]);\n") + elif m.is_struct_array(): + o.rxsrc("\t\tencode_", m.ty.name, "(z_buf, p.", m.name, "[i]);\n") + else: + raise RuntimeError("No encoding for array type '" + str(m.ty) + "'") + elif m.is_single_string(): + o.rxsrc("\trxrpc::enc_string(z_buf, p.", m.name, ", ", + m.what_max_obj(), ");\n") + elif m.is_single_opaque(): + o.rxsrc("\trxrpc::enc_opaque(z_buf, p.", m.name, ", ", m.what_max_obj(), ");\n") + elif m.is_single_uuid(): + o.rxsrc("\trxrpc::enc_uuid(z_buf, p.", m.name, ");\n") + elif m.is_bulk(): + o.rxsrc("\trxrpc::enc (z_buf, p.", m.name, ".size());\n") + o.rxsrc("\tfor (size_t i = 0; i < p.", m.name, ".size(); i++)\n") + if m.is_int32(): + o.rxsrc("\t\trxrpc::enc(z_buf, p.", m.name, "[i]);\n") + elif m.is_string(): + o.rxsrc("\t\trxrpc::enc_string(z_buf, p.", m.name, "[i], ", + m.what_max_obj(), ");\n") + elif m.is_opaque(): + o.rxsrc("\t\trxrpc::enc_opaque(z_buf, p.", m.name, "[i], ", + m.what_max_obj(), ");\n") + else: + o.rxsrc("\t\tencode_", m.ty.name, "(z_buf, p.", m.name, "[i]);\n") + else: + raise RuntimeError("No encoding for type '" + str(m.ty) + "'") + +############################################################################### +# +# Emit a structure member list decoder +# +############################################################################### +def emit_struct_decode_members(o, struct, members): + for m in members: + o.where(struct.name + "::" + m.name) + if m.is_single_int32(): + o.rxsrc("\tp.", m.name, "\t= rxrpc::dec(z_rxq);\n") + elif m.is_single_int64(): + o.rxsrc("\tp.", m.name, "\t= rxrpc::dec_u64(z_rxq);\n") + elif m.is_single_struct(): + o.rxsrc("\tdecode_", m.ty.name, "(z_rxq, p.", m.name, ");\n") + elif m.is_array(): + o.rxsrc("\tfor (size_t i = 0; i < ", m.dim.name, "; i++)\n") + if m.is_int32_array(): + o.rxsrc("\t\tp.", m.name, "[i] = rxrpc::dec(z_rxq);\n") + elif m.is_int64_array(): + o.rxsrc("\t\tp.", m.name, "[i] = rxrpc::dec_u64(z_rxq);\n") + elif m.is_struct_array(): + o.rxsrc("\t\tdecode_", m.ty.name, "(z_rxq, p.", m.name, "[i]);\n") + else: + raise RuntimeError("No decoding for array type '" + str(m.ty) + "'") + elif m.is_single_string(): + o.rxsrc("\trxrpc::dec_string(z_rxq, p.", m.name) + if m.max_obj != None: + o.rxsrc(", ", m.max_obj); + o.rxsrc(");\n") + elif m.is_single_opaque(): + o.rxsrc("\trxrpc::dec_opaque(z_rxq, p.", m.name) + if m.max_obj != None: + o.rxsrc(", ", m.max_obj); + o.rxsrc(");\n") + elif m.is_bulk(): + o.rxsrc("\tsize_t ", m.name, "__nr = rxrpc::dec(z_rxq);\n") + o.rxsrc("\tif (", m.name, "__nr > 0) {\n") + o.rxsrc("\t\tp.", m.name, ".resize(", m.name, "__nr);\n") + o.rxsrc("\t\tfor (size_t i = 0; i < ", m.name, "__nr; i++)\n") + if m.is_int32(): + o.rxsrc("\t\t\tp.", m.name, "[i]\t= rxrpc::dec(z_rxq);\n") + elif m.is_string(): + o.rxsrc("\t\t\trxrpc::dec_string(z_rxq, p.", m.name) + if m.max_obj != None: + o.rxsrc("[i], ", m.max_obj); + o.rxsrc(");\n") + elif m.is_opaque(): + o.rxsrc("\t\t\trxrpc::dec_opaque(z_rxq, p.", m.name) + if m.max_obj != None: + o.rxsrc("[i], ", m.max_obj); + o.rxsrc(");\n") + else: + o.rxsrc("\t\t\tdecode_", m.ty.name, "(z_rxq, p.", m.name, "[i]);\n") + o.rxsrc("\t}\n") + elif str(m.ty) == "opr_uuid": + o.rxsrc("\tz_rxq.read(&p.", m.name, ", 16);\n") + else: + raise RuntimeError("No decoding for type '" + str(m.ty) + "'") + +############################################################################### +# +# Emit union encoders and decoders +# +############################################################################### +def emit_union_encdec(o, struct): + selector = struct.selector_name + want_i = False + + # + # Write a size calculation function + # + o.rxsrc("\n") + o.rxsrc("void reserve_", struct.name, + "(rxrpc::Resv &resv, const ", struct.c_name, " &p)\n") + o.rxsrc("{\n") + o.rxsrc("\trxrpc::reserve(resv); // selector - p.", selector, "\n") + o.rxsrc("\tswitch (p.", selector, ") {\n") + for case in struct.members: + for m in case.members: + if m.is_array() and m.is_struct_array(): + o.rxsrc("\tint i;\n\n") + break + for case in struct.members: + o.rxsrc("\tcase ", case.tag, ":\n") + emit_struct_calc_members(o, case.members) + o.rxsrc("\tbreak;\n") + o.rxsrc("}\n") + o.rxsrc("}\n") + + # + # Write an encoding function + # + o.rxsrc("\n") + o.rxsrc("void encode_", struct.name, + "(rxrpc::Enc_buffer *z_buf, const ", struct.c_name, " &p)\n") + o.rxsrc("{\n") + + if want_i: + o.rxsrc("\tint i;\n\n") + + o.rxsrc("\trxrpc::enc(z_buf, p.", selector, ");\n") + o.rxsrc("\tswitch (p.", selector, ") {\n") + for case in struct.members: + o.rxsrc("\tcase ", case.tag, ":\n") + emit_struct_encode_members(o, struct, case.members) + o.rxsrc("\tbreak;\n") + o.rxsrc("\t}\n") + o.rxsrc("}\n") + + # + # Write a decoding function + # + o.rxsrc("\n") + #o.rxsrc("static __attribute__((unused))\n") + o.rxsrc("void decode_", struct.name, + "(rxrpc::Rx_queue &z_rxq, ", struct.c_name, " &p)\n") + o.rxsrc("{\n") + + if want_i: + o.rxsrc("\tint i;\n\n") + + o.rxsrc("\tp.", selector, " = rxrpc::dec(z_rxq);\n") + o.rxsrc("\tswitch (p.", selector, ") {\n") + for case in struct.members: + o.rxsrc("\tcase ", case.tag, ":\n") + emit_struct_decode_members(o, struct, case.members) + o.rxsrc("\tbreak;\n") + o.rxsrc("}\n") + o.rxsrc("}\n") + +############################################################################### +# +# Emit structure encoders and decoders +# +############################################################################### +def emit_struct_encdec(o, struct): + if struct.is_union(): + emit_union_encdec(o, struct) + return + + # + # Write a size calculation function + # + o.rxsrc("\n") + o.rxsrc("void reserve_", struct.name, + "(rxrpc::Resv &resv, const struct ", struct.name, " &p)\n") + o.rxsrc("{\n") + emit_struct_calc_members(o, struct.members) + o.rxsrc("}\n") + o.rxsrc("\n") + + # + # Write an encoding function + # + o.rxsrc("\n") + o.rxsrc("void encode_", struct.name, + "(rxrpc::Enc_buffer *z_buf, const struct ", struct.name, " &p)\n") + o.rxsrc("{\n") + + emit_struct_encode_members(o, struct, struct.members) + o.rxsrc("}\n") + + # + # Write a decoding function + # + o.rxsrc("\n") + o.rxsrc("void decode_", struct.name, + "(rxrpc::Rx_queue &z_rxq, struct ", struct.name, " &p)\n") + o.rxsrc("{\n") + + emit_struct_decode_members(o, struct, struct.members) + o.rxsrc("}\n") + +############################################################################### +# +# Emit C func definitions for enc/dec routines +# +############################################################################### +def emit_struct_encdec_decl(o, struct): + o.rxhdr("extern void reserve_", struct.name, + "(rxrpc::Resv &resv, const struct ", struct.name, " &p);\n") + o.rxhdr("extern void encode_", struct.name, + "(rxrpc::Enc_buffer *z_buf, const struct ", struct.name, " &p);\n") + o.rxhdr("extern void decode_", struct.name, + "(rxrpc::Rx_queue &z_rxq, struct ", struct.name, " &p);\n") diff --git a/rxgen/emit_c_sync_funcs.py b/rxgen/emit_c_sync_funcs.py new file mode 100644 index 0000000..1579508 --- /dev/null +++ b/rxgen/emit_c_sync_funcs.py @@ -0,0 +1,656 @@ +#!/usr/bin/python3 +# +# Emit C synchronous functions +# -*- coding: utf-8 -*- + +__copyright__ = """ +Copyright (C) 2020 Red Hat, Inc. All Rights Reserved. +Written by David Howells (dhowells@redhat.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public Licence version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public Licence for more details. + +You should have received a copy of the GNU General Public Licence +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +from rxgen_bits import * + +############################################################################### +# +# Calculate the C function prototypes +# +############################################################################### +def emit_func_prototype(o, func): + # Function prototype lists (we add commas and the closing bracket later) + send_request_protos = list() + send_response_protos = list() + + for p in func.params: + o.where(func.name + ":" + p.name) + s_req = list() + r_req = list() + s_rsp = list() + r_rsp = list() + + t = p.ty.c_name + if p.is_array(): + raise RuntimeError("Array arg not supported") + elif p.is_bulk(): + s_req.append("const std::vector<" + p.ty.c_name + "> &" + p.name) + r_req.append("const std::vector<" + p.ty.c_name + "> &" + p.name) + s_rsp.append("const std::vector<" + p.ty.c_name + "> &" + p.name) + r_rsp.append("std::vector<" + p.ty.c_name + "> &_" + p.name) + elif p.is_single_string() or p.is_single_opaque() or p.is_single_struct() or \ + p.is_single_uuid(): + s_req.append("const " + t + " &" + p.name) + r_req.append("const " + t + " &" + p.name) + s_rsp.append("const " + t + " &" + p.name) + r_rsp.append(t + " &_" + p.name) + else: + enc_const = "" + if not p.is_single_int(): + enc_const = "const " + proto = p.ty.c_name + " " + if not p.is_single_int(): + proto += "&" + s_req.append(enc_const + proto + p.name) + r_rsp.append(proto + "*" + p.name) + r_req.append(enc_const + proto + p.name) + s_rsp.append(enc_const + proto + p.name) + + if p.direction == xdr_direction.IN or p.direction == xdr_direction.INOUT: + send_request_protos += s_req + if p.direction == xdr_direction.OUT or p.direction == xdr_direction.INOUT: + send_response_protos += s_rsp + + o.rxhdr("\n") + o.rxhdr("/*\n") + o.rxhdr(" * ", func.name, "\n") + o.rxhdr(" */\n") + + o.rxhdr("extern rxrpc::ref encode_", func.name, "(\n") + need_sep = False + for proto in send_request_protos: + if need_sep: + o.rxhdr(",\n") + o.rxhdr("\t", proto) + need_sep = True + o.rxhdr(");\n") + o.rxhdr("\n") + + o.rxhdr("extern rxrpc::ref encode_S_", func.name, "(\n") + need_sep = False + for proto in send_response_protos: + if need_sep: + o.rxhdr(",\n") + o.rxhdr("\t", proto) + need_sep = True + o.rxhdr(");\n") + o.rxhdr("\n") + + o.rxhdr("extern rxrpc::ref begin_", func.name + "(\n") + o.rxhdr("\trxrpc::Call_params *z_params,\n") + o.rxhdr("\trxrpc::Enc_buffer *z_buf);\n") + + o.rxhdr("\n") + o.rxhdr("extern void decode_", func.name, "(\n") + o.rxhdr("\trxrpc::Call *z_call") + for p in func.response: + o.rxhdr(",\n\t") + if p.is_bulk(): + o.rxhdr("std::vector<", p.ty.c_name, "> &_", p.name) + need_i = True + else: + o.rxhdr(p.ty.c_name, " &_", p.name) + o.rxhdr(");\n") + + o.rxhdr("\n") + o.rxhdr("extern int S_", func.name, "(\n") + o.rxhdr("\trxrpc::Call *z_call") + for p in func.request: + o.rxhdr(",\n\t") + if p.is_single_int(): + o.rxhdr(p.ty.c_name, " ", p.name) + elif p.is_bulk(): + o.rxhdr("std::vector<", p.ty.c_name, "> &a_", p.name) + else: + o.rxhdr(p.ty.c_name, " &a_", p.name) + o.rxhdr(");\n") + + # Synchronous client call + o.rxhdr("\n") + o.rxhdr("extern void ", func.name, "(\n") + o.rxhdr("\trxrpc::Call_params *z_params") + + # Request parameters + for proto in send_request_protos: + o.rxhdr(",\n\t", proto) + + # Reply parameters + for p in func.response: + o.rxhdr(",\n\t") + if p.is_bulk(): + o.rxhdr("std::vector<", p.ty.c_name, "> &_", p.name) + elif p.is_single_string(): + o.rxhdr(p.ty.c_name, " &_", p.name) + elif p.is_single_opaque(): + o.rxhdr(p.ty.c_name, " &_", p.name) + elif p.is_single_int(): + o.rxhdr(p.ty.c_name, " &_", p.name) + elif p.is_single_struct(): + o.rxhdr(p.ty.c_name, " &_", p.name) + elif str(p.ty) == "opr_uuid": + o.rxhdr(p.ty.c_name, " &_", p.name) + else: + print(p.name) + raise RuntimeError("No prototype for type '" + str(p.ty) + "'") + o.rxhdr(");\n") + + func.send_request_protos = send_request_protos + func.send_response_protos = send_response_protos + +############################################################################### +# +# Emit a function to encode a request or a response into a buffer, not +# including any split insertion. +# +############################################################################### +def emit_func_encode(o, func, what): + # Function definition and arguments + if what == "request": + protos = func.send_request_protos + params = func.request + else: + protos = func.send_response_protos + params = func.response + + o.rxsrc("\n") + if what == "request": + o.rxsrc("rxrpc::ref encode_", func.name, "(") + else: + o.rxsrc("rxrpc::ref encode_S_", func.name, "(") + + need_sep = False + for proto in protos: + if need_sep: + o.rxsrc(",") + else: + need_sep = True + o.rxsrc("\n\t\t", proto) + + o.rxsrc(")\n") + o.rxsrc("{\n") + + blob_params = list() + bulk_params = list() + for p in params: + if p.is_single_string() or p.is_single_opaque(): + blob_params.append(p) + if p.is_bulk(): + bulk_params.append(p) + + # Local variables + o.rxsrc("\trxrpc::ref z_buf;\n") + o.rxsrc("\trxrpc::Resv z_resv = { .max_ioc = 1, };\n") + o.rxsrc("\n") + + # Parameter checks + if blob_params or bulk_params: + for p in blob_params: + o.where(func.name + ":" + p.name) + if p.max_obj: + o.rxsrc("\tif (", p.name, ".size() > ", p.max_obj.name, + ") throw std::invalid_argument(\"Size of ", p.name, " too large\");\n") + + for p in bulk_params: + o.where(func.name + ":" + p.name) + if p.max_count: + o.rxsrc("\tif (", p.name, ".size() > ", p.max_count.name, + ") throw std::invalid_argument(\"Size of ", p.name, " too large\");\n") + o.rxsrc("\n") + + # Calculate the size of the parameter. + o.rxsrc("\t/* Determine size */\n") + o.rxsrc("\trxrpc::reserve(z_resv); // ", func.opcode.name, "\n"); + for p in params: + if p.is_single_string(): + o.rxsrc("\trxrpc::reserve_string(z_resv, ", + p.name, ", ", p.what_max_obj(), ");\n") + elif p.is_single_opaque(): + o.rxsrc("\trxrpc::reserve_opaque(z_resv, ", + p.name, ", ", p.what_max_obj(), ");\n") + elif p.is_bulk(): + o.rxsrc("\trxrpc::reserve(z_resv); // #", p.name, "\n") + if p.is_bulk_int32(): + o.rxsrc("\trxrpc::reserve_a32(z_resv, ", p.name, ".size());\n") + elif p.is_bulk_int64(): + o.rxsrc("\trxrpc::reserve_a64(z_resv, ", p.name, ".size());\n") + elif p.is_bulk(): + o.rxsrc("\tfor (size_t i = 0; i < ", p.name, ".size(); i++)\n") + o.rxsrc("\t\txdr::reserve_", str(p.ty.name), "(z_resv, ", p.name, "[i]);\n") + elif p.is_int32(): + o.rxsrc("\trxrpc::reserve(z_resv); // ", p.name, "\n") + elif p.is_int64(): + o.rxsrc("\trxrpc::reserve_u64(z_resv); // ", p.name, "\n") + elif p.is_single_uuid(): + o.rxsrc("\trxrpc::reserve_opr_uuid(z_resv, ", p.name, ");\n") + else: + o.rxsrc("\txdr::reserve_", p.ty.name, "(z_resv, ", p.name, ");\n") + + # Allocate the buffer + o.rxsrc("\n") + o.rxsrc("\t/* Marshal */\n") + o.rxsrc("\tz_buf = rxrpc::alloc_enc_buffer(z_resv);\n") + + # Marshal the data + if what == "request": + o.rxsrc("\trxrpc::enc(z_buf, ", func.opcode.name, ");\n") + + for p in params: + o.where(func.name + ":" + p.name) + if p.is_single_int32(): + o.rxsrc("\trxrpc::enc(z_buf, ", p.name, ");\n") + elif p.is_single_int64(): + o.rxsrc("\trxrpc::enc_u64(z_buf, ", p.name, ");\n") + elif p.is_single_compound(): + o.rxsrc("\txdr::encode_", p.ty.name, "(z_buf, ", p.name, ");\n") + elif p.is_single_string(): + o.rxsrc("\trxrpc::enc_string(z_buf, ", p.name, ", ", p.what_max_obj(), ");\n") + elif p.is_single_opaque(): + o.rxsrc("\trxrpc::enc_opaque(z_buf, ", p.name, ", ", p.what_max_obj(), ");\n") + elif p.is_bulk(): + o.rxsrc("\trxrpc::enc(z_buf, ", p.name, ".size());\n") + o.rxsrc("\tfor (size_t i = 0; i < ", p.name, ".size(); i++)\n") + if p.is_bulk_int32(): + if not p.ty.name.startswith("u"): + o.rxsrc("\t\trxrpc::enc(z_buf, (u", p.ty.name, ")", p.name, "[i]);\n") + else: + o.rxsrc("\t\trxrpc::enc(z_buf, ", p.name, "[i]);\n") + elif p.is_bulk_int64(): + o.rxsrc("\t\trxrpc::enc_u64(z_buf, (uint32_t)", p.name, "[i]);\n") + elif p.is_bulk_struct(): + o.rxsrc("\t\txdr::encode_", p.ty.name, "(z_buf, ", p.name, "[i]);\n") + else: + raise RuntimeError("No decoding for array type '" + str(p.ty) + "'") + elif p.is_single_uuid(): + o.rxsrc("\trxrpc::enc_uuid(z_buf, ", p.name, ");\n") + else: + raise RuntimeError("Unsupported param encoding '" + str(p.ty) + "'") + + o.rxsrc("\trxrpc::seal_buffer(z_buf);\n") + + # Send the data + o.rxsrc("\treturn z_buf;\n") + o.rxsrc("}\n") + +############################################################################### +# +# Emit a function to encode and dispatch a request or a response +# +############################################################################### +def emit_func_send(o, func, what): + # Function definition and arguments + if what == "request": + protos = func.send_request_protos + params = func.request + else: + protos = func.send_response_protos + params = func.response + + o.rxsrc("\n") + if what == "request": + o.rxsrc("rxrpc::ref begin_", func.name, "(\n") + o.rxsrc("\trxrpc::Call_params *z_params,\n") + o.rxsrc("\trxrpc::Enc_buffer *z_buf)\n") + else: + o.rxsrc("void reply_to_", func.name, "(\n") + o.rxsrc("\trxrpc::Call *z_call,\n") + o.rxsrc("\trxrpc::Enc_buffer *z_buf)\n") + + o.rxsrc("{\n") + + # Local variables + if what == "request": + o.rxsrc("\trxrpc::ref z_call =\n") + o.rxsrc("\t\trxrpc::make_call(z_params, \"", + func.package.name, "::", func.name, "\", z_buf);\n") + o.rxsrc("\tz_call->throw_abort_func = afs_throw_abort;\n") + if func.split: + o.rxsrc("\tz_call->split = true;\n") + + # Send the data + if what == "request": + o.rxsrc("\treturn z_call;\n") + o.rxsrc("}\n") + +############################################################################### +# +# Emit a weak stub function to implement a server call. +# +############################################################################### +def emit_func_server_stub(o, func): + # Function definition and arguments + params = func.request + + o.rxsrc("\n") + o.rxsrc("__attribute__((weak))\n") + o.rxsrc("int S_", func.name, "(\n") + o.rxsrc("\trxrpc::Call *z_call") + for p in params: + o.rxsrc(",\n\t") + if p.is_bulk(): + o.rxsrc("std::vector<", p.ty.c_name, "> &_", p.name) + elif p.is_single_int(): + o.rxsrc(p.ty.c_name, " ", p.name) + elif p.is_single_string(): + o.rxsrc(p.ty.c_name, " &", p.name) + elif p.is_single_opaque(): + o.rxsrc(p.ty.c_name, " &", p.name) + elif p.is_single_compound(): + o.rxsrc(p.ty.c_name, " &", p.name) + elif str(p.ty) == "opr_uuid": + o.rxsrc(p.ty.c_name, " &", p.name) + else: + print(p.name) + raise RuntimeError("No prototype for type '" + str(p.ty) + "'") + + o.rxsrc(")\n") + o.rxsrc("{\n") + o.rxsrc("\tthrow rxrpc::AbortRXGEN_OPCODE(z_call->op_name);\n") + o.rxsrc("}\n") + +############################################################################### +# +# Emit a function to decode a request and invoke the appropriate server +# function. The opcode is expected to have been removed from the incoming call +# on the server side. +# +############################################################################### +def emit_func_receive_request(o, func): + # Function definition and arguments + params = func.request + nomem = False + need_i = False + + o.rxsrc("\n") + o.rxsrc("void decode_S_", func.name, "(rxrpc::Call *z_call)\n") + o.rxsrc("{\n") + + # Local variables + for p in params: + if p.is_bulk(): + o.rxsrc("\tstd::vector<", p.ty.c_name, "> a_", p.name, ";\n") + need_i = True + elif p.is_single_string(): + o.rxsrc("\t", p.ty.c_name, " a_", p.name, ";\n") + elif p.is_single_opaque(): + o.rxsrc("\t", p.ty.c_name, " a_", p.name, ";\n") + elif p.is_single_int() or p.is_single_struct(): + o.rxsrc("\t", p.ty.c_name, " a_", p.name, ";\n") + elif p.is_single_union(): + o.rxsrc("\t", p.ty.c_name, " a_", p.name, " = {};\n") + elif p.is_single_uuid(): + o.rxsrc("\t", p.ty.c_name, " a_", p.name, ";\n") + else: + print(p.name) + raise RuntimeError("No local vars for type '" + str(p.ty) + "'") + if need_i: + o.rxsrc("\tsize_t count;\n") + + o.rxsrc("\n"); + o.rxsrc("\ttry {\n"); + + # Decode the data. + if params: + o.rxsrc("\t\trxrpc::Rx_queue &z_rxq = *z_call;\n") + for p in params: + if p.is_single_string(): + o.rxsrc("\t\trxrpc::dec_string(z_rxq, a_", p.name) + if p.max_obj != None: + o.rxsrc(", ", p.max_obj) + o.rxsrc(");\n"); + elif p.is_single_opaque(): + o.rxsrc("\t\trxrpc::dec_opaque(z_rxq, a_", p.name) + if p.max_obj != None: + o.rxsrc(", ", p.max_obj) + o.rxsrc(");\n") + elif p.is_bulk(): + o.rxsrc("\t\t/* ", str(p.ty), " a_", p.name, " */\n"); + o.rxsrc("\t\tcount = rxrpc::dec(z_rxq") + if p.max_count != None: + o.rxsrc(", ", p.max_count) + o.rxsrc(");\n") + + o.rxsrc("\t\ta_", p.name, ".resize(count);\n") + if p.is_bulk_int(): + o.rxsrc("\t\tfor (size_t i = 0; i < count; i++)\n") + o.rxsrc("\t\t\ta_", p.name, "[i] = rxrpc::dec(z_rxq);\n") + nomem = True + elif p.is_bulk_struct(): + o.rxsrc("\t\tfor (size_t i = 0; i < count; i++)\n") + o.rxsrc("\t\t\txdr::decode_", p.ty.name, "(z_rxq, a_", p.name, "[i]);\n") + nomem = True + else: + print(func.name, p.name, str(p.ty)) + print("is_bulk: ", p.is_bulk()) + print("is_bulk_int", p.is_bulk_int()) + print("is_int:", p.is_int()) + raise RuntimeError("No decode for bulk type '" + str(p.ty) + "'") + elif p.is_single_int(): + o.rxsrc("\t\ta_", p.name, " = rxrpc::dec(z_rxq);\n") + elif p.is_single_compound(): + o.rxsrc("\t\txdr::decode_", p.ty.name, "(z_rxq, a_", p.name, ");\n") + elif p.is_single_uuid(): + o.rxsrc("\t\tz_rxq.read(&a_", p.name, ".uuid, sizeof(a_", p.name, ".uuid));\n") + else: + print(func.name, p.name, str(p.ty)) + print("is_bulk: ", p.is_bulk()) + print("is_bulk_int", p.is_bulk_int()) + print("is_int:", p.is_int()) + raise RuntimeError("No decode for type '" + str(p.ty) + "'") + + # Check for decode errors + o.rxsrc("\n") + o.rxsrc("\t\tz_call->request_received();\n") + + # Invoke the server stub + o.rxsrc("\n") + o.rxsrc("\t\tS_", func.name, "(\n") + o.rxsrc("\t\t\tz_call") + for p in params: + o.rxsrc(",\n\t\t\t") + o.rxsrc("a_", p.name) + o.rxsrc(");\n") + + o.rxsrc("\t} catch (rxrpc::rx_abort &a) {\n") + o.rxsrc("\t\tz_call->end(a.get_abort_code());\n") + o.rxsrc("\t\tthrow;\n") + o.rxsrc("\t} catch (...) {\n") + o.rxsrc("\t\tz_call->end(RX_USER_ABORT);\n") + o.rxsrc("\t\tthrow;\n") + o.rxsrc("\t}\n") + o.rxsrc("}\n") + +############################################################################### +# +# Emit a function to decode a reply and return it to the caller on the client +# side. +# +############################################################################### +def emit_func_receive_reply(o, func): + # Function definition and arguments + params = func.response + need_i = False + + o.rxsrc("void decode_", func.name, "(\n") + o.rxsrc("\trxrpc::Call *z_call") + for p in params: + o.rxsrc(",\n\t") + if p.is_single_string(): + o.rxsrc(p.ty.c_name, " &_", p.name) + elif p.is_single_opaque(): + o.rxsrc(p.ty.c_name, " &_", p.name) + elif p.is_bulk(): + o.rxsrc("std::vector<", p.ty.c_name, "> &_", p.name) + need_i = True + elif p.is_single_int(): + o.rxsrc(p.ty.c_name, " &_", p.name) + elif p.is_single_struct(): + o.rxsrc(p.ty.c_name, " &_", p.name) + elif p.is_single_uuid(): + o.rxsrc(p.ty.c_name, " &_", p.name) + else: + raise RuntimeError("No prototype for type '" + str(p.ty) + "'") + o.rxsrc(")\n") + o.rxsrc("{\n") + + # Local variables + if need_i: + o.rxsrc("\tsize_t count;\n") + + # Decode the data. + o.rxsrc("\n") + if params: + o.rxsrc("\t\trxrpc::Rx_queue &z_rxq = *z_call;\n") + for p in params: + if p.is_single_string(): + o.rxsrc("\trxrpc::dec_string(z_rxq, _", p.name) + if p.max_obj != None: + o.rxsrc(", ", p.max_obj) + o.rxsrc(");\n"); + elif p.is_single_opaque(): + o.rxsrc("\trxrpc::dec_opaque(z_rxq, _", p.name) + if p.max_obj != None: + o.rxsrc(", ", p.max_obj) + o.rxsrc(");\n"); + elif p.is_bulk(): + o.rxsrc("\t/* ", str(p.ty), " ", p.name, " */\n"); + o.rxsrc("\tcount = rxrpc::dec(z_rxq") + if p.max_count: + o.rxsrc(", ", p.max_count); + o.rxsrc(");\n") + o.rxsrc("\t_", p.name, ".resize(count);\n") + o.rxsrc("\tfor (size_t i = 0; i < count; i++)\n") + + if p.is_bulk_int(): + o.rxsrc("\t\t_", p.name, "[i] = rxrpc::dec(z_rxq);\n") + elif p.is_bulk_struct(): + o.rxsrc("\t\txdr::decode_", p.ty.name, "(z_rxq, _", p.name, "[i]);\n") + else: + print(func.name, p.name, str(p.ty)) + print("is_bulk: ", p.is_bulk()) + print("is_bulk_int", p.is_bulk_int()) + print("is_int:", p.is_int()) + raise RuntimeError("No decoding for bulk type '" + str(p.ty) + "'") + elif p.is_single_int(): + o.rxsrc("\t_", p.name, " = rxrpc::dec(z_rxq);\n") + elif p.is_single_struct(): + o.rxsrc("\txdr::decode_", p.ty.name, "(z_rxq, _", p.name, ");\n") + elif p.is_single_uuid(): + o.rxsrc("\tz_call->read(_", p.name, ".uuid, sizeof(_", p.name, ".uuid));\n") + else: + print(func.name, p.name, str(p.ty)) + print("is_bulk: ", p.is_bulk()) + print("is_bulk_int", p.is_bulk_int()) + print("is_int:", p.is_int()) + raise RuntimeError("No decoding for type '" + str(p.ty) + "'") + o.rxsrc("}\n") + +############################################################################### +# +# Emit a function to switch between service calls. +# +############################################################################### +def emit_package_switch(o, package): + o.rxsrc("\n") + o.rxsrc("void ", package.name, "_service(rxrpc::Call *z_call, unsigned int opcode)\n") + o.rxsrc("{\n") + o.rxsrc("\tswitch (opcode) {\n") + for f in package.procs: + o.rxsrc("\tcase ", f.opcode, ":\treturn decode_S_", f.name, "(z_call);\n") + o.rxsrc("\tdefault:\tthrow rxrpc::AbortRXGEN_OPCODE();\n") + o.rxsrc("\t}\n") + o.rxsrc("}\n") + +############################################################################### +# +# Emit a function to do a complete synchronous client call +# +############################################################################### +def emit_func_sync_client_call(o, func): + protos = func.send_request_protos + params = func.request + bad_ret = "NULL" + + o.rxsrc("\n") + o.rxsrc("void ", func.name, "(\n") + o.rxsrc("\trxrpc::Call_params *z_params") + + # Request parameters + for proto in protos: + o.rxsrc(",\n\t", proto) + + # Reply parameters + for p in func.response: + o.rxsrc(",\n\t") + if p.is_bulk(): + o.rxsrc("std::vector<", p.ty.c_name, "> &_", p.name) + else: + o.rxsrc(p.ty.c_name, " &_", p.name) + + o.rxsrc(")\n") + o.rxsrc("{\n") + + # Encode the parameters + o.rxsrc("\n") + o.rxsrc("\trxrpc::ref z_buf =\n") + o.rxsrc("\t\t encode_", func.name, "(") + need_sep = False + for p in func.request: + if need_sep: + o.rxsrc(",") + else: + need_sep = True + o.rxsrc("\n\t\t") + if p.is_single_string(): + o.rxsrc("\t", p.name) + elif p.is_single_opaque(): + o.rxsrc("\t", p.name) + elif p.is_bulk(): + o.rxsrc("\t", p.name) + else: + o.rxsrc("\t", p.name) + + o.rxsrc(");\n") + + # Begin the call + o.rxsrc("\n") + o.rxsrc("\trxrpc::ref z_call =\n") + o.rxsrc("\t\tbegin_", func.name, "(z_params, z_buf);\n") + + o.rxsrc("\tz_call->send_data(z_buf);\n") + + # Wait for the reply to come in + o.rxsrc("\n") + o.rxsrc("\twhile (z_call->state != rxrpc::Call::call_completed)\n") + o.rxsrc("\t\tz_call->endpoint->receive();\n") + + # Decode the reply + o.rxsrc("\n") + o.rxsrc("\tdecode_", func.name, "(\n") + o.rxsrc("\t\tz_call") + for p in func.response: + o.rxsrc(",\n\t\t_", p.name) + + o.rxsrc(");\n") + o.rxsrc("\tz_params->service_id_used = z_call->service_id;\n") + o.rxsrc("\tz_call->end(0);\n") + o.rxsrc("}\n") diff --git a/rxgen/rxgen.py b/rxgen/rxgen.py new file mode 100755 index 0000000..8b8b3e5 --- /dev/null +++ b/rxgen/rxgen.py @@ -0,0 +1,905 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# +# Tool for processing an RxRPC-based RPC API definition in a C header file to +# produce (un)marshalling code and RPC functions to implement that API. +# +# It also produces a python module containing wrappers for the types, RPC +# functions and constants in the API definition. + +__copyright__ = """ +Copyright (C) 2020 Red Hat, Inc. All Rights Reserved. +Written by David Howells (dhowells@redhat.com) + +Yacc & Lex bits based on pynfs rpcgen.py code: + + Written by Fred Isaman + Copyright (C) 2004 University of Michigan, Center for + Information Technology Integration + Based on version written by Peter Astrand + Copyright (C) 2001 Cendio Systems AB (http://www.cendio.se) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public Licence version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public Licence for more details. + +You should have received a copy of the GNU General Public Licence +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +import sys +import keyword +import time +import os +from rxgen_bits import * +from emit_c_struct import * +from emit_c_sync_funcs import * + +xdr = None # Current context + +########################################################################## +# # +# Lexical analysis # +# # +########################################################################## +import ply.lex as lex + +basic_types = ( + ( "char", "char", xdr_basic.int32 ), + ( "int8_t", "int8_t", xdr_basic.int32 ), + ( "int16_t", "int16_t", xdr_basic.int32 ), + ( "int32_t", "int32_t", xdr_basic.int32 ), + ( "int64_t", "int64_t", xdr_basic.int64 ), + ( "uint8_t", "uint8_t", xdr_basic.int32 ), + ( "uint16_t", "uint16_t", xdr_basic.int32 ), + ( "uint32_t", "uint32_t", xdr_basic.int32 ), + ( "uint64_t", "uint64_t", xdr_basic.int64 ), + ( "string", "std::string", xdr_basic.string ), + ( "opaque", "rxrpc::Opaque", xdr_basic.opaque ), + ( "opr_uuid", "rxrpc::Uuid", xdr_basic.opr_uuid ), + ) + +def load_basic_types(xdr): + global basic_types + for i in basic_types: + name = i[0] + t = xdr_type(xdr, name=name, c_name=i[1], basic=i[2]) + xdr.types[name] = t + +keywords = ( + "IN", + "INOUT", + "OUT", + "altonly", + "case", + "const", + "enum", + "multi", + "package", + "split", + "struct", + "switch", + "typedef", + "union", +) + tuple([i[0] for i in basic_types]) + +# Required by lex. Each token also allows a function t_. +tokens = tuple([t.upper() for t in keywords]) + ( + "ID", "CONST10", "CONST8", "CONST16", + # ( ) [ ] { } + "LPAREN", "RPAREN", "LSQUARE", "RSQUARE", "LBRACE", "RBRACE", + # ; : < > * = , : + "SEMI", "LT", "GT", "STAR", "EQUALS", "COMMA", "COLON", + "BEGIN_ERROR_CODES", "END_ERROR_CODES", "NEWFILE" +) + +# t_ functions are used by lex. They are called with t.value==, and t.type==. They expect a return value +# with attribute type= + +# Tell lexer to ignore Whitespace. +t_ignore = " \t" + +def t_NEWFILE(t): + r'__NEWFILE__ [^\n]*' + t.lexer.source = t.value[12:] + t.lexer.lineno = 0 + return t + +def t_ID(t): + r'[A-Za-z][A-Za-z0-9_]*' + if t.value in keywords: + t.type = t.value.upper() + return t + +def t_CONST16(t): + r'0x[0-9a-fA-F]+' + return t + +def t_CONST8(t): + r'0[0-7]+' + return t + +def t_CONST10(t): + r'-?(([1-9]\d*)|0)' + return t + +# Tokens +t_LPAREN = r'\(' +t_RPAREN = r'\)' +t_LSQUARE = r'\[' +t_RSQUARE = r'\]' +t_LBRACE = r'\{' +t_RBRACE = r'\}' +t_SEMI = r';' +t_LT = r'<' +t_GT = r'>' +t_STAR = r'\*' +t_EQUALS = r'=' +t_COMMA = r',' +t_COLON = r':' +t_BEGIN_ERROR_CODES = r'__BEGIN_ERROR_CODES__' +t_END_ERROR_CODES = r'__END_ERROR_CODES__' + +def t_newline(t): + r'\n+' + t.lexer.lineno += t.value.count("\n") + +def t_error(t): + print("Illegal character {:s} at {:d} type {:s}".format(repr(t.value[0]), + t.lineno, t.type)) + t.lexer.skip(1) + +# Build the lexer +lex.lex(debug=0) + +########################################################################## +# # +# Yacc Parsing Info # +# # +########################################################################## + +def p_specification(t): + '''specification : NEWFILE definition_list''' + +def p_definition_list(t): + '''definition_list : definition definition_list + | empty''' + +def p_definition(t): + '''definition : package_def + | constant_def + | enum_def + | type_def + | error_code_list_def + | proc_spec + | ALTONLY proc_spec''' + +def p_package_def(t): + '''package_def : PACKAGE ID''' + prefix = t[2] + name = t[2] + if name.endswith("_"): + name = name[:-1] + global xdr + xdr.lineno = t.lineno(1) + xdr.add_package(name, prefix) + +############################################################################### +# +# Constants and values +# +def p_constant_def(t): + '''constant_def : CONST ID EQUALS constant SEMI''' + name = t[2] + value = t[4] + global xdr + xdr.lineno = t.lineno(2) + t[0] = xdr.add_constant(name, value) + +def p_constant(t): + '''constant : CONST10 + | CONST8 + | CONST16''' + value = t[1] + if len(value) > 9: + value = value + 'L' + global xdr + xdr.lineno = t.lineno(1) + t[0] = xdr.add_number(value) + +def p_value_1(t): + '''value : constant''' + t[0] = t[1] + +def p_value_2(t): + '''value : ID''' + name = t[1] + global xdr + xdr.lineno = t.lineno(1) + t[0] = xdr.get_constant(name) + +def p_optional_value(t): + '''optional_value : value + | empty''' + # return value or None. + t[0] = t[1] + +def p_constant_list_1(t): + '''constant_list : constant_def constant_list''' + t[0] = [t[1]] + t[2] + +def p_constant_list_2(t): + '''constant_list : constant_def''' + t[0] = [t[1]] + +def p_error_code_list_def(t): + '''error_code_list_def : BEGIN_ERROR_CODES constant_list END_ERROR_CODES''' + global xdr + xdr.lineno = t.lineno(1) + xdr.add_error_codes(t[2]) + +def p_enum_def(t): + '''enum_def : ENUM ID LBRACE enum_list RBRACE SEMI''' + '''enum_def : ENUM ID LBRACE enum_list COMMA RBRACE SEMI''' + name = t[2] + global xdr + xdr.lineno = t.lineno(2) + enum = xdr_type(xdr, base=xdr.get_type("int32_t")) + t[0] = xdr.add_type(name, enum) + +def p_enum_list_1(t): + '''enum_list : enum_term''' + t[0] = [t[1]] + +def p_enum_list_2(t): + '''enum_list : enum_term COMMA enum_list''' + t[0] = [t[1]] + t[3] + +def p_enum_term(t): + '''enum_term : ID EQUALS constant''' + name = t[1] + value = t[3] + global xdr + xdr.lineno = t.lineno(1) + t[0] = xdr.add_constant(name, value) + +############################################################################### +# +# Type definition +# +def p_type_def_1(t): + '''type_def : TYPEDEF declaration SEMI''' + name = t[2].name + typespec = t[2].typespec + global xdr + xdr.lineno = t.lineno(1) + alias = xdr_type_alias(name, typespec, xdr) + xdr.add_type_alias(name, alias) + #xdr.debug("Typedef", name) + +def p_type_def_2(t): + '''type_def : STRUCT ID struct_body SEMI''' + name = t[2] + body = t[3] + global xdr + xdr.lineno = t.lineno(2) + if name in xdr.structs: + xdr.error("Structure {:s} already exists".format(name)) + else: + s = xdr_type(xdr, name=name, c_name="struct " + name, + basic=xdr_basic.struct, members=body) + xdr.structs[name] = s + xdr.all_structs.append(s) + xdr.add_type(name, s) + xdr.debug("New struct", name) + +def p_type_def_3(t): + '''type_def : UNION ID SWITCH LPAREN type_specifier ID RPAREN union_body SEMI''' + name = t[2] + body = t[8] + global xdr + xdr.lineno = t.lineno(2) + if name in xdr.structs: + xdr.error("Structure {:s} already exists".format(name)) + else: + s = xdr_type(xdr, name=name, c_name="struct " + name, + basic=xdr_basic.union, members=body) + s.selector_type = t[5] + s.selector_name = t[6] + xdr.structs[name] = s + xdr.all_structs.append(s) + xdr.add_type(name, s) + xdr.debug("New union", name) + +############################################################################### +# +# Type specification +# +def p_declaration_1(t): + '''declaration : type_specifier ID''' + typespec = t[1] + name = t[2] + global xdr + xdr.lineno = t.lineno(2) + t[0] = xdr_member(name, typespec, xdr); + +def p_declaration_2(t): + '''declaration : type_specifier STAR ID''' + # We ignore the pointer type marker + typespec = t[1] + name = t[3] + global xdr + xdr.lineno = t.lineno(3) + ty = xdr_type(xdr, base=typespec) + t[0] = xdr_member(name, ty, xdr) + +def p_declaration_3(t): + '''declaration : type_specifier ID LSQUARE value RSQUARE''' + typespec = t[1] + name = t[2] + array_size = t[4] + if not isinstance(typespec, xdr_type): + raise RuntimeError("Type is not type" + str(typespec)) + global xdr + xdr.lineno = t.lineno(2) + ty = xdr_type(xdr, base=typespec, array=xdr_array.fixed, dim=array_size) + t[0] = xdr_member(name, ty, xdr) + +def p_declaration_4(t): + '''declaration : type_specifier ID LT optional_value GT''' + typespec = t[1] + name = t[2] + max_count = t[4] + global xdr + xdr.lineno = t.lineno(2) + ty = xdr_type(xdr, base=typespec, array=xdr_array.bulk, max_count=max_count) + t[0] = xdr_member(name, ty, xdr) + +def p_declaration_5(t): + '''declaration : type_specifier STAR ID LT optional_value GT''' + typespec = t[1] + name = t[3] + max_count = t[5] + global xdr + xdr.lineno = t.lineno(3) + ty = xdr_type(xdr, base=typespec, array=xdr_array.bulk, max_count=max_count) + t[0] = xdr_member(name, ty, xdr) + +def p_declaration_6(t): + '''declaration : type_specifier LT optional_value GT STAR ID''' + typespec = t[1] + max_count = t[3] + name = t[6] + global xdr + xdr.lineno = t.lineno(6) + ty = xdr_type(xdr, base=typespec, array=xdr_array.bulk, max_count=max_count) + t[0] = xdr_member(name, ty, xdr) + +def p_declaration_7(t): + '''declaration : type_blob ID''' + typespec = t[1] + name = t[2] + global xdr + xdr.lineno = t.lineno(2) + t[0] = xdr_member(name, typespec, xdr); + +def p_declaration_8(t): + '''declaration : type_blob STAR ID''' + # We ignore the pointer type marker + typespec = t[1] + name = t[3] + global xdr + xdr.lineno = t.lineno(3) + ty = xdr_type(xdr, base=typespec) + t[0] = xdr_member(name, ty, xdr) + +def p_declaration_9(t): + '''declaration : type_blob ID LSQUARE value RSQUARE''' + typespec = t[1] + name = t[2] + array_size = t[4] + if not isinstance(typespec, xdr_type): + raise RuntimeError("Type is not type" + str(typespec)) + global xdr + xdr.lineno = t.lineno(2) + ty = xdr_type(xdr, base=typespec, array=xdr_array.fixed, dim=array_size) + t[0] = xdr_member(name, ty, xdr) + +def p_declaration_10(t): + '''declaration : type_blob ID LT optional_value GT''' + typespec = t[1] + name = t[2] + max_obj = t[4] + global xdr + xdr.lineno = t.lineno(2) + ty = xdr_type(xdr, base=typespec, max_obj=max_obj) + t[0] = xdr_member(name, ty, xdr) + +def p_declaration_11(t): + '''declaration : type_blob STAR ID LT optional_value GT''' + typespec = t[1] + name = t[3] + max_obj = t[5] + global xdr + xdr.lineno = t.lineno(3) + ty = xdr_type(xdr, base=typespec, max_obj=max_obj) + t[0] = xdr_member(name, ty, xdr) + +def p_declaration_12(t): + '''declaration : type_blob LT optional_value GT STAR ID''' + typespec = t[1] + max_count = t[3] + name = t[6] + global xdr + xdr.lineno = t.lineno(6) + ty = xdr_type(xdr, base=typespec, array=xdr_array.bulk, max_count=max_count) + t[0] = xdr_member(name, ty, xdr) + +def p_type_blob(t): + '''type_blob : STRING + | OPAQUE''' + name = t[1] + global xdr + xdr.lineno = t.lineno(1) + t[0] = xdr.types[name] + if not isinstance(t[0], xdr_type): + raise RuntimeError("Type is not type" + typespec); + +def p_type_specifier_1(t): + '''type_specifier : CHAR + | INT8_T + | INT16_T + | INT32_T + | INT64_T + | UINT8_T + | UINT16_T + | UINT32_T + | UINT64_T + | OPR_UUID''' + name = t[1] + global xdr + xdr.lineno = t.lineno(1) + t[0] = xdr.types[name] + if not isinstance(t[0], xdr_type): + raise RuntimeError("Type is not type" + typespec); + +def p_type_specifier_2(t): + '''type_specifier : ID''' + name = t[1] + global xdr + xdr.lineno = t.lineno(1) + t[0] = xdr.get_type(t[1]) + +def p_type_specifier_3(t): + '''type_specifier : struct_type_spec''' + t[0] = t[1] + +def p_type_specifier_4(t): + '''type_specifier : STRUCT ID''' + name = t[2] + global xdr + xdr.lineno = t.lineno(2) + t[0] = xdr.get_type(name) + + +############################################################################### +# +# Structure specification +# +def p_struct_type_spec(t): + '''struct_type_spec : STRUCT struct_body''' + t[0] = xdr_type(xdr, name="".format(t.lineno), c_name="struct", + compound=xdr_compound.struct, basic_type="struct", members=t[2]) + +def p_struct_body(t): + '''struct_body : LBRACE member_list RBRACE''' + t[0] = t[2] + +def p_member_list_1(t): + '''member_list : declaration SEMI''' + t[0] = [t[1]] + +def p_member_list_2(t): + '''member_list : declaration SEMI member_list''' + t[0] = [t[1]] + t[3] + +def p_union_body(t): + '''union_body : LBRACE union_case_list RBRACE''' + t[0] = t[2] + +def p_union_case(t): + '''union_case : CASE ID COLON member_list''' + t[0] = xdr_union_case(xdr, tag=t[2], members=t[4]) + +def p_union_case_list_1(t): + '''union_case_list : union_case''' + t[0] = [t[1]] + +def p_union_case_list_2(t): + '''union_case_list : union_case union_case_list''' + t[0] = [t[1]] + t[2] + +############################################################################### +# +# Procedure specification +# +def p_proc_spec_1(t): + '''proc_spec : ID LPAREN parameters RPAREN EQUALS value SEMI''' + name = t[1] + params = t[3] + op = t[6] + global xdr + proc = xdr_proc(name, xdr, params, op) + xdr.add_proc(proc) + t[0] = proc + +def p_proc_spec_2(t): + '''proc_spec : ID LPAREN parameters RPAREN SPLIT EQUALS value SEMI''' + name = t[1] + params = t[3] + op = t[7] + global xdr + proc = xdr_proc(name, xdr, params, op, split=True) + xdr.add_proc(proc) + t[0] = proc + +def p_proc_spec_3(t): + '''proc_spec : ID LPAREN parameters RPAREN MULTI EQUALS value SEMI''' + name = t[1] + params = t[3] + op = t[7] + global xdr + proc = xdr_proc(name, xdr, params, op, multi=True) + xdr.add_proc(proc) + t[0] = proc + +def p_parameters_0(t): + '''parameters : ''' + t[0] = [] + +def p_parameters_1(t): + '''parameters : parameter''' + t[0] = [t[1]] + +def p_parameters_2(t): + '''parameters : parameter COMMA parameters''' + t[0] = [t[1]] + t[3] + +def p_parameter_1(t): + '''parameter : IN declaration''' + t[2].direction = xdr_direction.IN + t[0] = t[2] + +def p_parameter_2(t): + '''parameter : INOUT declaration''' + t[2].direction = xdr_direction.INOUT + t[0] = t[2] + +def p_parameter_3(t): + '''parameter : OUT declaration''' + t[2].direction = xdr_direction.OUT + t[0] = t[2] + +############################################################################### +# +# Miscellany +# +def p_empty(t): + 'empty :' + +def p_error(t): + global error_occurred + error_occurred = True + if t: + print(t) + print("Syntax error at '{:s}' (lineno {:d})".format(t.value, t.lineno)) + else: + print("Syntax error: unexpectedly hit EOF") + +########################################################################## +# # +# Global Variables # +# # +########################################################################## + +error_occurred = False # Parsing of infile status + + + +########################################################################## +# # +# C Preprocessor # +# # +########################################################################## +def cpp(data, filename): + # Remove C comments + lines = data.splitlines() + inside_C_comment = False + inside_error_code_list = False + + for i in range(0, len(lines)): + l = lines[i] + begin = None + if inside_C_comment: + begin = 0 + cursor = 0 + + # Capture the error code list + # + if not inside_C_comment: + if l == "/* Error codes */" and not inside_error_code_list: + inside_error_code_list = True + lines[i] = "__BEGIN_ERROR_CODES__" + continue + + if inside_error_code_list and l == "": + inside_error_code_list = False + lines[i] = "__END_ERROR_CODES__" + continue + + while True: + if inside_C_comment: + p = l.find("*/", cursor) + if p == -1: + l = l[:begin] + lines[i] = l + break + l = l[:begin] + l[p + 2:] + lines[i] = l + cursor = begin + begin = None + inside_C_comment = False + else: + p = l.find("/*"); + if p == -1: + break + inside_C_comment = True + begin = p + cursor += 2 + + if inside_error_code_list: + lines.append("__END_ERROR_CODES__") + + # Remove C++ comments + for i in range(0, len(lines)): + l = lines[i] + p = l.find("//") + if p != -1: + lines[i] = l[:p] + + # Remove directives + skipping = False + for i in range(0, len(lines)): + l = lines[i] + if skipping: + if l == "#endif": + skipping = False; + lines[i] = "" + continue + if l == "#if 0": + skipping = True; + lines[i] = "" + continue + if (l.startswith("#include") or + l.startswith("#define") or + l.startswith("%")): + lines[i] = "" + continue + + lines.insert(0, "__NEWFILE__ {:s}".format(filename)) + return "\n".join(lines) + +########################################################################## +# # +# Main Loop # +# # +########################################################################## +xdr = xdr_context() +load_basic_types(xdr) +#xdr.add_constant("RXRPC_SECURITY_PLAIN", "0") +#xdr.add_constant("RXRPC_SECURITY_AUTH", "1") +#xdr.add_constant("RXRPC_SECURITY_ENCRYPT", "2") + +# Parse the input data with yacc +import ply.yacc as yacc +yacc.yacc(debug=0) + +def parse(infile, debug=False): + global xdr + xdr.source = infile + xdr.lineno = 0 + + f = open(infile, encoding="utf-8") + data = f.read() + f.close() + + data = cpp(data, infile) + + print("Parsing", infile); + global yacc + yacc.parse(data, debug=debug) + + if error_occurred: + print + print("Error occurred, did not write output files") + return False + return True + +def gen_abort_name(package, ac): + pname = package.name + acname = ac.name + #if acname.startswith(pname): + # acname = acname[len(pname):] + #if acname.startswith("_"): + # acname = acname[1:] + return acname + +# +# Section: main +# +def run(files, out_file_prefix): + for f in files: + if not parse(f): + break + + xdr.finished_parsing() + + o = file_generator(xdr, out_file_prefix) + o.rxhdr("/* AUTOGENERATED */\n") + o.rxhdr("#ifndef _RXGEN_AFS_XG_H\n"); + o.rxhdr("#define _RXGEN_AFS_XG_H\n"); + o.rxhdr("\n") + #o.rxhdr("#define _XOPEN_SOURCE\n"; + o.rxhdr("#include \n") + o.rxhdr("#include \n") + o.rxhdr("#include \"rxrpc.H\"\n") + o.rxhdr("\n") + o.rxhdr("namespace kafs::afs {\n") + + o.rxsrc("/* AUTOGENERATED */\n") + o.rxsrc("#include \"afs_xg.H\"\n") + o.rxsrc("\n") + o.rxsrc("namespace kafs::afs {\n") + + # Declare constants + o.rxhdr("\n") + for name in xdr.all_constants: + c = xdr.constants[name] + o.rxhdr("constexpr int ", c.name, " = ", c.value, ";\n") + + # Declare structure types + for s in xdr.all_structs: + emit_struct_decl(o, s) + + o.rxhdr("\n") + o.rxhdr("namespace xdr {\n") + for s in xdr.all_structs: + emit_struct_encdec_decl(o, s); + o.rxhdr("\n") + o.rxhdr("} /* end namespace xdr */\n") + + o.rxsrc("\n") + o.rxsrc("namespace xdr {\n") + for s in xdr.all_structs: + emit_struct_encdec(o, s); + o.rxsrc("\n") + o.rxsrc("} /* end namespace xdr */\n") + + # Emit RPC call functions. For this we need to classify parameters according + # to input and output usage and work out how big the RPC messages will be. + # + for package in xdr.packages.values(): + o.rxhdr("\n") + o.rxhdr("namespace ", package.name, " {\n") + o.rxsrc("\n") + o.rxsrc("namespace ", package.name, " {\n") + + for f in package.procs: + # Dump the banner comment block + o.rxsrc("\n") + o.rxsrc("/*\n") + o.rxsrc(" * RPC Call ", f.name, "\n") + o.rxsrc(" */\n") + + # Find the Operation ID + if not f.opcode: + raise RuntimeError("Operation ID unspecified for " + f.name) + + # Filter the parameters into request and response + f.request = list() + f.response = list() + + for p in f.params: + o.where(f.name + ":" + p.name) + if p.is_single_basic(): + pass + elif p.is_compound(): + pass + elif p.is_single_string() or p.is_single_opaque(): + # Could validate max_obj attribute + pass + elif p.is_bulk(): + pass + else: + raise RuntimeError("Unsupported param type \"" + str(p.ty) + "\"") + + if p.direction == xdr_direction.IN: + f.request.append(p) + elif p.direction == xdr_direction.OUT: + f.response.append(p) + elif p.direction == xdr_direction.INOUT: + f.request.append(p) + f.response.append(p) + + emit_func_prototype(o, f) + emit_func_encode(o, f, "request") + emit_func_encode(o, f, "response") + emit_func_send(o, f, "request") + emit_func_server_stub(o, f) + emit_func_receive_request(o, f) + emit_func_receive_reply(o, f) + emit_func_sync_client_call(o, f) + + # Emit RPC service switch functions. + if package.procs: + emit_package_switch(o, package) + + o.rxhdr("\n") + o.rxhdr("} /* end namespace ", package.name, " */\n") + o.rxsrc("\n") + o.rxsrc("} /* end namespace ", package.name, " */\n") + + # Emit an abort throwing function + o.rxhdr("extern void afs_throw_abort(int ac, const char *op=NULL);\n"); + o.rxsrc("\n") + o.rxsrc("void afs_throw_abort(int ac, const char *op)\n"); + o.rxsrc("{\n") + o.rxsrc("\tswitch (ac) {\n") + for package in xdr.packages.values(): + if package.abort_codes: + pabort = "Abort" + package.name; + o.rxhdr("\n") + o.rxhdr("namespace ", package.name, " {\n") + o.rxhdr("\tclass ", pabort, " : public rxrpc::rx_abort { public:\n") + o.rxhdr("\t\t", pabort, "(int ac, const char *sym, const char *desc, const char *op)\n"), + o.rxhdr("\t\t\t: rx_abort(ac, sym, desc, op) {}\n") + o.rxhdr("\t};\n") + for ac in package.abort_codes: + acclass = "Abort" + gen_abort_name(package, ac) + o.rxhdr("\tclass ", acclass, " : public ", pabort, " { public:\n") + o.rxhdr("\t\t", acclass, "(const char *op = NULL)\n") + o.rxhdr("\t\t\t: ", pabort, "(", ac.name, ", \"", ac.name, "\", \"\", op) {}\n") + o.rxhdr("\t};\n") + o.rxhdr("}\n") + + for ac in package.abort_codes: + acclass = "Abort" + gen_abort_name(package, ac) + o.rxsrc("\tcase ", ac.name, ":\tthrow ", package.name, "::", acclass, "(op);\n") + + o.rxsrc("\tdefault: rxrpc::throw_abort(ac, op);\n") + o.rxsrc("\t}\n") + o.rxsrc("}\n") + o.rxsrc("\n") + o.rxsrc("} /* end namespace kafs::afs */\n") + + o.rxhdr("\n") + o.rxhdr("} /* end namespace kafs::afs */\n") + o.rxhdr("\n") + o.rxhdr("#endif /* _RXGEN_AFS_XG_H */\n"); + +# +# Drive the program if executed as a standalone process +# +if __name__ == "__main__": + if len(sys.argv) < 2: + print("Usage: {:s} *".format(sys.argv[0])) + sys.exit(1) + + run(sys.argv[1:], "") diff --git a/rxgen/rxgen_bits.py b/rxgen/rxgen_bits.py new file mode 100644 index 0000000..cf11cb4 --- /dev/null +++ b/rxgen/rxgen_bits.py @@ -0,0 +1,603 @@ +# Bits for rxgen implementation +# -*- coding: utf-8 -*- + +__copyright__ = """ +Copyright (C) 2020 Red Hat, Inc. All Rights Reserved. +Written by David Howells (dhowells@redhat.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public Licence version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public Licence for more details. + +You should have received a copy of the GNU General Public Licence +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +import sys +from enum import Enum + +class xdr_basic(Enum): + int32 = 1 + int64 = 2 + string = 3 + opaque = 4 + struct = 5 + union = 6 + opr_uuid = 7 + +class xdr_array(Enum): + # single object is represented by None + fixed = 1 + bulk = 2 + +class xdr_direction(Enum): + IN = 1 + OUT = 2 + INOUT = 3 + +class xdr_context: + def __init__(self): + self.source = None # Current source file + self.lineno = None # Current line number + self.types = dict() # List of types + self.typedefs = dict() # List of type aliases + self.structs = dict() # Structure definitions + self.struct_sizes = dict() # Structure sizes + self.all_structs = list() # Structures in order of declaration + self.constants = dict() # Constants + self.packages = dict() # Packages + self.pkg = None # Current package + self.abort_syms = dict() # Abort symbol to code map + self.abort_ids = dict() # Abort code to symbol map + self.abort_count = 0 # Number of abort codes + self.error_codes = False # True if parsing error code list + self.debug_level = False + self.zero = xdr_constant("0", "0", self) + self.typespecs = dict() + + def debug(self, *s): + if (self.debug_level): + print(*s) + + def error(self, *s): + print("{:s}:{:d}: Error".format(self.source, self.lineno), *s) + + def add_package(self, name, prefix): + if name in self.packages: + self.error("Package {:s} already exists".format(name)) + else: + pkg = xdr_package(name, prefix, self) + self.packages[name] = pkg + self.pkg = pkg + self.debug("New package", name) + + def add_error_codes(self, codes): + self.abort_count += len(codes) + self.pkg.abort_codes += codes + for code in codes: + if not isinstance(code, xdr_constant): + raise TypeError("Expecting xdr_constant, got " + str(type(code))) + self.abort_syms[code.name] = code + value = code.value + suffix = "" + if value.endswith("L"): + value = value[0:-1] + suffix = "L" + if int(value, 0) < 0: + value = str(int(value, 0) + 0x100000000) + code.u32 = int(value, 0) + self.abort_ids[code.u32] = code + + def add_constant(self, name, value): + if name in self.constants: + self.error("Constant {:s} already exists".format(name)) + elif isinstance(value, xdr_constant): + self.constants[name] = xdr_constant(name, value.value, self) + else: + self.constants[name] = xdr_constant(name, value, self) + self.debug("New constant", name) + return self.constants[name] + + def add_number(self, value): + if value == 0: + return self.zero + return xdr_constant(value, value, self) + + def get_constant(self, name): + if name not in self.constants: + self.error("Constant {:s} undefined".format(name)) + return self.zero + return self.constants[name] + + def add_type(self, name, typespec): + if name in self.types: + self.error("Type {:s} already exists".format(name)) + else: + self.types[name] = typespec + self.debug("New type", name) + return self.types[name] + + def add_type_alias(self, name, alias): + if name in self.typedefs: + self.error("Type alias {:s} already exists".format(name)) + return self.typedefs[name] + if name in self.structs: + self.error("struct {:s} already exists, cannot shadow with alias".format(name)) + return alias + + self.typedefs[name] = alias + self.debug("New typedef", name) + + def get_type(self, name): + if name in self.types: + typespec = self.types[name] + elif name in self.typedefs: + typespec = self.typedefs[name].typespec + else: + raise RuntimeError("Undefined type requested '" + name + "'"); + if not isinstance(typespec, xdr_type): + raise TypeError("Retrieved type object is not xdr_type " + name + str(typespec)); + typespec.referenced = True + return typespec + + def add_proc(self, proc): + if not isinstance(proc, xdr_proc): + raise KeyError("proc is not an xdr_proc ", name, proc); + name = proc.name + if name in self.pkg.proc_names: + self.error("Proc {:s} already exists".format(name)) + return self.pkg.proc_names[name] + else: + self.pkg.proc_names[name] = proc + self.pkg.procs.append(proc) + self.debug("New proc", name) + return proc + + def finished_parsing(self): + self.all_constants = list(self.constants.keys()) + self.all_constants.sort() + self.all_types = list(self.types.keys()) + self.all_types.sort() + + +############################################################################### +# +# Token base class +# +############################################################################### +class token_base(object): + def __init__(self): + self.source = None + self.lineno = None + self.name = None + self.type = None + + def __str__(self): + return "{:s} {:s} at {:s}:{:d}".format( + self.type, self.name, self.source, self.lineno) + +############################################################################### +# +# XDR package +# +############################################################################### +class xdr_package(token_base): + """The result of 'package ID'""" + def __init__(self, name, prefix, xdr): + self.type = 'package' + self.name = name + self.source = xdr.source + self.lineno = xdr.lineno + self.prefix = prefix + self.abort_codes = list() + self.procs = list() # RPC procedures in declaration order + self.proc_names = dict() # RPC procedure name uniquifier + +############################################################################### +# +# XDR constant +# +############################################################################### +class xdr_constant(token_base): + """The result of 'CONST ID EQUALS constant SEMI'""" + def __init__(self, name, value, xdr): + self.type = 'const' + self.name = name + self.value = value + self.source = xdr.source + self.lineno = xdr.lineno + if not isinstance(value, str): + raise RuntimeError("Value should be a string"); + + def get_value(self): + if isinstance(self.value, xdr_constant): + return self.value.get_value() + return int(self.value) + + def __str__(self): + return self.value + + def __repr__(self): + return "constant {:s}={:s} at {:s}:{:d}".format( + self.name, self.value, self.source, self.lineno) + +############################################################################### +# +# XDR type definition +# +# Each type is specified by a hash of the following elements: +# +# name Name of non-anonymous type (char, {u,}int{8,16,32,64}_t, struct name) +# basic Basic XDR type (int32, int64, string, opaque, struct) +# array Array class (single, array, bulk) +# dim Number of elements in fixed-size array (or None) +# max_obj Max size of string/opaque +# max_count Max elements in bulk array +# members Members of struct +# source/lineno Where defined in which file +# +# Members/parameters take a copy of their parent type's hash and add: +# +# name Member or parameter name (overrides type name) +# direction Direction of parameter (IN, OUT or INOUT) +# +############################################################################### +class xdr_type(token_base): + def __init__(self, xdr, base=None, name=None, c_name=None, + basic=None, array=None, dim=None, max_obj=None, max_count=None, + members=None): + if not isinstance(xdr, xdr_context): + raise TypeError("XDR context isn't") + if array: + if not isinstance(array, xdr_array): + raise TypeError("Invalid array class") + if array == xdr_array.fixed and not dim: + raise RuntimeError("Dimension required for fixed-size array") + if dim and max_count: + raise RuntimeError("Can't be both variable and fixed-size array") + elif basic == "string" or basic == "opaque" or \ + base and (base.is_string() or base.is_opaque): + if dim: + raise RuntimeError("Can't specify fixed dimension limits on string/opaque") + else: + if dim or max_obj or max_count: + raise RuntimeError("Can't specify dimension limits on non-array") + + self.source = xdr.source + self.lineno = xdr.lineno + self.referenced = False + self.flat = None + + if base: + if name: + raise RuntimeError("Type basic name can't be changed on an extant type") + if c_name: + raise RuntimeError("Type C name can't be changed on an extant type") + if basic: + raise RuntimeError("Basic type can't be changed on an extant type") + if members: + raise RuntimeError("Members can't be added to an extant type") + if not isinstance(base, xdr_type): + raise TypeError("Base type is not a type", type(base)) + base.referenced = True + self.referenced = True + self.name = base.name + self.c_name = base.c_name + self.basic = base.basic + self.array = base.array + self.dim = base.dim + self.max_count = base.max_count + self.max_obj = base.max_obj + self.members = base.members + + if array: + if base.array: + xdr.error("Array-of-array not supported") + self.array = array + self.dim = dim + self.max_count = max_count + elif (self.is_single_string() or self.is_single_opaque()) and max_obj: + if self.max_obj: + xdr.error("Maximum size already set on string/opaque") + self.max_obj = max_obj + else: + if name and not isinstance(name, str): + raise TypeError("Type name is not a string") + if c_name and not isinstance(c_name, str): + raise TypeError("C type name is not a string") + if basic and not isinstance(basic, xdr_basic): + raise TypeError("Invalid basic XDR type") + self.name = name + self.c_name = c_name + self.basic = basic + self.array = array + self.array = array + self.dim = dim + self.max_obj = max_obj + self.max_count = max_count + self.members = members + if members: + if not isinstance(members, list): + raise RuntimeError("Members should be a list") + + if not self.basic: + raise RuntimeError("basic type unset") + + typespec = str(self) + if typespec not in xdr.typespecs: + xdr.typespecs[typespec] = self + + + def is_int(self): + return self.basic == xdr_basic.int32 or self.basic == xdr_basic.int64 + + def is_int32(self): + return self.basic == xdr_basic.int32 + + def is_int64(self): + return self.basic == xdr_basic.int64 + + def is_string(self): + return self.basic == xdr_basic.string + + def is_opaque(self): + return self.basic == xdr_basic.opaque + + def is_struct(self): + return self.basic == xdr_basic.struct + + def is_union(self): + return self.basic == xdr_basic.union + + def is_compound(self): + return self.is_struct() or self.is_union() + + def is_uuid(self): + return self.basic == xdr_basic.opr_uuid + + def is_single_int(self): + return not self.array and self.is_int() + + def is_single_int32(self): + return not self.array and self.is_int32() + + def is_single_int64(self): + return not self.array and self.is_int64() + + def is_single_string(self): + return not self.array and self.is_string() + + def is_single_opaque(self): + return not self.array and self.is_opaque() + + def is_single_basic(self): + return not self.array and not self.is_compound() + + def is_single_struct(self): + return not self.array and self.is_struct() + + def is_single_union(self): + return not self.array and self.is_union() + + def is_single_compound(self): + return not self.array and self.is_compound() + + def is_single_uuid(self): + return not self.array and self.is_uuid() + + def is_single(self): + return not self.array + + def is_array(self): + return self.array == xdr_array.fixed + + def is_char_array(self): + return self.array == xdr_array.fixed and self.name == "char" + + def is_int32_array(self): + return self.array == xdr_array.fixed and self.is_int32() + + def is_int64_array(self): + return self.array == xdr_array.fixed and self.is_int64() + + def is_int_array(self): + return self.array == xdr_array.fixed and self.is_int() + + def is_struct_array(self): + return self.array == xdr_array.fixed and self.is_struct() + + def is_bulk(self): + return self.array == xdr_array.bulk + + def is_bulk_char(self): + return self.is_bulk() and self.name == "char" + + def is_bulk_int32(self): + return self.is_bulk() and self.is_int32() + + def is_bulk_int64(self): + return self.is_bulk() and self.is_int64() + + def is_bulk_int(self): + return self.is_bulk() and self.is_int() + + def is_bulk_struct(self): + return self.is_bulk() and self.is_struct() + + def is_flat(self): + if self.flat != None: + return self.flat + if self.is_bulk() or self.is_string() or self.is_opaque(): + self.flat = False + return False + if self.members: + for i in self.members: + if not i.is_flat(): + self.flat = False + return False + self.flat = True + return True + + def what_max_obj(self): + if self.max_obj != None: + return self.max_obj + return "UINT_MAX" + + def what_max_count(self): + if self.max_count != None: + return self.max_count + return "UINT_MAX" + + def __str__(self): + t = self.name + if self.is_array(): + t += "[{:s}]".format(str(self.dim)) + elif self.is_bulk() or self.is_string() or self.is_opaque(): + if self.max_count: + t += "<{:s}>".format(str(self.max_count)) + if self.max_obj: + t += "<{:s}>".format(str(self.max_obj)) + else: + t += "<>" + return t + +############################################################################### +# +# XDR structure member definition +# +############################################################################### +class xdr_member(token_base): + """A structure member""" + def __init__(self, name, typespec, xdr): + self.typespec = typespec + self.ty = typespec + self.dim = typespec.dim + self.max_obj = typespec.max_obj + self.max_count = typespec.max_count + self.name = name + self.source = xdr.source + self.lineno = xdr.lineno + self.special = None + + def is_int(self): return self.ty.is_int() + def is_int32(self): return self.ty.is_int32() + def is_int64(self): return self.ty.is_int64() + def is_string(self): return self.ty.is_string() + def is_opaque(self): return self.ty.is_opaque() + def is_struct(self): return self.ty.is_struct() + def is_union(self): return self.ty.is_union() + def is_compound(self): return self.ty.is_compound() + def is_single_int(self): return self.ty.is_single_int() + def is_single_int32(self): return self.ty.is_single_int32() + def is_single_int64(self): return self.ty.is_single_int64() + def is_single_string(self): return self.ty.is_single_string() + def is_single_opaque(self): return self.ty.is_single_opaque() + def is_single_basic(self): return self.ty.is_single_basic() + def is_single_struct(self): return self.ty.is_single_struct() + def is_single_union(self): return self.ty.is_single_union() + def is_single_uuid(self): return self.ty.is_single_uuid() + def is_single_compound(self): return self.ty.is_single_compound() + def is_single(self): return self.ty.is_single() + def is_array(self): return self.ty.is_array() + def is_char_array(self): return self.ty.is_char_array() + def is_int32_array(self): return self.ty.is_int32_array() + def is_int64_array(self): return self.ty.is_int64_array() + def is_int_array(self): return self.ty.is_int_array() + def is_struct_array(self): return self.ty.is_struct_array() + def is_bulk(self): return self.ty.is_bulk() + def is_bulk_char(self): return self.ty.is_bulk_char() + def is_bulk_int32(self): return self.ty.is_bulk_int32() + def is_bulk_int64(self): return self.ty.is_bulk_int64() + def is_bulk_int(self): return self.ty.is_bulk_int() + def is_bulk_struct(self): return self.ty.is_bulk_struct() + def is_flat(self): return self.ty.is_flat() + def what_max_obj(self): return self.ty.what_max_obj() + def what_max_count(self): return self.ty.what_max_count() + + +############################################################################### +# +# XDR type alias definition +# +############################################################################### +class xdr_type_alias(token_base): + """A type alias""" + def __init__(self, name, typespec, xdr): + if not isinstance(typespec, xdr_type): + raise TypeError("Base type is not a type") + self.name = name + self.typespec = typespec + self.source = xdr.source + self.lineno = xdr.lineno + +############################################################################### +# +# XDR union case definition +# +############################################################################### +class xdr_union_case(token_base): + """An XDR union case""" + def __init__(self, xdr, tag, members): + self.source = xdr.source + self.lineno = xdr.lineno + self.tag = tag + self.members = members + +############################################################################### +# +# XDR procedure member definition +# +############################################################################### +class xdr_proc(token_base): + """An XDR procedure""" + def __init__(self, name, xdr, params, opcode, multi=False, split=False): + self.package = xdr.pkg + self.name = name + self.source = xdr.source + self.lineno = xdr.lineno + self.params = params + self.opcode = opcode + self.multi = multi + self.split = split + +############################################################################### +# +# Generated file writer class +# +############################################################################### +class file_generator: + """File generator class""" + def __init__(self, xdr, prefix): + self.xdr = xdr + self._rxhdr = open(prefix + "afs_xg.H", "w", encoding="utf-8") + self._rxsrc = open(prefix + "afs_xg.C", "w", encoding="utf-8") + + def rxhdr(self, *va): + for i in va: + self._rxhdr.write(str(i)) + + def rxsrc(self, *va): + for i in va: + self._rxsrc.write(str(i)) + + def rxhdrf(self, fmt, *va): + self._rxhdr.write(fmt.format(*va)) + + def rxsrcf(self, fmt, *va): + self._rxsrc.write(fmt.format(*va)) + + def where(self, loc): + self._where = loc + ": " + + def error(self, *va): + if self._where: + sys.stdout.write(self._where) + for i in va: + sys.stdout.write(str(i)) + sys.stdout.write("\n") -- 2.49.0