diff options
author | kartofen <mladenovnasko0@gmail.com> | 2025-04-02 01:15:23 +0300 |
---|---|---|
committer | kartofen <mladenovnasko0@gmail.com> | 2025-04-02 01:15:23 +0300 |
commit | 40618c2ff1c18815741888674cc76c8ddc486300 (patch) | |
tree | 707cd01dd35d9197e7627966a7ab84b393a0b1dc | |
parent | 5fba9e4d7492ca07d619999120b42495cf3df7c7 (diff) |
made building better and added README, everything else is very unfinished
-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; +} |