Skip to content
This repository has been archived by the owner on Mar 1, 2023. It is now read-only.

Commit

Permalink
Add mp_snprint() for debug output
Browse files Browse the repository at this point in the history
Other changes:

* Change mp_fprint() to return the number of bytes printed instead of 0
* Improve the test coverage for mp_fprintf()
  • Loading branch information
rtsisyk committed Oct 12, 2016
1 parent 4203ef6 commit f8a6a7f
Show file tree
Hide file tree
Showing 2 changed files with 193 additions and 96 deletions.
240 changes: 154 additions & 86 deletions msgpuck.h
Original file line number Diff line number Diff line change
Expand Up @@ -866,15 +866,33 @@ MP_PROTO size_t
mp_vformat(char *data, size_t data_size, const char *format, va_list args);

/**
* \brief print to \a file msgpacked data in JSON format.
* MP_EXT is printed as "EXT" only
* \brief print MsgPack data \a file using JSON-like format.
* MP_EXT is printed as "undefined"
* \param file - pointer to file (or NULL for stdout)
* \param data - pointer to buffer containing msgpack object
* \retval 0 - success
* \retval -1 - wrong msgpack
* \retval >=0 - the number of bytes printed
* \retval -1 - error
* \sa fprintf()
*/
MP_PROTO int
mp_fprint(FILE* file, const char *data);
mp_fprint(FILE *file, const char *data);

/**
* \brief format MsgPack data to \a buf using JSON-like format.
* \sa mp_fprint()
* \param buf - buffer to use
* \param size - buffer size. This function write at most size bytes
* (including the terminating null byte ('\0').
* \param data - pointer to buffer containing msgpack object
* \retval <size - the number of characters printed (excluding the null byte)
* \retval >=size - the number of characters (excluding the null byte),
* which would have been written to the final string if
* enough space had been available.
* \retval -1 - error
* \sa snprintf()
*/
MP_PROTO int
mp_snprint(char *buf, int size, const char *data);

/**
* \brief Check that \a cur buffer has enough bytes to decode a string header
Expand Down Expand Up @@ -2163,93 +2181,106 @@ mp_format(char *data, size_t data_size, const char *format, ...)
return res;
}

#define MP_PRINT(SELF, PRINTF) \
{ \
switch (mp_typeof(**data)) { \
case MP_NIL: \
mp_decode_nil(data); \
PRINTF("null"); \
break; \
case MP_UINT: \
PRINTF("%llu", (unsigned long long) mp_decode_uint(data)); \
break; \
case MP_INT: \
PRINTF("%lld", (long long) mp_decode_int(data)); \
break; \
case MP_STR: \
case MP_BIN: \
{ \
uint32_t len = mp_typeof(**data) == MP_STR ? \
mp_decode_strl(data) : mp_decode_binl(data); \
PRINTF("\""); \
const char *s; \
for (s = *data; s < *data + len; s++) { \
unsigned char c = (unsigned char ) *s; \
if (c < 128 && mp_char2escape[c] != NULL) { \
/* Escape character */ \
PRINTF("%s", mp_char2escape[c]); \
} else { \
PRINTF("%c", c); \
} \
} \
PRINTF("\""); \
*data += len; \
break; \
} \
case MP_ARRAY: \
{ \
uint32_t count = mp_decode_array(data); \
PRINTF("["); \
uint32_t i; \
for (i = 0; i < count; i++) { \
if (i) \
PRINTF(", "); \
SELF(data); \
} \
PRINTF("]"); \
break; \
} \
case MP_MAP: \
{ \
uint32_t count = mp_decode_map(data); \
PRINTF("{"); \
uint32_t i; \
for (i = 0; i < count; i++) { \
if (i) \
PRINTF(", "); \
SELF(data); \
PRINTF(": "); \
SELF(data); \
} \
PRINTF("}"); \
break; \
} \
case MP_BOOL: \
PRINTF(mp_decode_bool(data) ? "true" : "false"); \
break; \
case MP_FLOAT: \
PRINTF("%g", mp_decode_float(data)); \
break; \
case MP_DOUBLE: \
PRINTF("%lg", mp_decode_double(data)); \
break; \
case MP_EXT: \
mp_next(data); \
PRINTF("undefined"); \
break; \
default: \
mp_unreachable(); \
return -1; \
} \
}

