This is an automated email from the ASF dual-hosted git repository. astitcher pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/qpid-proton.git
commit b1b9b07a2552c69ad6512d5e272534d26538f692 Author: Andrew Stitcher <[email protected]> AuthorDate: Wed Dec 3 22:53:02 2025 -0500 PROTON-2910: [core] Changed generated code to use better names The generated code now uses the specs to generate the frame encode/decode functions, but allows you to specify their names. This allows the actual code to read a whole lot better. Also now documented the spec codes at the top of the generate.py code. I think this doc can still be improved. (Also removed some holdovers from the initial PROTON-2451 work) --- c/src/core/engine.c | 4 +- c/src/core/message.c | 30 ++++---- c/src/core/transport.c | 64 ++++++++--------- c/src/sasl/sasl.c | 22 +++--- c/tools/codec-generator/Pipfile | 12 ---- c/tools/codec-generator/find_specs.py | 103 --------------------------- c/tools/codec-generator/generate.py | 126 +++++++++++++++++++++++++++------- c/tools/codec-generator/specs.json | 97 +++++++++++++------------- 8 files changed, 208 insertions(+), 250 deletions(-) diff --git a/c/src/core/engine.c b/c/src/core/engine.c index f6e7d7fd4..91b7e47c2 100644 --- a/c/src/core/engine.c +++ b/c/src/core/engine.c @@ -2141,7 +2141,7 @@ uint64_t pn_transactional_disposition_get_outcome_type(pn_transactional_disposit if (disposition->outcome_raw.size) { bool qtype = false; uint64_t type; - pn_amqp_decode_DQLq(disposition->outcome_raw, &qtype, &type); + pn_amqp_decode_described_type_anything(disposition->outcome_raw, &qtype, &type); if (qtype) { return type; } @@ -2155,7 +2155,7 @@ void pn_transactional_disposition_set_outcome_type(pn_transactional_disposition_ // Generate a described LIST0 directly - this needs a max of 11 bytes char outcome_scratch[11]; pn_rwbytes_t scratch = {.size=sizeof(outcome_scratch), .start=outcome_scratch}; - pn_bytes_t outcome_raw = pn_amqp_encode_DLEe(&scratch, type); + pn_bytes_t outcome_raw = pn_amqp_encode_described_empty_list(&scratch, type); pn_bytes_free(disposition->outcome_raw); disposition->outcome_raw = pn_bytes_dup(outcome_raw); } diff --git a/c/src/core/message.c b/c/src/core/message.c index a4ddb5f7a..b3b1973ea 100644 --- a/c/src/core/message.c +++ b/c/src/core/message.c @@ -742,7 +742,7 @@ int pn_message_decode(pn_message_t *msg, const char *bytes, size_t size) while (msg_bytes.size) { bool scanned; uint64_t desc; - size_t section_size = pn_amqp_decode_DQLq(msg_bytes, &scanned, &desc); + size_t section_size = pn_amqp_decode_described_type_anything(msg_bytes, &scanned, &desc); if (!scanned) { desc = 0; } @@ -751,7 +751,7 @@ int pn_message_decode(pn_message_t *msg, const char *bytes, size_t size) case AMQP_DESC_HEADER: { bool priority_q; uint8_t priority; - pn_amqp_decode_DqEoQBIoIe(msg_bytes, + pn_amqp_decode_message_header(msg_bytes, &msg->durable, &priority_q, &priority, &msg->ttl, @@ -765,7 +765,7 @@ int pn_message_decode(pn_message_t *msg, const char *bytes, size_t size) group_id, reply_to_group_id; pn_atom_t id; pn_atom_t correlation_id; - pn_amqp_decode_DqEazSSSassttSISe(msg_bytes, &id, + pn_amqp_decode_message_properties(msg_bytes, &id, &user_id, &address, &subject, &reply_to, &correlation_id, &ctype, &cencoding, &msg->expiry_time, &msg->creation_time, &group_id, @@ -795,32 +795,32 @@ int pn_message_decode(pn_message_t *msg, const char *bytes, size_t size) break; } case AMQP_DESC_DELIVERY_ANNOTATIONS: { - pn_amqp_decode_DqR(msg_bytes, &instructions_bytes); + pn_amqp_decode_described_raw(msg_bytes, &instructions_bytes); break; } case AMQP_DESC_MESSAGE_ANNOTATIONS: { - pn_amqp_decode_DqR(msg_bytes, &annotations_bytes); + pn_amqp_decode_described_raw(msg_bytes, &annotations_bytes); break; } case AMQP_DESC_APPLICATION_PROPERTIES: { - pn_amqp_decode_DqR(msg_bytes, &properties_bytes); + pn_amqp_decode_described_raw(msg_bytes, &properties_bytes); break; } case AMQP_DESC_DATA: case AMQP_DESC_AMQP_SEQUENCE: { msg->inferred = true; - pn_amqp_decode_DqR(msg_bytes, &body_bytes); + pn_amqp_decode_described_raw(msg_bytes, &body_bytes); break; } case AMQP_DESC_AMQP_VALUE: { msg->inferred = false; - pn_amqp_decode_DqR(msg_bytes, &body_bytes); + pn_amqp_decode_described_raw(msg_bytes, &body_bytes); break; } case AMQP_DESC_FOOTER: break; default: { - pn_amqp_decode_R(msg_bytes, &unknown_section_bytes); + pn_amqp_decode_raw(msg_bytes, &unknown_section_bytes); break; } } @@ -856,7 +856,7 @@ int pn_message_encode(pn_message_t *msg, char *bytes, size_t *isize) size_t total = 0; /* "DL[?o?B?I?o?I]!" */ - size_t last_size = pn_amqp_encode_bytes_DLEQoQBQIQoQIeX(bytes, remaining, AMQP_DESC_HEADER, + size_t last_size = pn_amqp_encode_bytes_message_header(bytes, remaining, AMQP_DESC_HEADER, msg->durable, msg->durable, msg->priority!=AMQP_HEADER_PRIORITY_DEFAULT, msg->priority, (bool)msg->ttl, msg->ttl, @@ -870,7 +870,7 @@ int pn_message_encode(pn_message_t *msg, char *bytes, size_t *isize) if (msg->instructions_raw.size>0) { - last_size = pn_amqp_encode_bytes_DLR(bytes, remaining, AMQP_DESC_DELIVERY_ANNOTATIONS, msg->instructions_raw); + last_size = pn_amqp_encode_bytes_described_type_raw(bytes, remaining, AMQP_DESC_DELIVERY_ANNOTATIONS, msg->instructions_raw); if (last_size > remaining) return PN_OVERFLOW; remaining -= last_size; @@ -879,7 +879,7 @@ int pn_message_encode(pn_message_t *msg, char *bytes, size_t *isize) } if (msg->annotations_raw.size>0) { - last_size = pn_amqp_encode_bytes_DLR(bytes, remaining, AMQP_DESC_MESSAGE_ANNOTATIONS, msg->annotations_raw); + last_size = pn_amqp_encode_bytes_described_type_raw(bytes, remaining, AMQP_DESC_MESSAGE_ANNOTATIONS, msg->annotations_raw); if (last_size > remaining) return PN_OVERFLOW; remaining -= last_size; @@ -890,7 +890,7 @@ int pn_message_encode(pn_message_t *msg, char *bytes, size_t *isize) /* "DL[azSSSass?t?tS?IS]!" */ pn_atom_t id = pn_message_get_id(msg); pn_atom_t correlation_id = pn_message_get_correlation_id(msg); - last_size = pn_amqp_encode_bytes_DLEazSSSassQtQtSQISeX(bytes, remaining, AMQP_DESC_PROPERTIES, + last_size = pn_amqp_encode_bytes_message_properties(bytes, remaining, AMQP_DESC_PROPERTIES, &id, pn_string_size(msg->user_id), pn_string_get(msg->user_id), pn_string_bytes(msg->address), @@ -916,7 +916,7 @@ int pn_message_encode(pn_message_t *msg, char *bytes, size_t *isize) total += last_size; if (msg->properties_raw.size>0) { - last_size = pn_amqp_encode_bytes_DLR(bytes, remaining, AMQP_DESC_APPLICATION_PROPERTIES, msg->properties_raw); + last_size = pn_amqp_encode_bytes_described_type_raw(bytes, remaining, AMQP_DESC_APPLICATION_PROPERTIES, msg->properties_raw); if (last_size > remaining) return PN_OVERFLOW; remaining -= last_size; @@ -939,7 +939,7 @@ int pn_message_encode(pn_message_t *msg, char *bytes, size_t *isize) break; } } - last_size = pn_amqp_encode_bytes_DLR(bytes, remaining, descriptor, msg->body_raw); + last_size = pn_amqp_encode_bytes_described_type_raw(bytes, remaining, descriptor, msg->body_raw); if (last_size > remaining) return PN_OVERFLOW; remaining -= last_size; diff --git a/c/src/core/transport.c b/c/src/core/transport.c index 1b284dffd..63f642e73 100644 --- a/c/src/core/transport.c +++ b/c/src/core/transport.c @@ -870,7 +870,7 @@ static int pni_post_amqp_transfer_frame(pn_transport_t *transport, uint16_t ch, compute_performatives:; /* "DL[IIzI?o?on?DLC?o?o?o]" */ pn_bytes_t performative = - pn_amqp_encode_DLEIIzIQoQondQoQoQoe(&transport->scratch_space, AMQP_DESC_TRANSFER, + pn_amqp_encode_transfer(&transport->scratch_space, AMQP_DESC_TRANSFER, handle, id, tag.size, tag.start, @@ -920,7 +920,7 @@ static int pni_post_close(pn_transport_t *transport, pn_condition_t *cond) if (!cond && transport->connection) { cond = pn_connection_condition(transport->connection); } - pn_bytes_t buf = pn_amqp_encode_DLEce(&transport->scratch_space, AMQP_DESC_CLOSE, cond); + pn_bytes_t buf = pn_amqp_encode_close(&transport->scratch_space, AMQP_DESC_CLOSE, cond); return pn_framing_send_amqp(transport, 0, buf); } @@ -1013,7 +1013,7 @@ int pn_do_open(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_bytes_t remote_desired_capabilities; pn_bytes_t remote_properties; - pn_amqp_decode_DqEQSQSQIQHIqqRRRe(payload, + pn_amqp_decode_open(payload, &container_q, &remote_container, &hostname_q, &remote_hostname, &remote_max_frame_q, &remote_max_frame, @@ -1073,7 +1073,7 @@ int pn_do_begin(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, bool handle_max_q; uint32_t handle_max; - pn_amqp_decode_DqEQHIIIQIe(payload, &reply, &remote_channel, &next, &incoming_window, &outgoing_window, &handle_max_q, &handle_max); + pn_amqp_decode_begin(payload, &reply, &remote_channel, &next, &incoming_window, &outgoing_window, &handle_max_q, &handle_max); // AMQP 1.0 section 2.7.1 - if the peer doesn't honor our channel_max -- // express our displeasure by closing the connection with a framing error. @@ -1196,7 +1196,7 @@ int pn_do_attach(pn_transport_t *transport, uint8_t frame_type, uint16_t channel uint64_t max_msgsz; bool has_props; pn_bytes_t rem_props = (pn_bytes_t){0, NULL}; - pn_amqp_decode_DqESIoQBQBDqESIsIoqseDqESIsIoeqqILqqQRe(payload, + pn_amqp_decode_attach(payload, &name, &handle, &is_sender, &snd_settle, &snd_settle_mode, @@ -1256,7 +1256,7 @@ int pn_do_attach(pn_transport_t *transport, uint8_t frame_type, uint16_t channel pn_terminus_set_dynamic(rtgt, tgt_dynamic); } else { uint64_t code = 0; - pn_amqp_decode_DqEqqqqqDqqDLqqqqe(payload, &code); + pn_amqp_decode_attach_target_type(payload, &code); if (code == AMQP_DESC_COORDINATOR) { pn_terminus_set_type(rtgt, PN_COORDINATOR); } else if (code == AMQP_DESC_TARGET) { @@ -1275,7 +1275,7 @@ int pn_do_attach(pn_transport_t *transport, uint8_t frame_type, uint16_t channel pn_bytes_t rem_src_filter = (pn_bytes_t) {0, NULL}; pn_bytes_t rem_src_outcomes = (pn_bytes_t) {0, NULL}; pn_bytes_t rem_src_capabilities = (pn_bytes_t) {0, NULL}; - pn_amqp_decode_DqEqqqqqDqEqqqqqRqRqRRee(payload, + pn_amqp_decode_attach_source_props(payload, &rem_src_properties, &rem_src_filter, &rem_src_outcomes, @@ -1294,10 +1294,10 @@ int pn_do_attach(pn_transport_t *transport, uint8_t frame_type, uint16_t channel pn_bytes_t rem_tgt_capabilities = (pn_bytes_t) {0, NULL}; if (pn_terminus_get_type(&link->remote_target) == PN_COORDINATOR) { // coordinator target only has a capabilities field - pn_amqp_decode_DqEqqqqqDqqDqEReqqqe(payload, + pn_amqp_decode_attach_coordinator_caps(payload, &rem_tgt_capabilities); } else { - pn_amqp_decode_DqEqqqqqDqqDqEqqqqqRRee(payload, + pn_amqp_decode_attach_target_props(payload, &rem_tgt_properties, &rem_tgt_capabilities); } @@ -1348,7 +1348,7 @@ int pn_do_transfer(pn_transport_t *transport, uint8_t frame_type, uint16_t chann pn_bytes_t disp_data; size_t dsize = - pn_amqp_decode_DqEIQIzqQooqDQLRoooe(payload, &handle, &id_present, &id, &tag, + pn_amqp_decode_transfer(payload, &handle, &id_present, &id, &tag, &settled_set, &settled, &more, &has_type, &type, &disp_data, &resume, &aborted, &batchable); payload.size -= dsize; @@ -1477,7 +1477,7 @@ int pn_do_flow(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, uint32_t handle; bool inext_init, handle_init, dcount_init, drain; - pn_amqp_decode_DqEQIIIIQIQIIqoe(payload, &inext_init, &inext, &iwin, + pn_amqp_decode_flow(payload, &inext_init, &inext, &iwin, &onext, &owin, &handle_init, &handle, &dcount_init, &delivery_count, &link_credit, &drain); @@ -1556,7 +1556,7 @@ static void pni_amqp_decode_disposition (uint64_t type, pn_bytes_t disp_data, pn uint32_t number; bool qoffset; uint64_t offset; - pn_amqp_decode_EQIQLe(disp_data, &qnumber, &number, &qoffset, &offset); + pn_amqp_decode_disposition_received(disp_data, &qnumber, &number, &qoffset, &offset); disp->type = PN_DISP_RECEIVED; @@ -1576,7 +1576,7 @@ static void pni_amqp_decode_disposition (uint64_t type, pn_bytes_t disp_data, pn pn_bytes_t cond; pn_bytes_t desc; pn_bytes_t info; - pn_amqp_decode_EDqEsSRee(disp_data, &cond, &desc, &info); + pn_amqp_decode_disposition_rejected(disp_data, &cond, &desc, &info); disp->type = PN_DISP_REJECTED; pn_condition_set(&disp->u.s_rejected.condition, cond, desc, info); @@ -1592,7 +1592,7 @@ static void pni_amqp_decode_disposition (uint64_t type, pn_bytes_t disp_data, pn bool qundeliverable; bool undeliverable; pn_bytes_t annotations_raw = (pn_bytes_t){0, NULL}; - pn_amqp_decode_EQoQoRe(disp_data, &qfailed, &failed, &qundeliverable, &undeliverable, &annotations_raw); + pn_amqp_decode_disposition_modified(disp_data, &qfailed, &failed, &qundeliverable, &undeliverable, &annotations_raw); disp->type = PN_DISP_MODIFIED; pn_bytes_free(disp->u.s_modified.annotations_raw); disp->u.s_modified.annotations_raw = pn_bytes_dup(annotations_raw); @@ -1607,7 +1607,7 @@ static void pni_amqp_decode_disposition (uint64_t type, pn_bytes_t disp_data, pn } case AMQP_DESC_DECLARED: { pn_bytes_t id; - pn_amqp_decode_Eze(disp_data, &id); + pn_amqp_decode_disposition_declared(disp_data, &id); disp->type = PN_DISP_DECLARED; pn_bytes_free(disp->u.s_declared.id); disp->u.s_declared.id = pn_bytes_dup(id); @@ -1617,7 +1617,7 @@ static void pni_amqp_decode_disposition (uint64_t type, pn_bytes_t disp_data, pn pn_bytes_t id; bool qoutcome; pn_bytes_t outcome_raw; - pn_amqp_decode_EzQRe(disp_data, &id, &qoutcome, &outcome_raw); + pn_amqp_decode_disposition_transactional_state(disp_data, &id, &qoutcome, &outcome_raw); disp->type = PN_DISP_TRANSACTIONAL; pn_bytes_free(disp->u.s_transactional.id); disp->u.s_transactional.id = pn_bytes_dup(id); @@ -1629,7 +1629,7 @@ static void pni_amqp_decode_disposition (uint64_t type, pn_bytes_t disp_data, pn } default: { pn_bytes_t data_raw = (pn_bytes_t){0, NULL}; - pn_amqp_decode_R(disp_data, &data_raw); + pn_amqp_decode_raw(disp_data, &data_raw); disp->type = PN_DISP_CUSTOM; disp->u.s_custom.type = type; pn_bytes_free(disp->u.s_custom.data_raw); @@ -1662,7 +1662,7 @@ int pn_do_disposition(pn_transport_t *transport, uint8_t frame_type, uint16_t ch pn_bytes_t disp_data; bool type_init; uint64_t type; - pn_amqp_decode_DqEoIQIoDQLRe(payload, &role, &first, &last_init, + pn_amqp_decode_disposition(payload, &role, &first, &last_init, &last, &settled, &type_init, &type, &disp_data); if (!last_init) last = first; @@ -1720,7 +1720,7 @@ int pn_do_detach(pn_transport_t *transport, uint8_t frame_type, uint16_t channel bool closed; pn_bytes_t error_condition; - pn_amqp_decode_DqEIoRe(payload, &handle, &closed, &error_condition); + pn_amqp_decode_detach(payload, &handle, &closed, &error_condition); pn_link_t *link = pni_handle_state(ssn, handle); if (!link) { @@ -1730,7 +1730,7 @@ int pn_do_detach(pn_transport_t *transport, uint8_t frame_type, uint16_t channel pn_bytes_t cond; pn_bytes_t desc; pn_bytes_t info; - pn_amqp_decode_DqEsSRe(error_condition, &cond, &desc, &info); + pn_amqp_decode_error_condition(error_condition, &cond, &desc, &info); pn_condition_t* condition = &link->endpoint.remote_condition; pn_condition_set(condition, cond, desc, info); @@ -1756,7 +1756,7 @@ int pn_do_end(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, p pn_bytes_t cond; pn_bytes_t desc; pn_bytes_t info; - pn_amqp_decode_DqEDqEsSRee(payload, &cond, &desc, &info); + pn_amqp_decode_close(payload, &cond, &desc, &info); pn_condition_t* condition = &ssn->endpoint.remote_condition; pn_condition_set(condition, cond, desc, info); PN_SET_REMOTE(ssn->endpoint.state, PN_REMOTE_CLOSED); @@ -1772,7 +1772,7 @@ int pn_do_close(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_bytes_t cond; pn_bytes_t desc; pn_bytes_t info; - pn_amqp_decode_DqEDqEsSRee(payload, &cond, &desc, &info); + pn_amqp_decode_close(payload, &cond, &desc, &info); pn_condition_t* condition = &transport->remote_condition; pn_condition_set(condition, cond, desc, info); transport->close_rcvd = true; @@ -1868,7 +1868,7 @@ static int pni_process_conn_setup(pn_transport_t *transport, pn_endpoint_t *endp pni_switch_to_raw_multiple(&transport->scratch_space, &connection->offered_capabilities, &connection->offered_capabilities_raw); pni_switch_to_raw_multiple(&transport->scratch_space, &connection->desired_capabilities, &connection->desired_capabilities_raw); pni_switch_to_raw(&transport->scratch_space, &connection->properties, &connection->properties_raw); - pn_bytes_t buf = pn_amqp_encode_DLESSQIQHQInnMMRe(&transport->scratch_space, AMQP_DESC_OPEN, + pn_bytes_t buf = pn_amqp_encode_open(&transport->scratch_space, AMQP_DESC_OPEN, cid, pn_string_bytes(connection->hostname), // TODO: This is messy, because we also have to allow local_max_frame_ to be 0 to mean unlimited @@ -1971,7 +1971,7 @@ static int pni_process_ssn_setup(pn_transport_t *transport, pn_endpoint_t *endpo state->incoming_window = pni_session_incoming_window(ssn); state->outgoing_window = pni_session_outgoing_window(ssn); /* "DL[?HIIII]" */ - pn_bytes_t buf = pn_amqp_encode_DLEQHIIIIe(&transport->scratch_space, AMQP_DESC_BEGIN, + pn_bytes_t buf = pn_amqp_encode_begin(&transport->scratch_space, AMQP_DESC_BEGIN, ((int16_t) state->remote_channel >= 0), state->remote_channel, state->outgoing_transfer_count, state->incoming_window, @@ -2037,7 +2037,7 @@ static int pni_process_link_setup(pn_transport_t *transport, pn_endpoint_t *endp pni_switch_to_raw_multiple(&transport->scratch_space, &link->source.capabilities, &link->source.capabilities_raw); pni_switch_to_raw_multiple(&transport->scratch_space, &link->target.capabilities, &link->target.capabilities_raw); if (link->target.type == PN_COORDINATOR) { - pn_bytes_t buf = pn_amqp_encode_DLESIoBBQDLESIsIoRQsRnRReDLERennIe(&transport->scratch_space, AMQP_DESC_ATTACH, + pn_bytes_t buf = pn_amqp_encode_attach_coordinator(&transport->scratch_space, AMQP_DESC_ATTACH, pn_string_bytes(link->name), state->local_handle, endpoint->type == RECEIVER, @@ -2061,7 +2061,7 @@ static int pni_process_link_setup(pn_transport_t *transport, pn_endpoint_t *endp } else { pni_switch_to_raw(&transport->scratch_space, &link->properties, &link->properties_raw); pni_switch_to_raw(&transport->scratch_space, &link->target.properties, &link->target.properties_raw); - pn_bytes_t buf = pn_amqp_encode_DLESIoBBQDLESIsIoRQsRnMMeQDLESIsIoRMennILnnRe(&transport->scratch_space, AMQP_DESC_ATTACH, + pn_bytes_t buf = pn_amqp_encode_attach(&transport->scratch_space, AMQP_DESC_ATTACH, pn_string_bytes(link->name), state->local_handle, endpoint->type == RECEIVER, @@ -2110,7 +2110,7 @@ static int pni_post_flow(pn_transport_t *transport, pn_session_t *ssn, pn_link_t bool linkq = (bool) link; pn_link_state_t *state = linkq ? &link->state : NULL; /* "DL[?IIII?I?I?In?o]" */ - pn_bytes_t buf = pn_amqp_encode_DLEQIIIIQIQIQInQoe(&transport->scratch_space, AMQP_DESC_FLOW, + pn_bytes_t buf = pn_amqp_encode_flow(&transport->scratch_space, AMQP_DESC_FLOW, (int16_t) ssn->state.remote_channel >= 0, ssn->state.incoming_transfer_count, ssn->state.incoming_window, ssn->state.outgoing_transfer_count, @@ -2157,7 +2157,7 @@ static int pni_flush_disp(pn_transport_t *transport, pn_session_t *ssn) bool settled = ssn->state.disp_settled; if (ssn->state.disp) { /* "DL[oI?I?o?DL[]]" */ - pn_bytes_t buf = pn_amqp_encode_DLEoIQIQoQDLEee(&transport->scratch_space, AMQP_DESC_DISPOSITION, + pn_bytes_t buf = pn_amqp_encode_disposition_batch(&transport->scratch_space, AMQP_DESC_DISPOSITION, ssn->state.disp_type, ssn->state.disp_first, ssn->state.disp_last!=ssn->state.disp_first, ssn->state.disp_last, @@ -2191,7 +2191,7 @@ static int pni_post_disp(pn_transport_t *transport, pn_delivery_t *delivery) } if (!pni_disposition_batchable(&delivery->local)) { - pn_bytes_t buf = pn_amqp_encode_DLEoInQode(&transport->scratch_space, AMQP_DESC_DISPOSITION, + pn_bytes_t buf = pn_amqp_encode_disposition(&transport->scratch_space, AMQP_DESC_DISPOSITION, role, state->id, delivery->local.settled, delivery->local.settled, &delivery->local); @@ -2418,7 +2418,7 @@ static int pni_process_link_teardown(pn_transport_t *transport, pn_endpoint_t *e (int16_t) ssn_state->remote_channel != -2 && !transport->close_rcvd) return 0; - pn_bytes_t buf = pn_amqp_encode_DLEIQoce(&transport->scratch_space, AMQP_DESC_DETACH, + pn_bytes_t buf = pn_amqp_encode_detach(&transport->scratch_space, AMQP_DESC_DETACH, state->local_handle, !link->detached, !link->detached, &endpoint->condition); @@ -2484,7 +2484,7 @@ static int pni_process_ssn_teardown(pn_transport_t *transport, pn_endpoint_t *en return 0; } - pn_bytes_t buf = pn_amqp_encode_DLEce(&transport->scratch_space, AMQP_DESC_END, &endpoint->condition); + pn_bytes_t buf = pn_amqp_encode_close(&transport->scratch_space, AMQP_DESC_END, &endpoint->condition); int err = pn_framing_send_amqp(transport, state->local_channel, buf); if (err) return err; pni_unmap_local_channel(session); @@ -2560,7 +2560,7 @@ static void pn_error_amqp(pn_transport_t* transport, unsigned int layer) if (!transport->close_sent) { if (!transport->open_sent) { /* "DL[S]" */ - pn_bytes_t buf = pn_amqp_encode_DLESe(&transport->scratch_space, AMQP_DESC_OPEN, (pn_bytes_t){.size=0, .start=""}); + pn_bytes_t buf = pn_amqp_encode_open_minimal(&transport->scratch_space, AMQP_DESC_OPEN, (pn_bytes_t){.size=0, .start=""}); pn_framing_send_amqp(transport, 0, buf); } diff --git a/c/src/sasl/sasl.c b/c/src/sasl/sasl.c index 4e84bfb25..7f0bc21e2 100644 --- a/c/src/sasl/sasl.c +++ b/c/src/sasl/sasl.c @@ -492,7 +492,7 @@ static void pni_post_sasl_frame(pn_transport_t *transport) switch (desired_state) { case SASL_POSTED_INIT: { /* GENERATE_CODEC_CODE: "DL[szS]" */ - pn_bytes_t buf = pn_amqp_encode_DLEszSe(&transport->scratch_space, AMQP_DESC_SASL_INIT, pn_string_bytes(sasl->selected_mechanism), out.size, out.start, pn_string_bytes(sasl->local_fqdn)); + pn_bytes_t buf = pn_amqp_encode_sasl_init(&transport->scratch_space, AMQP_DESC_SASL_INIT, pn_string_bytes(sasl->selected_mechanism), out.size, out.start, pn_string_bytes(sasl->local_fqdn)); pn_framing_send_sasl(transport, buf); pni_emit(transport); break; @@ -507,7 +507,7 @@ static void pni_post_sasl_frame(pn_transport_t *transport) pni_split_mechs(mechlist, sasl->included_mechanisms, mechs, &count); } /* GENERATE_CODEC_CODE: "DL[@T[*s]]" */ - pn_bytes_t buf = pn_amqp_encode_DLEATEjsee(&transport->scratch_space, AMQP_DESC_SASL_MECHANISMS, PN_SYMBOL, count, mechs); + pn_bytes_t buf = pn_amqp_encode_sasl_mechanisms(&transport->scratch_space, AMQP_DESC_SASL_MECHANISMS, PN_SYMBOL, count, mechs); free(mechlist); pn_framing_send_sasl(transport, buf); pni_emit(transport); @@ -516,7 +516,7 @@ static void pni_post_sasl_frame(pn_transport_t *transport) case SASL_POSTED_RESPONSE: if (sasl->last_state != SASL_POSTED_RESPONSE) { /* "DL[Z]" */ - pn_bytes_t buf = pn_amqp_encode_DLEZe(&transport->scratch_space, AMQP_DESC_SASL_RESPONSE, out.size, out.start); + pn_bytes_t buf = pn_amqp_encode_sasl_binary(&transport->scratch_space, AMQP_DESC_SASL_RESPONSE, out.size, out.start); pn_framing_send_sasl(transport, buf); pni_emit(transport); } @@ -527,7 +527,7 @@ static void pni_post_sasl_frame(pn_transport_t *transport) continue; } else if (sasl->last_state != SASL_POSTED_CHALLENGE) { /* "DL[Z]" */ - pn_bytes_t buf = pn_amqp_encode_DLEZe(&transport->scratch_space, AMQP_DESC_SASL_CHALLENGE, out.size, out.start); + pn_bytes_t buf = pn_amqp_encode_sasl_binary(&transport->scratch_space, AMQP_DESC_SASL_CHALLENGE, out.size, out.start); pn_framing_send_sasl(transport, buf); pni_emit(transport); } @@ -538,7 +538,7 @@ static void pni_post_sasl_frame(pn_transport_t *transport) continue; } /* "DL[Bz]" */ - pn_bytes_t buf = pn_amqp_encode_DLEBze(&transport->scratch_space, AMQP_DESC_SASL_OUTCOME, sasl->outcome, out.size, out.start); + pn_bytes_t buf = pn_amqp_encode_sasl_outcome(&transport->scratch_space, AMQP_DESC_SASL_OUTCOME, sasl->outcome, out.size, out.start); pn_framing_send_sasl(transport, buf); pni_emit(transport); if (sasl->outcome!=PN_SASL_OK) { @@ -908,7 +908,7 @@ int pn_do_init(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_bytes_t mech; pn_bytes_t recv; - pn_amqp_decode_DqEsze(payload, &mech, &recv); + pn_amqp_decode_sasl_init(payload, &mech, &recv); sasl->selected_mechanism = pn_stringn(mech.start, mech.size); // We need to filter out a supplied mech in in the inclusion list @@ -940,7 +940,7 @@ int pn_do_mechanisms(pn_transport_t *transport, uint8_t frame_type, uint16_t cha pn_string_t *mechs = pn_string(""); pn_bytes_t subpayload; - pn_amqp_decode_DqERe(payload, &subpayload); + pn_amqp_decode_described_list_raw(payload, &subpayload); pni_consumer_t consumer = make_consumer_from_bytes(subpayload); uint8_t element_type; @@ -975,7 +975,7 @@ int pn_do_mechanisms(pn_transport_t *transport, uint8_t frame_type, uint16_t cha } else { // If not then see if it is a single symbol pn_bytes_t symbol; - pn_amqp_decode_DqEse(payload, &symbol); + pn_amqp_decode_sasl_mechanism_symbol(payload, &symbol); if (pni_sasl_client_included_mech(sasl->included_mechanisms, symbol)) { pn_string_setn(mechs, symbol.start, symbol.size); @@ -1007,7 +1007,7 @@ int pn_do_challenge(pn_transport_t *transport, uint8_t frame_type, uint16_t chan pn_bytes_t recv; - pn_amqp_decode_DqEze(payload, &recv); + pn_amqp_decode_sasl_binary(payload, &recv); pni_sasl_impl_process_challenge(transport, &recv); @@ -1028,7 +1028,7 @@ int pn_do_response(pn_transport_t *transport, uint8_t frame_type, uint16_t chann pn_bytes_t recv; - pn_amqp_decode_DqEze(payload, &recv); + pn_amqp_decode_sasl_binary(payload, &recv); pni_sasl_impl_process_response(transport, &recv); @@ -1050,7 +1050,7 @@ int pn_do_outcome(pn_transport_t *transport, uint8_t frame_type, uint16_t channe uint8_t outcome; pn_bytes_t recv; - pn_amqp_decode_DqEBze(payload, &outcome, &recv); + pn_amqp_decode_sasl_outcome(payload, &outcome, &recv); // Preset the outcome to what the server sent us - the plugin can alter this. // In practise the plugin processing here should only fail because it fails diff --git a/c/tools/codec-generator/Pipfile b/c/tools/codec-generator/Pipfile deleted file mode 100644 index dbda1e878..000000000 --- a/c/tools/codec-generator/Pipfile +++ /dev/null @@ -1,12 +0,0 @@ -[[source]] -name = "pypi" -url = "https://pypi.org/simple" -verify_ssl = true - -[dev-packages] - -[packages] -pycparser = "*" - -[requires] -python_version = "3.7" diff --git a/c/tools/codec-generator/find_specs.py b/c/tools/codec-generator/find_specs.py deleted file mode 100644 index 15fcb6e47..000000000 --- a/c/tools/codec-generator/find_specs.py +++ /dev/null @@ -1,103 +0,0 @@ -import argparse -import json -import os -import re -import sys - -from pycparser import c_ast, parse_file - -from typing import Any, Dict, List, Set, Tuple, Union - - -def strip_quotes(arg: str) -> str: - if arg[0] != '"' or arg[-1:] != '"': - raise Exception(arg) - return arg[1:-1] - - -def find_function_calls(file: str, name: str, includes: List[str], defines: List[str]) -> List[List[Any]]: - class FillFinder(c_ast.NodeVisitor): - def __init__(self): - self._name = name - self.result = [] - - def visit_FuncCall(self, node): - if node.name.name == self._name: - r = [] - for e in node.args.exprs: - r.append(e) - self.result.append(r) - - include_args = [f'-I{d}' for d in includes] - define_args = [f'-D{d}' for d in defines] - ast = parse_file(file, use_cpp=True, - cpp_args=[ - *include_args, - *define_args - ]) - ff = FillFinder() - ff.visit(ast) - return ff.result - - -c_defines = ['GENERATE_CODEC_CODE', - 'NDEBUG', - '__attribute__(X)=', - '__asm__(X)=', - '__inline=', - '__extension__=', - '__restrict=', - '__builtin_va_list=int'] - - -def find_fill_specs(c_includes, pn_source): - amqp_calls = find_function_calls(os.path.join(pn_source, 'c/src/core/transport.c'), 'pn_fill_performative', - c_includes, c_defines) - sasl_calls = find_function_calls(os.path.join(pn_source, 'c/src/sasl/sasl.c'), 'pn_fill_performative', - c_includes, c_defines) - message_calls = find_function_calls(os.path.join(pn_source, 'c/src/core/message.c'), 'pn_data_fill', - c_includes, c_defines) - fill_spec_args = [c[1] for c in amqp_calls] - fill_spec_args += [c[1] for c in sasl_calls] - fill_spec_args += [c[1] for c in message_calls] - fill_specs: Set[str] = \ - {strip_quotes(e.value) for e in fill_spec_args if type(e) is c_ast.Constant and e.type == 'string'} - return fill_specs - - -def find_scan_specs(c_includes, pn_source): - amqp_calls = find_function_calls(os.path.join(pn_source, 'c/src/core/transport.c'), 'pn_data_scan', - c_includes, c_defines) - message_calls = find_function_calls(os.path.join(pn_source, 'c/src/core/message.c'),'pn_data_scan', - c_includes, c_defines) - scan_spec_args = [c[1] for c in amqp_calls] - scan_spec_args += [c[1] for c in message_calls] - # Only try to generate code for constant strings - scan_specs: Set[str] = \ - {strip_quotes(e.value) for e in scan_spec_args if type(e) is c_ast.Constant and e.type == 'string'} - return scan_specs - - -def main(): - argparser = argparse.ArgumentParser(description='Find scan/fill specs in proton code for code generation') - argparser.add_argument('-o', '--output', help='output json file', type=str, required=True) - argparser.add_argument('-s', '--source', help='proton source directory', type=str, required=True) - argparser.add_argument('-b', '--build', help='proton build directory', type=str, required=True) - - args = argparser.parse_args() - - pn_source = args.source - pn_build = args.build - json_filename = args.output - - c_includes = [f'{os.path.join(pn_build, "c/include")}', - f'{os.path.join(pn_build, "c/src")}'] - fill_specs = find_fill_specs(c_includes, pn_source) - scan_specs = find_scan_specs(c_includes, pn_source) - with open(json_filename, 'w') as file: - json.dump({'fill_specs': sorted(list(fill_specs)), 'scan_specs': sorted(list(scan_specs))}, file, indent=2) - - -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/c/tools/codec-generator/generate.py b/c/tools/codec-generator/generate.py index c9d8322ac..2dd292f8a 100644 --- a/c/tools/codec-generator/generate.py +++ b/c/tools/codec-generator/generate.py @@ -1,3 +1,77 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +""" +AMQP Codec Generator + +Generates C code for encoding (fill/emit) and decoding (scan/consume) AMQP data +based on format specification strings defined in specs.json. + +Format Specification Characters +=============================== + +Structural: + D Described type marker (followed by type specifier) + L Descriptor is uint64 type code (used after D) + . Skip/ignore this position (anything), or unknown type (after D) + [ Start of list + ] End of list + @T Start of typed array (T = type marker) + ? Optional field - followed by presence boolean, then the value + ! Suffix: omit entire described list if resulting list would be empty + +Primitive Types: + R Raw bytes (pn_bytes_t) + S String (pn_bytes_t, encoded as AMQP string) + s Symbol (pn_bytes_t, encoded as AMQP symbol) + I Unsigned 32-bit integer (uint32_t) + H Unsigned 16-bit integer (uint16_t) + B Unsigned 8-bit integer (uint8_t) + L Unsigned 64-bit integer (uint64_t) - context dependent with DL + o Boolean (bool) + t Timestamp (pn_timestamp_t) + z Binary or null (size_t + const char*, decodes to pn_bytes_t*) + Z Binary, never null (size_t + const char*, decodes to pn_bytes_t*) + n Null (no argument, emits AMQP null) + +Complex/Special: + a Atom (pn_atom_t* - polymorphic AMQP value) + c Condition (pn_condition_t* - AMQP error condition) + d Disposition (pn_disposition_t* - delivery state) + M Multiple (pn_bytes_t - array or single value as raw) + *s Counted symbols (size_t count + char** array) + C Copy from pn_data_t (used after D. or DL) + +Combined Patterns: + DL[...] Described list with uint64 descriptor, containing fields + D.[...] Described list, ignoring/skipping the descriptor type + DLR Described type with raw value + D.R Described value as raw (ignoring descriptor) + D?L. Maybe described, with type, skip value + D?LR Maybe described, with type, raw value + +Examples: + "DL[?HIIII]" - Described list (BEGIN): optional ushort, 4 uints + "DL[SIoBB?DL[...]]" - Described list (ATTACH): string, uint, bool, ... + "D.[sSR]" - Scan described list ignoring type: symbol, symbol, raw +""" + import argparse import itertools import json @@ -396,10 +470,10 @@ def make_legal_identifier(s: str) -> str: return r -def consume_function(name_prefix: str, scan_spec: str, prefix_args: List[Tuple[str, str]]) -> Tuple[str, List[str]]: +def consume_function(name_prefix: str, scan_spec: str, func_name: str, prefix_args: List[Tuple[str, str]]) -> Tuple[str, List[str]]: p, _ = parse_item(scan_spec) params = p.gen_consume_params(0) - function_name = name_prefix + '_' + make_legal_identifier(scan_spec) + function_name = name_prefix + '_' + func_name param_list = ', '.join([t+' '+arg for arg, t in prefix_args+params]) function_spec = f'size_t {function_name}({param_list})' @@ -418,19 +492,19 @@ def consume_function(name_prefix: str, scan_spec: str, prefix_args: List[Tuple[s return function_decl, function_defn -def emit_function(name_prefix: str, fill_spec: str, prefix_args: List[Tuple[str, str]]) -> Tuple[str, List[str]]: +def emit_function(name_prefix: str, fill_spec: str, func_name: str, prefix_args: List[Tuple[str, str]]) -> Tuple[str, List[str]]: p, _ = parse_item(fill_spec) params = p.gen_params(0) - function_name = name_prefix + '_' + make_legal_identifier(fill_spec) + function_name = name_prefix + '_' + func_name param_list = ', '.join([t+' '+arg for arg, t in prefix_args+params]) function_spec = f'pn_bytes_t {function_name}({param_list})' bytes_args = [('bytes', 'char*'), ('size', 'size_t')] - bytes_function_name = name_prefix + '_bytes_' + make_legal_identifier(fill_spec) + bytes_function_name = name_prefix + '_bytes_' + func_name bytes_param_list = ', '.join([t+' '+arg for arg, t in bytes_args+params]) bytes_function_spec = f'size_t {bytes_function_name}({bytes_param_list})' - inner_function_name = name_prefix + '_inner_' + make_legal_identifier(fill_spec) + inner_function_name = name_prefix + '_inner_' + func_name inner_param_list = [('emitter', 'pni_emitter_t*')]+params inner_params = ', '.join([t+' '+arg for arg, t in inner_param_list]) inner_function_spec = f'bool {inner_function_name}({inner_params})' @@ -504,12 +578,12 @@ prefix_consume_header = """ """ -def output_header(decls: Dict[str, str], prefix: str, file=None): - # Output declarations +def output_header(decls: Dict[str, Tuple[str, str]], prefix: str, file=None): + # Output declarations sorted by function name print(prefix, file=file) - for fill_spec, decl in sorted(decls.items()): + for func_name, (spec, decl) in sorted(decls.items()): print( - f'/* {fill_spec} */\n' + f'/* {spec} */\n' f'{decl}', file=file ) @@ -524,28 +598,28 @@ prefix_consume_implementation = """ """ -def output_implementation(defns: Dict[str, List[str]], prefix: str, header=None, file=None): - # Output implementations +def output_implementation(defns: Dict[str, Tuple[str, List[str]]], prefix: str, header=None, file=None): + # Output implementations sorted by function name if header: print(f'#include "{header}"', file=file) print(prefix, file=file) - for fill_spec, defn in sorted(defns.items()): + for func_name, (spec, defn) in sorted(defns.items()): printable_defn = '\n'.join(defn) print( - f'/* {fill_spec} */\n' + f'/* {spec} */\n' f'{printable_defn}', file=file ) def emit(fill_specs, decl_filename, impl_filename): - decls: Dict[str, str] = {} - defns: Dict[str, List[str]] = {} - for fill_spec in fill_specs: - decl, defn = emit_function('pn_amqp_encode', fill_spec, [('buffer', 'pn_rwbytes_t*')]) - decls[fill_spec] = decl - defns[fill_spec] = defn + decls: Dict[str, Tuple[str, str]] = {} + defns: Dict[str, Tuple[str, List[str]]] = {} + for fill_spec, func_name in fill_specs: + decl, defn = emit_function('pn_amqp_encode', fill_spec, func_name, [('buffer', 'pn_rwbytes_t*')]) + decls[func_name] = (fill_spec, decl) + defns[func_name] = (fill_spec, defn) if decl_filename and impl_filename: with open(decl_filename, 'w') as dfile: output_header(decls, prefix_emit_header, file=dfile) @@ -558,12 +632,12 @@ def emit(fill_specs, decl_filename, impl_filename): def consume(scan_specs, decl_filename, impl_filename): - decls: Dict[str, str] = {} - defns: Dict[str, List[str]] = {} - for scan_spec in scan_specs: - decl, defn = consume_function('pn_amqp_decode', scan_spec, [('bytes', 'pn_bytes_t')]) - decls[scan_spec] = decl - defns[scan_spec] = defn + decls: Dict[str, Tuple[str, str]] = {} + defns: Dict[str, Tuple[str, List[str]]] = {} + for scan_spec, func_name in scan_specs: + decl, defn = consume_function('pn_amqp_decode', scan_spec, func_name, [('bytes', 'pn_bytes_t')]) + decls[func_name] = (scan_spec, decl) + defns[func_name] = (scan_spec, defn) if decl_filename and impl_filename: with open(decl_filename, 'w') as dfile: output_header(decls, prefix_consume_header, file=dfile) diff --git a/c/tools/codec-generator/specs.json b/c/tools/codec-generator/specs.json index 2def140f8..535fdf3b6 100644 --- a/c/tools/codec-generator/specs.json +++ b/c/tools/codec-generator/specs.json @@ -1,55 +1,54 @@ { "fill_specs": [ - "R", - "DLR", - "DL[]", - "DL[c]", - "DL[?HIIII]", - "DL[?IIII?I?I?In?o]", - "DL[?o?B?I?o?I]!", - "DL[@T[*s]]", - "DL[Bz]", - "DL[I?oc]", - "DL[IIzI?o?ond?o?o?o]", - "DL[SIoBB?DL[SIsIoR?sRnRR]DL[R]nnI]", - "DL[SIoBB?DL[SIsIoR?sRnMM]?DL[SIsIoRM]nnILnnR]", - "DL[SS?I?H?InnMMR]", - "DL[S]", - "DL[Z]", - "DL[azSSSass?t?tS?IS]!", - "DL[oI?I?o?DL[]]", - "DL[oIn?od]", - "DL[szS]" + ["R", "raw"], + ["DL[SS?I?H?InnMMR]", "open"], + ["DL[S]", "open_minimal"], + ["DL[?HIIII]", "begin"], + ["DL[SIoBB?DL[SIsIoR?sRnMM]?DL[SIsIoRM]nnILnnR]", "attach"], + ["DL[SIoBB?DL[SIsIoR?sRnRR]DL[R]nnI]", "attach_coordinator"], + ["DL[?IIII?I?I?In?o]", "flow"], + ["DL[IIzI?o?ond?o?o?o]", "transfer"], + ["DL[oI?I?o?DL[]]", "disposition_batch"], + ["DL[oIn?od]", "disposition"], + ["DL[I?oc]", "detach"], + ["DL[c]", "close"], + ["DL[?o?B?I?o?I]!", "message_header"], + ["DL[azSSSass?t?tS?IS]!", "message_properties"], + ["DL[szS]", "sasl_init"], + ["DL[@T[*s]]", "sasl_mechanisms"], + ["DL[Z]", "sasl_binary"], + ["DL[Bz]", "sasl_outcome"], + ["DLR", "described_type_raw"], + ["DL[]", "described_empty_list"] ], "scan_specs": [ - "R", - "[?I?L]", - "[D.[sSR]]", - "[?o?oR]", - "[z?R]", - "[z]", - "D.R", - "D.[.....D..D.[.....RR]]", - "D.[.....D..D.[R]...]", - "D.[.....D..DL....]", - "D.[.....D.[.....R.R.RR]]", - "D.[?HIII?I]", - "D.[?IIII?I?II.o]", - "D.[?S?S?I?HI..RRR]", - "D.[I?Iz.?oo.D?LRooo]", - "D.[IoR]", - "D.[sSR]", - "D.[D.[sSR]]", - "D.[SIo?B?BD.[SIsIo.s]D.[SIsIo]..IL..?R]", - "D.[azSSSassttSIS]", - "D.[o?BIoI]", - "D.[oI?IoD?LR]", - "D.[sz]", - "D.[s]", - "D.[z]", - "D.[Bz]", - "D.[R]", - "D?L.", - "D?L?." + ["R", "raw"], + ["D.[?S?S?I?HI..RRR]", "open"], + ["D.[?HIII?I]", "begin"], + ["D.[SIo?B?BD.[SIsIo.s]D.[SIsIo]..IL..?R]", "attach"], + ["D.[.....D.[.....R.R.RR]]", "attach_source_props"], + ["D.[.....D..D.[.....RR]]", "attach_target_props"], + ["D.[.....D..D.[R]...]", "attach_coordinator_caps"], + ["D.[.....D..DL....]", "attach_target_type"], + ["D.[?IIII?I?II.o]", "flow"], + ["D.[I?Iz.?oo.D?LRooo]", "transfer"], + ["D.[oI?IoD?LR]", "disposition"], + ["[?I?L]", "disposition_received"], + ["[D.[sSR]]", "disposition_rejected"], + ["[?o?oR]", "disposition_modified"], + ["[z?R]", "disposition_transactional_state"], + ["[z]", "disposition_declared"], + ["D.[IoR]", "detach"], + ["D.[D.[sSR]]", "close"], + ["D.[o?BIoI]", "message_header"], + ["D.[azSSSassttSIS]", "message_properties"], + ["D.[sSR]", "error_condition"], + ["D.[sz]", "sasl_init"], + ["D.[s]", "sasl_mechanism_symbol"], + ["D.[z]", "sasl_binary"], + ["D.[Bz]", "sasl_outcome"], + ["D.R", "described_raw"], + ["D.[R]", "described_list_raw"], + ["D?L.", "described_type_anything"] ] } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
