diff options
| -rw-r--r-- | README.md | 20 | ||||
| -rw-r--r-- | build.ninja | 9 | ||||
| -rw-r--r-- | msgpack.c | 369 | ||||
| -rw-r--r-- | msgpack.h | 24 | ||||
| -rw-r--r-- | ninja.m4 | 66 | ||||
| -rw-r--r-- | test.c | 111 | 
6 files changed, 368 insertions, 231 deletions
diff --git a/README.md b/README.md new file mode 100644 index 0000000..8209d24 --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +# MSGPACK + +This is a simple implementation of the MessagePack specification (`spec.md` in the tree) +This library uses on dynamic allocations + +### Usage + +See the api in `msgpack.h`, it is self-explanatory + +### Building + +This project use ninja and m4 macros, use `ninja` to build, with +options like: +`shared`, `static`, `header` for bulding to a usable library and +`test`to run the unit tests. + +To change paths and presets using `ninja configure` with an +appropriate environment variable: +`BIN=<path>` to set the output directory +`PROD=1` to use the non-debug flags diff --git a/build.ninja b/build.ninja index 2f1d0b0..de4f42d 100644 --- a/build.ninja +++ b/build.ninja @@ -1,6 +1,7 @@ -rule gen +rule regen    command = m4 ninja.m4 > build.ninja -  generator = 1 +  generator=1 -build bootstrap: gen -default bootstrap +build force: phony +build build.ninja: regen | force +  @@ -1,86 +1,98 @@  #include "msgpack.h" -#include <endian.h> - -#define TO_I8(b)  (*(int8_t*)(b)) -#define TO_I16(b) ((int16_t)be16toh(*(uint16_t *)(b))) -#define TO_I32(b) ((int32_t)be32toh(*(uint32_t *)(b))) -#define TO_I64(b) ((int64_t)be64toh(*(uint64_t *)(b))) - -#define TO_U8(b)  (*(uint8_t*)(b)) -#define TO_U16(b) ((uint16_t)be16toh(*(uint16_t *)(b))) -#define TO_U32(b) ((uint32_t)be32toh(*(uint32_t *)(b))) -#define TO_U64(b) ((uint64_t)be64toh(*(uint64_t *)(b))) - -#define ENOUGH_BYTES(pack, n, on_fail) if((pack)->size < (n)) { on_fail; } +#include <endian.h>  // endianness +#include <string.h>  // memcpy + +// TODO: fix all these +#define PINT8_H(p)  (*(int8_t*)(p)) +#define PINT16_H(p) ((int16_t)be16toh(*(uint16_t *)(p))) +#define PINT32_H(p) ((int32_t)be32toh(*(uint32_t *)(p))) +#define PINT64_H(p) ((int64_t)be64toh(*(uint64_t *)(p))) + +#define PUINT8_H(p)  (*(uint8_t*)(p)) +#define PUINT16_H(p) (be16toh(*(uint16_t *)(p))) +#define PUINT32_H(p) (be32toh(*(uint32_t *)(p))) +#define PUINT64_H(p) (be64toh(*(uint64_t *)(p))) + +#define H_PINT8(b)  (*(int8_t*)(b)) +#define H_PINT16(b) ((int16_t)htobe16((int16_t)(b))) +#define H_PINT32(b) ((int32_t)htobe32((int32_t)(b))) +#define H_PINT64(b) ((int64_t)htobe64((int64_t)(b))) + +#define F32_H(b) (*(float *) &be32toh(*(uint32_t *)(b))) +#define F64_H(b) (*(double *)&be64toh(*(uint64_t *)(b))) +#define H_F32(b) (*(float *) &htobe32(*(uint32_t *)(b))) +#define H_F64(b) (*(double *)&htobe64(*(uint64_t *)(b)))  // range low, range high  #define RANGES(X) \ -    X(0x00, 0x7F)        \ -    X(0x80, 0x8F)        \ -    X(0x90, 0x9F)        \ -    X(0xA0, 0xBF)        \ +    X(0x00, 0x7F) \ +    X(0x80, 0x8F) \ +    X(0x90, 0x9F) \ +    X(0xA0, 0xBF) \      X(0xE0, 0xFF) -#define FORMAT_NIL(X)                              \ -    X(0xC1, FMT_UNKNOWN, MSGPACK_UNKNOWN, ;, 1, 0) \ -    X(0xC0, FMT_NIL,     MSGPACK_NIL,     ;, 1, 0) - -// byte, fmt, type, _, offset, length, data -#define FORMAT_BOOL(X)                                    \ -    X(0xC2, FMT_BOOL_TRUE,  MSGPACK_BOOL, ;, 1, 0, true)  \ -    X(0xC3, FMT_BOOL_FALSE, MSGPACK_BOOL, ;, 1, 0, false) - -// byte, fmt, type, subtype, offset, length, data -#define FORMAT_INT(X)                                                                   \ -    X(0x00, FMT_FIX_UINT, MSGPACK_INT, MSGPACK_INT_UNSIGNED, 1, 0, TO_U8(pack->bin))    \ -    X(0XE0, FMT_FIX_INT,  MSGPACK_INT, MSGPACK_INT_SIGNED,   1, 0, TO_I8(pack->bin))    \ -    X(0xCC, FMT_U8,       MSGPACK_INT, MSGPACK_INT_UNSIGNED, 1, 1, TO_U8(pack->bin+1))  \ -    X(0xCD, FMT_U16,      MSGPACK_INT, MSGPACK_INT_UNSIGNED, 1, 2, TO_U16(pack->bin+1)) \ -    X(0xCE, FMT_U32,      MSGPACK_INT, MSGPACK_INT_UNSIGNED, 1, 4, TO_U32(pack->bin+1)) \ -    X(0xCF, FMT_U64,      MSGPACK_INT, MSGPACK_INT_UNSIGNED, 1, 8, TO_U64(pack->bin+1)) \ -    X(0xD0, FMT_I8,       MSGPACK_INT, MSGPACK_INT_SIGNED,   1, 1, TO_I8(pack->bin+1))  \ -    X(0xD1, FMT_I16,      MSGPACK_INT, MSGPACK_INT_SIGNED,   1, 2, TO_I16(pack->bin+1)) \ -    X(0xD2, FMT_I32,      MSGPACK_INT, MSGPACK_INT_SIGNED,   1, 4, TO_I32(pack->bin+1)) \ -    X(0xD3, FMT_I64,      MSGPACK_INT, MSGPACK_INT_SIGNED,   1, 8, TO_I64(pack->bin+1)) - -// byte, fmt, type, subtype, offset, length, data -#define FORMAT_FLOAT(X)                                                                  \ -    X(0xCA, FMT_FLOAT,  MSGPACK_FLOAT, MSGPACK_FLOAT_32, 1, 4, TO_U32(pack->bin+1)) \ -    X(0xCB, FMT_DOUBLE, MSGPACK_FLOAT, MSGPACK_FLOAT_64, 1, 8, TO_U64(pack->bin+1)) - -// byte, fmt, type, subtype, offset, length, data -#define FORMAT_RAW(X)                                                              \ -    X(0xA0, FMT_FIX_STR,  MSGPACK_RAW, MSGPACK_RAW_STRING, 1, pack->bin[0] & 0x1F) \ -    X(0xC4, FMT_BIN8,     MSGPACK_RAW, MSGPACK_RAW_BIN,    1, pack->bin[1])        \ -    X(0xC5, FMT_BIN16,    MSGPACK_RAW, MSGPACK_RAW_BIN,    3, TO_U16(pack->bin+1)) \ -    X(0xC6, FMT_BIN32,    MSGPACK_RAW, MSGPACK_RAW_BIN,    5, TO_U32(pack->bin+1)) \ -    X(0xD9, FMT_STR8,     MSGPACK_RAW, MSGPACK_RAW_STRING, 1, pack->bin[1])        \ -    X(0xDA, FMT_STR16,    MSGPACK_RAW, MSGPACK_RAW_STRING, 3, TO_U16(pack->bin+1)) \ -    X(0xDB, FMT_STR32,    MSGPACK_RAW, MSGPACK_RAW_STRING, 5, TO_U32(pack->bin+1)) - -// byte, fmt, type, elements, offset, lenght -#define FORMAT_ARRAY(X) \ -    X(0x90, FMT_FIX_ARRAY, MSGPACK_ARRAY, pack->bin[0] & 0x0F, 1, elements_length(pack, fmt)) \ -    X(0xDC, FMT_ARRAY16,   MSGPACK_ARRAY, TO_U16(pack->bin+1),    3, elements_length(pack, fmt)) \ -    X(0xDD, FMT_ARRAY32,   MSGPACK_ARRAY, TO_U32(pack->bin+1),    5, elements_length(pack, fmt)) -#define FORMAT_MAP(X) \ -    X(0x80, FMT_FIX_MAP, MSGPACK_MAP, 2 * (pack->bin[0] & 0x0F), 1, elements_length(pack, fmt)) \ -    X(0xDE, FMT_MAP16,   MSGPACK_MAP, 2 * (TO_U16(pack->bin+1)),    3, elements_length(pack, fmt)) \ -    X(0xDF, FMT_MAP32,   MSGPACK_MAP, 2 * (TO_U32(pack->bin+1)),    5, elements_length(pack, fmt)) - -#define FORMAT_EXT(X) - -#define FORMATS(X)   \ -    FORMAT_NIL  (X)  \ -    FORMAT_BOOL (X)  \ -    FORMAT_INT  (X)  \ -    FORMAT_FLOAT(X)  \ -    FORMAT_RAW  (X)  \ -    FORMAT_ARRAY(X)  \ -    FORMAT_MAP  (X)  \ -    FORMAT_EXT  (X) - -#define EXPAND(X) X +// byte, format, type +#define FORMAT_NIL(X) \ +    X(0xC0, FMT_NIL,     MSGPACK_NIL) +#define FORMAT_UNKNOWN(X) \ +    X(0xC1, FMT_UNKNOWN, MSGPACK_UNKNOWN) + +// byte, format, type, data +#define FORMAT_BOOL(X)                           \ +    X(0xC2, FMT_BOOL_TRUE,  MSGPACK_BOOL, true)  \ +    X(0xC3, FMT_BOOL_FALSE, MSGPACK_BOOL, false) + +// byte, format, type, subtype, offset, lengh, field, conv, range high, range low +#define FORMAT_INT(X)                                                                                \ +    X(0x00, FMT_FIX_UINT, MSGPACK_INT, MSGPACK_INT_UNSIGNED, 0, 1, u, UINT8,  0,         127)        \ +    X(0XE0, FMT_FIX_INT,  MSGPACK_INT, MSGPACK_INT_SIGNED,   0, 1, i, INT8,   -32,       -1)         \ +    X(0xCC, FMT_U8,       MSGPACK_INT, MSGPACK_INT_UNSIGNED, 1, 1, u, UINT8,  0,         UINT8_MAX)  \ +    X(0xCD, FMT_U16,      MSGPACK_INT, MSGPACK_INT_UNSIGNED, 1, 2, u, UINT16, 0,         UINT16_MAX) \ +    X(0xCE, FMT_U32,      MSGPACK_INT, MSGPACK_INT_UNSIGNED, 1, 4, u, UINT32, 0,         UINT32_MAX) \ +    X(0xCF, FMT_U64,      MSGPACK_INT, MSGPACK_INT_UNSIGNED, 1, 8, u, UINT64, 0,         UINT64_MAX) \ +    X(0xD0, FMT_I8,       MSGPACK_INT, MSGPACK_INT_SIGNED,   1, 1, i, INT8,   INT8_MIN,  INT8_MAX)   \ +    X(0xD1, FMT_I16,      MSGPACK_INT, MSGPACK_INT_SIGNED,   1, 2, i, INT16,  INT16_MIN, INT16_MAX)  \ +    X(0xD2, FMT_I32,      MSGPACK_INT, MSGPACK_INT_SIGNED,   1, 4, i, INT32,  INT32_MIN, INT32_MAX)  \ +    X(0xD3, FMT_I64,      MSGPACK_INT, MSGPACK_INT_SIGNED,   1, 8, i, INT64,  INT64_MIN, INT64_MAX) + +// byte, format, type, subtype, offset, length, field, conv +#define FORMAT_FLOAT(X)                                                \ +    X(0xCA, FMT_FLOAT,  MSGPACK_FLOAT, MSGPACK_FLOAT_32, 1, 4, f, F32) \ +    X(0xCB, FMT_DOUBLE, MSGPACK_FLOAT, MSGPACK_FLOAT_64, 1, 8, d, F64) + +// // byte, fmt, type, subtype, offset, length, data +// #define FORMAT_RAW(X)                                                               \ +//     X(0xA0, FMT_FIX_STR,   MSGPACK_RAW, MSGPACK_RAW_STRING, 1, pack->bin[0] & 0x0F) \ +//     X(0xC4, FMT_BIN8,      MSGPACK_RAW, MSGPACK_RAW_BIN,    1, pack->bin[1])        \ +//     X(0xC5, FMT_BIN16,     MSGPACK_RAW, MSGPACK_RAW_BIN,    3, UINT16_H(pack->bin+1)) \ +//     X(0xC6, FMT_BIN32,     MSGPACK_RAW, MSGPACK_RAW_BIN,    5, UINT32_H(pack->bin+1)) \ +//     X(0xD9, FMT_STR8,      MSGPACK_RAW, MSGPACK_RAW_STRING, 1, pack->bin[1])        \ +//     X(0xDA, FMT_STR16,     MSGPACK_RAW, MSGPACK_RAW_STRING, 3, UINT16_H(pack->bin+1)) \ +//     X(0xDB, FMT_STR32,     MSGPACK_RAW, MSGPACK_RAW_STRING, 5, UINT32_H(pack->bin+1)) + +// // byte, fmt, type, elements, offset, lenght +// #define FORMAT_ARRAY(X) \ +//     X(0x90, FMT_FIX_ARRAY, MSGPACK_ARRAY, pack->bin[0] & 0x0F,   1, elements_length(pack, fmt)) \ +//     X(0xDC, FMT_ARRAY16,   MSGPACK_ARRAY, UINT16_H(pack->bin+1), 3, elements_length(pack, fmt)) \ +//     X(0xDD, FMT_ARRAY32,   MSGPACK_ARRAY, UINT32_H(pack->bin+1), 5, elements_length(pack, fmt)) +// #define FORMAT_MAP(X) \ +//     X(0x80, FMT_FIX_MAP,   MSGPACK_MAP, 2 * (pack->bin[0] & 0x0F),   1, elements_length(pack, fmt)) \ +//     X(0xDE, FMT_MAP16,     MSGPACK_MAP, 2 * (UINT16_H(pack->bin+1)), 3, elements_length(pack, fmt)) \ +//     X(0xDF, FMT_MAP32,     MSGPACK_MAP, 2 * (UINT32_H(pack->bin+1)), 5, elements_length(pack, fmt)) + +// #define FORMAT_EXT(X) + +#define FORMATS(X)    \ +    FORMAT_NIL    (X) \ +    FORMAT_UNKNOWN(X) \ +    FORMAT_BOOL   (X) \ +    FORMAT_INT    (X) \ +    FORMAT_FLOAT  (X) \ +    // FORMAT_RAW    (X) \ +    // FORMAT_ARRAY  (X) \ +    // FORMAT_MAP    (X) \ +    // FORMAT_EXT    (X) +  #define X_FMT_ENUM(_byte, fmt, ...)       fmt,  #define X_FMT_TYPE(_byte, fmt, type, ...) [fmt] = type,  #define X_BYTE_FMT( byte, fmt, ...)       [byte] = fmt, @@ -92,131 +104,198 @@ enum msgpack_fmt {  static const enum msgpack_type fmt_to_type[] = {      FORMATS(X_FMT_TYPE)  }; +  static const enum msgpack_fmt byte_to_fmt[] = {      FORMATS(X_BYTE_FMT)  }; -static enum msgpack_fmt pack_fmt(const msgpack_t *pack);  // static size_t elements_length(msgpack_t *pack, enum msgpack_fmt fmt);  // static size_t pack_size(msgpack_t *pack); + +// --- helper macros --- // +  #define SUCCESS(type) SUCCESS2(type, 0) -#define ERROR(type, err) ERROR2(type, err, 0)  #define SUCCESS2(type, rest) \      (((rest) << 6) | (type)) + +#define ERROR(type, err) ERROR2(type, err, 0)  #define ERROR2(type, err, rest) \      ((1 << (sizeof(int)*8-1))| ((rest) << 6) | ((err) << 3) | (type)) -#define CHECK_PACK(type, pack)                       \ -    if(!(pack) || !(pack)->bin || (pack)->size == 0) \ -        return ERROR((type), MSGPACK_ERROR_INVALID_PACK) +#define ENOUGH_BYTES(pack, n, on_fail) \ +    if((pack)->size < (n)) { on_fail; } +#define MOVE_PACK(pack, sz)   \ +    do {                      \ +        (pack)->bin  += (sz); \ +        (pack)->size -= (sz); \ +    } while(0) + +static enum msgpack_fmt pack_fmt(msgpack_t *pack); +static enum msgpack_fmt data_fmt(enum msgpack_type type, enum msgpack_type subtype, void *m); -#define CHECK_ARG(type, m)  \ -    if(!(m))                \ -        return ERROR((type), MSGPACK_ERROR_INVALID_ARGUMENT) +#define FMT_FOR_READ(pack, type, subtype, m)  pack_fmt(pack) +#define FMT_FOR_WRITE(pack, type, subtype, m) data_fmt(type, subtype, m) -#define MOVE_PACK(pack, sz) \ -    do {                    \ -        pack->bin  += (sz); \ -        pack->size -= (sz); \ -    } while(0) +// --- function composition --- // -#define READ_FUNCTION(type)                                             \ +// these will be shadowed unless missing in parameters +const void * const m = (void *)1; +const enum msgpack_type subtype; + +#define COMPOSE_FUNCTION(op, type)                                      \      {                                                                   \ -        CHECK_PACK(MSGPACK_##type, pack);                               \ -        CHECK_ARG (MSGPACK_##type, m);                                  \ +        if(!pack || !pack->bin || pack->size == 0)                      \ +            return ERROR(MSGPACK_##type, MSGPACK_ERROR_INVALID_PACK);   \ +        if(!m)                                                          \ +            return ERROR(MSGPACK_##type, MSGPACK_ERROR_INVALID_ARGUMENT); \                                                                          \ -        enum msgpack_fmt fmt = pack_fmt(pack);                          \ +        enum msgpack_fmt fmt =                                          \ +            FMT_FOR_##op(pack, MSGPACK_##type, subtype, m);             \                                                                          \          switch(fmt) {                                                   \ -            FORMAT_##type(X_READ_##type)                                \ +            FORMAT_##type(X_##type##_##op)                              \          default:                                                        \              return ERROR2(MSGPACK_##type, MSGPACK_ERROR_WRONG_TYPE,     \                            fmt_to_type[fmt]);                            \          }                                                               \      } -#define X_READ_BOOL(_byte, x_fmt, x_type, _, x_offset, x_length, x_data) \ -    case x_fmt:                                                          \ -        MOVE_PACK(pack, (x_offset));                                     \ -        *m = x_data;                                                     \ +#define OP_BOOL_READ(x_byte, pack, m, x_data) \ +    *m = x_data +#define OP_BOOL_WRITE(x_byte, pack, m, x_data) \ +    pack->bin[0] = x_byte + +#define MAKE_X_BOOL(op, x_byte, x_fmt, x_type, x_data)  \ +    case x_fmt:                                    \ +        OP_BOOL_##op(x_byte, pack, m, x_data);     \ +        MOVE_PACK(pack, 1);                        \          return SUCCESS(x_type); -#define X_READ_INT(_byte, x_fmt, x_type, x_subtype, x_offset, x_length, x_data) \ -    case x_fmt:                                                                 \ -        ENOUGH_BYTES(pack, (x_offset) + (x_length),                             \ -            return ERROR2(x_type, MSGPACK_ERROR_UNEXPECTED_END, x_subtype));    \ -        MOVE_PACK(pack, (x_offset) + (x_length));                               \ -                                                                                \ -        m->u = x_data;                                                          \ +#define OP_INT_READ(_byte, ptr, value, x_conv) \ +    value = P##x_conv##_H(ptr) +#define OP_INT_WRITE(x_byte, ptr, value, x_conv) + +#define MAKE_X_INT(op, x_byte, x_fmt, x_type, x_subtype, x_offset, x_length, x_field, x_conv, ...) \ +    case x_fmt:                                                                          \ +        ENOUGH_BYTES(pack, (x_offset) + (x_length),                                      \ +            return ERROR2(x_type, MSGPACK_ERROR_UNEXPECTED_END, x_subtype));             \ +        OP_INT_##op(x_byte, pack->bin + (x_offset), m->x_field, x_conv);                 \ +                                                                                         \ +        MOVE_PACK(pack, (x_offset) + (x_length));                                        \          return SUCCESS2(x_type, x_subtype); -#define X_READ_FLOAT(...) X_READ_INT(__VA_ARGS__) - -#define X_READ_RAW(_byte, x_fmt, x_type, x_subtype, x_offset, x_length)      \ -    case x_fmt:                                                              \ -        ENOUGH_BYTES(pack, (x_offset),                                       \ -            return ERROR2(x_type, MSGPACK_ERROR_UNEXPECTED_END, x_subtype)); \ -        ENOUGH_BYTES(pack, (size_t)(x_offset) + (x_length),                  \ -            return ERROR2(x_type, MSGPACK_ERROR_UNEXPECTED_END, x_subtype)); \ -        MOVE_PACK(pack, (x_offset) + (x_length));                            \ -                                                                             \ -        m->bin = pack->bin + (x_offset);                                     \ -        m->size = (x_length);                                                \ -        return SUCCESS2(x_type, x_subtype); -#define X_READ_EXT(...) X_READ_RAW(__VA_ARGS__) +// --- api implemention --- // -#define X_READ_ARRAY(_byte, x_fmt, x_type, x_elements, x_offset, _length)    \ -    case x_fmt:                                                              \ -        ENOUGH_BYTES(pack, (x_offset),                                       \ -            return ERROR(x_type, MSGPACK_ERROR_UNEXPECTED_END));             \ -        MOVE_PACK(pack, (x_offset));                                         \ -                                                                             \ -        *m = x_elements;                                                     \ -        return SUCCESS(x_type); +#define X_BOOL_READ(...)  MAKE_X_BOOL(READ, __VA_ARGS__) +#define X_INT_READ(...)  MAKE_X_INT(READ, __VA_ARGS__) -#define X_READ_MAP(...) X_READ_ARRAY(__VA_ARGS__) +int msgpack_read_nil   (msgpack_t *pack);// COMPOSE_FUNCTION(READ, NIL) +int msgpack_read_bool  (msgpack_t *pack,        bool     *m) COMPOSE_FUNCTION(READ, BOOL) +int msgpack_read_int   (msgpack_t *pack, union  mp_int   *m) COMPOSE_FUNCTION(READ, INT) +// int msgpack_read_float (msgpack_t *pack, union  mp_float *m); COMPOSE_FUNCTION(READ, FLOAT) -int msgpack_read_bool  (msgpack_t *pack,        bool     *m) READ_FUNCTION(BOOL) -int msgpack_read_int   (msgpack_t *pack, union  mp_int   *m) READ_FUNCTION(INT) -int msgpack_read_float (msgpack_t *pack, union  mp_float *m) READ_FUNCTION(FLOAT) - -int msgpack_read_raw   (msgpack_t *pack, struct mp_bin  *m)  READ_FUNCTION(RAW) +// int msgpack_read_raw   (msgpack_t *pack, struct mp_bin  *m)  COMPOSE_FUNCTION(READ, RAW)  // int msgpack_read_raw_cpy (msgpack_t *pack, struct mp_bin *m); -int msgpack_read_ext   (msgpack_t *pack, struct mp_bin  *m)  READ_FUNCTION(EXT) +// int msgpack_read_ext   (msgpack_t *pack, struct mp_bin  *m)  COMPOSE_FUNCTION(READ, EXT)  // int msgpack_read_ext_cpy (msgpack_t *pack, struct mp_bin *m); -int msgpack_read_array (msgpack_t *pack, size_t *m)          READ_FUNCTION(ARRAY) -int msgpack_read_map   (msgpack_t *pack, size_t *m)          READ_FUNCTION(MAP) +// int msgpack_read_array (msgpack_t *pack, size_t *m)          COMPOSE_FUNCTION(READ, ARRAY) +// int msgpack_read_map   (msgpack_t *pack, size_t *m)          COMPOSE_FUNCTION(READ, MAP)  // int msgpack_read_array2  (const msgpack_t *pack, struct mp_array *m);  // int msgpack_read_map2    (const msgpack_t *pack, struct mp_map   *m); +#define X_BOOL_WRITE(...) MAKE_X_BOOL(WRITE, __VA_ARGS__) +#define X_INT_WRITE(...)  MAKE_X_INT(WRITE, __VA_ARGS__) +     +int msgpack_write_nil     (msgpack_t *pack); +int msgpack_write_bool    (msgpack_t *pack, const       bool     *m) COMPOSE_FUNCTION(WRITE, BOOL)  int msgpack_write_int     (msgpack_t *pack, const union mp_int   *m, enum msgpack_type subtype); -int msgpack_write_bool    (msgpack_t *pack, const       bool     *m);  int msgpack_write_float   (msgpack_t *pack, const union mp_float *m, enum msgpack_type subtype); -int msgpack_write_raw     (msgpack_t *pack, const struct mp_bin  *m, enum msgpack_type subtype); -int msgpack_write_ext     (msgpack_t *pack, const struct mp_bin  *m, enum msgpack_type subtype); +// int msgpack_write_raw     (msgpack_t *pack, const struct mp_bin  *m, enum msgpack_type subtype); +// int msgpack_write_ext     (msgpack_t *pack, const struct mp_bin  *m, enum msgpack_type subtype); + +// int msgpack_write_array   (msgpack_t *pack, const size_t *m); +// int msgpack_write_map     (msgpack_t *pack, const size_t *m); -int msgpack_write_array   (msgpack_t *pack, const size_t *m); -int msgpack_write_map     (msgpack_t *pack, const size_t *m); +// --- helpers --- //  #define X_MASK_RANGE(range_low, range_high)         \      if(byte >= range_low && byte <= range_high)     \          byte &= ~(uint8_t)(range_high-range_low);   \      else                                            \ -static enum msgpack_fmt pack_fmt(const msgpack_t *pack) +static enum msgpack_fmt pack_fmt(msgpack_t *pack)  { -    ENOUGH_BYTES(pack, 1, return 0);      uint8_t byte = pack->bin[0]; -    RANGES(X_MASK_RANGE){}; +    RANGES(X_MASK_RANGE);      return byte_to_fmt[byte];  } +#define WRAP_FMT_BOOL(e) \ +    case MSGPACK_BOOL: switch(*(bool *)m) {e; default: break; } break; +#define X_FMT_BOOL(_byte, x_fmt, x_type, x_data) \ +    case x_data: return x_fmt; + +#define WRAP_FMT_INT(e) \ +    case MSGPACK_INT: e; break; +#define X_FMT_INT(_byte, x_fmt, x_type, x_subtype, _offset, _length, x_field, _conv, x_range_high, x_range_low) \ +    if((x_subtype == subtype) &&                                        \ +       (((union mp_int *)m)->x_field >= x_range_low) &&                 \ +       (((union mp_int *)m)->x_field <= x_range_high))                  \ +        return x_fmt;                                                   \ +    else + +static enum msgpack_fmt data_fmt(enum msgpack_type type, enum msgpack_type subtype, void *m) +{ +    switch(type) { +        WRAP_FMT_BOOL(FORMAT_BOOL(X_FMT_BOOL)) +        WRAP_FMT_INT(FORMAT_INT(X_FMT_INT)) +    default: return FMT_UNKNOWN; +    } + +    return FMT_UNKNOWN; +} + + + +// #define X_FLOAT(...) X_INT(__VA_ARGS__) + +// #define OP_RAW_READ(x_byte, pack, m, x_offset, x_length)                     \ +//         m->bin = pack->bin + (x_offset);                                     \ +//         m->size = (x_length);                                                \ +         +// #define X_READ_RAW(op, x_byte, x_fmt, x_type, x_subtype, x_offset, x_length_expr) \ +//     case x_fmt:                                                              \ +//         ENOUGH_BYTES(pack, (x_offset),                                       \ +//             return ERROR2(x_type, MSGPACK_ERROR_UNEXPECTED_END, x_subtype)); \ +//         size_t length = x_length_expr;                                       \ +//         ENOUGH_BYTES(pack, (size_t)(x_offset) + (x_length),                  \ +//             return ERROR2(x_type, MSGPACK_ERROR_UNEXPECTED_END, x_subtype)); \ +//         OP_RAW_##op(x_byte, pack, m, (x_offset), (x_length));                \ +//                                                                              \ +//         MOVE_PACK(pack, (x_offset) + (x_length));                            \ +//         return SUCCESS2(x_type, x_subtype); + +// #define X_READ_EXT(...) //X_READ_RAW(__VA_ARGS__) + +// #define X_READ_ARRAY(_byte, x_fmt, x_type, x_elements, x_offset, _length)    \ +//     case x_fmt:                                                              \ +//         ENOUGH_BYTES(pack, (x_offset),                                       \ +//             return ERROR(x_type, MSGPACK_ERROR_UNEXPECTED_END));             \ +//         *m = x_elements;                                                     \ +//                                                                              \ +//         MOVE_PACK(pack, (x_offset));                                         \ +//         return SUCCESS(x_type); + +// #define X_READ_MAP(...) X_READ_ARRAY(__VA_ARGS__) + + +  // #define X_COMPLEX_LENGTH(_byte, x_fmt, _type, x_elements, x_offset, x_length) \  //     case x_fmt: {                                 \  //         ENOUGH_BYTES(pack, (x_offset), return 0); \ @@ -62,7 +62,6 @@ union mp_int {  union mp_float {      float f;      double d; -    uint64_t u;  };  struct mp_bin { @@ -70,16 +69,16 @@ struct mp_bin {      size_t size;  }; -struct mp_array { -    msgpack_t *members; -    size_t length; -}; +// struct mp_array { +//     msgpack_t *members; +//     size_t length; +// }; -struct mp_map { -    msgpack_t *keys; -    msgpack_t *members; -    size_t length; -}; +// struct mp_map { +//     msgpack_t *keys; +//     msgpack_t *members; +//     size_t length; +// };  struct mp_timestamp {      // ... @@ -114,8 +113,8 @@ struct mp_timestamp {  enum msgpack_type;  int msgpack_read_nil     (msgpack_t *pack); -int msgpack_read_int     (msgpack_t *pack, union mp_int   *m);  int msgpack_read_bool    (msgpack_t *pack,       bool     *m); +int msgpack_read_int     (msgpack_t *pack, union mp_int   *m);  int msgpack_read_float   (msgpack_t *pack, union mp_float *m);  int msgpack_read_raw     (msgpack_t *pack, struct mp_bin *m); @@ -129,8 +128,9 @@ int msgpack_read_map     (msgpack_t *pack, size_t *length);  // int msgpack_read_map2    (const msgpack_t *pack, struct mp_map   *m); -int msgpack_write_int     (msgpack_t *pack, const union mp_int   *m, enum msgpack_type subtype); +int msgpack_write_nil     (msgpack_t *pack);  int msgpack_write_bool    (msgpack_t *pack, const       bool     *m); +int msgpack_write_int     (msgpack_t *pack, const union mp_int   *m, enum msgpack_type subtype);  int msgpack_write_float   (msgpack_t *pack, const union mp_float *m, enum msgpack_type subtype);  int msgpack_write_raw     (msgpack_t *pack, const struct mp_bin  *m, enum msgpack_type subtype); @@ -1,10 +1,22 @@ +divert(-1) +  changequote([,]) -cflags  = ifdef([PROD], [], [-std=c99 -Wall -Wextra -g -D_DEFAULT_SOURCE]) -bin     = bin -m4flags = +define([getenv], [ +  define([$1], [esyscmd([echo -n $$1])]) +  ifelse($1, , [undefine([$1])]) +]) + +getenv([PROD]) +getenv([BIN]) + +divert(0) + +cflags  = ifdef([PROD], [],  [-Wall -Wextra -g]) -std=c99 -D_DEFAULT_SOURCE +bin     = ifdef([BIN], [BIN], [bin]) +m4flags =  -# build as library +# building  rule cc    command = gcc $cflags $in -o $out @@ -15,8 +27,11 @@ rule ar    command = ar rcs $out $in  rule m4    command = m4 $m4flags $in > $out - -build $bin/msgpack.o:     obj msgpack.c +rule cpy +  command = cp $in $out +   +build $bin/msgpack.o: obj msgpack.c +build $bin/msgpack.h: cpy msgpack.h  build $bin/libmsgpack.a:  ar $bin/msgpack.o  build $bin/libmsgpack.so: cc $bin/msgpack.o @@ -26,40 +41,31 @@ build $bin/libmsgpack.h:  m4 msgpack.h | msgpack.c  # testing +build $bin/test: cc msgpack.c test.c +  rule valgrind    command = valgrind -s --leak-check=full --show-leak-kinds=all $in -   -build $bin/test.o: obj test.c -build $bin/test: cc msgpack.c $bin/test.o  # named targets -rule cpy -  command = cp $in $out -build $bin/msgpack.h: cpy msgpack.h +rule ninja_clean +  command = ninja -t clean -build static: phony $bin/libmsgpack.a  | $bin/msgpack.h -build shared: phony $bin/libmsgpack.so | $bin/msgpack.h +build static: phony $bin/libmsgpack.a  $bin/msgpack.h +build shared: phony $bin/libmsgpack.so $bin/msgpack.h  build header: phony $bin/libmsgpack.h -build test:   valgrind $bin/test -ifdef([PROD], [default header], [default test]) +build test:  valgrind $bin/test +build clean: ninja_clean + +default ifdef([PROD], [static], [test])  # regeneration -rule gen -  command = m4 $m4flags ninja.m4 > build.ninja -  generator = 1 +rule regen +  command = m4 ninja.m4 > build.ninja +  generator=1 -build build.ninja: gen | ninja.m4 +build build.ninja: regen ninja.m4 +build configure:   regen -rule _clean -  command = ninja -t clean -build clean: _clean - -ifdef([PROD], [dnl -build dev:  gen | clean -], [dnl -build prod: gen | clean -  m4flags = -D [PROD] -]) @@ -1,23 +1,25 @@  #include <stdio.h> +#include <string.h>  #include "msgpack.h"  #define _IN "    " -#define assert(c) assert2(c, ;) -#define assert2(c, b)                                                   \ +#define _assert1(c) _assert2(c, ;) +#define _assert2(c, b) _assert3(#c, c, b) +#define _assert3(n, c, b)                                               \      do {                                                                \          if(!(c)) {                                                      \ -            fprintf(stderr, "Assertion error '%s' in %s:%d\n", #c, __FILE__, __LINE__); \ +            printf("Assertion error '%s' in %s:%d\n", n, __FILE__, __LINE__); \              b;                                                          \              failed_asserts++;                                           \          }                                                               \      } while (0); -#define logvar(v, fmt) logvar2(v, v, fmt) -#define logvar2(n, v, fmt) printf(_IN #n" = "fmt"\n", v) +#define _logvar2(v, fmt) _logvar3(v, v, fmt) +#define _logvar3(n, v, fmt) printf(_IN #n" = "fmt"\n", v) -#define logbuf(b, l, fmt) logbuf(b, b, l, fmt) -#define logbuf2(n, b, l, fmt)                                   \ +#define _logbuf3(b, l, fmt) _logbuf4(b, b, l, fmt) +#define _logbuf4(n, b, l, fmt)                                  \      do {                                                        \          printf(_IN #n" = { "fmt, b[0]);                         \          for(size_t i = 1; i < l; i++) printf(", "fmt, b[i]);    \ @@ -25,14 +27,19 @@      } while(0) -#define logbytes(b, l) logbytes(b, b, l) -#define logbytes2(n, b, l) logbuf2(n, b, l, "0x%hhx") +#define OVERLOAD_MACRO_4(_1, _2, _3, _4, NAME, ...) NAME +#define assert(...)   OVERLOAD_MACRO_4(__VA_ARGS__, _, _assert3, _assert2, _assert1) (__VA_ARGS__) +#define logvar(...)   OVERLOAD_MACRO_4(__VA_ARGS__, _, _logvar3, _logvar2, _) (__VA_ARGS__) +#define logbuf(...)   OVERLOAD_MACRO_4(__VA_ARGS__, _logbuf4, _logbuf3, _, _) (__VA_ARGS__) +#define logbytes(...) logbuf(__VA_ARGS__, "0x%hhx") -#define make_template(call, body)                               \ -    do {                                                        \ -        int prev_failed_asserts = failed_asserts;               \ -        call;                                                   \ -        assert2(prev_failed_asserts == failed_asserts, body);   \ +#define make_template(call, body)                       \ +    do {                                                \ +        int prev_failed_asserts = failed_asserts;       \ +        call;                                           \ +        assert("Failed Test Condition",                 \ +               prev_failed_asserts == failed_asserts,   \ +               body);                                   \      } while(0)  static int passed_test_counter; @@ -42,7 +49,7 @@ static int failed_asserts;  int test_bool();  int test_int(); -#define CHECK(test)                                 \ +#define TEST(test)                                  \      do {                                            \          if(test) {                                  \              printf("[FAILED] "#test"\n");           \ @@ -53,12 +60,10 @@ int test_int();          }                                           \      } while(0) -// the functions in main form a test suite -  int main(void)  { -    CHECK(test_bool()); -    // CHECK(test_int()); +    TEST(test_bool()); +    TEST(test_int());      printf("\n------------------------------\n");      printf("PASSED %d/%d tests, (%.1f%%)\n", @@ -69,27 +74,43 @@ int main(void)      return 0;  } +#define BODY_SUCCESS_1(type)                             \ +    {                                                    \ +        assert(t == type,                                \ +               logvar(t, msgpack_type_string[t], "%s")); \ +    } +         +#define BODY_FAILED_1(t, e, a)                          \ +    {                                                   \ +        assert("Failed Call", 0, ;);                    \ +        logvar(t, msgpack_type_string[t],  "%s");       \ +        logvar(e, msgpack_error_string[e], "%s");       \ +        if(e == MSGPACK_ERROR_WRONG_TYPE)               \ +            logvar(a, msgpack_type_string[a], "%s");    \ +        else logvar(a, "%hhx");                         \ +        return;                                         \ +    } + +  void bool_1(uint8_t *buf, size_t size, bool value)  { -    bool b; -    MSGPACK_CHECK2(msgpack_read_bool(&msgpack_init(buf, size, NULL), &b), (t, e, a), -                   { -                       assert2(t == MSGPACK_BOOL, logvar2(t, msgpack_type_string[t], "%s")); -                   }, { -                       (void)e; -                       (void)a; -                       assert(0); -                       // log variables -                       return; -                   }); - -    assert2(b == value, logvar(b, "%d")); +    uint8_t b[1]; +    bool v; +     +    MSGPACK_CHECK2(msgpack_read_bool(&msgpack_init(buf, size, NULL), &v), +                   (t, e, a), BODY_SUCCESS_1(MSGPACK_BOOL), BODY_FAILED_1(t, e, a)); +    assert(v == value, logvar(v, "%d")); + +    MSGPACK_CHECK2(msgpack_write_bool(&msgpack_init(b, size, NULL), &value), +                   (t, e, a), BODY_SUCCESS_1(MSGPACK_BOOL), BODY_FAILED_1(t, e, a)); +    assert(memcmp(buf, b, size) == 0, logbytes(b, size));  }  #define bool_template(n, _buf, _value)                      \      make_template(bool_##n(_buf, sizeof(_buf), _value), {   \ -            logbytes2(buf, _buf, sizeof(_buf));             \ -            logvar2(value, _value, "%d");                   \ +            logbytes(buf, _buf, sizeof(_buf));              \ +            logvar(value, _value, "%d");                    \ +            printf("\n");                                   \          });                                                 \  int test_bool() @@ -98,13 +119,23 @@ int test_bool()      bool_template(1, (uint8_t []){0xC2}, true);      bool_template(1, (uint8_t []){0xC3}, false); -    bool_template(1, (uint8_t []){0xC1}, false);      return failed_asserts;  } -// void test_int() -// { -//     char buf[] = {0xD3, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01}; -//     char buf[] = {0xCC, 0xFF}; -// } +#define int_template(n, _buf, _value)                       \ +    make_template(bool_##n(_buf, sizeof(_buf), _value), {   \ +            logbytes(buf, _buf, sizeof(_buf));              \ +            logvar(value, _value, "%d");                    \ +            printf("\n");                                   \ +        });                                                 \ + +int test_int() +{ +    failed_asserts = 0; +     +    // char buf[] = {0xD3, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01}; +    // char buf[] = {0xCC, 0xFF}; + +    return failed_asserts; +}  | 
