From 947305d9ccbb4a8733b113049ae759499e8709c5 Mon Sep 17 00:00:00 2001 From: Randy Jordan Date: Thu, 25 Jun 2026 21:26:34 -0500 Subject: [PATCH] ci2_pack and tests --- include/ci2.h | 1 + include/platform/mem/ci2_pack.h | 46 +++ src/ci2_pack.c | 596 ++++++++++++++++++++++++++++++++ tests/07_ci2_pack.c | 212 ++++++++++++ 4 files changed, 855 insertions(+) create mode 100644 include/platform/mem/ci2_pack.h create mode 100644 src/ci2_pack.c create mode 100644 tests/07_ci2_pack.c diff --git a/include/ci2.h b/include/ci2.h index 135831b..706f2cb 100644 --- a/include/ci2.h +++ b/include/ci2.h @@ -34,6 +34,7 @@ You get to decide which parts of that platform layer you'd like to use. #include "./platform/error/ci2_exception.h" #include "./platform/mem/ci2_arena.h" #include "./platform/mem/ci2_mem.h" +#include "./platform/mem/ci2_pack.h" #include "./platform/try/ci2_try.h" #endif // ci2.h diff --git a/include/platform/mem/ci2_pack.h b/include/platform/mem/ci2_pack.h new file mode 100644 index 0000000..57f8033 --- /dev/null +++ b/include/platform/mem/ci2_pack.h @@ -0,0 +1,46 @@ +/* - | Copyright / About | ---------------------------------------------------- + Copyright (c) 2026 Randy Jordan + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + * --------------------------------------------------------------------------*/ +#ifndef CI2_PACK_H +#define CI2_PACK_H + +#include "../ci2_platform.h" + +// macros for packing floats and doubles: +#define pack754_32(f) (pack754((f), 32, 8)) +#define pack754_64(f) (pack754((f), 64, 11)) +#define unpack754_32(i) (unpack754((i), 32, 8)) +#define unpack754_64(i) (unpack754((i), 64, 11)) + +/* Get the size required to pack data according to the format string.*/ +CI2_DEF size_t +ci2_pre_pack(const char* format, ...); + +/* Pack data according to the format string into the buffer. */ +CI2_DEF size_t +ci2_pack(uint8_t* buf, const char* format, ...); + +/* Unpack data according to the format string from the buffer. */ +CI2_DEF size_t +ci2_unpack(uint8_t* buf, const char* format, ...); + +#endif // ci2_pack.h diff --git a/src/ci2_pack.c b/src/ci2_pack.c new file mode 100644 index 0000000..75c0dce --- /dev/null +++ b/src/ci2_pack.c @@ -0,0 +1,596 @@ +/* - | Copyright / About | ---------------------------------------------------- + Copyright (c) 2026 Randy Jordan + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + * --------------------------------------------------------------------------*/ +#include "../include/platform/mem/ci2_pack.h" +#include +#include +#include + +uint64_t +pack754(long double f, unsigned bits, unsigned expbits) +{ + long double fnorm; + int shift; + long long sign, exp, significand; + unsigned significandbits = bits - expbits - 1; // -1 for sign bit + + if (f == 0.0) + return 0; // get this special case out of the way + + // check sign and begin normalization + if (f < 0) { + sign = 1; + fnorm = -f; + } else { + sign = 0; + fnorm = f; + } + + // get the normalized form of f and track the exponent + shift = 0; + while (fnorm >= 2.0) { + fnorm /= 2.0; + shift++; + } + while (fnorm < 1.0) { + fnorm *= 2.0; + shift--; + } + fnorm = fnorm - 1.0; + + // calculate the binary form (non-float) of the significand data + significand = fnorm * ((1LL << significandbits) + 0.5f); + + // get the biased exponent + exp = shift + ((1 << (expbits - 1)) - 1); // shift + bias + + // return the final answer + return (sign << (bits - 1)) | (exp << (bits - expbits - 1)) | significand; +} + +long double +unpack754(uint64_t i, unsigned bits, unsigned expbits) +{ + long double result; + long long shift; + unsigned bias; + unsigned significandbits = bits - expbits - 1; // -1 for sign bit + + if (i == 0) + return 0.0; + + // pull the significand + result = (i & ((1LL << significandbits) - 1)); // mask + result /= (1LL << significandbits); // convert back to float + result += 1.0f; // add the one back on + + // deal with the exponent + bias = (1 << (expbits - 1)) - 1; + shift = ((i >> significandbits) & ((1LL << expbits) - 1)) - bias; + while (shift > 0) { + result *= 2.0; + shift--; + } + while (shift < 0) { + result /= 2.0; + shift++; + } + + // sign it + result *= (i >> (bits - 1)) & 1 ? -1.0 : 1.0; + + return result; +} + +static inline void +packi8(uint8_t* buf, int8_t v) +{ + *buf = (uint8_t)v; +} + +static inline void +packu8(uint8_t* buf, uint8_t v) +{ + *buf = v; +} + +static inline void +packi16(uint8_t* buf, int16_t v) +{ + uint16_t u = (uint16_t)v; + buf[0] = (uint8_t)(u >> 8); + buf[1] = (uint8_t)(u); +} + +static inline void +packu16(uint8_t* buf, uint16_t v) +{ + buf[0] = (uint8_t)(v >> 8); + buf[1] = (uint8_t)(v); +} + +static inline void +packi32(uint8_t* buf, int32_t v) +{ + uint32_t u = (uint32_t)v; + buf[0] = (uint8_t)(u >> 24); + buf[1] = (uint8_t)(u >> 16); + buf[2] = (uint8_t)(u >> 8); + buf[3] = (uint8_t)(u); +} + +static inline void +packu32(uint8_t* buf, uint32_t v) +{ + buf[0] = (uint8_t)(v >> 24); + buf[1] = (uint8_t)(v >> 16); + buf[2] = (uint8_t)(v >> 8); + buf[3] = (uint8_t)(v); +} + +static inline void +packi64(uint8_t* buf, int64_t v) +{ + uint64_t u = (uint64_t)v; + buf[0] = (uint8_t)(u >> 56); + buf[1] = (uint8_t)(u >> 48); + buf[2] = (uint8_t)(u >> 40); + buf[3] = (uint8_t)(u >> 32); + buf[4] = (uint8_t)(u >> 24); + buf[5] = (uint8_t)(u >> 16); + buf[6] = (uint8_t)(u >> 8); + buf[7] = (uint8_t)(u); +} + +static inline void +packu64(uint8_t* buf, uint64_t v) +{ + buf[0] = (uint8_t)(v >> 56); + buf[1] = (uint8_t)(v >> 48); + buf[2] = (uint8_t)(v >> 40); + buf[3] = (uint8_t)(v >> 32); + buf[4] = (uint8_t)(v >> 24); + buf[5] = (uint8_t)(v >> 16); + buf[6] = (uint8_t)(v >> 8); + buf[7] = (uint8_t)(v); +} + +static inline int8_t +unpacki8(const uint8_t* buf) +{ + return (int8_t)buf[0]; +} + +static inline uint8_t +unpacku8(const uint8_t* buf) +{ + return buf[0]; +} + +static inline int16_t +unpacki16(const uint8_t* buf) +{ + uint16_t u = ((uint16_t)buf[0] << 8) | ((uint16_t)buf[1]); + return (int16_t)u; +} + +static inline uint16_t +unpacku16(const uint8_t* buf) +{ + return ((uint16_t)buf[0] << 8) | ((uint16_t)buf[1]); +} + +static inline int32_t +unpacki32(const uint8_t* buf) +{ + uint32_t u = ((uint32_t)buf[0] << 24) | ((uint32_t)buf[1] << 16) | + ((uint32_t)buf[2] << 8) | ((uint32_t)buf[3]); + return (int32_t)u; +} + +static inline uint32_t +unpacku32(const uint8_t* buf) +{ + return ((uint32_t)buf[0] << 24) | ((uint32_t)buf[1] << 16) | + ((uint32_t)buf[2] << 8) | ((uint32_t)buf[3]); +} + +static inline int64_t +unpacki64(const uint8_t* buf) +{ + uint64_t u = ((uint64_t)buf[0] << 56) | ((uint64_t)buf[1] << 48) | + ((uint64_t)buf[2] << 40) | ((uint64_t)buf[3] << 32) | + ((uint64_t)buf[4] << 24) | ((uint64_t)buf[5] << 16) | + ((uint64_t)buf[6] << 8) | ((uint64_t)buf[7]); + return (int64_t)u; +} + +static inline uint64_t +unpacku64(const uint8_t* buf) +{ + return ((uint64_t)buf[0] << 56) | ((uint64_t)buf[1] << 48) | + ((uint64_t)buf[2] << 40) | ((uint64_t)buf[3] << 32) | + ((uint64_t)buf[4] << 24) | ((uint64_t)buf[5] << 16) | + ((uint64_t)buf[6] << 8) | ((uint64_t)buf[7]); +} + +size_t +ci2_pre_pack(const char* format, ...) +{ + /* Signed Formats */ + int8_t g; + int16_t h; + int32_t i; + int64_t j; + + /* Unsigned Formats */ + uint8_t G; + uint16_t H; + uint32_t I; + uint64_t J; + + /* Float Formats */ + float f; + double F; + // uint32_t l; // float32 + // uint64_t L; // double-64 + + /* Strings */ + char* s; // strings + size_t len = 0; // track string size + size_t size = 0; // total pack size + + /* Args */ + va_list ap; + va_start(ap, format); + + for (; *format != '\0'; format++) { + switch (*format) { + + case ' ': // Ignore spaces + break; + + case 'g': // 8-bit Signed + size += 1; + g = (int8_t)va_arg(ap, int); // promoted + (void)g; + break; + + case 'G': // 8-bit Unsigned + size += 1; + G = (uint8_t)va_arg(ap, int); // promoted + (void)G; + break; + + case 'h': // 16-bit Signed + size += 2; + h = (int16_t)va_arg(ap, int); // promoted + (void)h; + break; + + case 'H': // 16-bit Unsigned + size += 2; + H = (uint16_t)va_arg(ap, int); // promoted + (void)H; + break; + + case 'i': // 32-bit Signed + size += 4; + i = va_arg(ap, int32_t); + (void)i; + break; + + case 'I': // 32-bit Unsigned + size += 4; + I = va_arg(ap, uint32_t); + (void)I; + break; + + case 'j': // 64-bit Signed + size += 8; + j = va_arg(ap, int64_t); + (void)j; + break; + + case 'J': // 64-bit Unigned + size += 8; + J = va_arg(ap, uint64_t); + (void)J; + break; + + case 'f': // float 32-bit + size += 4; + f = (float)va_arg(ap, double); // promoted + (void)f; + break; + + case 'F': // double 64-bit + size += 8; + F = (double)va_arg(ap, double); + (void)F; + break; + + case 's': // string + s = va_arg(ap, char*); + len = strlen(s); + size += len + 8; + break; + } + } + + va_end(ap); + + return size; +} + +size_t +ci2_pack(uint8_t* buf, const char* format, ...) +{ + /* Signed Formats */ + int8_t g; + int16_t h; + int32_t i; + int64_t j; + + /* Unsigned Formats */ + uint8_t G; + uint16_t H; + uint32_t I; + uint64_t J; + + /* Float Formats */ + float f; + double F; + uint32_t l; // float32 + uint64_t L; // double-64 + + /* Strings */ + char* s; // strings + size_t len = 0; // track string size + size_t size = 0; // total pack size + + /* Args */ + va_list ap; + va_start(ap, format); + + for (; *format != '\0'; format++) { + switch (*format) { + + case ' ': // Ignore spaces + break; + + case 'g': // 8-bit Signed + size += 1; + g = (int8_t)va_arg(ap, int); // promoted + packi8(buf, g); + buf += 1; + break; + + case 'G': // 8-bit Unsigned + size += 1; + G = (uint8_t)va_arg(ap, int); // promoted + packu8(buf, G); + buf += 1; + break; + + case 'h': // 16-bit Signed + size += 2; + h = (int16_t)va_arg(ap, int); // promoted + packi16(buf, h); + buf += 2; + break; + + case 'H': // 16-bit Unsigned + size += 2; + H = (uint16_t)va_arg(ap, int); // promoted + packu16(buf, H); + buf += 2; + break; + + case 'i': // 32-bit Signed + size += 4; + i = va_arg(ap, int32_t); + packi32(buf, i); + buf += 4; + break; + + case 'I': // 32-bit Unsigned + size += 4; + I = va_arg(ap, uint32_t); + packu32(buf, I); + buf += 4; + break; + + case 'j': // 64-bit Signed + size += 8; + j = va_arg(ap, int64_t); + packi64(buf, j); + buf += 8; + break; + + case 'J': // 64-bit Unigned + size += 8; + J = va_arg(ap, uint64_t); + packu64(buf, J); + buf += 8; + break; + + case 'f': // float 32-bit + size += 4; + f = (float)va_arg(ap, double); // promoted + l = pack754_32(f); // convert to IEEE 754 + packi32(buf, l); + buf += 4; + break; + + case 'F': // double 64-bit + size += 8; + F = (double)va_arg(ap, double); + L = pack754_64(F); // convert to IEEE 754 + packi64(buf, L); + buf += 8; + break; + + case 's': // string + s = va_arg(ap, char*); + len = strlen(s); + size += len + 8; + packu64(buf, (uint64_t)len); + buf += 8; + memcpy(buf, s, len); + buf += len; + break; + } + } + + va_end(ap); + + return size; +} + +size_t +ci2_unpack(uint8_t* buf, const char* format, ...) +{ + int8_t* g; + int16_t* h; + int32_t* i; + int64_t* j; + + uint8_t* G; + uint16_t* H; + uint32_t* I; + uint64_t* J; + + float* f; + double* F; + + char* s; + uint64_t len = 0; + size_t count = 0; + size_t size = 0; + size_t maxstrlen = 0; + + va_list ap; + va_start(ap, format); + + for (; *format != '\0'; format++) { + switch (*format) { + case 'g': + g = va_arg(ap, int8_t*); + *g = unpacki8(buf); + buf += 1; + size += 1; + break; + + case 'G': + G = va_arg(ap, uint8_t*); + *G = unpacku8(buf); + buf += 1; + size += 1; + break; + + case 'h': + h = va_arg(ap, int16_t*); + *h = unpacki16(buf); + buf += 2; + size += 2; + break; + + case 'H': + H = va_arg(ap, uint16_t*); + *H = unpacku16(buf); + buf += 2; + size += 2; + break; + + case 'i': + i = va_arg(ap, int32_t*); + *i = unpacki32(buf); + buf += 4; + size += 4; + break; + + case 'I': + I = va_arg(ap, uint32_t*); + *I = unpacku32(buf); + buf += 4; + size += 4; + break; + + case 'j': + j = va_arg(ap, int64_t*); + *j = unpacki64(buf); + buf += 8; + size += 8; + break; + + case 'J': + J = va_arg(ap, uint64_t*); + *J = unpacku64(buf); + buf += 8; + size += 8; + break; + + case 'f': + f = va_arg(ap, float*); + *f = unpack754_32(unpacku32(buf)); + buf += 4; + size += 4; + break; + + case 'F': + F = va_arg(ap, double*); + *F = unpack754_64(unpacku64(buf)); + buf += 8; + size += 8; + break; + + case 's': + s = va_arg(ap, char*); + len = unpacku64(buf); + buf += 8; + size += 8 + (size_t)len; + + if (maxstrlen > 0 && len > maxstrlen) + count = maxstrlen - 1; + else + count = (size_t)len; + + memcpy(s, buf, count); + s[count] = '\0'; + buf += len; + break; + + default: + if (isdigit((unsigned char)*format)) { + maxstrlen = maxstrlen * 10 + (*format - '0'); + } + break; + } + + if (!isdigit((unsigned char)*format)) + maxstrlen = 0; + } + + va_end(ap); + return size; +} diff --git a/tests/07_ci2_pack.c b/tests/07_ci2_pack.c new file mode 100644 index 0000000..57ffaa3 --- /dev/null +++ b/tests/07_ci2_pack.c @@ -0,0 +1,212 @@ +/* - | Copyright / About | ---------------------------------------------------- + Copyright (c) 2026 Randy Jordan + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + * --------------------------------------------------------------------------*/ +#define DEBUG +#include "../include/platform/mem/ci2_pack.h" +#include +#include +#include +static inline void +packu64(uint8_t* buf, uint64_t v) +{ + buf[0] = (uint8_t)(v >> 56); + buf[1] = (uint8_t)(v >> 48); + buf[2] = (uint8_t)(v >> 40); + buf[3] = (uint8_t)(v >> 32); + buf[4] = (uint8_t)(v >> 24); + buf[5] = (uint8_t)(v >> 16); + buf[6] = (uint8_t)(v >> 8); + buf[7] = (uint8_t)(v); +} + +static void +test_integers(void) +{ + uint8_t buf[1024]; + + int8_t g1, g2; + uint8_t G1, G2; + int16_t h1, h2; + uint16_t H1, H2; + int32_t i1, i2; + uint32_t I1, I2; + int64_t j1, j2; + uint64_t J1, J2; + + size_t n = ci2_pack(buf, + "gG hH iI jJ", + INT8_MIN, + UINT8_MAX, + INT16_MIN, + UINT16_MAX, + INT32_MIN, + UINT32_MAX, + INT64_MIN, + UINT64_MAX); + size_t m = ci2_pre_pack("gG hH iI jJ", + INT8_MIN, + UINT8_MAX, + INT16_MIN, + UINT16_MAX, + INT32_MIN, + UINT32_MAX, + INT64_MIN, + UINT64_MAX); + + CI2_ASSERT(n == 1 + 1 + 2 + 2 + 4 + 4 + 8 + 8); + CI2_ASSERT(n == m); + ci2_unpack(buf, "gG hH iI jJ", &g1, &G1, &h1, &H1, &i1, &I1, &j1, &J1); + + CI2_ASSERT(g1 == INT8_MIN); + CI2_ASSERT(G1 == UINT8_MAX); + CI2_ASSERT(h1 == INT16_MIN); + CI2_ASSERT(H1 == UINT16_MAX); + CI2_ASSERT(i1 == INT32_MIN); + CI2_ASSERT(I1 == UINT32_MAX); + CI2_ASSERT(j1 == INT64_MIN); + CI2_ASSERT(J1 == UINT64_MAX); + + /* also test the other extremes */ + n = ci2_pack( + buf, "gG hH iI jJ", INT8_MAX, 0, INT16_MAX, 0, INT32_MAX, 0, INT64_MAX, 0); + + ci2_unpack(buf, "gG hH iI jJ", &g2, &G2, &h2, &H2, &i2, &I2, &j2, &J2); + + CI2_ASSERT(g2 == INT8_MAX); + CI2_ASSERT(G2 == 0); + CI2_ASSERT(h2 == INT16_MAX); + CI2_ASSERT(H2 == 0); + CI2_ASSERT(i2 == INT32_MAX); + CI2_ASSERT(I2 == 0); + CI2_ASSERT(j2 == INT64_MAX); + CI2_ASSERT(J2 == 0); +} + +static void +test_floats(void) +{ + uint8_t buf[1024]; + float f1, f2; + double d1, d2; + + size_t n = ci2_pack(buf, "fF", 0.0f, 0.0); + size_t m = ci2_pre_pack("fF", 0.0f, 0.0); + CI2_ASSERT(n == m); + CI2_ASSERT(n == 4 + 8); + ci2_unpack(buf, "fF", &f1, &d1); + CI2_ASSERT(f1 == 0.0f); + CI2_ASSERT(d1 == 0.0); + + n = ci2_pack(buf, "fF", -123.5f, 3490.5); + m = ci2_pre_pack("fF", -123.5f, 3490.5); + CI2_ASSERT(n == m); + ci2_unpack(buf, "fF", &f2, &d2); + CI2_ASSERT(f2 == -123.5f); + CI2_ASSERT(d2 == 3490.5); + + /* IEEE-754 helpers support them, test extremes too */ + n = ci2_pack(buf, "fF", FLT_MAX, DBL_MAX); + m = ci2_pre_pack("fF", FLT_MAX, DBL_MAX); + CI2_ASSERT(n == m); + ci2_unpack(buf, "fF", &f1, &d1); + CI2_ASSERT(f1 == FLT_MAX); + CI2_ASSERT(d1 == DBL_MAX); +} + +static void +test_strings(void) +{ + uint8_t buf[1024]; + char in[] = "Great unmitigated Zot! You've found the Runestaff!"; + char out[128]; + char out2[16]; + + size_t n = ci2_pack(buf, "s", in); + size_t m = ci2_pre_pack("s", in); + CI2_ASSERT(n == m); + CI2_ASSERT(n == 8 + strlen(in)); + + ci2_unpack(buf, "s", out); + CI2_ASSERT(strcmp(out, in) == 0); + + /* max string length handling: format "15s" means cap at 15 chars incl NUL */ + ci2_unpack(buf, "15s", out2); + CI2_ASSERT(strcmp(out2, "Great unmitiga") == + 0); /* 15 chars total incl '\0' => 14 copied */ + CI2_ASSERT(out2[15 - 1] == '\0'); +} + +static void +test_mixed_packet(void) +{ + uint8_t buf[1024]; + + uint8_t magic; + uint64_t ps2; + int16_t monkeycount; + char* s = "Great unmitigated Zot! You've found the Runestaff!"; + char s2[96]; + double absurdityfactor; + size_t packetsize; + size_t packetsize2; + + packetsize = ci2_pre_pack("JGHsF", + 0, /* placeholder for size */ + 'B', + 37, + s, + -3490.5); + packetsize2 = ci2_pack(buf, + "JGHsF", + 0, /* placeholder for size */ + 'B', + 37, + s, + -3490.5); + + CI2_ASSERT(packetsize == packetsize2); + packu64(buf, (uint64_t)packetsize); + + ci2_unpack(buf, "JGHsF", &ps2, &magic, &monkeycount, s2, &absurdityfactor); + + CI2_ASSERT(ps2 == packetsize); + CI2_ASSERT(magic == 'B'); + CI2_ASSERT(monkeycount == 37); + CI2_ASSERT(strcmp(s2, s) == 0); + CI2_ASSERT(absurdityfactor == -3490.5); +} + +int +main(int argc, char* argv[]) +{ + (void)argc; + (void)argv; + + test_integers(); + test_floats(); + test_strings(); + test_mixed_packet(); + + puts("All tests passed."); + + return EXIT_SUCCESS; +}