--- /dev/null
+/* -*-c-*-
+ *
+ * Test program for the keyword-argument machinery
+ *
+ * (c) 2015 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the Sensible Object Design, an object system for C.
+ *
+ * SOD is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * SOD is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with SOD; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "keyword.h"
+
+static void show_kwval(const char *what, int f, const char *fmt, ...)
+{
+ va_list ap;
+
+ printf(" %s = ", what);
+ if (!f)
+ puts("<unset>");
+ else {
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+ putchar('\n');
+ }
+}
+
+#define SHOW(mem, fmt) show_kwval(#mem, kw.mem##_suppliedp, fmt, kw.mem)
+
+#define t1_KWSET(_) \
+ _(int, x, 0) \
+ _(double, y, 69.0) \
+ _(const char *, z, "default")
+KWSET_STRUCT(t1);
+static KWSET_PARSEFN(t1)
+static KWCALL void t1(const char *what, KWTAIL)
+{
+ KWPARSE(t1);
+
+ printf("t1: %s\n", what);
+ SHOW(x, "%d");
+ SHOW(y, "%g");
+ SHOW(z, "`%s'");
+}
+
+static KWCALL void t2(const char *what, ...)
+{
+ va_list ap;
+
+ printf("t2: %s\n", what);
+ va_start(ap, what);
+ t1("via t2", KWARGS(K_VALIST(ap)));
+ va_end(ap);
+}
+
+#define t3_KWSET(_) \
+ _(int, q, 0) \
+ t1_KWSET(_)
+KWSET_STRUCT(t3);
+static KWSET_PARSEFN(t3)
+static KWCALL void t3(const char *what, KWTAIL)
+{
+ struct kwval v[KW_COUNT(t1)];
+ size_t n = 0;
+ KWPARSE(t3);
+
+ printf("t3: %s\n", what);
+ SHOW(q, "%c");
+ SHOW(z, "`%s'");
+
+ KW_COPY(t3, t1, kw, v, n);
+ t1("via t3", KWARGS(K_TAB(v, n)
+ K(x, kw.x_suppliedp ? kw.x + 1 : 42)));
+}
+
+/* The @KW_TEST@ machinery from the manpage... */
+#define KWARGS_TEST(k, val) KWARGS(K(k, val) K(kw.unknown, 0))
+
+static jmp_buf kw_test_jmp;
+
+static void kw_test_unknown(const char *set, const char *kw)
+{
+ if (strcmp(kw, "kw.unknown") == 0) longjmp(kw_test_jmp, 1);
+ else longjmp(kw_test_jmp, 2);
+}
+
+#define KW_TEST(flag, set, call) do { \
+ kw_unkhookfn *oldunk = kw_unkhook; \
+ kw_unkhook = kw_test_unknown; \
+ switch (setjmp(kw_test_jmp)) { \
+ case 0: call; abort(); \
+ case 1: flag = 1; break; \
+ case 2: flag = 0; break; \
+ default: abort(); \
+ } \
+ kw_unkhook = oldunk; \
+} while (0)
+/* END */
+
+int main(void)
+{
+ t1("no args", NO_KWARGS);
+ t1("some args", KWARGS(K(z, "set") K(x, 42)));
+
+ t2("indirection", KWARGS(K(y, 6.283)));
+
+ t3("no args", NO_KWARGS);
+ t3("x initially 19", KWARGS(K(q, 't') K(x, 19) K(z, "boing")));
+
+#define TEST_KWTEST(kw, val) do { \
+ int f_; \
+ KW_TEST(f_, t3, t3(0, KWARGS_TEST(kw, val))); \
+ printf("t3 arg `%s' %s\n", #kw, f_ ? "present" : "absent"); \
+} while (0)
+ TEST_KWTEST(q, '!');
+ TEST_KWTEST(z, "splat");
+ TEST_KWTEST(nope, 0);
+
+ return (0);
+}
+
+/*----- That's all, folks -------------------------------------------------*/