MP_PROTO int
mp_fprint_internal(FILE *file, const char **data);

MP_IMPL int
mp_fprint_internal(FILE *file, const char **data)
{
#define _CHECK_RC(exp) do { if (mp_unlikely((exp) < 0)) return -1; } while(0)
switch (mp_typeof(**data)) {
case MP_NIL:
mp_decode_nil(data);
_CHECK_RC(fputs("null", file));
break;
case MP_UINT:
_CHECK_RC(fprintf(file, "%llu", (unsigned long long)
mp_decode_uint(data)));
break;
case MP_INT:
_CHECK_RC(fprintf(file, "%lld", (long long)
mp_decode_int(data)));
break;
case MP_STR:
case MP_BIN:
{
uint32_t len = mp_typeof(**data) == MP_STR ?
mp_decode_strl(data) : mp_decode_binl(data);
_CHECK_RC(fputc('"', file));
const char *s;
for (s = *data; s < *data + len; s++) {
unsigned char c = (unsigned char ) *s;
if (c < 128 && mp_char2escape[c] != NULL) {
/* Escape character */
_CHECK_RC(fputs(mp_char2escape[c], file));
} else {
_CHECK_RC(fputc(c, file));
}
}
_CHECK_RC(fputc('"', file));
*data += len;
break;
}
case MP_ARRAY:
{
uint32_t size = mp_decode_array(data);
_CHECK_RC(fputc('[', file));
uint32_t i;
for (i = 0; i < size; i++) {
if (i)
_CHECK_RC(fputs(", ", file));
_CHECK_RC(mp_fprint_internal(file, data));
}
_CHECK_RC(fputc(']', file));
break;
}
case MP_MAP:
{
uint32_t size = mp_decode_map(data);
_CHECK_RC(fputc('{', file));
uint32_t i;
for (i = 0; i < size; i++) {
if (i)
_CHECK_RC(fprintf(file, ", "));
_CHECK_RC(mp_fprint_internal(file, data));
_CHECK_RC(fputs(": ", file));
_CHECK_RC(mp_fprint_internal(file, data));
}
_CHECK_RC(fputc('}', file));
break;
}
case MP_BOOL:
_CHECK_RC(fputs(mp_decode_bool(data) ? "true" : "false", file));
break;
case MP_FLOAT:
_CHECK_RC(fprintf(file, "%g", mp_decode_float(data)));
break;
case MP_DOUBLE:
_CHECK_RC(fprintf(file, "%lg", mp_decode_double(data)));
break;
case MP_EXT:
mp_next(data);
_CHECK_RC(fputs("undefined", file));
break;
default:
mp_unreachable();
return -1;
}
return 0;
#undef _CHECK_RC
int total_bytes = 0;
#define HANDLE(FUN, ...) do { \
int bytes = FUN(file, __VA_ARGS__); \
if (mp_unlikely(bytes < 0)) \
return -1; \
total_bytes += bytes; \
} while (0)
#define PRINT(...) HANDLE(fprintf, __VA_ARGS__)
#define SELF(...) HANDLE(mp_fprint_internal, __VA_ARGS__)
MP_PRINT(SELF, PRINT)
#undef HANDLE
#undef SELF
#undef PRINT
return total_bytes;
}

MP_IMPL int
Expand All @@ -2261,6 +2292,43 @@ mp_fprint(FILE *file, const char *data)
return res;
}

MP_PROTO int
mp_snprint_internal(char *buf, int size, const char **data);

