From 07d540498026f59622130e1f44534e32a73f23d0 Mon Sep 17 00:00:00 2001
From: Tomasz Kramkowski <tk@the-tk.com>
Date: Fri, 6 Aug 2021 20:16:31 +0100
Subject: use xmacros to generate type related code

---
 common.h | 12 ++++++++++
 pack.c   | 34 ++++++++++++--------------
 unpack.c | 83 +++++++++++++++++++++++++++++-----------------------------------
 3 files changed, 65 insertions(+), 64 deletions(-)

diff --git a/common.h b/common.h
index 183392a..f22f588 100644
--- a/common.h
+++ b/common.h
@@ -24,6 +24,18 @@
    #endif
 #endif
 
+#define ITYPE_MACROS \
+	T(SCHAR,  signed,   char,      int) \
+	T(UCHAR,  unsigned, char,      int) \
+	T(SHORT,  signed,   short,     int) \
+	T(USHORT, unsigned, short,     int) \
+	T(INT,    signed,   int,       int) \
+	T(UINT,   unsigned, int,       int) \
+	T(LONG,   signed,   long,      long) \
+	T(ULONG,  unsigned, long,      long) \
+	T(LLONG,  signed,   long long, long long) \
+	T(ULLONG, unsigned, long long, long long)
+
 size_t getsize(enum pack_type t);
 
 #endif // !PACK_COMMON_H
