]> git.draconx.ca Git - dxcommon.git/commitdiff
Import integer packing library.
authorNick Bowler <nbowler@draconx.ca>
Sat, 14 Mar 2015 02:38:45 +0000 (19:38 -0700)
committerNick Bowler <nbowler@draconx.ca>
Wed, 28 Jun 2017 23:24:24 +0000 (19:24 -0400)
This simple library is used in a couple projects, better to maintain
it in one place.

Hook it into the newfangled test suite too.

13 files changed:
.gitignore
Makefile.am
src/pack.c [new file with mode: 0644]
src/pack.h [new file with mode: 0644]
src/tap.c [new file with mode: 0644]
src/tap.h [new file with mode: 0644]
t/.gitignore [new file with mode: 0644]
t/packtests.c [new file with mode: 0644]
t/packtests64.c [new file with mode: 0644]
t/packtestu.c [new file with mode: 0644]
t/packtestu64.c [new file with mode: 0644]
tests/functions.at [new file with mode: 0644]
testsuite.at

index 9171f9ddf33cb210b21840c7a42d05984cbdb299..02e9985ac1979fa66447dfde9fac8b9759ef5384 100644 (file)
@@ -4,6 +4,8 @@
 /autom4te.cache
 /install-sh
 /missing
+/depcomp
+/compile
 /testsuite.dir
 /testsuite.log
 /testsuite
@@ -11,4 +13,7 @@
 /atconfig
 Makefile.in
 Makefile
+.dirstamp
 .deps
+*.lo
+*.o
index 21b5f954f7df0c292356671cf7f49480d3139c26..6f5e77657a412ebf4ce975e47596d8cc3d7eef44 100644 (file)
@@ -6,6 +6,15 @@
 
 ACLOCAL_AMFLAGS = -I m4
 
+AM_CFLAGS = -I$(top_srcdir)/src
+
+check_PROGRAMS = t/packtestu t/packtests t/packtestu64 t/packtests64
+
+t_packtestu_SOURCES = t/packtestu.c src/pack.c src/tap.c
+t_packtests_SOURCES = t/packtests.c src/pack.c src/tap.c
+t_packtestu64_SOURCES = t/packtestu64.c src/pack.c src/tap.c
+t_packtests64_SOURCES = t/packtests64.c src/pack.c src/tap.c
+
 EXTRA_DIST =
 SUFFIXES =
 