MP_IMPL int
mp_snprint_internal(char *buf, int size, const char **data)
{
int total_bytes = 0;
#define HANDLE(FUN, ...) do { \
int bytes = FUN(buf, size, __VA_ARGS__); \
if (mp_unlikely(bytes < 0)) \
return -1; \
total_bytes += bytes; \
if (bytes < size) { \
buf += bytes; \
size -= bytes; \
} else { \
/* Calculate the number of bytes needed */ \
buf = NULL; \
size = 0; \
} \
} while (0)
#define PRINT(...) HANDLE(snprintf, __VA_ARGS__)
#define SELF(...) HANDLE(mp_snprint_internal, __VA_ARGS__)
MP_PRINT(SELF, PRINT)
#undef HANDLE
#undef SELF
#undef PRINT
return total_bytes;
}

MP_IMPL int
mp_snprint(char *buf, int size, const char *data)
{
return mp_snprint_internal(buf, size, &data);
}

#undef MP_PRINT
/** \endcond */

/*
Expand Down
49 changes: 39 additions & 10 deletions test/msgpuck.c
Original file line number Diff line number Diff line change
Expand Up @@ -723,12 +723,11 @@ test_format(void)
int
test_mp_print()
{
plan(1);
plan(10);
header();

char data[512];

char *d = data;
char msgpack[128];
char *d = msgpack;
d = mp_encode_array(d, 6);
d = mp_encode_int(d, -5);
d = mp_encode_uint(d, 42);
Expand All @@ -751,30 +750,60 @@ test_mp_print()
*d++ = 0;
char bin[] = "\x12test\x34\b\t\n\"bla\\-bla\"\f\r";
d = mp_encode_bin(d, bin, sizeof(bin));
assert(d <= msgpack + sizeof(msgpack));

const char *expected =
"[-5, 42, \"kill bill\", "
"{\"bool true\": true, \"bool false\": false, \"null\": null, "
"\"float\": 3.14, \"double\": 3.14, 100: 500}, undefined, "
"\"\\u0012test4\\b\\t\\n\\\"bla\\\\-bla\\\"\\f\\r\\u0000\"]";
int esize = strlen(expected);

char result[256];

int fsize = mp_snprint(result, sizeof(result), msgpack);
ok(fsize == esize, "mp_snprint return value");
ok(strcmp(result, expected) == 0, "mp_snprint result");

fsize = mp_snprint(NULL, 0, msgpack);
ok(fsize == esize, "mp_snprint limit = 0");

fsize = mp_snprint(result, 1, msgpack);
ok(fsize == esize && result[0] == '\0', "mp_snprint limit = 1");

fsize = mp_snprint(result, 2, msgpack);
ok(fsize == esize && result[1] == '\0', "mp_snprint limit = 2");

fsize = mp_snprint(result, esize, msgpack);
ok(fsize == esize && result[esize - 1] == '\0',
"mp_snprint limit = expected");

fsize = mp_snprint(result, esize + 1, msgpack);
ok(fsize == esize && result[esize] == '\0',
"mp_snprint limit = expected + 1");

FILE *tmpf = tmpfile();
if (tmpf != NULL) {
mp_fprint(tmpf, data);
int fsize = mp_fprint(tmpf, msgpack);
ok(fsize == esize, "mp_fprint return value");
(void) rewind(tmpf);
memset(data, 0, sizeof(data));
if (fgets(data, sizeof(data), tmpf) != NULL) {
ok(strcmp(data, expected) == 0, "identical");
}
int rsize = fread(result, 1, sizeof(result), tmpf);
ok(rsize == esize && memcmp(result, expected, esize) == 0,
"mp_fprint result");
fclose(tmpf);
}

/* stdin is read-only */
int rc = mp_fprint(stdin, msgpack);
is(rc, -1, "mp_fprint I/O error");

footer();
return check_plan();
}

int main()
{
plan(17);

test_uints();
test_ints();
test_bools();
Expand Down

0 comments on commit f8a6a7f

Please sign in to comment.