--- /dev/null
+#!/usr/bin/python3
+#
+# Emit C structure
+# -*- coding: utf-8 -*-
+
+__copyright__ = """
+Copyright (C) 2015 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 structure encoders and decoders predeclarations
+#
+###############################################################################
+def emit_struct_encdec_decl(o, struct):
+ o.rxsrc("/* ", struct.name, " XDR size ", struct.xdr_size, " */\n")
+
+###############################################################################
+#
+# Emit structure encoders and decoders
+#
+###############################################################################
+def emit_struct_encdec(o, struct):
+ # Write out a C structure definition for this type
+ o.rxhdr("struct ", struct.name, " {\n")
+ for m in struct.members:
+ ty = m.typespec
+ o.where(struct.name + "::" + m.name)
+ if ty.is_single():
+ o.rxhdr("\t", ty.c_name, "\t", m.name)
+ elif ty.is_int_array() or ty.is_struct_array():
+ o.rxhdr("\t", ty.c_name, "\t", m.name, "[", ty.dim, "]")
+ else:
+ o.error("Unsupported type '", ty, "'\n")
+ o.rxhdr(";\n")
+ o.rxhdr("};\n")
+
+ # Write an encoding function
+ o.rxhdr("extern void rxgen_encode_", struct.name,
+ "(struct rx_call *call, const struct ", struct.name, " *p);\n")
+
+ o.rxsrc("void rxgen_encode_", struct.name,
+ "(struct rx_call *call, const struct ", struct.name, " *p)\n")
+ o.rxsrc("{\n")
+
+ for m in struct.members:
+ ty = m.typespec
+ if ty.is_array():
+ o.rxsrc("\tint i;\n\n")
+ break
+
+ for m in struct.members:
+ ty = m.typespec
+ o.where(struct.name + "::" + m.name)
+ if ty.is_single_int32():
+ o.rxsrc("\trxrpc_enc(call, p->", m.name, ");\n")
+ elif ty.is_single_struct():
+ o.rxsrc("\trxgen_encode_", ty.name, "(call, &p->", m.name, ");\n")
+ elif ty.is_array():
+ o.rxsrc("\tfor (i = 0; i < ", ty.dim.name, "; i++)\n")
+ if ty.is_int32_array():
+ o.rxsrc("\t\trxrpc_enc(call, p->", m.name, "[i]);\n")
+ elif ty.is_struct_array():
+ o.rxsrc("\t\trxgen_encode_", ty.name, "(call, &p->", m.name, "[i]);\n")
+ else:
+ o.error("No encoding for array type '", ty, "'")
+ else:
+ o.error("No encoding for type '", ty, "'")
+
+ o.rxsrc("}\n")
+ o.rxsrc("\n")
+
+ # Write a decoding function
+ o.rxhdr("extern void rxgen_decode_", struct.name,
+ "(struct rx_call *call, struct ", struct.name, " *p);\n")
+
+ o.rxsrc("void rxgen_decode_", struct.name,
+ "(struct rx_call *call, struct ", struct.name, " *p)\n")
+ o.rxsrc("{\n")
+
+ for m in struct.members:
+ ty = m.typespec
+ if ty.is_array():
+ o.rxsrc("\tint i;\n\n")
+ break
+
+ for m in struct.members:
+ ty = m.typespec
+ o.where(struct.name + "::" + m.name)
+ if ty.is_single_int32():
+ o.rxsrc("\tp->", m.name, " = rxrpc_dec(call);\n")
+ elif ty.is_single_struct():
+ o.rxsrc("\trxgen_decode_", ty.name, "(call, &p->", m.name, ");\n")
+ elif ty.is_array():
+ o.rxsrc("\tfor (i = 0; i < ", ty.dim.name, "; i++)\n")
+ if ty.is_int32_array():
+ o.rxsrc("\t\tp->", m.name, "[i] = rxrpc_dec(call);\n")
+ elif ty.is_struct_array():
+ o.rxsrc("\t\trxgen_decode_", ty.name, "(call, &p->", m.name, "[i]);\n")
+ else:
+ o.error("No decoding for array type '", ty, "'")
+ else:
+ o.error("No decoding for type '", ty, "'")
+
+ o.rxsrc("}\n")
}
}
- if ($phase->{type} ne "blob" || $phase->{type} ne "bulk") {
+ if ($phase->{type} ne "blob" && $phase->{type} ne "bulk") {
print RXOUT "\t\tif (rxrpc_post_dec(call) < 0)\n";
print RXOUT "\t\t\treturn -1;\n";
}
} elsif ($p->{class} eq "blob") {
print RXOUT "\trxrpc_enc_blob(call, ", $p->{name}, ", nr__", $p->{name}, ");\n";
print RXOUT "\trxrpc_enc_align(call);\n";
- } elsif ($p->{class} eq "blob") {
- print RXOUT "\trxrpc_enc(call, nr__", $p->{name}, ");\n";
- print RXOUT "\tcall->blob_size = nr__", $p->{name}, ";\n";
- print RXOUT "\tfor (call->blob_offset = 0; call->blob_offset < call->blob_size; call->blob_offset++) {\n";
- if ($p->{elem}->{class} eq "struct") {
- print RXOUT "\t\tstruct ", $p->{elem}->{type}, " x;\n";
- } else {
- print RXOUT "\t\t", $p->{elem}->{type}, " x;\n";
- }
- print RXOUT "\t\tcall->blob = &x;\n";
- print RXOUT "\t\tif (get__", $p->{name}, "(call, token__", $p->{name}, ") < 0)\n";
- print RXOUT "\t\t\tgoto error;\n";
- die $p->{where}, "No decoding for array type '$type'";
- print RXOUT "\t}\n";
} elsif ($p->{class} eq "bulk") {
print RXOUT "\trxrpc_enc(call, nr__", $p->{name}, ");\n";
print RXOUT "\tcall->bulk_count = nr__", $p->{name}, ";\n";
--- /dev/null
+#!/usr/bin/python3
+#
+# Emit C synchronous functions
+# -*- coding: utf-8 -*-
+
+__copyright__ = """
+Copyright (C) 2015 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)
+ protos = list()
+ protos.append("int " + func.name + "(\n")
+ send_request_protos = list()
+ send_response_protos = list()
+ recv_request_protos = list()
+ recv_response_protos = list()
+
+ # Arguments to pass when sending a call or processing a reply
+ send_args = list()
+ recv_args = list()
+
+ for p in func.params:
+ o.where(func.name + ":" + p.name)
+ ty = p.typespec
+ enclines = list()
+ declines = list()
+ args = list()
+
+ if ty.is_array():
+ raise RuntimeError("Array arg not supported")
+ elif ty.is_bulk():
+ # Encode
+ if ty.is_bulk_struct():
+ proto = "int (*get__" + p.name + ")(struct rx_call *call, void *token)"
+ else:
+ proto = "int (*get__" + p.name + ")(struct rx_call *call, void *token)"
+
+ enclines.append(proto)
+ enclines.append("void *token__" + p.name)
+ enclines.append("size_t nr__" + p.name)
+ args.append("get__" + p.name)
+ args.append("token__" + p.name)
+ args.append("nr__" + p.name)
+
+ # Decode
+ if ty.is_bulk_struct():
+ proto = "int (*alloc__" + p.name + ")(struct rx_call *call, void **token)"
+ args.append("alloc__" + p.name)
+ else:
+ proto = "int (*store__" + p.name + ")(struct rx_call *call, void **token)"
+ args.append("store__" + p.name)
+
+ declines.append(proto)
+ declines.append("void *token__" + p.name)
+ declines.append("size_t nr__" + p.name)
+ args.append("token__" + p.name)
+ elif ty.is_single_blob():
+ # Do we want to insert a "*" in the following?
+ proto = ty.c_name + " *" + p.name
+ enclines.append("size_t nr__" + p.name)
+ enclines.append("const " + proto)
+
+ declines.append("size_t nr__" + p.name)
+ declines.append("void *token__" + p.name)
+ declines.append("int (*alloc__" + p.name + ")(struct rx_call *call, void **token)")
+ args.append("nr__" + p.name)
+ args.append(p.name)
+ args.append("alloc__" + p.name)
+ else:
+ enc_const = ""
+ if not ty.is_single_int():
+ enc_const = "const "
+ proto = ty.c_name + " "
+ if not ty.is_single_int():
+ proto += "*"
+ proto += p.name
+ enclines.append(enc_const + proto)
+ declines.append(proto)
+ args.append(p.name)
+
+ if p.direction == xdr_direction.IN or p.direction == xdr_direction.INOUT:
+ send_request_protos += enclines
+ recv_request_protos += declines
+ send_args += args
+ if p.direction == xdr_direction.OUT or p.direction == xdr_direction.INOUT:
+ send_response_protos += enclines
+ recv_response_protos += declines
+ recv_args += args
+
+ o.rxhdr("\n")
+ o.rxhdr("/*\n")
+ o.rxhdr(" * ", func.name, "\n")
+ o.rxhdr(" */\n")
+
+ if recv_request_protos:
+ o.rxhdr("struct ", func.name, "_request {\n")
+ for p in recv_request_protos:
+ o.rxhdr("\t", p, ";\n")
+ o.rxhdr("};\n")
+
+ o.rxhdr("\n")
+ if recv_response_protos:
+ o.rxhdr("struct ", func.name, "_response {\n")
+ for p in recv_response_protos:
+ o.rxhdr("\t", p, ";\n")
+ o.rxhdr("};\n")
+
+ # # Terminate each line with a comma, excepting the last, which we terminate
+ # # with a closing bracket.
+ # for (my $i = 1; $i < $#protos; $i++:
+ # protos[$i] .= ",\n")
+ # }
+ # protos[$#protos] .= ")")
+
+ # for (my $i = 1; $i < $#send_protos; $i++:
+ # $send_protos[$i] .= ",\n")
+ # }
+ # $send_protos[$#send_protos] .= ")")
+
+ # for (my $i = 1; $i < $#recv_protos; $i++:
+ # $recv_protos[$i] .= ",\n")
+ # }
+ # $recv_protos[$#recv_protos] .= ")")
+
+ func.protos = protos
+ func.send_request_protos = send_request_protos
+ func.recv_request_protos = recv_request_protos
+ func.send_response_protos = send_response_protos
+ func.recv_response_protos = recv_response_protos
+ func.send_args = send_args
+ func.recv_args = recv_args
+
+###############################################################################
+#
+# Emit a function to decode a block in a way that can be used from asynchronous
+# code. The opcode is expected to have been removed from the incoming call on
+# the server side.
+#
+###############################################################################
+class decode_phase:
+ def __init__(self, form="flat", size=0, xdr_size=0, name=None):
+ self.form = form
+ self.size = size
+ self.params = list()
+ self.xdr_size = xdr_size
+ self.elem_count = 0
+ self.name = name
+
+def emit_func_decode(o, func, side, subname, params):
+ # We fetch the data in a number of phases. Each phase receives a chunk of
+ # data of a certain size. A phase's size might be dependent on a variable
+ # in the previous phase. Variable-sized bulk arrays are split across
+ # multiple phases, with the length being at the end of the first phase and
+ # the data in the second.
+ phases = list()
+ phase = None
+ have_bulk = False
+
+ for p in params:
+ o.where(func.name + ":" + p.name)
+ ty = p.typespec
+
+ if not phase:
+ phase = decode_phase()
+ phases.append(phase)
+
+ if ty.is_single_int() or ty.is_single_struct():
+ phase.size += ty.xdr_size
+ phase.params.append(p)
+ elif ty.is_single_blob():
+ have_bulk = True
+
+ # Blob objects begin with a size for which we institute a special
+ # parameter
+ phase.elem_count = phase.size
+ phase.size += 4
+
+ count_type = xdr_type(o.xdr, base=o.xdr.get_type("uint32_t"))
+ pseudoparam = xdr_member("nr__" + p.name, count_type, o.xdr)
+ pseudoparam.special = "blob_size"
+ phase.params.append(pseudoparam)
+
+ # Create a new phase
+ phase = decode_phase(form="blob", name=p.name, size=4, xdr_size=ty.xdr_size)
+ phase.params.append(p)
+ phases.append(phase)
+ phase = None
+
+ elif ty.is_bulk():
+ have_bulk = True
+
+ # Bulk objects begin with an element count for which we institute a
+ # special parameter
+ phase.elem_count = phase.size
+ phase.size += 4
+
+ count_type = xdr_type(o.xdr, base=o.xdr.get_type("uint32_t"))
+ pseudoparam = xdr_member("nr__" + p.name, count_type, o.xdr)
+ pseudoparam.special = "bulk_size"
+ phase.params.append(pseudoparam)
+
+ # Create a new phase
+ phase = decode_phase(form="bulk", name=p.name, size=4, xdr_size=ty.xdr_size)
+ phase.params.append(p)
+ phases.append(phase)
+
+ # We don't want to be asking recvmsg() for one object at a time if
+ # they're really small.
+ n_buf = 1
+ if ty.xdr_size < 1020:
+ n_buf = int(1020 / ty.xdr_size)
+ n_buf *= ty.xdr_size
+ phase.size = ty.xdr_size
+ phase = None
+
+ else:
+ raise RuntimeError("Reply array not supported")
+
+ # Function definition and arguments
+ o.rxsrc("\n")
+ o.rxsrc("static int rxgen_decode_", func.name, "_", subname, "(struct rx_call *call)\n")
+ o.rxsrc("{\n")
+
+ if not params:
+ o.rxsrc("\treturn 0;\n")
+ o.rxsrc("}\n")
+ return
+
+ # Local variables
+ o.rxsrc("\tstruct ", func.name, "_", subname, " *obj = call->decoder_private;\n")
+ o.rxsrc("\tunsigned count;\n")
+ o.rxsrc("\tunsigned phase = call->phase;\n")
+
+ # Deal with each phase
+ o.rxsrc("\n")
+ if have_bulk:
+ o.rxsrc("select_phase:\n")
+ o.rxsrc("\tcount = call->data_count;\n")
+ o.rxsrc("\tswitch (phase) {\n")
+
+ o.rxsrc("\tcase 0:\n")
+
+ next_phase_id = 1
+ for phase in phases:
+ phase.phase_id = next_phase_id
+ next_phase_id += 1
+
+ phase_goto_label = None
+ for phase in phases:
+ phase_id = phase.phase_id
+ o.rxsrc("\n")
+ o.rxsrc("\t\t/* --- Phase ", phase_id, " --- */\n")
+
+ if phase_goto_label == phase_id:
+ o.rxsrc("\tphase_", phase_id, ":\n")
+ phase_goto_label = None
+
+ # Determine how big bulk objects are
+ if phase.form == "blob":
+ p = phase.params[0]
+ o.rxsrc("\t\tcall->blob_size = obj->nr__", p.name, ";\n")
+ o.rxsrc("\t\tcall->blob_offset = UINT_MAX;\n")
+ o.rxsrc("\t\tif (obj->alloc__", p.name, "(call, &obj->token__", p.name, ") < 0)\n")
+ o.rxsrc("\t\t\treturn -1;\n")
+ o.rxsrc("\t\tif (call->blob_size == 0)\n")
+ o.rxsrc("\t\t\tgoto phase_", phase_id + 1, ";\n")
+ phase_goto_label = phase_id + 1
+ o.rxsrc("\t\tcall->blob_offset = 0;\n")
+ elif phase.form == "bulk":
+ p = phase.params[0]
+ o.rxsrc("\t\tcall->bulk_count = obj->nr__", p.name, ";\n")
+ o.rxsrc("\t\tcall->bulk_index = UINT_MAX;\n")
+
+ if ty.is_bulk_int():
+ o.rxsrc("\t\tif (obj->store__", p.name, "(call, &obj->token__", p.name, ") < 0)\n")
+ else:
+ o.rxsrc("\t\tif (obj->alloc__", p.name, "(call, &obj->token__", p.name, ") < 0)\n")
+
+ o.rxsrc("\t\t\treturn -1;\n")
+ o.rxsrc("\t\tif (call->bulk_count == 0)\n")
+ o.rxsrc("\t\t\tgoto phase_", phase_id + 1, ";\n")
+ phase_goto_label = phase_id + 1
+ o.rxsrc("\t\tcall->bulk_index = 0;\n")
+ else:
+ o.rxsrc("\t\tcall->need_size = ", phase.size, ";\n")
+
+ # Entry point for a phase
+ o.rxsrc("\t\tcall->phase = ", phase_id, ";\n")
+ o.rxsrc("\tcase ", phase_id, ":\n")
+
+ o.rxsrc("\t\tif (count < ", phase.size, ")")
+ if phase.form == "bulk" and phase.xdr_size <= 512:
+ o.rxsrc(" {\n")
+ o.rxsrc("\t\t\tunsigned n = call->bulk_count - call->bulk_index;\n")
+ o.rxsrc("\t\t\tn = MIN(n, ", int(1024 / phase.xdr_size), ");\n")
+ o.rxsrc("\t\t\tcall->need_size = n * ", phase.xdr_size, ";\n")
+ o.rxsrc("\t\t\treturn 1;\n")
+ o.rxsrc("\t\t}")
+ else:
+ o.rxsrc("\n")
+ o.rxsrc("\t\t\treturn 1;\n")
+
+ # Unmarshal the data
+ o.rxsrc("\n")
+ for p in phase.params:
+ o.where(func.name + ":" + p.name)
+ ty = p.typespec
+ if p.special == None:
+ pass
+ elif p.special == "blob_size" or p.special == "bulk_size":
+ o.rxsrc("\t\tobj->", p.name, " = rxrpc_dec(call);\n")
+ continue
+ else:
+ raise RuntimeError
+
+ if ty.is_bulk_int():
+ if ty.is_bulk_int32():
+ o.rxsrc("\t\tcall->bulk_u32 = rxrpc_dec(call);\n")
+ o.rxsrc("\t\tif (obj->store__", p.name, "(call, &obj->token__", p.name, ") < 0)\n")
+ elif ty.is_bulk_int64():
+ o.rxsrc("\t\tcall->bulk_u64 = (uint64_t)rxrpc_dec(call) << 32;\n")
+ o.rxsrc("\t\tcall->bulk_u64 |= (uint64_t)rxrpc_dec(call);\n")
+ o.rxsrc("\t\tif (obj->store__", p.name, "(call, &obj->token__", p.name, ") < 0)\n")
+ else:
+ raise RuntimeError
+ o.rxsrc("\t\t\treturn -1;\n")
+ o.rxsrc("\t\tcall->bulk_index++;\n")
+
+ elif ty.is_bulk_struct():
+ o.rxsrc("\t\tif (obj->alloc__", p.name, "(call, &obj->token__", p.name, ") < 0)\n")
+ o.rxsrc("\t\t\treturn -1;\n")
+ o.rxsrc("\t\trxgen_decode_", ty.name, "(call, call->bulk_item);\n")
+ o.rxsrc("\t\tcall->bulk_index++;\n")
+ elif ty.is_single_blob():
+ o.rxsrc("\t\trxrpc_dec_blob(call);\n")
+ o.rxsrc("\t\trxrpc_dec_align(call);\n")
+ elif ty.is_single_int32():
+ o.rxsrc("\t\tobj->", p.name, " = rxrpc_dec(call);\n")
+ elif ty.is_single_int64():
+ o.rxsrc("\t\tobj->", p.name, " = (uint64_t)rxrpc_dec(call) << 32;\n")
+ o.rxsrc("\t\tobj->", p.name, " |= (uint64_t)rxrpc_dec(call);\n")
+ elif ty.is_single_struct():
+ o.rxsrc("\t\trxgen_decode_", ty.name, "(call, obj->", p.name, ");\n")
+ else:
+ raise RuntimeError("Unsupported type in decode " + str(ty))
+
+ if ty.is_single_blob():
+ o.rxsrc("\t\tif (rxrpc_post_dec(call) < 0)\n")
+ o.rxsrc("\t\t\treturn -1;\n")
+ o.rxsrc("\t\tif (call->blob_offset < call->blob_size) {\n")
+ o.rxsrc("\t\t\tphase = ", phase_id, ";\n")
+ o.rxsrc("\t\t\tgoto select_phase;\n")
+ o.rxsrc("\t\t}\n")
+ elif ty.is_bulk():
+ o.rxsrc("\t\tif (rxrpc_post_dec(call) < 0)\n")
+ o.rxsrc("\t\t\treturn -1;\n")
+ o.rxsrc("\t\tif (call->bulk_index < call->bulk_count) {\n")
+ o.rxsrc("\t\t\tphase = ", phase_id, ";\n")
+ o.rxsrc("\t\t\tgoto select_phase;\n")
+ o.rxsrc("\t\t}\n")
+
+ # --- TODO: Check the following condition as it must always be true
+ if phase.form != "blob" or phase.form != "bulk":
+ o.rxsrc("\t\tif (rxrpc_post_dec(call) < 0)\n")
+ o.rxsrc("\t\t\treturn -1;\n")
+
+ o.rxsrc("\n")
+ o.rxsrc("\t\t/* --- Phase ", next_phase_id, " --- */\n")
+ if phase_goto_label:
+ o.rxsrc("\tphase_", next_phase_id, ":\n")
+ o.rxsrc("\t\tcall->phase = ", next_phase_id, ";\n")
+ o.rxsrc("\t\tcall->need_size = 0;\n")
+ o.rxsrc("\tdefault:\n")
+ o.rxsrc("\t\treturn 0;\n")
+ o.rxsrc("\t}\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
+ bad_ret = "NULL"
+ else:
+ protos = func.send_response_protos
+ params = func.response
+ bad_ret = "-1"
+
+ o.rxsrc("\n")
+ if what == "request":
+ o.rxsrc("struct rx_call *", func.name + "(\n")
+ o.rxsrc("\tstruct rx_connection *z_conn")
+ else:
+ o.rxsrc("int respond_to_", func.name + "(\n")
+ o.rxsrc("\tstruct rx_call *call")
+
+ for proto in protos:
+ o.rxsrc(",\n\t", proto)
+
+ if what == "request" and func.response:
+ o.rxsrc(",\n")
+ o.rxsrc("\tstruct ", func.name, "_response *response")
+
+ o.rxsrc(")\n")
+ o.rxsrc("{\n")
+
+ if what == "request":
+ o.rxsrc("\tstruct rx_call *call;\n")
+
+ blob_params = list()
+ bulk_params = list()
+ for p in params:
+ ty = p.typespec
+ if ty.is_single_blob():
+ blob_params.append(p)
+ if ty.is_bulk():
+ bulk_params.append(p)
+
+ # Local variables
+ o.rxsrc("\tint ret;\n")
+
+ # Check lengths
+ if blob_params or bulk_params:
+ o.rxsrc("\n")
+ o.rxsrc("\tif (")
+ first = True
+ for p in blob_params:
+ o.where(func.name + ":" + p.name)
+ ty = p.typespec
+ if first:
+ first = False
+ else:
+ o.rxsrc(" ||\n\t ")
+ o.rxsrc("!", p.name)
+ if ty.max_size:
+ o.rxsrc(" || nr__", p.name, " > ", ty.max_size.name)
+
+ for p in bulk_params:
+ o.where(func.name + ":" + p.name)
+ ty = p.typespec
+ if first:
+ first = False
+ else:
+ o.rxsrc(" ||\n\t ")
+ o.rxsrc("!get__", p.name)
+ if ty.max_size:
+ o.rxsrc(" || nr__", p.name, " > ", ty.max_size.name)
+
+ o.rxsrc(") {\n")
+ o.rxsrc("\t\terrno = EINVAL;\n")
+ o.rxsrc("\t\treturn ", bad_ret, ";\n")
+ o.rxsrc("\t};\n")
+
+ # Allocate call
+ if what == "request":
+ o.rxsrc("\n")
+ o.rxsrc("\tcall = rxrpc_alloc_call(z_conn, 0);\n")
+ o.rxsrc("\tif (!call)\n")
+ o.rxsrc("\t\treturn ", bad_ret, ";\n")
+ o.rxsrc("\tcall->decoder = rxgen_decode_", func.name, "_response;\n")
+ if func.response:
+ o.rxsrc("\tcall->decoder_private = response;\n")
+
+ # Marshal the data
+ if what == "request" or params:
+ o.rxsrc("\n")
+ if what == "request":
+ o.rxsrc("\trxrpc_enc(call, ", func.opcode.name, ");\n")
+
+ for p in params:
+ o.where(func.name + ":" + p.name)
+ ty = p.typespec
+ if ty.is_single_int32():
+ o.rxsrc("\trxrpc_enc(call, ", p.name, ");\n")
+ elif ty.is_single_int64():
+ o.rxsrc("\trxrpc_enc(call, (uint32_t)", p.name, ");\n")
+ o.rxsrc("\trxrpc_enc(call, (uint32_t)(", p.name, " >> 32));\n")
+ elif ty.is_single_struct():
+ o.rxsrc("\trxgen_encode_", ty.name, "(call, ", p.name, ");\n")
+ elif ty.is_single_blob():
+ o.rxsrc("\trxrpc_enc_blob(call, ", p.name, ", nr__", p.name, ");\n")
+ o.rxsrc("\trxrpc_enc_align(call);\n")
+ elif ty.is_bulk():
+ o.rxsrc("\trxrpc_enc(call, nr__", p.name, ");\n")
+ o.rxsrc("\tcall->bulk_count = nr__", p.name, ";\n")
+ o.rxsrc("\tfor (call->bulk_index = 0; call->bulk_index < call->bulk_count; call->bulk_index++) {\n")
+ o.rxsrc("\t\t", ty.c_name, " x;\n")
+
+ o.rxsrc("\t\tcall->bulk_item = &x;\n")
+ o.rxsrc("\t\tif (get__", p.name, "(call, token__", p.name, ") < 0)\n")
+ o.rxsrc("\t\t\tgoto error;\n")
+ if ty.is_bulk_int32():
+ if not ty.name.startswith("u"):
+ o.rxsrc("\t\trxrpc_enc(call, (u", ty.name, ")x);\n")
+ else:
+ o.rxsrc("\t\trxrpc_enc(call, x);\n")
+ elif ty.is_bulk_int64():
+ o.rxsrc("\t\trxrpc_enc(call, (uint32_t)", p.name, ");\n")
+ o.rxsrc("\t\trxrpc_enc(call, (uint32_t)(", p.name, " >> 32));\n")
+ elif ty.is_bulk_struct():
+ o.rxsrc("\t\trxgen_encode_", ty.name, "(call, &x);\n")
+ else:
+ raise RuntimeError("No decoding for array type '" + str(ty) + "'")
+
+ o.rxsrc("\t}\n")
+ else:
+ raise RuntimeError("Unsupported param encoding")
+
+ o.rxsrc("\tif (rxrpc_post_enc(call) < 0)\n")
+ o.rxsrc("\t\tgoto error;\n")
+ o.rxsrc("\tcall->more_send = 0;\n")
+
+ # Send the message
+ o.rxsrc("\n")
+ o.rxsrc("\tret = rxrpc_send_data(call);\n")
+ o.rxsrc("\tif (ret < 0)\n")
+ o.rxsrc("\t\tgoto error;\n")
+ if what == "request":
+ o.rxsrc("\treturn call;\n")
+ else:
+ o.rxsrc("\treturn 0;\n")
+
+ o.rxsrc("\n")
+ o.rxsrc("error:\n")
+ o.rxsrc("\trxrpc_terminate_call(call, 0);\n")
+ o.rxsrc("\treturn ", bad_ret, ";\n")
+ o.rxsrc("}\n")
--- /dev/null
+#!/usr/bin/python3
+#
+# Emit python module definition.
+# -*- coding: utf-8 -*-
+
+__copyright__ = """
+Copyright (C) 2015 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 python module definition.
+#
+###############################################################################
+def emit_py_module(o):
+ # We want an exception we can raise when we get a remote abort
+ o.pyhdr("extern PyObject *kafs_remote_abort;\n")
+
+ o.pysrc("\n")
+ o.pysrc("/*\n")
+ o.pysrc(" * The remote-abort exception.\n")
+ o.pysrc(" */\n")
+ o.pysrc("PyObject *kafs_remote_abort;\n")
+
+ pkgnames = list(o.xdr.packages.keys())
+ pkgnames.sort()
+
+ for pkgname in pkgnames:
+ pkg = o.xdr.packages[pkgname]
+ codes = pkg.abort_codes
+ if codes:
+ o.pysrc("PyObject *kafs_", pkg.name, "_abort;\n")
+
+ o.pysrc("\n")
+ o.pyhdr("extern struct kafs_abort_list kafs_abort_map[", o.xdr.abort_count, "];\n")
+
+ index = 0
+ o.pysrc("struct kafs_abort_list kafs_abort_map[", o.xdr.abort_count, "] = {\n")
+ abort_ids = list(o.xdr.abort_ids.keys())
+ abort_ids.sort()
+ for aid in abort_ids:
+ abort = o.xdr.abort_ids[aid]
+ o.pysrc("\t{ .id = ", abort.name)
+ #if abort.msg:
+ # o.pysrc(", .msg = \"", abort.msg, "\"")
+ o.pysrc(" }, /* ", abort.u32, " */\n")
+ abort.index = index
+ index += 1
+
+ o.pysrc("};\n\n")
+
+ # Emit python structure wrapper static method table
+ o.pysrc("\n")
+ o.pysrc("/*\n")
+ o.pysrc(" * The static methods.\n")
+ o.pysrc(" */\n")
+ o.pysrc("static PyMethodDef module_methods[] = {\n")
+
+ o.pysrc("\t{\"rx_new_connection\", (PyCFunction)kafs_py_rx_new_connection, METH_VARARGS, \"\" },\n")
+ o.pysrc("\t{\"afs_string_to_key\", (PyCFunction)kafs_py_string_to_key, METH_VARARGS, \"\" },\n")
+
+ for pyf in o.xdr.py_func_defs:
+ o.pysrc("\t{\"", pyf.name, "\", (PyCFunction)", pyf.c_func, ", METH_VARARGS,")
+ o.pysrc(" \"", pyf.doc, "\" },\n")
+
+ o.pysrc("\t{}\n")
+ o.pysrc("};\n")
+
+ # Emit python structure wrapper loader
+ o.pysrc("\n")
+
+ o.pysrc("static PyModuleDef kafs_module = {\n")
+ o.pysrc("\t.m_base = PyModuleDef_HEAD_INIT,\n")
+ o.pysrc("\t.m_name = \"kafs\",\n")
+ o.pysrc("\t.m_doc = \"AFS stuff.\",\n")
+ o.pysrc("\t.m_size = -1,\n")
+ o.pysrc("\t.m_methods = module_methods,\n")
+ o.pysrc("};\n")
+
+ o.pyhdr("\n")
+ o.pyhdr("extern PyObject *pykafs_load_wrappers(void);\n")
+
+ o.pysrc("\n")
+ o.pysrc("PyObject *pykafs_load_wrappers(void)\n")
+ o.pysrc("{\n")
+ o.pysrc("\tPyObject *m;\n")
+
+ # Load types
+ if o.xdr.py_type_defs:
+ o.pysrc("\tif (")
+ o.pysrc("PyType_Ready(&py_rx_connectionType) < 0 ||\n\t ")
+ o.pysrc("PyType_Ready(&py_rx_split_infoType) < 0")
+ for pyt in o.xdr.py_type_defs:
+ o.pysrc(" ||\n\t ")
+ o.pysrc("PyType_Ready(&", pyt.c_type, ") < 0")
+ o.pysrc(")\n")
+ o.pysrc("\t\treturn NULL;\n")
+
+
+ o.pysrc("\n")
+ o.pysrc("\tm = PyModule_Create(&kafs_module);\n")
+ o.pysrc("\tif (!m)\n")
+ o.pysrc("\t\treturn NULL;\n")
+
+ if o.xdr.constants:
+ o.pysrc("\n")
+ con_names = list(o.xdr.constants.keys())
+ con_names.sort()
+ for c in con_names:
+ o.pysrc("\tPyModule_AddIntConstant(m, \"", c, "\", ", c, ");\n")
+
+ if o.xdr.py_type_defs:
+ o.pysrc("\n")
+ for pyt in o.xdr.py_type_defs:
+ o.pysrc("\tPy_INCREF(&", pyt.c_type, ");\n")
+ o.pysrc("\tPyModule_AddObject(m, \"", pyt.name, "\", (PyObject *)&", pyt.c_type, ");\n")
+
+ # Emit a base remote abort class that all others can be subclassed off
+ o.pysrc("\n")
+ o.pysrc("\tkafs_remote_abort = PyErr_NewException(\"kafs.RemoteAbort\", NULL, NULL);\n")
+ o.pysrc("\tif (!kafs_remote_abort)\n")
+ o.pysrc("\t\treturn NULL;\n")
+ o.pysrc("\tPy_INCREF(kafs_remote_abort);\n")
+ o.pysrc("\tPyModule_AddObject(m, \"RemoteAbort\", kafs_remote_abort);\n")
+
+ for pkgname in pkgnames:
+ pkg = o.xdr.packages[pkgname]
+ abort_codes = pkg.abort_codes
+ if not abort_codes:
+ continue
+
+ pkg_abort = pkg.name + "Abort"
+ pkg_sym = "kafs_" + pkg.name + "_abort"
+
+ o.pysrc("\n")
+ o.pysrc("\t", pkg_sym, " = PyErr_NewException(\"kafs.", pkg_abort, "\", kafs_remote_abort, NULL);\n")
+ o.pysrc("\tif (!", pkg_sym, ")\n")
+ o.pysrc("\t\treturn NULL;\n")
+ o.pysrc("\tPy_INCREF(", pkg_sym, ");\n")
+ o.pysrc("\tPyModule_AddObject(m, \"", pkg_abort, "\", ", pkg_sym, ");\n")
+
+ def get_constant_value(abort):
+ return abort.u32
+ abort_codes.sort(key=get_constant_value)
+
+ for abort in abort_codes:
+ abort_name = "Abort" + abort.name
+ abort_var = "kafs_abort_map[" + str(abort.index) + "].obj"
+
+ o.pysrc("\n")
+ o.pysrc("\t", abort_var, " = PyErr_NewException(\"kafs.", abort_name, "\", ", pkg_sym, ", NULL);\n")
+ o.pysrc("\tif (!", abort_var, ")\n")
+ o.pysrc("\t\treturn NULL;\n")
+ o.pysrc("\tPy_INCREF(", abort_var, ");\n")
+ o.pysrc("\tPyModule_AddObject(m, \"", abort_name, "\", ", abort_var, ");\n")
+
+ o.pysrc("\n")
+ o.pysrc("\treturn m;\n")
+ o.pysrc("}\n")
--- /dev/null
+#!/usr/bin/python3
+#
+# Emit C synchronous functions
+# -*- coding: utf-8 -*-
+
+__copyright__ = """
+Copyright (C) 2015 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 *
+
+class decode_phase:
+ def __init__(self, form="flat", size=0, xdr_size=0, name=None):
+ self.form = form
+ self.size = size
+ self.params = list()
+ self.xdr_size = xdr_size
+ self.elem_count = 0
+ self.name = name
+
+bulk_get_helpers = dict();
+bulk_set_helpers = dict();
+
+c_to_py_type_map = dict([("char", "T_CHAR"),
+ ("int8_t", "T_BYTE"),
+ ("int16_t", "T_SHORT"),
+ ("int32_t", "T_INT"),
+ ("int64_t", "T_LONGLONG"),
+ ("uint8_t", "T_UBYTE"),
+ ("uint16_t", "T_USHORT"),
+ ("uint32_t", "T_UINT"),
+ ("uint64_t", "T_ULONGLONG")
+ ])
+
+###############################################################################
+#
+# Emit python objects to represent received parameter sets and received
+# response sets for RPC calls.
+#
+###############################################################################
+def emit_py_func_param_object(o, func, way):
+ struct_req = "py_" + func.name + "_" + way;
+ basic_params = list()
+ complex_params = list()
+ params = list()
+ division = ""
+
+ global c_to_py_type_map
+
+ t = py_type_def(func.name + "_" + way, struct_req + "Type")
+ o.xdr.py_type_defs.append(t)
+
+ if way == "request":
+ params = func.request
+ division = "calls"
+ else:
+ params = func.response
+ division = "responses"
+
+ # Define a C structure to hold the python object header and the data.
+ o.pyhdr("\n")
+ o.pyhdr("struct ", struct_req, " {\n")
+ o.pyhdr("\tstruct py_rx_", way, " common;\n")
+ if params:
+ have_opaque = False
+ o.pyhdr("\tstruct {\n")
+ for p in params:
+ o.where(func.name + ":" + p.name)
+ ty = p.typespec
+ if ty.is_single_int():
+ basic_params.append(p)
+ o.pyhdr("\t\t", ty.name, "\t", p.name, ";\n")
+ else:
+ complex_params.append(p)
+ o.pyhdr("\t\tPyObject\t*", p.name, ";\n")
+
+ if ty.is_single_opaque():
+ have_opaque = True
+
+ o.pyhdr("\t} x;\n")
+ if have_opaque:
+ o.pyhdr("\tPy_buffer dec_buf;\n")
+
+ o.pyhdr("};\n")
+
+ # We need to have a new function if the object is to be allocatable by the
+ # Python interpreter
+ o.pysrc("\n")
+ o.pysrc("static PyObject *\n")
+ o.pysrc(struct_req, "_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)\n")
+ o.pysrc("{\n")
+ o.pysrc("\tPyObject *obj;\n")
+ o.pysrc("\n")
+ o.pysrc("\tobj = subtype->tp_alloc(subtype, 1);\n")
+ if params:
+ o.pysrc("\tif (obj) {\n")
+ o.pysrc("\t\tstruct ", struct_req, " *self = (struct ", struct_req, " *)obj;\n")
+ o.pysrc("\t\tmemset(&self->x, 0, sizeof(self->x));\n")
+ o.pysrc("\t}\n")
+ o.pysrc("\treturn obj;\n")
+ o.pysrc("}\n")
+
+ # We have to have a deallocation function
+ o.pysrc("\n")
+ o.pysrc("static void ", struct_req, "_dealloc(struct ", struct_req, " *self)\n")
+ o.pysrc("{\n")
+ for p in complex_params:
+ o.pysrc("\tPy_XDECREF(self->x.", p.name, ");\n")
+ o.pysrc("\tPy_TYPE(self)->tp_free((PyObject *)self);\n")
+ o.pysrc("}\n")
+
+ # All elements are made directly accessible to the Python interpreter,
+ # either as integer types or as object types.
+ if params:
+ o.pysrc("\n")
+ o.pysrc("static PyMemberDef ", struct_req, "_members[] = {\n")
+ for p in params:
+ o.where(func.name + ":" + p.name)
+ ty = p.typespec
+ o.pysrc("\t{ \"", p.name, "\", ")
+ if ty.is_single_blob(): o.pysrc("T_OBJECT_EX")
+ elif ty.is_bulk(): o.pysrc("T_OBJECT_EX")
+ elif ty.is_single_int(): o.pysrc(c_to_py_type_map[ty.name])
+ else:
+ o.pysrc("T_OBJECT_EX")
+ o.pysrc(", offsetof(struct ", struct_req, ", x.", p.name, "), 0, \"\"},\n")
+
+ o.pysrc("\t{}\n")
+ o.pysrc("};\n")
+
+ # Emit the Python type definition
+ o.pysrc("\n")
+ o.pysrc("static PyTypeObject ", struct_req, "Type = {\n")
+ o.pysrc("\tPyVarObject_HEAD_INIT(NULL, 0)\n")
+ o.pysrc("\t\"kafs.", func.name, "_", way, "\",\t\t/*tp_name*/\n")
+ o.pysrc("\tsizeof(struct ", struct_req, "),\t/*tp_basicsize*/\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_itemsize*/\n")
+ o.pysrc("\t(destructor)", struct_req, "_dealloc, /*tp_dealloc*/\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_print*/\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_getattr*/\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_setattr*/\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_compare*/\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_repr*/\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_as_number*/\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_as_sequence*/\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_as_mapping*/\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_hash */\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_call */\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_str*/\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_getattro*/\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_setattro*/\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_as_buffer*/\n")
+ o.pysrc("\tPy_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/\n")
+ o.pysrc("\t\"\",\t\t\t\t/* tp_doc */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_traverse */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_clear */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_richcompare */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_weaklistoffset */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_iter */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_iternext */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_methods */\n")
+ if params:
+ o.pysrc("\t", struct_req, "_members,\n")
+ else:
+ o.pysrc("\t0,\t\t\t\t/* tp_members */\n")
+
+ o.pysrc("\t0,\t\t\t\t/* tp_getset */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_base */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_dict */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_descr_get */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_descr_set */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_dictoffset */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_init */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_alloc */\n")
+ o.pysrc("\t", struct_req, "_new,\n")
+ o.pysrc("};\n")
+
+
+###############################################################################
+#
+# Emit functions to help deal with bulk lists
+#
+###############################################################################
+def emit_py_func_bulk_helper(o, func):
+ for p in func.params:
+ o.where(func.name + ":" + p.name)
+ ty = p.typespec
+ if not ty.is_bulk():
+ continue
+
+ # Data encoding
+ if ty.name not in bulk_get_helpers:
+ bulk_get_helpers[ty.name] = True
+
+ o.pysrc("\n")
+ o.pysrc("static __attribute__((unused))\n")
+ o.pysrc("int py_encode_bulk_", ty.name, "(struct rx_call *call, PyObject *list)\n")
+ o.pysrc("{\n")
+ o.pysrc("\tPyObject *item;\n")
+ o.pysrc("\tunsigned count, i;\n")
+ o.pysrc("\n")
+ o.pysrc("\tcount = PyList_Size(list);\n")
+ o.pysrc("\trxrpc_enc(call, count);\n")
+ o.pysrc("\n")
+ o.pysrc("\tfor (i = 0; i < count; i++) {\n")
+ o.pysrc("\t\titem = PyList_GetItem(list, i);\n")
+ o.pysrc("\t\tif (!item)\n")
+ o.pysrc("\t\t\treturn -1;\n")
+
+ o.pysrc("\n")
+ if ty.is_bulk_int():
+ o.pysrc("\t\tif (!PyLong_Check(item)) {\n")
+ o.pysrc("\t\t\tPyErr_SetString(PyExc_TypeError, \"Expected list of ", ty.name, "\");\n")
+ o.pysrc("\t\t\treturn -1;\n")
+ o.pysrc("\t\t}\n")
+ else:
+ o.pysrc("\t\tif (py_premarshal_", ty.name, "(item))\n")
+ o.pysrc("\t\t\treturn -1;\n")
+
+ if ty.is_bulk_int():
+ if ty.name == "int64_t":
+ o.pysrc("\t\tuint64_t x = PyLong_AsLongLong(item);\n")
+ o.pysrc("\t\trxrpc_enc(call, x >> 32);\n")
+ o.pysrc("\t\trxrpc_enc(call, x);\n")
+ elif ty.name == "uint64_t":
+ o.pysrc("\t\tuint64_t x = PyLong_AsUnsignedLongLong(item);\n")
+ o.pysrc("\t\trxrpc_enc(call, x >> 32);\n")
+ o.pysrc("\t\trxrpc_enc(call, x);\n")
+ elif ty.name.startswith("int"):
+ o.pysrc("\t\trxrpc_enc(call, PyLong_AsLong(item));\n")
+ elif ty.name.startswith("uint") or ty.name.startswith("char"):
+ o.pysrc("\t\trxrpc_enc(call, PyLong_AsUnsignedLong(item));\n")
+ else:
+ raise RuntimeError
+ else:
+ o.pysrc("\t\trxgen_encode_", ty.name, "(call, &((struct py_", ty.name, " *)item)->x);\n")
+
+ o.pysrc("\t}\n")
+ o.pysrc("\treturn 0;\n")
+ o.pysrc("}\n")
+
+###############################################################################
+#
+# Emit a python wrapper function to make a simple synchronous call
+#
+###############################################################################
+def emit_py_func_simple_sync_call(o, func):
+
+ o.xdr.py_func_defs.append(py_func_def(func.name, "kafs_" + func.name))
+
+ o.pysrc("\n")
+ o.pysrc("PyObject *\n")
+ o.pysrc("kafs_", func.name, "(PyObject *_self, PyObject *args)\n")
+ o.pysrc("{\n")
+
+ # Local variable declarations representing parameters to send
+ o.pysrc("\tstruct rx_call *call;\n")
+ o.pysrc("\tstruct py_rx_connection *z_conn;\n")
+ o.pysrc("\tstruct py_", func.name, "_response *response;\n")
+ for p in func.request:
+ o.where(func.name + ":" + p.name)
+ ty = p.typespec
+ if ty.is_single_blob():
+ o.pysrc("\tPy_buffer param_", p.name, ";\n")
+ elif ty.is_single_int():
+ o.pysrc("\t", ty.name, " param_", p.name, ";\n")
+ elif ty.is_single_struct():
+ o.pysrc("\tstruct py_", ty.name, " *param_", p.name, ";\n")
+ elif ty.is_bulk():
+ if p.direction != "OUT":
+ o.pysrc("\tPyObject *param_", p.name, ";\n")
+ else:
+ raise RuntimeError("Unsupported type \"" + str(ty) + "\"")
+
+ if func.split:
+ o.pysrc("\tPyObject *split_callback, *split_info;\n")
+ o.pysrc("\tPyObject *res = NULL;\n")
+ o.pysrc("\tint ret;\n")
+
+ # Make use of the tuple parser to extract the arguments and check their
+ # types for us.
+ o.pysrc("\n")
+ o.pysrc("\tif (!PyArg_ParseTuple(args, \"O!")
+
+ for p in func.request:
+ o.where(func.name + ":" + p.name)
+ ty = p.typespec
+ if ty.is_bulk(): o.pysrc("O!")
+ elif ty.is_array(): raise RuntimeError
+ elif ty.name == "int8_t": o.pysrc("B")
+ elif ty.name == "int16_t": o.pysrc("h")
+ elif ty.name == "int32_t": o.pysrc("i")
+ elif ty.name == "int64_t": o.pysrc("L")
+ elif ty.name == "uint8_t": o.pysrc("b")
+ elif ty.name == "uint16_t": o.pysrc("H")
+ elif ty.name == "uint32_t": o.pysrc("I")
+ elif ty.name == "uint64_t": o.pysrc("K")
+ elif ty.is_single_struct(): o.pysrc("O!")
+ elif ty.is_single_string(): o.pysrc("s*")
+ elif ty.is_single_opaque(): o.pysrc("z*")
+ else:
+ raise RuntimeError("No py parse for param")
+
+ if func.split:
+ o.pysrc("O")
+ o.pysrc("\",\n")
+ o.pysrc("\t\t\t &py_rx_connectionType, &z_conn")
+
+ for p in func.request:
+ o.where(func.name + ":" + p.name)
+ ty = p.typespec
+ o.pysrc(",\n")
+ o.pysrc("\t\t\t ")
+ if ty.is_single_int():
+ o.pysrc("¶m_", p.name)
+ elif ty.is_single_struct():
+ o.pysrc("&py_", ty.name, "Type, ¶m_", p.name)
+ elif ty.is_single_blob():
+ o.pysrc("¶m_", p.name)
+ elif ty.is_bulk():
+ o.pysrc("&PyList_Type, ¶m_", p.name)
+ else:
+ raise RuntimeError(": Unsupported type \"" + str(ty) + "\"")
+
+ if func.split:
+ o.pysrc(",\n\t\t\t &split_callback")
+ o.pysrc("))\n")
+ o.pysrc("\t\treturn NULL;\n")
+
+ if func.split:
+ o.pysrc("\n")
+ o.pysrc("\tsplit_info = py_rxgen_split_client_prepare();\n")
+ o.pysrc("\tif (!split_info)\n")
+ o.pysrc("\t\treturn NULL;\n")
+
+ o.pysrc("\n")
+ o.pysrc("\tcall = rxrpc_alloc_call(z_conn->x, 0);\n")
+ o.pysrc("\tif (!call) {\n")
+ if func.split:
+ o.pysrc("\t\tPy_XDECREF(split_info);\n");
+ o.pysrc("\t\treturn PyErr_NoMemory();\n")
+ o.pysrc("\t}\n")
+ o.pysrc("\tcall->decoder_cleanup = py_rxgen_decoder_cleanup;\n")
+ if func.split:
+ o.pysrc("\tpy_rxgen_split_client_set(call, split_callback, split_info);\n")
+
+ # Marshal the arguments
+ o.pysrc("\n")
+ o.pysrc("\trxrpc_enc(call, ", func.opcode.name, ");\n")
+ for p in func.request:
+ o.where(func.name + ":" + p.name)
+ ty = p.typespec
+ if ty.is_blob():
+ dim = -1
+ if ty.max_size:
+ dim = ty.max_size.name
+ o.pysrc("\tif (py_enc_buffer(call, ¶m_", p.name, ", ", dim, ") < 0) {\n")
+ o.pysrc("\t\trxrpc_terminate_call(call, EINVAL);\n")
+ o.pysrc("\t\treturn NULL;\n")
+ o.pysrc("\t}\n")
+ elif ty.is_bulk():
+ o.pysrc("\tif (py_encode_bulk_", ty.name, "(call, param_", p.name, ") < 0)\n")
+ o.pysrc("\t\tgoto error;\n")
+ elif ty.is_single_int32():
+ o.pysrc("\trxrpc_enc(call, param_", p.name, ");\n")
+ elif ty.is_single_int64():
+ o.pysrc("\trxrpc_enc(call, param_", p.name, " >> 32);\n")
+ o.pysrc("\trxrpc_enc(call, param_", p.name, ");\n")
+ elif ty.is_single_struct():
+ o.pysrc("\tif (py_premarshal_", ty.name, "((PyObject *)param_", p.name, ")) {\n")
+ o.pysrc("\t\trxrpc_terminate_call(call, EINVAL);\n")
+ o.pysrc("\t\treturn NULL;\n")
+ o.pysrc("\t}\n")
+ o.pysrc("\trxgen_encode_", ty.name, "(call, ¶m_", p.name, "->x);\n")
+ else:
+ raise RuntimeError("Unsupported type in decode " + str(ty))
+
+ o.pysrc("\tif (rxrpc_post_enc(call) < 0)\n")
+ o.pysrc("\t\tgoto error_no_res;\n")
+
+ # Allocate a reply object
+ o.pysrc("\n")
+ o.pysrc("\tres = _PyObject_New(&py_", func.name, "_responseType);\n")
+ o.pysrc("\tresponse = (struct py_", func.name, "_response *)res;\n")
+ o.pysrc("\tif (!response)\n")
+ o.pysrc("\t\tgoto enomem;\n")
+ if func.response:
+ o.pysrc("\tmemset(&response->x, 0, sizeof(response->x));\n")
+ o.pysrc("\tcall->decoder = py_", func.name, "_decode_response;\n")
+ o.pysrc("\tcall->decoder_private = response;\n")
+
+ # Transmit the split data
+ if func.split:
+ o.pysrc("\tif (py_rxgen_split_transmit(call) < 0)\n")
+ o.pysrc("\t\tgoto error_no_res;\n")
+ else:
+ o.pysrc("\tcall->more_send = 0;\n")
+
+ # Make the call
+ o.pysrc("\n")
+ o.pysrc("\tret = rxrpc_send_data(call);\n")
+ o.pysrc("\tif (ret == -1)\n")
+ o.pysrc("\t\tgoto error;\n")
+
+ # Wait for the reply
+ #
+ # If we're dealing with a split function or are in asynchronous mode, we
+ # need to return the call here.
+ #
+ o.pysrc("\n")
+ o.pysrc("\tret = rxrpc_run_sync_call(call);\n")
+ o.pysrc("\tif (ret == -1)\n")
+ o.pysrc("\t\tgoto error;\n")
+
+ # Successful return
+ o.pysrc("\n")
+ o.pysrc("\trxrpc_terminate_call(call, 0);\n")
+ o.pysrc("\treturn res;\n")
+
+ # Error cleanups
+ o.pysrc("\n")
+ o.pysrc("error:\n")
+ o.pysrc("\tPy_XDECREF(res);\n")
+ o.pysrc("error_no_res:\n")
+ o.pysrc("\tif (errno == ENOMEM)\n")
+ o.pysrc("enomem:\n")
+ o.pysrc("\t\tres = PyErr_NoMemory();\n")
+ o.pysrc("\telse if (errno == ECONNABORTED)\n")
+ o.pysrc("\t\tres = py_rxgen_received_abort(call);\n")
+ o.pysrc("\telse\n")
+ o.pysrc("\t\tres = PyErr_SetFromErrno(PyExc_IOError);\n")
+ o.pysrc("\trxrpc_terminate_call(call, ENOMEM);\n")
+ o.pysrc("\treturn res;\n")
+
+ # End the function
+ o.pysrc("}\n")
+
+###############################################################################
+#
+# Emit a function to decode a block into a python object in a way that can be
+# used from asynchronous code. The opcode is expected to have been removed
+# from the incoming call on the server side.
+#
+###############################################################################
+def emit_py_func_decode(o, func, side, subname, params):
+ ptr = "obj->"
+
+ # We fetch the data in a number of phases. Each phase receives a chunk of
+ # data of a certain size. A phase's size might be dependent on a variable
+ # in the previous phase. Variable-sized bulk arrays are split across
+ # multiple phases, with the length being at the end of the first phase and
+ # the data in the second.
+ #
+ # We also need to interpolate a phase to deal with decoding split-op
+ # auxiliary data. This comes last when decoding the request and first when
+ # decoding the response.
+ #
+ phases = list()
+ phase = None
+ have_bulk = False
+ want_item = False
+
+ if func.split and subname == "response":
+ phase = decode_phase(form="split",
+ size="py_rxgen_split_receive(call)")
+ phases.append(phase)
+ phase = None
+ have_bulk = True
+
+ for p in params:
+ o.where(func.name + ":" + p.name)
+ ty = p.typespec
+
+ if not phase:
+ phase = decode_phase(form="flat")
+ phases.append(phase)
+
+ if ty.is_single_int() or ty.is_single_struct():
+ phase.size += ty.xdr_size
+ phase.params.append(p)
+ elif ty.is_single_blob():
+ have_bulk = True
+
+ # Bulk objects begin with an element count
+ phase.elem_count = phase.size
+ phase.size += 4
+
+ count_type = xdr_type(o.xdr, base=o.xdr.get_type("uint32_t"))
+ pseudoparam = xdr_member("nr__" + p.name, count_type, o.xdr)
+ pseudoparam.special = "blob_size"
+ phase.params.append(pseudoparam)
+
+ # Create a new phase
+ phase = decode_phase(form="blob", name=p.name, size=4, xdr_size=ty.xdr_size)
+ phase.params.append(p)
+ phases.append(phase)
+
+ # We don't want to be asking recvmsg() for one object at a time if
+ # they're really small.
+ phase.size = ty.xdr_size
+ phase = None
+ elif ty.is_bulk():
+ have_bulk = True
+
+ # Bulk objects begin with an element count
+ phase.elem_count = phase.size
+ phase.size += 4
+
+ count_type = xdr_type(o.xdr, base=o.xdr.get_type("uint32_t"))
+ pseudoparam = xdr_member("nr__" + p.name, count_type, o.xdr)
+ pseudoparam.special = "bulk_size"
+ phase.params.append(pseudoparam)
+
+ # Create a new phase
+ phase = decode_phase(form="bulk", name=p.name, size=4, xdr_size=ty.xdr_size)
+ phase.params.append(p)
+ phases.append(phase)
+
+ want_item = True
+
+ # We don't want to be asking recvmsg() for one object at a time if
+ # they're really small.
+ phase.size = ty.xdr_size
+ phase = None
+ else:
+ raise RuntimeError("Reply array not supported")
+
+ if func.split and subname == "request":
+ phase = decode_phase(form="split",
+ size="py_rxgen_split_receive(call)")
+ phases.append(phase)
+ phase = None
+ have_bulk = True
+
+ # Function definition and arguments
+ o.pysrc("\n")
+ o.pysrc("int py_", func.name, "_decode_", subname, "(struct rx_call *call)\n")
+ o.pysrc("{\n")
+
+ if not params and not func.split:
+ o.pysrc("\treturn 0;\n")
+ o.pysrc("}\n")
+ return
+
+ # Local variables
+ if params:
+ o.pysrc("\tstruct py_", func.name, "_", subname, " *obj = call->decoder_private;\n")
+ if want_item:
+ o.pysrc("\tPyObject *item;\n")
+ o.pysrc("\tunsigned phase = call->phase;\n")
+ o.pysrc("\tunsigned count;\n")
+
+ # Deal with each phase
+ o.pysrc("\n")
+ if have_bulk:
+ o.pysrc("select_phase:\n")
+ o.pysrc("\tcount = call->data_count;\n")
+ #o.pysrc("\tprintf(\"-- Phase %u (%u) --\\n\", phase, count);\n")
+ o.pysrc("\tswitch (phase) {\n")
+
+ o.pysrc("\tcase 0:\n")
+
+ next_phase_id = 1
+ for phase in phases:
+ phase.phase_id = next_phase_id
+ next_phase_id += 1
+
+ phase_goto_label = None
+ for phase in phases:
+ phase_id = phase.phase_id
+ o.pysrc("\n")
+ o.pysrc("\t\t/* --- Phase ", phase_id, " --- */\n")
+
+ if phase_goto_label == phase_id:
+ o.pysrc("\tphase_", phase_id, ":\n")
+ phase_goto_label = None
+
+ # Determine how big bulk objects are
+ if phase.form == "blob":
+ p = phase.params[0]
+ ty = p.typespec
+ if ty.is_single_string():
+ o.pysrc("\t\tswitch (py_dec_init_string(call, &obj->x.", p.name, ")) {\n")
+ elif ty.is_single_opaque():
+ o.pysrc("\t\tobj->x.", p.name, " = PyByteArray_FromStringAndSize(\"\", 0);\n")
+ o.pysrc("\t\tif (!obj->x.", p.name, ")\n")
+ o.pysrc("\t\t\treturn -1;\n")
+ o.pysrc("\t\tif (PyByteArray_Resize(obj->x.", p.name, ", call->blob_size) == -1)\n")
+ o.pysrc("\t\t\treturn -1;\n")
+
+ o.pysrc("\t\tswitch (py_dec_init_opaque(call, obj->x.", p.name, ")) {\n")
+ else:
+ raise RuntimeError("Unsupported blob type " + str(ty))
+
+ o.pysrc("\t\tcase -1: return -1;\n")
+ o.pysrc("\t\tcase 0: goto phase_", phase_id + 1, ";\n")
+ o.pysrc("\t\tcase 1: break;\n")
+ o.pysrc("\t\t}\n")
+ phase_goto_label = phase_id + 1
+
+ elif phase.form == "bulk":
+ p = phase.params[0]
+ ty = p.typespec
+ if ty.is_bulk_int() or ty.is_bulk_struct():
+ o.pysrc("\t\tobj->x.", p.name, " = PyList_New(call->bulk_count);\n")
+ o.pysrc("\t\tif (!obj->x.", p.name, ")\n")
+ o.pysrc("\t\t\treturn -1;\n")
+ else:
+ raise RuntimeError
+
+ o.pysrc("\t\tif (call->bulk_count == 0)\n")
+ o.pysrc("\t\t\tgoto phase_", phase_id + 1, ";\n")
+ phase_goto_label = phase_id + 1
+ o.pysrc("\t\tcall->bulk_index = 0;\n")
+
+ # Entry point for a phase
+ elif phase.form == "split":
+ o.pysrc("\t\tif (py_rxgen_split_receive(call, 1) < 0)\n")
+ o.pysrc("\t\t\treturn -1;\n")
+ o.pysrc("\t\tif (call->need_size == 0)\n")
+ o.pysrc("\t\t\tgoto phase_", phase_id + 1, ";\n")
+ phase_goto_label = phase_id + 1
+
+ o.pysrc("\t\tcall->phase = ", phase_id, ";\n")
+ o.pysrc("\tcase ", phase_id, ":\n")
+
+ if phase.form != "split":
+ o.pysrc("\t\tcall->need_size = ", phase.size, ";\n")
+ o.pysrc("\t\tif (count < call->need_size)\n")
+ o.pysrc("\t\t\treturn 1;\n")
+ else:
+ o.pysrc("\t\tif (call->need_size == UINT_MAX ? count == 0 : count < call->need_size) {\n")
+ #o.pysrc("\t\t\tprintf(\"NEED %u (phase %u)\\n\", call->need_size, phase);\n")
+ o.pysrc("\t\t\treturn 1;\n")
+ o.pysrc("\t\t}\n")
+
+ # Unmarshal the data
+ o.pysrc("\n")
+ for p in phase.params:
+ o.where(func.name + ":" + p.name)
+ ty = p.typespec
+ if p.special == None:
+ pass
+ elif p.special == "blob_size":
+ o.pysrc("\t\tcall->blob_size = rxrpc_dec(call);\n")
+ continue
+ elif p.special == "bulk_size":
+ o.pysrc("\t\tcall->bulk_count = rxrpc_dec(call);\n")
+ continue
+ else:
+ raise RuntimeError
+
+ if ty.is_bulk():
+ if ty.is_bulk_struct():
+ o.pysrc("\t\titem = py_decode_", ty.name, "(call);\n")
+ elif ty.is_bulk_int32() and ty.name.startswith("u"):
+ o.pysrc("\t\titem = PyLong_FromUnsignedLong((", ty.name, ")rxrpc_dec(call));\n")
+ elif ty.is_bulk_int32():
+ o.pysrc("\t\titem = PyLong_FromLong((", ty.name, ")rxrpc_dec(call));\n")
+ elif ty.is_bulk_int64() and ty.name.startswith("u"):
+ o.pysrc("\t\tcall->bulk_u64 = (uint64_t)rxrpc_dec(call) << 32;\n")
+ o.pysrc("\t\tcall->bulk_u64 |= (uint64_t)rxrpc_dec(call);\n")
+ o.pysrc("\t\titem = PyLong_FromUnsignedLongLong(call->bulk_u64);\n")
+ elif ty.is_bulk_int64():
+ o.pysrc("\t\tcall->bulk_s64 = (int64_t)rxrpc_dec(call) << 32;\n")
+ o.pysrc("\t\tcall->bulk_s64 |= (int64_t)rxrpc_dec(call);\n")
+ o.pysrc("\t\titem = PyLong_FromLongLong(call->bulk_s64);\n")
+ else:
+ raise RuntimeError
+
+ o.pysrc("\t\tif (!item)\n")
+ o.pysrc("\t\t\treturn -1;\n")
+ o.pysrc("\t\tif (PyList_SetItem(obj->x.", p.name, ", call->bulk_index, item) < 0)\n")
+ o.pysrc("\t\t\treturn -1;\n")
+ o.pysrc("\t\tcall->bulk_index++;\n")
+
+ elif ty.is_single_blob():
+ if ty.is_single_string():
+ o.pysrc("\t\tswitch (py_dec_into_string(call)) {\n")
+ else:
+ o.pysrc("\t\tswitch (py_dec_into_buffer(call)) {\n")
+ o.pysrc("\t\tcase -1: return -1;\n")
+ o.pysrc("\t\tcase 0: break;\n")
+ o.pysrc("\t\tcase 1: phase = ", phase_id, "; goto select_phase;\n")
+ o.pysrc("\t\t}\n")
+ elif ty.is_single_int32():
+ o.pysrc("\t\tobj->x.", p.name, " = (", ty.name, ")rxrpc_dec(call);\n")
+ elif ty.is_single_int64():
+ o.pysrc("\t\tobj->x.", p.name, " = (", ty.name, ")rxrpc_dec(call) << 32;\n")
+ o.pysrc("\t\tobj->x.", p.name, " |= (", ty.name, ")rxrpc_dec(call) << 32;\n")
+ elif ty.is_single_struct():
+ o.pysrc("\t\tobj->x.", p.name, " = py_decode_", ty.name, "(call);\n")
+ else:
+ raise RuntimeError("Unsupported type in decode")
+
+ if ty.is_single_string():
+ o.pysrc("\t\tif (rxrpc_post_dec(call) < 0)\n")
+ o.pysrc("\t\t\treturn -1;\n")
+ o.pysrc("\t\tif (call->blob_offset < call->blob_size) {\n")
+ o.pysrc("\t\t\tphase = ", phase_id, ";\n")
+ o.pysrc("\t\t\tgoto select_phase;\n")
+ o.pysrc("\t\t}\n")
+ if ty.is_bulk():
+ o.pysrc("\t\tif (rxrpc_post_dec(call) < 0)\n")
+ o.pysrc("\t\t\treturn -1;\n")
+ o.pysrc("\t\tif (call->bulk_index < call->bulk_count) {\n")
+ o.pysrc("\t\t\tphase = ", phase_id, ";\n")
+ o.pysrc("\t\t\tgoto select_phase;\n")
+ o.pysrc("\t\t}\n")
+
+ if phase.form == "split":
+ o.pysrc("\t\tswitch (py_rxgen_split_receive(call, 0)) {\n")
+ o.pysrc("\t\tcase -1: return -1;\n")
+ o.pysrc("\t\tcase 0: break;\n")
+ o.pysrc("\t\tcase 1: phase = ", phase_id, "; goto select_phase;\n")
+ o.pysrc("\t\t}\n")
+ #o.pysrc("\t\tif (rxrpc_post_dec(call) < 0)\n")
+ #o.pysrc("\t\t\treturn -1;\n")
+ #o.pysrc("\t\tif (call->need_size != 0) {\n")
+ #o.pysrc("\t\t\tphase = ", phase_id, ";\n")
+ #o.pysrc("\t\t\tgoto select_phase;\n")
+ #o.pysrc("\t\t}\n")
+
+ if phase.form != "bulk" and phase.form != "blob":
+ o.pysrc("\t\tif (rxrpc_post_dec(call) < 0)\n")
+ o.pysrc("\t\t\treturn -1;\n")
+
+ o.pysrc("\n")
+ o.pysrc("\t\t/* --- Phase ", next_phase_id, " --- */\n")
+ if phase_goto_label:
+ o.pysrc("\tphase_", next_phase_id, ":\n")
+ o.pysrc("\t\tcall->phase = ", next_phase_id, ";\n")
+ o.pysrc("\t\tcall->need_size = 0;\n")
+ o.pysrc("\tdefault:\n")
+ o.pysrc("\t\treturn 0;\n")
+ o.pysrc("\t}\n")
+
+ o.pysrc("}\n")
--- /dev/null
+# Emission of Python type wrappers
+# -*- coding: utf-8 -*-
+
+__copyright__ = """
+Copyright (C) 2015 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 python type wrapper declarations
+#
+###############################################################################
+def emit_py_type_wrapper_decls(o, s):
+ o.pysrc("static PyTypeObject py_", s.name, "Type;\n")
+
+
+###############################################################################
+#
+# Emit python type wrappers for C structs.
+#
+###############################################################################
+def emit_py_type_wrapper(o, struct):
+ o.xdr.py_type_defs.append(py_type_def(struct.name, "py_" + struct.name + "Type"))
+
+ # Divide the struct members into single ints, single structs, char arrays
+ # (strings) and other arrays
+ single_ints = list();
+ single_structs = list();
+ char_arrays = list();
+ arrays = list();
+ for m in struct.members:
+ ty = m.typespec
+ o.where(struct.name + "::" + m.name)
+ if ty.is_char_array():
+ char_arrays.append(m)
+ elif ty.is_single_basic():
+ single_ints.append(m)
+ elif ty.is_single_struct():
+ single_structs.append(m)
+ elif ty.is_array():
+ arrays.append(m)
+ else:
+ o.error(": Unsupported struct member type")
+
+ # Write a python wrapper struct
+ #
+ # We have a copy of the raw struct and we also have caches for python
+ # objects for non-integer, non-array bits of the struct. We populate the
+ # caches when these bits are called for and then fold their contents back
+ # into the raw struct when we're about to marshal it.
+ #
+ o.pyhdr("\n")
+ o.pyhdr("struct py_", struct.name, " {\n")
+ o.pyhdr("\tPyObject_HEAD\n")
+ o.pyhdr("\tstruct ", struct.name, " x;\n")
+ if single_structs or arrays:
+ o.pyhdr("\tstruct {\n")
+ for m in single_structs + arrays:
+ o.pyhdr("\t\tPyObject *", m.name, ";\n")
+ o.pyhdr("\t} c;\n")
+ o.pyhdr("};\n")
+
+ # We need to have a new function if the object is to be allocatable by the
+ # Python interpreter
+ o.pysrc("\n")
+ o.pysrc("static PyObject *\n")
+ o.pysrc("py_", struct.name, "_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)\n")
+ o.pysrc("{\n")
+ o.pysrc("\treturn subtype->tp_alloc(subtype, 1);\n;")
+ o.pysrc("}\n")
+
+ # We have to have a deallocation function
+ o.pysrc("\n")
+ o.pysrc("static void\n")
+ o.pysrc("py_", struct.name, "_dealloc(struct py_", struct.name, " *self)\n")
+ o.pysrc("{\n")
+ for m in single_structs + arrays:
+ o.pysrc("\tPy_XDECREF(self->c.", m.name, ");\n")
+ o.pysrc("\tPy_TYPE(self)->tp_free((PyObject *)self);\n")
+ o.pysrc("}\n")
+
+ # Any integer non-array elements are made directly accessible to the Python
+ # interpreter
+ if single_ints:
+ o.pysrc("\n")
+ o.pysrc("static PyMemberDef py_", struct.name, "_members[] = {\n")
+ for m in single_ints:
+ ty = m.typespec
+ o.where(struct.name + "::" + m.name)
+ o.pysrc("\t{ \"", m.name, "\", ")
+ if ty.name == "char":
+ o.pysrc("T_CHAR")
+ elif ty.name == "int8_t":
+ o.pysrc("T_BYTE")
+ elif ty.name == "int16_t":
+ o.pysrc("T_SHORT")
+ elif ty.name == "int32_t":
+ o.pysrc("T_INT")
+ elif ty.name == "int64_t":
+ o.pysrc("T_LONGLONG")
+ elif ty.name == "uint8_t":
+ o.pysrc("T_UBYTE")
+ elif ty.name == "uint16_t":
+ o.pysrc("T_USHORT")
+ elif ty.name == "uint32_t":
+ o.pysrc("T_UINT")
+ elif ty.name == "uint64_t":
+ o.pysrc("T_ULONGLONG")
+ else:
+ o.error(": Unsupported type \"", ty.name, "\"")
+ o.pysrc(", offsetof(struct py_", struct.name, ", x.", m.name, "), 0, \"\"},\n")
+ o.pysrc("\t{}\n")
+ o.pysrc("};\n")
+
+ # Non-single integer elements need to be turned into their respective
+ # Python types and returned.
+
+ # Array elements have to be accessed through ->tp_[sg]etattro() as
+ # tuples (int[]/uint[]/struct[]) or strings (char[])
+ #
+ attro_list = char_arrays + single_structs + arrays
+ if attro_list:
+ # The attribute get function
+ o.pysrc("\n")
+ o.pysrc("static PyObject *\n")
+ o.pysrc("py_", struct.name, "_getattro(PyObject *_self, PyObject *name)\n")
+ o.pysrc("{\n")
+ o.pysrc("\tstruct py_", struct.name, " *self = (struct py_", struct.name, " *)_self;\n")
+ o.pysrc("\n")
+ o.pysrc("\tif (PyUnicode_Check(name)) {\n")
+
+ for m in attro_list:
+ ty = m.typespec
+ o.where(struct.name + "::" + m.name)
+ o.pysrc("\t\tif (PyUnicode_CompareWithASCIIString(name, \"", m.name, "\") == 0)\n")
+ if ty.is_single_struct():
+ o.pysrc("\t\t\treturn py_rxgen_get_struct(&self->x.", m.name, ",\n")
+ o.pysrc("\t\t\t\t\t\t &self->c.", m.name, ",\n")
+ o.pysrc("\t\t\t\t\t\t py_data_to_", ty.name, ");\n")
+ elif not ty.is_array():
+ raise RuntimeError("Unsupported basic type \"" + str(ty) + "\"")
+ elif ty.is_struct_array():
+ o.pysrc("\t\t\treturn py_rxgen_get_structs(&self->x.", m.name, ", ", ty.dim.name, ",\n")
+ o.pysrc("\t\t\t\t\t\t sizeof(struct ", ty.name, "),\n")
+ o.pysrc("\t\t\t\t\t\t &self->c.", m.name, ",\n")
+ o.pysrc("\t\t\t\t\t\t py_data_to_", ty.name, ");\n")
+ elif not ty.is_int_array():
+ o.error(": Unsupported array type class \"", ty, "\"")
+ elif ty.name == "char":
+ o.pysrc("\t\t\treturn py_rxgen_get_string(&self->x.", m.name, ", ", ty.dim.name, ");\n")
+ elif ty.name == "uint8_t":
+ o.pysrc("\t\t\treturn py_rxgen_get_uint8(&self->x.", m.name, ", ", ty.dim.name, ",\n")
+ o.pysrc("\t\t\t\t\t\t &self->c.", m.name, ");\n")
+ elif ty.name == "uint16_t":
+ o.pysrc("\t\t\treturn py_rxgen_get_uint16(&self->x.", m.name, ", ", ty.dim.name, ",\n")
+ o.pysrc("\t\t\t\t\t\t &self->c.", m.name, ");\n")
+ elif ty.name == "uint32_t":
+ o.pysrc("\t\t\treturn py_rxgen_get_uint32(&self->x.", m.name, ", ", ty.dim.name, ",\n")
+ o.pysrc("\t\t\t\t\t\t &self->c.", m.name, ");\n")
+ elif ty.name == "int8_t":
+ o.pysrc("\t\t\treturn py_rxgen_get_int8(&self->x.", m.name, ", ", ty.dim.name, ",\n")
+ o.pysrc("\t\t\t\t\t\t &self->c.", m.name, ");\n")
+ elif ty.name == "int16_t":
+ o.pysrc("\t\t\treturn py_rxgen_get_int16(&self->x.", m.name, ", ", ty.dim.name, ",\n")
+ o.pysrc("\t\t\t\t\t\t &self->c.", m.name, ");\n")
+ elif ty.name == "int32_t":
+ o.pysrc("\t\t\treturn py_rxgen_get_int32(&self->x.", m.name, ", ", ty.dim.name, ",\n")
+ o.pysrc("\t\t\t\t\t\t &self->c.", m.name, ");\n")
+ else:
+ raise RuntimeError("Unsupported array type \"" + str(ty) + "\"")
+
+ o.pysrc("\t}\n")
+ o.pysrc("\n")
+ o.pysrc("\treturn PyObject_GenericGetAttr(_self, name);\n")
+ o.pysrc("}\n")
+ o.pysrc("\n")
+
+ # The attribute set function
+ o.pysrc("static int\n")
+ o.pysrc("py_", struct.name, "_setattro(PyObject *_self, PyObject *name, PyObject *val)\n")
+ o.pysrc("{\n")
+ o.pysrc("\tstruct py_", struct.name, " *self = (struct py_", struct.name, " *)_self;\n")
+ o.pysrc("\n")
+ o.pysrc("\tif (PyUnicode_Check(name)) {\n")
+
+ for m in attro_list:
+ ty = m.typespec
+ o.where(struct.name + "::" + m.name)
+ o.pysrc("\t\tif (PyUnicode_CompareWithASCIIString(name, \"", m.name, "\") == 0)\n")
+ if ty.is_single_struct():
+ o.pysrc("\t\t\treturn py_rxgen_set_struct(&self->c.", m.name, ",\n")
+ o.pysrc("\t\t\t\t\t\t &py_", ty.name, "Type, val);\n")
+ elif not ty.is_array():
+ raise RuntimeError("Unsupported basic type \"" + str(ty) + "\"")
+ elif ty.is_char_array():
+ o.pysrc("\t\t\treturn py_rxgen_set_string(&self->x.", m.name, ", ", ty.dim.name, ", val);\n")
+ elif ty.is_int_array() or ty.is_struct_array():
+ o.pysrc("\t\t\treturn py_rxgen_set_array(", ty.dim.name, ", &self->c.", m.name, ", val);\n")
+ else:
+ raise RuntimeError("Unsupported array type \"" + str(ty) + "\"")
+
+ o.pysrc("\t}\n")
+ o.pysrc("\n")
+ o.pysrc("\treturn PyObject_GenericSetAttr(_self, name, val);\n")
+ o.pysrc("}\n")
+ o.pysrc("\n")
+
+ # Emit the Python type definition
+ o.pysrc("static PyTypeObject py_", struct.name, "Type = {\n")
+ o.pysrc("\tPyVarObject_HEAD_INIT(NULL, 0)\n")
+ o.pysrc("\t\"kafs.", struct.name, "\",\t\t/*tp_name*/\n")
+ o.pysrc("\tsizeof(struct py_", struct.name, "),\t/*tp_basicsize*/\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_itemsize*/\n")
+ o.pysrc("\t(destructor)py_", struct.name, "_dealloc, /*tp_dealloc*/\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_print*/\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_getattr*/\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_setattr*/\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_compare*/\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_repr*/\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_as_number*/\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_as_sequence*/\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_as_mapping*/\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_hash */\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_call*/\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_str*/\n")
+ if attro_list:
+ o.pysrc("\tpy_", struct.name, "_getattro,\n")
+ o.pysrc("\tpy_", struct.name, "_setattro,\n")
+ else:
+ o.pysrc("\t0,\t\t\t\t/*tp_getattro*/\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_setattro*/\n")
+ o.pysrc("\t0,\t\t\t\t/*tp_as_buffer*/\n")
+ o.pysrc("\tPy_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/\n")
+ o.pysrc("\t\"\",\t\t\t/* tp_doc */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_traverse */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_clear */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_richcompare */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_weaklistoffset */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_iter */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_iternext */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_methods */\n")
+ if single_ints:
+ o.pysrc("\tpy_", struct.name, "_members,\n")
+ else:
+ o.pysrc("\t0,\t\t\t/* tp_members */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_getset */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_base */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_dict */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_descr_get */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_descr_set */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_dictoffset */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_init */\n")
+ o.pysrc("\t0,\t\t\t\t/* tp_alloc */\n")
+ o.pysrc("\tpy_", struct.name, "_new,\n")
+ o.pysrc("};\n")
+
+ # Emit a function to allocate such a type
+ o.pyhdr("extern PyObject *kafs_new_py_", struct.name, "(PyObject *, PyObject *);\n")
+
+ o.pysrc("\n")
+ o.pysrc("PyObject *\n")
+ o.pysrc("kafs_new_py_", struct.name, "(PyObject *_self, PyObject *args)\n")
+ o.pysrc("{\n")
+ o.pysrc("\tPyObject *obj = _PyObject_New(&py_", struct.name, "Type);\n")
+ o.pysrc("\tstruct py_", struct.name, " *self = (struct py_", struct.name, " *)obj;\n")
+ o.pysrc("\tif (!obj)\n")
+ o.pysrc("\t\treturn PyExc_MemoryError;\n")
+ o.pysrc("\tmemset(&self->x, 0, sizeof(self->x));\n")
+ if single_structs or arrays:
+ o.pysrc("\tmemset(&self->c, 0, sizeof(self->c));\n")
+ o.pysrc("\treturn obj;\n")
+ o.pysrc("}\n")
+
+ # Emit a function to create an object of this type from raw data
+ o.pyhdr("extern PyObject *py_data_to_", struct.name, "(const void *);\n")
+
+ o.pysrc("\n")
+ o.pysrc("PyObject *py_data_to_", struct.name, "(const void *data)\n")
+ o.pysrc("{\n")
+ o.pysrc("\tPyObject *obj = _PyObject_New(&py_", struct.name, "Type);\n")
+ o.pysrc("\tstruct py_", struct.name, " *self = (struct py_", struct.name, " *)obj;\n")
+ o.pysrc("\tif (!obj)\n")
+ o.pysrc("\t\treturn PyExc_MemoryError;\n")
+ o.pysrc("\tmemcpy(&self->x, data, sizeof(self->x));\n")
+ if single_structs or arrays:
+ o.pysrc("\tmemset(&self->c, 0, sizeof(self->c));\n")
+ o.pysrc("\treturn obj;\n")
+ o.pysrc("}\n")
+
+ # Emit a function to unmarshal on object of this type.
+ o.pysrc("\n")
+ o.pysrc("PyObject *py_decode_", struct.name, "(struct rx_call *call)\n")
+ o.pysrc("{\n")
+ o.pysrc("\tPyObject *obj = _PyObject_New(&py_", struct.name, "Type);\n")
+ o.pysrc("\tstruct py_", struct.name, " *self = (struct py_", struct.name, " *)obj;\n")
+ o.pysrc("\tif (!obj)\n")
+ o.pysrc("\t\treturn PyExc_MemoryError;\n")
+ o.pysrc("\trxgen_decode_", struct.name, "(call, &self->x);\n")
+ if single_structs or arrays:
+ o.pysrc("\tmemset(&self->c, 0, sizeof(self->c));\n")
+ o.pysrc("\treturn obj;\n")
+ o.pysrc("}\n")
+
+ # Emit a function to premarshal such a type. This checks the Python object
+ # type and folds the contents of the cached Python objects into their raw
+ # fields.
+ #
+ o.pyhdr("extern int py_premarshal_", struct.name, "(PyObject *);\n")
+
+ o.pysrc("\n")
+ o.pysrc("int py_premarshal_", struct.name, "(PyObject *_self)\n")
+ o.pysrc("{\n")
+ o.pysrc("\tstruct py_", struct.name, " *self = (struct py_", struct.name, " *)_self;\n")
+
+ # Check that the type we've been given is the right one
+ o.pysrc("\n")
+ o.pysrc("\tif (!PyObject_TypeCheck(self, &py_", struct.name, "Type)) {\n")
+ o.pysrc("\t\tPyErr_Format(PyExc_TypeError, \"Expected object of type ", struct.name, "\");\n")
+ o.pysrc("\t\treturn -1;\n")
+ o.pysrc("\t}\n")
+
+ if single_structs or arrays:
+ o.pysrc("\n")
+ first = 1
+ for m in single_structs + arrays:
+ ty = m.typespec
+ o.where(struct.name + "::" + m.name)
+ if first:
+ o.pysrc("\tif (")
+ first = 0
+ else:
+ o.pysrc(" ||\n")
+ o.pysrc("\t ")
+
+ if ty.is_single_struct():
+ o.pysrc("py_rxgen_premarshal_struct(&self->x.", m.name, ",\n")
+ o.pysrc("\t\t\t\t sizeof(struct ", ty.name, "),\n")
+ o.pysrc("\t\t\t\t offsetof(struct py_", ty.name, ", x),\n")
+ o.pysrc("\t\t\t\t self->c.", m.name, ",\n")
+ o.pysrc("\t\t\t\t py_premarshal_", ty.name, ") < 0")
+ elif not ty.is_array():
+ raise RuntimeError("Unsupported basic type \"" + str(ty) + "\"")
+ elif ty.is_struct_array():
+ o.pysrc("py_rxgen_premarshal_structs(&self->x.", m.name, ",\n")
+ o.pysrc("\t\t\t\t\t", ty.dim.name, ", sizeof(struct ", ty.name, "),\n")
+ o.pysrc("\t\t\t\t\toffsetof(struct py_", ty.name, ", x),\n")
+ o.pysrc("\t\t\t\t\tself->c.", m.name, ",\n")
+ o.pysrc("\t\t\t\t\tpy_premarshal_", ty.name, ") < 0")
+ elif not ty.is_int_array():
+ raise RuntimeError("Unsupported array type \"", ty, "\"")
+ elif ty.name == "uint8_t":
+ o.pysrc("py_rxgen_premarshal_uint8(&self->x.", m.name, ", ", ty.dim.name, ", self->c.", m.name, ") < 0")
+ elif ty.name == "uint16_t":
+ o.pysrc("py_rxgen_premarshal_uint16(&self->x.", m.name, ", ", ty.dim.name, ", self->c.", m.name, ") < 0")
+ elif ty.name == "uint32_t":
+ o.pysrc("py_rxgen_premarshal_uint32(&self->x.", m.name, ", ", ty.dim.name, ", self->c.", m.name, ") < 0")
+ elif ty.name == "int8_t":
+ o.pysrc("py_rxgen_premarshal_int8(&self->x.", m.name, ", ", ty.dim.name, ", self->c.", m.name, ") < 0")
+ elif ty.name == "int16_t":
+ o.pysrc("py_rxgen_premarshal_int16(&self->x.", m.name, ", ", ty.dim.name, ", self->c.", m.name, ") < 0")
+ elif ty.name == "int32_t":
+ o.pysrc("py_rxgen_premarshal_int32(&self->x.", m.name, ", ", ty.dim.name, ", self->c.", m.name, ") < 0")
+ else:
+ o.error(": Unsupported array type \"", ty.name, "\"")
+
+ o.pysrc(")\n")
+ o.pysrc("\t\treturn -1;\n")
+
+ o.pysrc("\treturn 0;\n")
+ o.pysrc("}\n")
+
--- /dev/null
+#!/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) 2015 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 <iisaman@citi.umich.edu>
+ Copyright (C) 2004 University of Michigan, Center for
+ Information Technology Integration
+ Based on version written by Peter Astrand <peter@cendio.se>
+ 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 *
+from emit_py_types import *
+from emit_py_sync_funcs import *
+from emit_py_module import *
+
+xdr = None # Current context
+
+##########################################################################
+# #
+# Lexical analysis #
+# #
+##########################################################################
+import ply.lex as lex
+
+basic_types = (
+ ( "char", "char", xdr_basic.int32, 4 ),
+ ( "int8_t", "int8_t", xdr_basic.int32, 4 ),
+ ( "int16_t", "int16_t", xdr_basic.int32, 4 ),
+ ( "int32_t", "int32_t", xdr_basic.int32, 4 ),
+ ( "int64_t", "int64_t", xdr_basic.int64, 8 ),
+ ( "uint8_t", "uint8_t", xdr_basic.int32, 4 ),
+ ( "uint16_t", "uint16_t", xdr_basic.int32, 4 ),
+ ( "uint32_t", "uint32_t", xdr_basic.int32, 4 ),
+ ( "uint64_t", "uint64_t", xdr_basic.int64, 8 ),
+ ( "string", "char", xdr_basic.string, 4 ),
+ ( "opaque", "void", xdr_basic.opaque, 4 ),
+ )
+
+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_size=i[3])
+ xdr.types[name] = t
+
+keywords = (
+ "IN",
+ "INOUT",
+ "OUT",
+ "const",
+ "enum",
+ "multi",
+ "package",
+ "split",
+ "struct",
+ "typedef",
+) + tuple([i[0] for i in basic_types])
+
+# Required by lex. Each token also allows a function t_<token>.
+tokens = tuple([t.upper() for t in keywords]) + (
+ "ID", "CONST10", "CONST8", "CONST16",
+ # ( ) [ ] { }
+ "LPAREN", "RPAREN", "LSQUARE", "RSQUARE", "LBRACE", "RBRACE",
+ # ; : < > * = ,
+ "SEMI", "LT", "GT", "STAR", "EQUALS", "COMMA",
+ "BEGIN_ERROR_CODES", "END_ERROR_CODES", "NEWFILE"
+)
+
+# t_<name> functions are used by lex. They are called with t.value==<match
+# of rule in comment>, and t.type==<name>. They expect a return value
+# with attribute type=<token>
+
+# 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_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'''
+
+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(1)
+ 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(1)
+ 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(1)
+ 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)
+
+###############################################################################
+#
+# Type specification
+#
+def p_declaration_1(t):
+ '''declaration : type_specifier ID'''
+ typespec = t[1]
+ name = t[2]
+ global xdr
+ xdr.lineno = t.lineno(1)
+ 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(1)
+ 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(1)
+ 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_size = t[4]
+ global xdr
+ xdr.lineno = t.lineno(1)
+ if typespec.is_single_blob():
+ ty = xdr_type(xdr, base=typespec, max_size=max_size)
+ else:
+ ty = xdr_type(xdr, base=typespec, array=xdr_array.bulk, max_size=max_size)
+ 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_size = t[5]
+ global xdr
+ xdr.lineno = t.lineno(1)
+ if typespec.is_single_blob():
+ ty = xdr_type(xdr, base=typespec, max_size=max_size)
+ else:
+ ty = xdr_type(xdr, base=typespec, array=xdr_array.bulk, max_size=max_size)
+ 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_size = t[3]
+ name = t[6]
+ global xdr
+ xdr.lineno = t.lineno(1)
+ ty = xdr_type(xdr, base=typespec, array=xdr_array.bulk, max_size=max_size)
+ t[0] = xdr_member(name, ty, xdr)
+
+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
+ | 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_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(1)
+ 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="<anon struct {:s}>".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]
+
+###############################################################################
+#
+# 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)
+
+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)
+
+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)
+
+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
+
+ # We need to capture the error code list so that we can build a set of
+ # Python exceptions for it - but the only way to do that is to snoop
+ # the comments
+ #
+ 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)
+ 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
+
+#
+# Section: main
+#
+if __name__ == "__main__":
+ if len(sys.argv) < 2:
+ print("Usage: {:s} <filename>*".format(sys.argv[0]))
+ sys.exit(1)
+
+ for f in sys.argv[1:]:
+ if not parse(f):
+ break
+
+ xdr.finished_parsing()
+
+ o = file_generator(xdr)
+ o.rxhdr("/* AUTOGENERATED */\n")
+ #o.rxhdr("#define _XOPEN_SOURCE\n";
+ o.rxhdr("#include <stdint.h>\n")
+ o.rxhdr("#include \"rxgen.h\"\n")
+
+ o.rxsrc("/* AUTOGENERATED */\n")
+ o.rxsrc("#include \"afs_xg.h\"\n")
+ o.rxsrc("#include <stdio.h>\n")
+ o.rxsrc("#include <stdlib.h>\n")
+ o.rxsrc("#include <string.h>\n")
+ o.rxsrc("#include <unistd.h>\n")
+ o.rxsrc("#include <errno.h>\n")
+ o.rxsrc("#include <sys/socket.h>\n")
+ o.rxsrc("#include <sys/param.h>\n")
+ o.rxsrc("#include <arpa/inet.h>\n")
+ o.rxsrc("\n")
+
+ o.pyhdr("/* AUTOGENERATED */\n")
+ o.pyhdr("#include <Python.h>\n")
+ o.pyhdr("#include \"afs_xg.h\"\n")
+ o.pyhdr("#include \"py_rxgen.h\"\n")
+
+ o.pysrc("/* AUTOGENERATED */\n")
+ o.pysrc("#include <Python.h>\n")
+ o.pysrc("#include \"structmember.h\"\n")
+ o.pysrc("#include \"afs_py.h\"\n")
+ o.pysrc("#include <arpa/inet.h>\n")
+ o.pysrc("\n")
+
+ # Declare constants
+ o.rxhdr("\n")
+ for name in xdr.all_constants:
+ c = xdr.constants[name]
+ o.rxhdr("#define ", c.name, " ", c.value, "\n")
+
+ # Declare structure types
+ for s in xdr.all_structs:
+ emit_struct_encdec_decl(o, s)
+ emit_py_type_wrapper_decls(o, s)
+
+ for s in xdr.all_structs:
+ emit_struct_encdec(o, s);
+ emit_py_type_wrapper(o, s);
+
+ # 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 f in xdr.funcs:
+ # Dump the banner comment block
+ 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)
+ ty = p.typespec
+ if ty.is_single_basic():
+ pass
+ elif ty.is_struct():
+ assert(ty.xdr_size)
+ elif ty.is_single_blob():
+ # Could validate max_size attribute
+ pass
+ elif ty.is_bulk():
+ assert(ty.xdr_size)
+ else:
+ raise RuntimeError("Unsupported param type \"" + str(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_decode(o, f, "client", "response", f.response)
+ emit_func_send(o, f, "request")
+ #emit_func_decode(f, "server", "request", request)
+ #emit_func_send(f, "response")
+
+ emit_py_func_param_object(o, f, "request")
+ emit_py_func_param_object(o, f, "response")
+ emit_py_func_bulk_helper(o, f)
+ emit_py_func_decode(o, f, "client", "response", f.response)
+ emit_py_func_decode(o, f, "server", "request", f.request)
+ emit_py_func_simple_sync_call(o, f)
+
+ emit_py_module(o);
--- /dev/null
+# Bits for rxgen implementation
+# -*- coding: utf-8 -*-
+
+__copyright__ = """
+Copyright (C) 2015 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
+
+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.funcs = list() # Functions in declaration order
+ self.func_names = dict() # Function name uniquifier
+ 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.py_type_defs = list() # Python type definitions
+ self.py_func_defs = list() # Python function definitions
+ 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:
+ value = str(int(value) + 0x100000000)
+ code.u32 = int(value)
+ 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.func_names:
+ self.error("Proc {:s} already exists".format(name))
+ else:
+ self.func_names[name] = proc
+ self.funcs.append(proc)
+ self.debug("New proc", name)
+ return self.func_names[name]
+
+ 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()
+
+###############################################################################
+#
+# 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_size Max elements in bulk array (if array/bulk)
+# members Members of struct
+# xdr_size Size of XDR encoded object
+# 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_size=None,
+ xdr_size=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_size:
+ raise RuntimeError("Can't be both variable and fixed-size array")
+ elif basic == "string" or basic == "opaque" or base and base.is_blob():
+ if dim:
+ raise RuntimeError("Can't specify fixed dimension limits on string/opaque")
+ else:
+ if dim or max_size:
+ raise RuntimeError("Can't specify dimension limits on non-array")
+
+ self.source = xdr.source
+ self.lineno = xdr.lineno
+ self.referenced = False
+
+ 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_size = base.max_size
+ self.xdr_size = base.xdr_size
+ self.members = base.members
+
+ if array:
+ if base.array:
+ xdr.error("Array-of-array not supported")
+ self.array = array
+ self.dim = dim
+ self.max_size = max_size
+ if self.xdr_size and dim:
+ self.xdr_size *= int(str(dim))
+ elif self.is_single_blob() and max_size:
+ if self.max_size:
+ xdr.error("Maximum size already set on string/opaque")
+ self.max_size = max_size
+ 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.xdr_size = xdr_size
+ self.array = array
+ self.dim = dim
+ self.max_size = max_size
+ self.members = members
+ self.xdr_size = xdr_size
+ if members:
+ if not isinstance(members, list):
+ raise RuntimeError("Members should be a list")
+ self.xdr_size = 0
+ for i in members:
+ if i.typespec.xdr_size:
+ self.xdr_size += i.typespec.xdr_size
+
+ 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_blob(self):
+ return self.is_string() or self.is_opaque()
+
+ 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_blob(self):
+ return not self.array and self.is_blob()
+
+ def is_single_basic(self):
+ return not self.array and not self.is_struct()
+
+ def is_single_struct(self):
+ return not self.array and self.is_struct()
+
+ 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_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 __str__(self):
+ t = self.name
+ if self.is_array():
+ t += "[{:s}]".format(str(self.dim))
+ elif self.is_bulk() or self.is_blob():
+ if self.max_size:
+ t += "<{:s}>".format(str(self.max_size))
+ 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.name = name
+ self.source = xdr.source
+ self.lineno = xdr.lineno
+ self.special = None
+
+###############################################################################
+#
+# 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 procedure member definition
+#
+###############################################################################
+class xdr_proc(token_base):
+ """An XDR procedure"""
+ def __init__(self, name, xdr, params, opcode, multi=False, split=False):
+ self.name = xdr.pkg.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):
+ self.xdr = xdr
+ self._rxhdr = open("2_afs_xg.h", "w", encoding="utf-8")
+ self._rxsrc = open("2_afs_xg.c", "w", encoding="utf-8")
+ self._pyhdr = open("2_afs_py.h", "w", encoding="utf-8")
+ self._pysrc = open("2_afs_py.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 pyhdr(self, *va):
+ for i in va:
+ self._pyhdr.write(str(i))
+
+ def pysrc(self, *va):
+ for i in va:
+ self._pysrc.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 pyhdrf(self, fmt, *va):
+ self._pyhdr.write(fmt.format(*va))
+
+ def pysrcf(self, fmt, *va):
+ self._pysrc.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")
+
+###############################################################################
+#
+# Python type def
+#
+###############################################################################
+class py_type_def:
+ def __init__(self, name, c_type):
+ self.name = name
+ self.c_type = c_type
+
+###############################################################################
+#
+# Python function def
+#
+###############################################################################
+class py_func_def:
+ def __init__(self, name, c_func, doc=""):
+ self.name = name
+ self.c_func = c_func
+ self.doc = doc