diff --git a/pack.c b/pack.c
index 9d7046c..f06aafe 100644
--- a/pack.c
+++ b/pack.c
@@ -32,23 +32,19 @@ enum pack_status pack(void *buf_, size_t size, const char *fmt, ...)
 	for (int i = 0; fmt[i] != '\0'; i++) {
 		bool sign;
 		size_t s;
-		union { uintmax_t u; intmax_t s; } val;
+		union { uintmax_t unsigned_; intmax_t signed_; } v;
 		tr_debug("i: %d, fmt[i]: %c", i, fmt[i]);
 		sign = islower(fmt[i]);
 		switch (fmt[i]) {
 		case '>': endianness = PACK_ENDIAN_BIG; continue;
 		case '<': endianness = PACK_ENDIAN_LITTLE; continue;
-		case PACK_TYPE_SCHAR: val.s = va_arg(ap, int); break;
-		case PACK_TYPE_UCHAR: val.u = va_arg(ap, unsigned); break;
-		case PACK_TYPE_SHORT: val.s = va_arg(ap, int); break;
-		case PACK_TYPE_USHORT: val.u = va_arg(ap, unsigned); break;
-		case PACK_TYPE_INT: val.s = va_arg(ap, int); break;
-		case PACK_TYPE_UINT: val.u = va_arg(ap, unsigned); break;
-		case PACK_TYPE_LONG: val.s = va_arg(ap, long); break;
-		case PACK_TYPE_ULONG: val.u = va_arg(ap, unsigned long); break;
-		case PACK_TYPE_LLONG: val.s = va_arg(ap, long long); break;
-		case PACK_TYPE_ULLONG: val.u = va_arg(ap, unsigned long long); break;
-		case PACK_TYPE_PADDING: val.u = 0; sign = false; break;
+		#define T(type, sign, c_type, va_type) \
+			case (char)PACK_TYPE_##type: \
+				v.sign##_ = va_arg(ap, sign va_type); \
+				break;
+		ITYPE_MACROS
+		#undef T
+		case 'x': v.unsigned_ = 0; sign = false; break;
 		default: return PACK_FMTINVAL;
 		}
 		tr_debug("i: %d, fmt[i]: %c, sign: %ssigned", i, fmt[i], sign ? "" : "un");
@@ -60,18 +56,18 @@ enum pack_status pack(void *buf_, size_t size, const char *fmt, ...)
 		if (size - offset < s) return PACK_TOOSMALL;
 
 		if (sign) {
-			intmax_t n = val.s;
-			tr_debug("val.s: %" PRIdMAX, val.s);
-			if (val.s >= 0) {
-				val.u = n;
+			intmax_t n = v.signed_;
+			tr_debug("val.s: %" PRIdMAX, v.signed_);
+			if (v.signed_ >= 0) {
+				v.unsigned_ = n;
 			} else {
 				uintmax_t offt = BITMASK(s * 8);
 				n += 1;
-				val.u = offt + n;
+				v.unsigned_ = offt + n;
 			}
 		}
-		tr_debug("val.u: %" PRIuMAX, val.u);
-		write_val(&buf[offset], s, endianness, val.u);
+		tr_debug("val.u: %" PRIuMAX, v.unsigned_);
+		write_val(&buf[offset], s, endianness, v.unsigned_);
 		offset += s;
 	}
 
diff --git a/unpack.c b/unpack.c
index 467b6bf..c33ff36 100644
--- a/unpack.c
+++ b/unpack.c
@@ -51,20 +51,19 @@ enum pack_status unpack(const void *buf_, size_t size, const char *fmt, ...)
 		bool sign;
 		size_t count = 1, s;
 		union {
-			signed   char      *b;
-			unsigned char      *B;
-			         short     *h;
-			unsigned short     *H;
-			         int       *i;
-			unsigned int       *I;
-			         long      *l;
-			unsigned long      *L;
-			         long long *q;
-			unsigned long long *Q;
-			         float     *f;
-			         double    *d;
+			#define T(type, sign, c_type, va_type) \
+				sign c_type *type;
+			ITYPE_MACROS
+			#undef T
+			float     *f;
+			double    *d;
 		} arg;
-		union { uintmax_t u; intmax_t s; float f; double d; } val;
+		union {
+			uintmax_t unsigned_;
+			intmax_t signed_;
+			float f;
+			double d;
+		} val;
 		tr_debug("i: %d, fmt[i]: %c", i, fmt[i]);
 		if (isdigit(fmt[i])) {
 			unsigned long long c;
@@ -86,19 +85,15 @@ enum pack_status unpack(const void *buf_, size_t size, const char *fmt, ...)
 		switch (fmt[i]) {
 		case '>': endianness = PACK_ENDIAN_BIG; continue;
 		case '<': endianness = PACK_ENDIAN_LITTLE; continue;
-		case PACK_TYPE_UCHAR: arg.b = va_arg(ap, signed char *); break;
-		case PACK_TYPE_SCHAR: arg.B = va_arg(ap, unsigned char *); break;
-		case PACK_TYPE_SHORT: arg.h = va_arg(ap, short *); break;
-		case PACK_TYPE_USHORT: arg.H = va_arg(ap, unsigned short *); break;
-		case PACK_TYPE_INT: arg.i = va_arg(ap, int *); break;
-		case PACK_TYPE_UINT: arg.I = va_arg(ap, unsigned *); break;
-		case PACK_TYPE_LONG: arg.l = va_arg(ap, long *); break;
-		case PACK_TYPE_ULONG: arg.L = va_arg(ap, unsigned long *); break;
-		case PACK_TYPE_LLONG: arg.q = va_arg(ap, long long *); break;
-		case PACK_TYPE_ULLONG: arg.Q = va_arg(ap, unsigned long long *); break;
-		case PACK_TYPE_FLOAT: arg.f = va_arg(ap, float *); break;
-		case PACK_TYPE_DOUBLE: arg.d = va_arg(ap, double *); break;
-		case PACK_TYPE_PADDING: break;
+		#define T(type, sign, c_type, va_type) \
+			case (char)PACK_TYPE_##type: \
+				arg.type = va_arg(ap, sign c_type *); \
+				break;
+		ITYPE_MACROS
+		#undef T
+		case 'f': arg.f = va_arg(ap,          float     *); break;
+		case 'd': arg.d = va_arg(ap,          double    *); break;
+		case 'x': break;
 		default: return PACK_FMTINVAL;
 		}
 
@@ -111,40 +106,38 @@ enum pack_status unpack(const void *buf_, size_t size, const char *fmt, ...)
 		if (fmt[i] == 'x') goto skip;
 
 		for (size_t j = 0; j < count; j++) {
-			val.u = read_val(buf + offset + s * j, s, endianness);
-			tr_debug("val.u: %" PRIuMAX ", at: %" PRIuSIZE, val.u, offset + s * j);
+			val.unsigned_ =
+				read_val(buf + offset + s * j, s, endianness);
+			tr_debug("val.u: %" PRIuMAX ", at: %" PRIuSIZE,
+			         val.unsigned_, offset + s * j);
 
 			if (fmt[i] == 'f') {
-				float f = ieee754b32_deserialise(val.u);
+				float f = ieee754b32_deserialise(val.unsigned_);
 				val.f = f;
 				tr_debug("val.f: %f", val.f);
 			} else if (fmt[i] == 'd') {
-				double d = ieee754b64_deserialise(val.u);
+				double d = ieee754b64_deserialise(val.unsigned_);
 				val.d = d;
 				tr_debug("val.d: %f", val.d);
 			} else if (sign) {
 				intmax_t vals;
-				if (!(val.u & (UINTMAX_C(1) << (s * 8 - 1)))) {
-					vals = val.u;
+				if (!(val.unsigned_ & (UINTMAX_C(1) << (s * 8 - 1)))) {
+					vals = val.unsigned_;
 				} else {
 					vals = minval(s);
-					vals += val.u ^ (UINTMAX_C(1) << (s * 8 - 1));
+					vals += val.unsigned_ ^ (UINTMAX_C(1) << (s * 8 - 1));
 				}
-				val.s = vals;
-				tr_debug("val.s: %" PRIdMAX, val.s);
+				val.signed_ = vals;
+				tr_debug("val.s: %" PRIdMAX, val.signed_);
 			}
 
 			switch (fmt[i]) {
-			case 'b': arg.b[j] = val.s; break;
-			case 'B': arg.B[j] = val.u; break;
-			case 'h': arg.h[j] = val.s; break;
-			case 'H': arg.H[j] = val.u; break;
-			case 'i': arg.i[j] = val.s; break;
-			case 'I': arg.I[j] = val.u; break;
-			case 'l': arg.l[j] = val.s; break;
-			case 'L': arg.L[j] = val.u; break;
-			case 'q': arg.q[j] = val.s; break;
-			case 'Q': arg.Q[j] = val.u; break;
+			#define T(type, sign, c_type, va_type) \
+				case (char)PACK_TYPE_##type: \
+					arg.type[j] = val.sign##_; \
+					break;
+			ITYPE_MACROS
+			#undef T
 			case 'f': arg.f[j] = val.f; break;
 			case 'd': arg.d[j] = val.d; break;
 			}
-- 
cgit v1.2.3-54-g00ecf