in c/src/core/codec.c [590:812]
int pn_data_vfill(pn_data_t *data, const char *fmt, va_list ap)
{
int err = 0;
const char *begin = fmt;
while (*fmt) {
char code = *(fmt++);
if (!code) return 0;
switch (code) {
case 'n':
err = pn_data_put_null(data);
break;
case 'o':
err = pn_data_put_bool(data, va_arg(ap, int));
break;
case 'B':
err = pn_data_put_ubyte(data, va_arg(ap, unsigned int));
break;
case 'b':
err = pn_data_put_byte(data, va_arg(ap, int));
break;
case 'H':
err = pn_data_put_ushort(data, va_arg(ap, unsigned int));
break;
case 'h':
err = pn_data_put_short(data, va_arg(ap, int));
break;
case 'I':
err = pn_data_put_uint(data, va_arg(ap, uint32_t));
break;
case 'i':
err = pn_data_put_int(data, va_arg(ap, uint32_t));
break;
case 'L':
err = pn_data_put_ulong(data, va_arg(ap, uint64_t));
break;
case 'l':
err = pn_data_put_long(data, va_arg(ap, int64_t));
break;
case 't':
err = pn_data_put_timestamp(data, va_arg(ap, pn_timestamp_t));
break;
case 'f':
err = pn_data_put_float(data, va_arg(ap, double));
break;
case 'd':
err = pn_data_put_double(data, va_arg(ap, double));
break;
case 'Z': /* encode binary, must not be NULL */
{
// For maximum portability, caller must pass these as two separate args, not a single struct
size_t size = va_arg(ap, size_t);
char *start = va_arg(ap, char *);
err = pn_data_put_binary(data, pn_bytes(size, start));
}
break;
case 'z': /* encode binary or null if pointer is NULL */
{
// For maximum portability, caller must pass these as two separate args, not a single struct
size_t size = va_arg(ap, size_t);
char *start = va_arg(ap, char *);
if (start) {
err = pn_data_put_binary(data, pn_bytes(size, start));
} else {
err = pn_data_put_null(data);
}
}
break;
case 'S': /* encode string or null if NULL */
case 's': /* encode symbol or null if NULL */
{
char *start = va_arg(ap, char *);
size_t size;
if (start) {
size = strlen(start);
if (code == 'S') {
err = pn_data_put_string(data, pn_bytes(size, start));
} else {
err = pn_data_put_symbol(data, pn_bytes(size, start));
}
} else {
err = pn_data_put_null(data);
}
}
break;
case 'D':
/* The next 2 args are the descriptor, value for a described value. */
err = pn_data_put_described(data);
pn_data_enter(data);
break;
case 'T': /* Set type of open array */
{
pni_node_t *parent = pn_data_node(data, data->parent);
if (parent->atom.type == PN_ARRAY) {
parent->type = (pn_type_t) va_arg(ap, int);
} else {
return pn_error_format(pni_data_error(data), PN_ERR, "naked type");
}
}
break;
case '@': /* begin array */
{
bool described;
if (*(fmt + 1) == 'D') {
fmt++;
described = true;
} else {
described = false;
}
err = pn_data_put_array(data, described, (pn_type_t) 0);
pn_data_enter(data);
}
break;
case '[': /* begin list */
if (fmt < (begin + 2) || *(fmt - 2) != 'T') {
err = pn_data_put_list(data);
if (err) return err;
pn_data_enter(data);
}
break;
case '{': /* begin map */
err = pn_data_put_map(data);
if (err) return err;
pn_data_enter(data);
break;
case '}':
case ']':
if (!pn_data_exit(data))
return pn_error_format(pni_data_error(data), PN_ERR, "exit failed");
break;
case '?':
if (!va_arg(ap, int)) {
err = pn_data_put_null(data);
if (err) return err;
pn_data_enter(data);
}
break;
case '*':
{
int count = va_arg(ap, int);
void *ptr = va_arg(ap, void *);
char c = *(fmt++);
switch (c)
{
case 's':
{
char **sptr = (char **) ptr;
for (int i = 0; i < count; i++)
{
char *sym = *(sptr++);
err = pn_data_fill(data, "s", sym);
if (err) return err;
}
}
break;
default:
PN_LOG_DEFAULT(PN_SUBSYSTEM_AMQP, PN_LEVEL_CRITICAL, "unrecognized * code: 0x%.2X '%c'", code, code);
return PN_ARG_ERR;
}
}
break;
case 'C': /* Append an existing pn_data_t * */
{
pn_data_t *src = va_arg(ap, pn_data_t *);
if (src && pn_data_size(src) > 0) {
err = pn_data_appendn(data, src, 1);
if (err) return err;
} else {
err = pn_data_put_null(data);
if (err) return err;
}
}
break;
case 'a': /* Append an existing pn_atom_t * */
{
pn_atom_t *src = va_arg(ap, pn_atom_t *);
if (src) {
err = pn_data_put_atom(data, *src);
if (err) return err;
} else {
err = pn_data_put_null(data);
if (err) return err;
}
}
break;
case 'M':
{
pn_data_t *src = va_arg(ap, pn_data_t *);
err = (src && pn_data_size(src) > 0) ?
pni_normalize_multiple(data, src) : pn_data_put_null(data);
break;
}
default:
PN_LOG_DEFAULT(PN_SUBSYSTEM_AMQP, PN_LEVEL_CRITICAL, "unrecognized fill code: 0x%.2X '%c'", code, code);
return PN_ARG_ERR;
}
if (err) return err;
pni_node_t *parent = pn_data_node(data, data->parent);
pni_node_t *current = pn_data_node(data, data->current);
while (parent) {
if (parent->atom.type == PN_DESCRIBED && parent->children == 2) {
current->described = true;
pn_data_exit(data);
current = pn_data_node(data, data->current);
parent = pn_data_node(data, data->parent);
} else if (parent->atom.type == PN_NULL && parent->children == 1) {
pn_data_exit(data);
current = pn_data_node(data, data->current);
current->down = 0;
current->children = 0;
parent = pn_data_node(data, data->parent);
} else {
break;
}
}
}
return 0;
}