diff --git a/src/pack.c b/src/pack.c
new file mode 100644 (file)
index 0000000..a4dd119
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright © 2009 Nick Bowler
+ *
+ * Portable binary (de-)serialisation of integral types.
+ *
+ * License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+ * This is free software: you are free to do what the fuck you want to.
+ * There is NO WARRANTY, to the extent permitted by law.
+ */
+
+#include "pack.h"
+
+/* Unsigned integer packing. */
+#define DEFPACK_BE(bits, type) void pack_ ## bits ## _be ( \
+       unsigned char *out, type v \
+) { \
+       unsigned i; \
+       for (i = 1; i <= bits/8; i++) { \
+               out[bits/8 - i] = v % 256; \
+               v /= 256; \
+       } \
+}
+
+#define DEFPACK_LE(bits, type) void pack_ ## bits ## _le ( \
+       unsigned char *out, type v \
+) { \
+       unsigned i; \
+       for (i = 0; i < bits/8; i++) { \
+               out[i] = v % 256; \
+               v /= 256; \
+       } \
+}
+
+DEFPACK_BE(16, unsigned short)
+DEFPACK_BE(32, unsigned long)
+#if PACK_HAVE_64BIT
+DEFPACK_BE(64, unsigned long long)
+#endif
+
+DEFPACK_LE(16, unsigned short)
+DEFPACK_LE(32, unsigned long)
+#if PACK_HAVE_64BIT
+DEFPACK_LE(64, unsigned long long)
+#endif
+
+#define DEFUNPACK_BE(bits, type) type unpack_ ## bits ## _be ( \
+       const unsigned char *in \
+) { \
+       type v = 0; \
+       unsigned i; \
+       for (i = 0; i < bits/8; i++) { \
+               v *= 256; \
+               v += in[i]; \
+       } \
+       return v; \
+}
+
+#define DEFUNPACK_LE(bits, type) type unpack_ ## bits ## _le ( \
+       const unsigned char *in \
+) { \
+       type v = 0; \
+       unsigned i; \
+       for (i = 1; i <= bits/8; i++) { \
+               v *= 256; \
+               v += in[bits/8 - i]; \
+       } \
+       return v; \
+}
+
+DEFUNPACK_BE(16, unsigned short)
+DEFUNPACK_BE(32, unsigned long)
+#if PACK_HAVE_64BIT
+DEFUNPACK_BE(64, unsigned long long)
+#endif
+
+DEFUNPACK_LE(16, unsigned short)
+DEFUNPACK_LE(32, unsigned long)
+#if PACK_HAVE_64BIT
+DEFUNPACK_LE(64, unsigned long long)
+#endif
+
+/*
+ * Two's complement signed integer packing.  This is unlikely to work on
+ * systems that don't themselves use two's complement.
+ */
+
+#define DEFUNPACK_SBE(bits, max, type) type unpack_s ## bits ## _be ( \
+       const unsigned char *in \
+) { \
+       type v = 0; \
+       unsigned i; \
+       int sign = (in[0] & 0x80) ? 1 : 0; \
+       for (i = 0; i < bits/8; i++) { \
+               v *= 256; \
+               v += in[i] & (i == 0 ? 0x7f : 0xff); \
+       } \
+       return sign*(-max-1) + v; \
+}
+
+#define DEFUNPACK_SLE(bits, max, type) type unpack_s ## bits ## _le ( \
+       const unsigned char *in \
+) { \
+       type v = 0; \
+       unsigned i; \
+       int sign = (in[bits/8 - 1] & 0x80) ? 1 : 0; \
+       for (i = 1; i <= bits/8; i++) { \
+               v *= 256; \
+               v += in[bits/8 - i] & (i == 1 ? 0x7f : 0xff); \
+       } \
+       return sign*(-max-1) + v; \
+}
+
+DEFUNPACK_SBE(16, 32767, short)
+DEFUNPACK_SBE(32, 2147483647l, long)
+#if PACK_HAVE_64BIT
+DEFUNPACK_SBE(64, 9223372036854775807ll, long long)
+#endif
+
+DEFUNPACK_SLE(16, 32767, short)
+DEFUNPACK_SLE(32, 2147483647l, long)
+#if PACK_HAVE_64BIT
+DEFUNPACK_SLE(64, 9223372036854775807ll, long long)
+#endif
diff --git a/src/pack.h b/src/pack.h
new file mode 100644 (file)
index 0000000..26c2546
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright © 2009 Nick Bowler
+ *
+ * Portable binary (de-)serialisation of integral types.
+ *
+ * License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+ * This is free software: you are free to do what the fuck you want to.
+ * There is NO WARRANTY, to the extent permitted by law.
+ */
+
+#ifndef DX_PACK_H_
+#define DX_PACK_H_
+
+#include <limits.h>
+#if !defined(PACK_HAVE_64BIT) && defined(ULLONG_MAX) && defined(LLONG_MAX)
+#      define PACK_HAVE_64BIT 1
+#endif
+
+void pack_16_be(unsigned char *, unsigned short);
+void pack_32_be(unsigned char *, unsigned long);
+#if PACK_HAVE_64BIT
+void pack_64_be(unsigned char *, unsigned long long);
+#endif
+
+void pack_16_le(unsigned char *, unsigned short);
+void pack_32_le(unsigned char *, unsigned long);
+#if PACK_HAVE_64BIT
+void pack_64_le(unsigned char *, unsigned long long);
+#endif
+
+unsigned short unpack_16_be(const unsigned char *);
+unsigned long  unpack_32_be(const unsigned char *);
+#if PACK_HAVE_64BIT
+unsigned long long unpack_64_be(const unsigned char *);
+#endif
+
+unsigned short unpack_16_le(const unsigned char *);
+unsigned long  unpack_32_le(const unsigned char *);
+#if PACK_HAVE_64BIT
+unsigned long long unpack_64_le(const unsigned char *);
+#endif
+
+short unpack_s16_be(const unsigned char *);
+long  unpack_s32_be(const unsigned char *);
+#if PACK_HAVE_64BIT
+long long unpack_s64_be(const unsigned char *);
+#endif
+
+short unpack_s16_le(const unsigned char *);
+long  unpack_s32_le(const unsigned char *);
+#if PACK_HAVE_64BIT
+long long unpack_s64_le(const unsigned char *);
+#endif
+
+#endif
diff --git a/src/tap.c b/src/tap.c
new file mode 100644 (file)
index 0000000..4416a9c
--- /dev/null
+++ b/src/tap.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright © 2015 Nick Bowler
+ *
+ * Simple TAP output library for C programs.
+ *
+ * License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+ * This is free software: you are free to do what the fuck you want to.
+ * There is NO WARRANTY, to the extent permitted by law.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "tap.h"
+
+static unsigned plan, total, passed, xpassed, failed, xfailed;
+
+void tap_plan(unsigned expected_tests)
+{
+       if (plan)
+               tap_bail_out("tap_plan: tests already planned!");
+       if (!expected_tests)
+               tap_bail_out("tap_plan: no tests to run!");
+
+       plan = expected_tests;
+       printf("1..%u\n", plan);
+}
+
+void tap_done(void)
+{
+       if (!plan) {
+               tap_plan(total);
+       } else if (total != plan) {
+               tap_bail_out("tap_done: planned %u tests, ran %u", plan, total);
+       }
+
+       assert(total == passed + xpassed + failed + xfailed);
+       exit(failed || xpassed);
+}
+
+void tap_vbail_out(const char *fmt, va_list ap)
+{
+       printf("Bail out!%*s", fmt != NULL, "");
+       if (fmt)
+               vprintf(fmt, ap);
+       putchar('\n');
+       exit(99);
+}
+
+void tap_bail_out(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       tap_vbail_out(fmt, ap);
+       va_end(ap);
+}
+
+void tap_vskip_all(const char *fmt, va_list ap)
+{
+       if (plan || total)
+               tap_bail_out("tap_skip_all: already started tests");
+
+       printf("1..0 # skip%*s", fmt != NULL, "");
+       if (fmt)
+               vprintf(fmt, ap);
+       putchar('\n');
+       exit(77);
+}
+
+void tap_skip_all(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       tap_vskip_all(fmt, ap);
+       va_end(ap);
+}
+
+void tap_vdiag(const char *fmt, va_list ap)
+{
+       printf("#%*s", fmt != NULL, "");
+       if (fmt)
+               vprintf(fmt, ap);
+       putchar('\n');
+}
+
+void tap_diag(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       tap_vdiag(fmt, ap);
+       va_end(ap);
+}
+
+int tap_vresult(int ok, const char *fmt, va_list ap)
+{
+       if (!ok)
+               printf("not ");
+       printf("ok %u%*s", ++total, fmt != NULL, "");
+       if (fmt)
+               vprintf(fmt, ap);
+       putchar('\n');
+
+       if (!total)
+               tap_bail_out("cannot handle so many tests");
+
+       passed += !!ok;
+       failed += !ok;
+
+       return ok;
+}
+
+int tap_result(int ok, const char *fmt, ...)
+{
+       va_list ap;
+       int ret;
+
+       va_start(ap, fmt);
+       ret = tap_vresult(ok, fmt, ap);
+       va_end(ap);
+
+       return ret;
+}
diff --git a/src/tap.h b/src/tap.h
new file mode 100644 (file)
index 0000000..16a4617
--- /dev/null
+++ b/src/tap.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright © 2015 Nick Bowler
+ *
+ * Simple TAP output library for C programs.
+ *
+ * License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+ * This is free software: you are free to do what the fuck you want to.
+ * There is NO WARRANTY, to the extent permitted by law.
+ */
+
+#ifndef DX_TAP_H_
+#define DX_TAP_H_
+
+#include <stdarg.h>
+
+void tap_plan(unsigned expected_tests);
+void tap_done(void);
+
+void tap_vbail_out(const char *fmt, va_list ap);
+void tap_bail_out(const char *fmt, ...);
+
+void tap_vskip_all(const char *fmt, va_list ap);
+void tap_skip_all(const char *fmt, ...);
+
+void tap_vdiag(const char *fmt, va_list ap);
+void tap_diag(const char *fmt, ...);
+
+int tap_vresult(int ok, const char *fmt, va_list ap);
+int tap_result(int ok, const char *fmt, ...);
+
+#endif
diff --git a/t/.gitignore b/t/.gitignore
new file mode 100644 (file)
index 0000000..b36f577
--- /dev/null
@@ -0,0 +1,2 @@
+packtest[su]
+packtest[su]64
diff --git a/t/packtests.c b/t/packtests.c
new file mode 100644 (file)
index 0000000..b3a7a8b
--- /dev/null
@@ -0,0 +1,48 @@
+#include "pack.h"
+#include "tap.h"
+
+static const unsigned char zero[8];
+static const unsigned char minus_one[8] = {
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static const unsigned char min[9] = {
+       0x80, 0, 0, 0, 0, 0, 0, 0, 0x80
+};
+
+static const unsigned char test_pattern[8] = {
+       0xde, 0xad, 0xbe, 0xef, 0xf0, 0x0d, 0xca, 0xfe
+};
+
+#define test(func, pattern, expected) do { \
+       long result__ = (func)(pattern); \
+       if (!tap_result(result__ == (expected), "%s(%s)", #func, #expected)) { \
+               tap_diag("  expected: %ld", (long)(expected)); \
+               tap_diag("  actual:   %ld", result__); \
+       } \
+} while (0)
+
+int main(void)
+{
+       tap_plan(16);
+
+       test(unpack_s16_be, zero,          0);
+       test(unpack_s16_be, minus_one,    -1);
+       test(unpack_s16_be, test_pattern, -8531);
+       test(unpack_s16_be, min,          -32767-1);
+       test(unpack_s32_be, zero,          0);
+       test(unpack_s32_be, minus_one,    -1);
+       test(unpack_s32_be, test_pattern, -559038737);
+       test(unpack_s32_be, min,          -2147483647-1);
+
+       test(unpack_s16_le, zero,          0);
+       test(unpack_s16_le, minus_one,    -1);
+       test(unpack_s16_le, test_pattern, -21026);
+       test(unpack_s16_le, min+7,        -32767-1);
+       test(unpack_s32_le, zero,          0);
+       test(unpack_s32_le, minus_one,    -1);
+       test(unpack_s32_le, test_pattern, -272716322);
+       test(unpack_s32_le, min+5,        -2147483647-1);
+
+       tap_done();
+}
diff --git a/t/packtests64.c b/t/packtests64.c
new file mode 100644 (file)
index 0000000..a8fefe9
--- /dev/null
@@ -0,0 +1,44 @@
+#include "pack.h"
+#include "tap.h"
+
+static const unsigned char zero[8];
+static const unsigned char minus_one[8] = {
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static const unsigned char min[9] = {
+       0x80, 0, 0, 0, 0, 0, 0, 0, 0x80
+};
+
+static const unsigned char test_pattern[8] = {
+       0xde, 0xad, 0xbe, 0xef, 0xf0, 0x0d, 0xca, 0xfe
+};
+
+#define test(func, pattern, expected) do { \
+       long long result__ = (func)(pattern); \
+       if (!tap_result(result__ == (expected), "%s(%s)", #func, #expected)) { \
+               tap_diag("  expected: %ld", (long long)(expected)); \
+               tap_diag("  actual:   %ld", result__); \
+       } \
+} while (0)
+
+int main(void)
+{
+#if PACK_HAVE_64BIT
+       tap_plan(8);
+
+       test(unpack_s64_be, zero,          0);
+       test(unpack_s64_be, minus_one,    -1);
+       test(unpack_s64_be, test_pattern, -2401053088584709378);
+       test(unpack_s64_be, min,          -9223372036854775807-1);
+
+       test(unpack_s64_le, zero,          0);
+       test(unpack_s64_le, minus_one,    -1);
+       test(unpack_s64_le, test_pattern, -87241914314740258);
+       test(unpack_s64_le, min+1,        -9223372036854775807-1);
+#else
+       tap_skip_all("no 64-bit support");
+#endif
+
+       tap_done();
+}
diff --git a/t/packtestu.c b/t/packtestu.c
new file mode 100644 (file)
index 0000000..5ae3af9
--- /dev/null
@@ -0,0 +1,40 @@
+#include "pack.h"
+#include "tap.h"
+
+static const unsigned char zero[8];
+static const unsigned char minus_one[8] = {
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static const unsigned char test_pattern[8] = {
+       0xde, 0xad, 0xbe, 0xef, 0xf0, 0x0d, 0xca, 0xfe
+};
+
+#define test(func, pattern, expected) do { \
+       unsigned long result__ = (func)(pattern); \
+       if (!tap_result(result__ == (expected), "%s(%s)", #func, #expected)) { \
+               tap_diag("  expected: %lu", (unsigned long)(expected)); \
+               tap_diag("  actual:   %lu", result__); \
+       } \
+} while (0)
+
+int main(void)
+{
+       tap_plan(12);
+
+       test(unpack_16_be, zero,         0);
+       test(unpack_16_be, minus_one,    0xffff);
+       test(unpack_16_be, test_pattern, 0xdead);
+       test(unpack_32_be, zero,         0);
+       test(unpack_32_be, minus_one,    0xffffffff);
+       test(unpack_32_be, test_pattern, 0xdeadbeef);
+
+       test(unpack_16_le, zero,         0);
+       test(unpack_16_le, minus_one,    0xffff);
+       test(unpack_16_le, test_pattern, 0xadde);
+       test(unpack_32_le, zero,         0);
+       test(unpack_32_le, minus_one,    0xffffffff);
+       test(unpack_32_le, test_pattern, 0xefbeadde);
+
+       tap_done();
+}
diff --git a/t/packtestu64.c b/t/packtestu64.c
new file mode 100644 (file)
index 0000000..217404f
--- /dev/null
@@ -0,0 +1,37 @@
+#include "pack.h"
+#include "tap.h"
+
+static const unsigned char zero[8];
+static const unsigned char minus_one[8] = {
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static const unsigned char test_pattern[8] = {
+       0xde, 0xad, 0xbe, 0xef, 0xf0, 0x0d, 0xca, 0xfe
+};
+
+#define test(func, pattern, expected) do { \
+       unsigned long long result__ = (func)(pattern); \
+       if (!tap_result(result__ == (expected), "%s(%s)", #func, #expected)) { \
+               tap_diag("  expected: %llu", (unsigned long long)(expected)); \
+               tap_diag("  actual:   %llu", result__); \
+       } \
+} while (0)
+
+int main(void)
+{
+#if PACK_HAVE_64BIT
+       tap_plan(6);
+
+       test(unpack_64_be, zero,         0);
+       test(unpack_64_be, minus_one,    0xffffffffffffffff);
+       test(unpack_64_be, test_pattern, 0xdeadbeeff00dcafe);
+       test(unpack_64_le, zero,         0);
+       test(unpack_64_le, minus_one,    0xffffffffffffffff);
+       test(unpack_64_le, test_pattern, 0xfeca0df0efbeadde);
+#else
+       tap_skip_all("no 64-bit support");
+#endif
+
+       tap_done();
+}
diff --git a/tests/functions.at b/tests/functions.at
new file mode 100644 (file)
index 0000000..115b8cf
--- /dev/null
@@ -0,0 +1,30 @@
+dnl Copyright © 2015 Nick Bowler
+dnl
+dnl License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+dnl This is free software: you are free to do what the fuck you want to.
+dnl There is NO WARRANTY, to the extent permitted by law.
+
+m4_divert_push([PREPARE_TESTS])dnl
+test_run_tap () {
+  "$builddir/t/$1" > "$1.tap"
+  status=$?
+  cat "$1.tap"
+  prove -e cat "$1.tap"
+  return $status
+}
+m4_divert_pop([PREPARE_TESTS])
+
+m4_define([TEST_TAP], [AT_CHECK([test_run_tap "$1"], [0], [ignore])])
+m4_define([TEST_TAP_SIMPLE], [dnl
+AT_SETUP([$1])
+AT_KEYWORDS([$4])dnl
+m4_n([$3])dnl
+TEST_TAP([$2])
+AT_CLEANUP])
+
+AT_BANNER([Binary packing functions])
+
+TEST_TAP_SIMPLE([signed unpacking], [packtests], [], [pack])
+TEST_TAP_SIMPLE([unsigned unpacking], [packtestu], [], [pack])
+TEST_TAP_SIMPLE([64-bit signed unpacking], [packtests64], [], [pack])
+TEST_TAP_SIMPLE([64-bit unsigned unpacking], [packtestu64], [], [pack])
index aa5abaf5ca79a7463afa89fc9a6308616b38651a..ee9925f876d941fc749241b5b3a60e4ed0e81412 100644 (file)
@@ -7,4 +7,7 @@ dnl There is NO WARRANTY, to the extent permitted by law.
 AT_INIT
 AT_COLOR_TESTS
 
+AT_TESTED([prove])
+
 m4_include([tests/macros.at])
+m4_include([tests/functions.at])