]> pd.if.org Git - hexagon/commitdiff
rework library to use structs
authorNathan Wagner <nw@hydaspes.if.org>
Sun, 17 Jun 2018 17:41:06 +0000 (17:41 +0000)
committerNathan Wagner <nw@hydaspes.if.org>
Sun, 17 Jun 2018 17:41:06 +0000 (17:41 +0000)
15 files changed:
Makefile
astar.c
doc/Makefile [deleted file]
hexagon.c
hexagon.h
t/adjacency.c
t/astar.c
t/cantor.c
t/center.c
t/distance.c
t/hexbin.c
t/range.c
t/tap.3 [deleted file]
t/tap.c [deleted file]
t/tap.h [deleted file]

index 3856ab77211cc95f6b2ef6bc7a586459ce019568..05a253eeecbe0d91ce7b215b8bf7a552a8ba7363 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,27 +2,45 @@
 # build.  This means you Mac users.
 # ARCH= -arch x386 -arch x86_64
 
-LDFLAGS= $(ARCH) -lm
+LDFLAGS= $(ARCH) -lm -L.
 CFLAGS=        -Wall -Wno-parentheses $(ARCH) -I. -I..
-OBJS= hexagon.o astar.o
+OBJS= hexagon.o astar.o lib/cantor.o
 SRC=$(OBJS:.o=.c)
 TESTS= t/cantor.t t/distance.t t/adjacency.t t/range.t t/hexbin.t \
-       t/gridsize.t t/center.t t/astar.t t/polar.t
+       t/gridsize.t t/center.t t/polar.t
 PREFIX=/usr/local
+RELEASE = $(shell git tag | tail -1)
 
-all:   libhexagon.a docs testfiles
+all:   libhexagon.a docs testfiles hexagon
+
+hexagon: cli/hexagon.o libhexagon.a
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lhexagon
 
 clean:
        rm -f $(OBJS) libhexagon.a $(TESTS)
+       rm -f doc/hexagon.3 doc/hexagon.pdf doc/hexagon.tex doc/hexagon.txt \
+               doc/hexagon.idx doc/hexagon.aux doc/hexagon.log doc/hexagon.toc
 
-t/%.t:  t/%.o t/ctap.o $(OBJS)
+t/%.t:  t/%.o t/ctap.o t/ctap.h $(OBJS)
        $(CC) -I.. -I. -o $@ $+ $(LDFLAGS)
 
-testfiles:     $(TESTS)
+testfiles: $(TESTS)
+
+test:   libhexagon.a prove $(TESTS)
+       @./prove $(TESTS) 2>/dev/null
 
-test:   libhexagon.a $(TESTS)
+ptest:   libhexagon.a $(TESTS)
        @prove --exec '' $(TESTS) 2>/dev/null
 
+t/ctap.c: ctap/ctap.c
+       cp $< $@
+
+t/ctap.h: ctap/ctap.h
+       cp $< $@
+
+prove.c: ctap/prove.c
+       cp $< $@
+
 libhexagon.a:  $(OBJS)
        ar r $@ $+
        ranlib $@
@@ -32,10 +50,23 @@ install: libhexagon.a hexagon.h doc/hexagon.3
        cp hexagon.h $(PREFIX)/include
        cp doc/hexagon.3 $(PREFIX)/share/man/man3
 
-docs:
-       make -C doc
+docs: doc/hexagon.3 doc/hexagon.txt
+
+doc/hexagon.3: doc/hexagon.pod
+       pod2man --center='hexagon library' --section=3 --release='Version $(RELEASE)' $+ > $@
+
+doc/hexagon.txt: doc/hexagon.pod
+       pod2text -l $+ > $@
+
+doc/hexagon.pdf:       doc/hexagon.pod
+       pod2latex -full $+
+       pdflatex hexagon.tex
+       pdflatex hexagon.tex
+       pdflatex hexagon.tex
+       rm -f hexagon.tex hexagon.idx hexagon.aux hexagon.toc hexagon.log
 
 .c.o:
        $(CC) $(CFLAGS) -c -o $@ $<
 
 .SUFFIXES:     .c .h 
+
diff --git a/astar.c b/astar.c
index fd92bfcc8ddc24f611ff3d7b71980a119fead6c4..67889c24b0e29402054ea4aa604712e2d1c28eb1 100644 (file)
--- a/astar.c
+++ b/astar.c
 #define DEBUG_ASTAR 1 
 #endif
 
-static double default_metric(int a, int b) {
+static double default_metric(struct HL_hex a, struct HL_hex b) {
        return 1.0;
 }
 
-static double default_heuristic(int a, int b) {
+static double default_heuristic(struct HL_hex a, struct HL_hex b) {
        return (double)HL_distance(a, b);
 }
 
@@ -42,7 +42,7 @@ struct HL_astar *HL_astar_init(struct HL_astar *state) {
 
        state->metric = default_metric;
        state->heuristic = default_heuristic;
-       state->neighbor = HL_adjacent_hex;
+       state->neighbor = HL_adjhexp;
 
        return state;
 }
@@ -91,10 +91,10 @@ void HL_astar_free(struct HL_astar *s) {
        }
 }
 
-static struct HL_astar_hex *add_open(struct HL_astar *s, int hex) {
+static struct HL_astar_hex *add_open(struct HL_astar *s, struct HL_hex hex) {
        struct HL_astar_hex *node;
 #ifdef DEBUG_ASTAR
-               fprintf(stderr, "add to open %d\n", hex);
+               fprintf(stderr, "add to open %d\n", HL_cantor(hex));
 #endif
 
        if (!s || s->error) {
@@ -111,7 +111,7 @@ static struct HL_astar_hex *add_open(struct HL_astar *s, int hex) {
        /* TODO check in open or closed */
        node = malloc(sizeof *node);
 #ifdef DEBUG_ASTAR
-               fprintf(stderr, "add to open %d = %p\n", hex, node);
+               fprintf(stderr, "add to open %d = %p\n", HL_cantor(hex), node);
 #endif
 
        node->hex = hex;
@@ -138,7 +138,7 @@ static struct HL_astar_hex *closehex(struct HL_astar *s, struct HL_astar_hex *h)
        }
 
 #ifdef DEBUG_ASTAR
-       fprintf(stderr, "Closing hex: (%d,%d)\n",  HL_cantor_x(h->hex), HL_cantor_y(h->hex));
+       fprintf(stderr, "Closing hex: (%d,%d)\n",  h->hex.x, h->hex.y);
 #endif
        h->open = 0;
        if (h->prev) h->prev->next = h->next;
@@ -152,22 +152,22 @@ static struct HL_astar_hex *closehex(struct HL_astar *s, struct HL_astar_hex *h)
        return h;
 }
 
-struct HL_astar_hex *in_closed(struct HL_astar *s, int hex) {
+struct HL_astar_hex *in_closed(struct HL_astar *s, struct HL_hex hex) {
        struct HL_astar_hex *h;
        if (!s) return 0;
 
        for (h = s->closed; h; h = h->next) {
-               if (h->hex == hex) return h;
+               if (h->hex.x == hex.x && h->hex.y == hex.y) return h;
        }
        return NULL;
 }
 
-struct HL_astar_hex *in_open(struct HL_astar *s, int hex) {
+struct HL_astar_hex *in_open(struct HL_astar *s, struct HL_hex hex) {
        struct HL_astar_hex *h;
        if (!s) return 0;
 
        for (h = s->open; h; h = h->next) {
-               if (h->hex == hex) return h;
+               if (h->hex.x == hex.x && h->hex.y == hex.y) return h;
        }
        return NULL;
 }
@@ -191,7 +191,7 @@ static struct HL_astar_hex *lowrank(struct HL_astar *s) {
 void dump_list(char *name, struct HL_astar_hex *x) {
        fprintf(stderr, "%s list: ", name);
        for(; x; x = x->next) {
-               fprintf(stderr, "(%d,%d)",  HL_cantor_x(x->hex), HL_cantor_y(x->hex));
+               fprintf(stderr, "(%d,%d)",  x->hex.x, x->hex.y);
        }
        fprintf(stderr, "\n");
 }
@@ -201,14 +201,15 @@ void dump_list(char *name, struct HL_astar_hex *x) {
  * find a path from start to end.  we use A*
  */
 int HL_findpath(struct HL_astar *s, int loops) {
-       int dir, y;
+       int dir;
+       struct HL_hex y;
        struct HL_astar_hex *node, *x, *yopen;
        int tent_better;
        double cost;
 
        s->error = 0;
 
-       if (s->start == s->goal) return 0;
+       if (HL_distance(s->start, s->goal) == 0) return 0;
 
        node = add_open(s, s->start);
        node->g = 0.0;
@@ -217,9 +218,9 @@ int HL_findpath(struct HL_astar *s, int loops) {
 
 #ifdef DEBUG_ASTAR
        fprintf(stderr, "A* findpath: ");
-       fprintf(stderr, "(%d,%d)",  HL_cantor_x(s->start), HL_cantor_y(s->start));
+       fprintf(stderr, "(%d,%d)",  s->start.x, s->start.y);
        fprintf(stderr, " -> ");
-       fprintf(stderr, "(%d,%d)",  HL_cantor_x(s->goal), HL_cantor_y(s->goal));
+       fprintf(stderr, "(%d,%d)",  s->goal.x, s->goal.y);
        fprintf(stderr, "\n");
 #endif
 
@@ -233,23 +234,24 @@ int HL_findpath(struct HL_astar *s, int loops) {
                x = lowrank(s);
 #ifdef DEBUG_ASTAR
                fprintf(stderr, "checking lowest f hex = (%d,%d) f = %f, g = %f, h = %f\n",
-                       HL_cantor_x(x->hex), HL_cantor_y(x->hex),
+                       x->hex.x, x->hex.y,
                                x->f, x->g, x->h
                                );
 #endif
-               if (x->hex == s->goal) {
+               if (HL_distance(x->hex, s->goal) == 0) {
                        break;
                }
                closehex(s, x);
 
-               for (dir = 0; y = s->neighbor(x->hex, dir),dir<6; dir++) {
-                       if (y == 0) continue; /* no hex in that direction */
+               int n;
+               for (dir = 0; n = s->neighbor(x->hex, dir, &y),dir<6; dir++) {
+                       if (n == 0) continue; /* no hex in that direction */
                        if (in_closed(s, y)) {
                                continue;
                        }
 #ifdef DEBUG_ASTAR
                        fprintf(stderr, "checking dir %d, hex (%d, %d)\n", dir,
-                                       HL_cantor_x(y), HL_cantor_y(y));
+                                       y.x, y.y);
 #endif
 
                        cost = x->g + s->metric(x->hex, y);
@@ -280,7 +282,7 @@ int HL_findpath(struct HL_astar *s, int loops) {
                                yopen->f = yopen->g + yopen->h;
 #ifdef DEBUG_ASTAR
                fprintf(stderr, "maybe better hex = (%d,%d) f = %f, g = %f, h = %f\n",
-                       HL_cantor_x(yopen->hex), HL_cantor_y(yopen->hex),
+                       yopen->hex.x, yopen->hex.y,
                                yopen->f, yopen->g, yopen->h
                                );
 #endif
@@ -290,7 +292,7 @@ int HL_findpath(struct HL_astar *s, int loops) {
        }
 
        /* error no path ? */
-       if (x->hex != s->goal) {
+       if (HL_distance(x->hex, s->goal) != 0) {
                s->error = 1;
                return 0;
        }
@@ -306,12 +308,12 @@ int HL_findpath(struct HL_astar *s, int loops) {
                if (yopen->parent) {
                        yopen->parent->next = yopen;
                }
-               if (yopen->hex == s->start) s->from = yopen;
+               if (HL_distance(yopen->hex, s->start) == 0) s->from = yopen;
 #ifdef DEBUG_ASTAR
                fprintf(stderr, "(%p %d %d,%d)",
                                yopen, yopen->hex,
-                               HL_cantor_x(yopen->hex),
-                               HL_cantor_y(yopen->hex)
+                               yopen->hex.x,
+                               yopen->hex.y
                                );
 #endif
                s->pathlen++;
diff --git a/doc/Makefile b/doc/Makefile
deleted file mode 100644 (file)
index c00373a..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-RELEASE = $(shell git tag | tail -1)
-
-hexagon.3:     hexagon.pod
-       pod2man --center='hexagon library' --section=3 --release='Version $(RELEASE)' $+ > $@
-
-hexagon.txt: hexagon.pod
-       pod2text -l $+
-
-hexagon.pdf:   hexagon.pod
-       pod2latex -full $+
-       pdflatex hexagon.tex
-       pdflatex hexagon.tex
-       pdflatex hexagon.tex
-       rm -f hexagon.tex hexagon.idx hexagon.aux hexagon.toc hexagon.log
-
-clean:
-       rm -f hexagon.3 hexagon.pdf hexagon.tex hexagon.txt \
-               hexagon.idx hexagon.aux hexagon.log hexagon.toc
index 2dd1f3a3e5e6094b5633e8ebc93e08d0a6ba8d14..155a5d2f1bd4676797c0dbb9c226d6d21391e34c 100644 (file)
--- a/hexagon.c
+++ b/hexagon.c
@@ -5,7 +5,27 @@
 #include <stdlib.h>
 #include <limits.h>
 
-static int inversecantor(int cantor, int *x, int *y);
+/* constructor function */
+struct HL_hex HL_hex_xy(int x, int y) {
+       struct HL_hex h;
+       h.x = x;
+       h.y = y;
+       return h;
+}
+
+int HL_hex_cmp(struct HL_hex const *a, struct HL_hex const *b) {
+        if (a->x != b->x) {
+                return a->x > b->x ? 1 : -1;
+        }
+        if (a->y != b->y) {
+                return a->y > b->y ? 1 : -1;
+        }
+        return 0;
+}
+
+int HL_hex_eq(struct HL_hex const *a, struct HL_hex const *b) {
+        return a->x == b->x && a->y == b->y;
+}
 
 /*
  * This file is written by Nathan Wagner and dedicated to the public
@@ -101,53 +121,57 @@ static double          hexpthd[6][2] = {
 
 #endif
 
-/*
-c = 1.0 = distance from center to vertex
-b = distance to hex side
-a = distance along hex side
-
-A = angle at point center, this is the polar coord angle
-B = angle from vertex, this is 60 degrees
-C = Other angle, which is 180 - 60 - A = 120 - A
-
-sin B = sin 60 = sqrt(3) / 2
-cos B = cos 60 = 1/2
-
-b = c * sin B / ( sin A cos B + sin B cos A)
-
-c * sin B / ( sin A cos B + sin B cos A)
-
-0.5 * sqrt3
--------------
-sinA 0.5 + sqrt3 * 0.5 cosA
-
-sqrt3
--------------
-sinA + sqrt3 cosA
-
-b=
-3
--------------
-cosA + sqrt3 sinA
-
-x = b cosA
-y = b sinA
-*/
-
 #define RD (180.0 / M_PI)
 /* angle ranges from 0-6 */
 /* distance is 0 at origin, 1.0 at the hex side */
 
-/* return the polar distance ? */
-double HL_polar(double angle, double distance, double *x, double *y) {
-       double A, B, C, b, c;
-       double sinB, sinC;
 #if 0
        double sqrt3;
 
        sqrt3 = sqrt(3.0);
+
+        1
+      /---\
+    2/     \0
+    /       \
+    \       /
+    3\     /5
+      \---/
+        4
+
+      /\
+    0/  \5
+    /    \
+    |    |
+   1|    |4
+    |    |
+    \    /
+    2\  /3
+      \/
+
 #endif
 
+/* return the polar distance */
+struct HL_point HL_polar(double angle, double distance, double *d) {
+       double A, B, C, b;
+       struct HL_point pt;
+
+#if 0
+           C
+          /\
+       b /  \ a
+        /    \
+       /      \
+     A -------- B
+           c
+
+     c = 1 ; fixed, will scale later
+     B = 60 ; exterior angle of hextant
+     C = 180-B-A = 120-A ; sum of angles of a triangle
+     A = function argument ; the polar coordinate we are calculating
+     b = c * sin(B) / sin(C) ; law of sines
+
+#endif
        /* convert angle to radians */
        angle = angle * M_PI / 3.0;
 
@@ -155,36 +179,34 @@ double HL_polar(double angle, double distance, double *x, double *y) {
 
        A = fmod(angle, M_PI/3.0); /* constrain to within an equilateral */
        B = M_PI / 3.0;
-       C = M_PI - A - B;
+       C = M_PI - B - A;
 
-       sinB = sin(B);
-       sinC = sin(C);
+       b = sin(B) / sin(C);
 
-       c = 1.0;
-       c = HL_vertexv[0];
-#if 0
-       /* provided for completeness, but we don't use the value */
-       sinA = sin(A);
-       a = c * sinA / sinC;
-#endif
-       b = c * sinB / sinC;
+       /* scale for hex one unit from side to side, rather than
+        * one unit from center to vertex
+        */
+/*     b = b * sqrt(3.0) / 2.0 / 2.0; */
+       b = b / sqrt(3);
 
-       if (x) {
-               *x = b * cos(angle);
-       }
+       pt.x = distance * b * cos(angle);
+       pt.y = distance * b * sin(angle);
        
-       if (y) {
-               *y = b * sin(angle);
+       if (d) {
+               *d = distance * b;
        }
 
-       return b;
+       return pt;
 }
 
-void HL_vertices(int cantor, double *vc) {
+void HL_vertices(struct HL_hex hex, double *vc) {
        int i;
        double xc, yc;
+       struct HL_point center;
 
-       HL_hexcenter(cantor, &xc, &yc);
+       center = HL_hexcenter(hex);
+       xc = center.x;
+       yc = center.y;
 
        for (i=0; i<6; i++) {
                *vc++ = hexptvd[i][0] + xc;
@@ -194,36 +216,31 @@ void HL_vertices(int cantor, double *vc) {
        *vc++ = hexptvd[0][1] + yc;
 }
 
+#if 0
 void HL_trianglefan(int cantor, double *vc) {
        HL_hexcenter(cantor, vc, vc+1);
        HL_vertices(cantor, vc+2);
 }
+#endif
 
-double HL_center_x(int cantor) {
-       double x;
-
-       HL_hexcenter(cantor, &x, 0);
-       return x;
-}
+struct HL_point HL_hexcenter(struct HL_hex hex) {
+       int x, y;
+       struct HL_point center;
+       double yc;
 
-double HL_center_y(int cantor) {
-       double y;
+       double stride = 1.5/sqrt(3.0);
 
-       HL_hexcenter(cantor, 0, &y);
-       return y;
-}
+       x = hex.x;
+       y = hex.y;
 
-int HL_hexcenter(int cantor, double *xc, double *yc) {
-       int x, y;
-       double stride = 1.5/sqrt(3.0);
+       center.x = x * stride;
 
-       inversecantor(cantor, &x, &y);
+       if (x >= 0) yc = y + ((x + 1) % 2) / 2.0 - 0.5;
+       if (x < 0) yc = y + ((-x + 1) % 2) / 2.0 - 0.5;
 
-       if (xc) *xc = x * stride;
-       if (yc && x >= 0) *yc = y + ((x + 1) % 2) / 2.0 - 0.5;
-       if (yc && x < 0) *yc = y + ((-x + 1) % 2) / 2.0 - 0.5;
+       center.y = yc;
 
-       return cantor;
+       return center;
 }
 
 /*
@@ -231,10 +248,37 @@ int HL_hexcenter(int cantor, double *xc, double *yc) {
  * oriented.  If that is not the case, you will need to transform
  * your input coordinates first.
  */
-int HL_cantor_bin(double x, double y) {
-       return HL_hexbin(1.0, x, y, 0, 0);
+struct HL_hex HL_bin(double x, double y) {
+       return HL_hexbin(1.0, x, y);
+}
+
+struct HL_isohex HL_xy2ijk(struct HL_hex hex) {
+       int pi, pj, pk;
+       int x, y;
+       struct HL_isohex iso;
+
+       x = hex.x;
+       y = hex.y;
+
+       pi = x;
+       pj = -y;
+
+       if (x < 0) {
+               pj = pj + (-x + 1) / 2;
+       } else {
+               pj = pj - x/2;
+       }
+       pk = -pi - pj;
+
+       iso.i = pi;
+       iso.j = pj;
+       iso.k = pk;
+
+       return iso;
 }
 
+#if 0
+
 static int xy2ijk(int x, int y, int *i, int *j, int *k) {
        int pi, pj, pk;
 
@@ -253,7 +297,6 @@ static int xy2ijk(int x, int y, int *i, int *j, int *k) {
 
        return HL_cantor_xy(x,y);
 }
-
 static int ijk2xy(int i, int j, int k, int *x, int *y) {
        int px, py;
 
@@ -274,16 +317,49 @@ static int ijk2xy(int i, int j, int k, int *x, int *y) {
        return HL_cantor_xy(px,py);
 }
 
-int HL_cantor_ijk(int i, int j, int k) {
-       return ijk2xy(i,j,k,0,0);
+#endif
+
+struct HL_hex HL_ijk2xy(struct HL_isohex iso) {
+       int px, py;
+       struct HL_hex xy;
+       int i,j;
+
+       i = iso.i;
+       j = iso.j;
+
+       px = i;
+
+       /* py = -j - i/2; */
+       py = -j;
+
+       if (i < 0) {
+               py += (-i + 1)/2;
+       } else {
+               py -= i/2;
+       }
+
+       xy.x = px;
+       xy.y = py;
+
+       return xy;
 }
 
-int HL_distance(int from, int to) {
+
+static void xy2ijkp(struct HL_hex h, int *ijk) {
+       struct HL_isohex iso;
+
+       iso = HL_xy2ijk(h);
+       ijk[0] = iso.i;
+       ijk[1] = iso.j;
+       ijk[2] = iso.k;
+}
+
+int HL_distance(struct HL_hex from, struct HL_hex to) {
        int dist = 0, i;;
        int fc[3], tc[3];
 
-       HL_cantor_arrays(from, 0, fc);
-       HL_cantor_arrays(to, 0, tc);
+       xy2ijkp(from, fc);
+       xy2ijkp(to, tc);
 
        for (i=0;i<=2;i++) {
                dist += abs(fc[i] - tc[i]);
@@ -292,7 +368,7 @@ int HL_distance(int from, int to) {
        return dist / 2;
 }
 
-int HL_hexes_within_range(int hex, int range, int *list, int size) {
+int HL_hexes_within_range(struct HL_hex hex, int range, struct HL_hex *list, int size) {
        int count = 0;
        int i;
 
@@ -306,9 +382,10 @@ int HL_hexes_within_range(int hex, int range, int *list, int size) {
        return count;
 }
 
-int HL_hexes_at_range(int hex, int range, int *list, int size) {
+int HL_hexes_at_range(struct HL_hex hex, int range, struct HL_hex *list, int size) {
        int q; /* p and q are count/loop vars */
-       int c[3]; /* ijk coord array */
+       struct HL_isohex iso;
+
 
        if (range == 0) {
                if (list) {
@@ -323,10 +400,12 @@ int HL_hexes_at_range(int hex, int range, int *list, int size) {
        /* i.e. if (!list || size < range * 6) */
        if (!list || size < 1) return range * 6;
 
-       HL_cantor_arrays(hex, 0, c);
-       c[0] += range;
-       c[2] = -c[0] - c[1];
-       hex = HL_cantor_ijkp(c);
+       iso = HL_xy2ijk(hex);
+
+       iso.i += range;
+       iso.k = -iso.i - iso.j;
+
+       hex = HL_ijk2xy(iso);
 
        for(q=0; q<size && q < range * 6; q++) { 
                list[q] = hex;
@@ -336,17 +415,15 @@ int HL_hexes_at_range(int hex, int range, int *list, int size) {
        return range * 6;
 }
 
-int HL_adjacent_hex(int start, int dir) {
-       if (dir < 0 || dir > 5) return 0;
-
-       return HL_adjhex(start, dir);
-}
-
 /* direction 0 is positive X , counter clockwise from there */
-int HL_adjhex(int start, int dir) {
+struct HL_hex HL_adjhex(struct HL_hex hex, int dir) {
        int c[3];
+       struct HL_isohex iso;
 
-       HL_cantor_arrays(start, 0, c);
+       iso = HL_xy2ijk(hex);
+       c[0] = iso.i;
+       c[1] = iso.j;
+       c[2] = iso.k;
 
        switch (dir%6) {
                case 2:
@@ -363,65 +440,18 @@ int HL_adjhex(int start, int dir) {
                        c[0]--;       ; c[2]++; break;
        }
 
-       return HL_cantor_ijkp(c);
-}
-
-int HL_cantor_xyp(int *xy) {
-       return HL_cantor_xy(xy[0], xy[1]);
-}
-
-int HL_cantor_ijkp(int *ijk) {
-       return HL_cantor_ijk(ijk[0], ijk[1], ijk[2]);
-}
-
-int HL_cantor_arrays(int can, int *xy, int *ijk) {
-       return HL_cantor_decode(can, xy, xy ? xy+1 : 0,
-                       ijk, ijk ? ijk+1 : 0, ijk ? ijk+2 : 0);
-}
-
-int HL_cantor_decode(int can, int *x, int *y, int *i, int *j, int *k) {
-       int px, py;
-
-       inversecantor(can, &px, &py);
-       if (x) *x = px;
-       if (y) *y = py;
-
-       xy2ijk(px, py, i, j, k);
-
-       return can;
-}
-
-int HL_cantor_i(int cantor) {
-       int i;
-
-       HL_cantor_decode(cantor, 0,0, &i,0,0);
-       return i;
-}
-
-int HL_cantor_j(int cantor) {
-       int j;
+       iso.i = c[0];
+       iso.j = c[1];
+       iso.k = c[2];
 
-       HL_cantor_decode(cantor, 0,0, 0,&j,0);
-       return j;
+       return HL_ijk2xy(iso);
 }
 
-int HL_cantor_k(int cantor) {
-       int k;
-
-       HL_cantor_decode(cantor, 0,0, 0,0,&k);
-       return k;
-}
-
-int HL_cantor_x(int cantor) {
-       int x;
-       inversecantor(cantor, &x, 0);
-       return x;
-}
-
-int HL_cantor_y(int cantor) {
-       int y;
-       inversecantor(cantor, 0, &y);
-       return y;
+int HL_adjhexp(struct HL_hex hex, int dir, struct HL_hex *adj) {
+       if (adj) {
+               *adj = HL_adjhex(hex, dir);
+       }
+       return dir;
 }
 
 /* Determine if a map with these dimensions will overflow */
@@ -454,78 +484,6 @@ int HL_map_max_dimension(void) {
         return low;
 }
 
-static int inversenatcantor(int cantor, int *x, int *y) {
-       int w, t, py;
-
-       cantor -= 1;
-
-       w = (int)floor((sqrt(8.0 * cantor + 1.0) - 1.0)/2.0);
-       t = (w * w + w)/2;
-
-       py = cantor - t;
-
-       if (y) *y = py;
-       if (x) *x = w - py;
-
-       return cantor;
-}
-
-/*
- * map non negative integer pairs to their cantor pairing function
- * number, plus one.  We add one so that the result is never zero,
- * leaving zero to be "invalid" or "none" or what have you.
- */
-
-static int natcantor(int x, int y) {
-       return (x+y) * (x + y + 1) / 2 + y+1;
-}
-
-/* See http://en.wikipedia.org/wiki/Cantor_pairing_function */
-/* see also http://szudzik.com/ElegantPairing.pdf */
-/*
- * if either coordinate is negative, map the integers onto the
- * whole numbers, and then return the negative of the adjusted
- * cantor number.  As for most grids negative coordinates will
- * be invalid, this will allow for a <= 0 test for invalid
- * or out of bounds (on the negative side anyway, you'll
- * still have to test for out of range on the positive side).
- *
- * TODO figure out what the maximum supported coordinates are
- * for given integer sizes.
- */
-int HL_cantor_xy(int x, int y) {
-       if (x < 0 || y < 0) {
-               x = abs(2 * x) - (x < 0);
-               y = abs(2 * y) - (y < 0);
-               return -natcantor(x, y);
-       }
-       return natcantor(x,y);
-}
-
-static int inversecantor(int cantor, int *x, int *y) {
-       if (cantor < 0) {
-               inversenatcantor(-cantor, x, y);
-               if (x) {
-                       if (*x % 2) {
-                               *x = -(*x+1)/2;
-                       } else {
-                               *x = *x / 2;
-                       }
-               }
-               if (y) {
-                       if (*y % 2) {
-                               *y =  -(*y+1)/2;
-                       } else {
-                               *y = *y/2;
-                       }
-               }
-       } else {
-               inversenatcantor(cantor, x, y);
-       }
-
-       return cantor;
-}
-
 struct hex {
         int iso;
         int x, y, z;
@@ -566,11 +524,12 @@ static int hex_iso(struct hex *h) {
 
 #define COS30 (.866025403784438646763723170752)
 
-int HL_hexbin(double width, double x, double y, int *i, int *j) {
+struct HL_hex HL_hexbin(double width, double x, double y) {
        double z, rx, ry, rz;
        double abs_dx, abs_dy, abs_dz;
        int ix, iy, iz, s;
        struct hex h;
+       struct HL_hex hex;
 
        /*x = x / cos(30 * M_PI / 180.0); */ /* rotated X coord */
        x = x / COS30;
@@ -607,7 +566,9 @@ int HL_hexbin(double width, double x, double y, int *i, int *j) {
        h.iso = 1;
 
        hex_xy(&h);
-       if (i) *i = h.x;
-       if (j) *j = h.y;
-       return HL_cantor_xy(h.x, h.y);
+
+       hex.x = h.x;
+       hex.y = h.y;
+
+       return hex;
 }
index 9578bdd055611a58ad3f25f9f755050a1d9a65c4..a2d4f2f98a8e18306a3352bd32ab3af7b1708d18 100644 (file)
--- a/hexagon.h
+++ b/hexagon.h
@@ -1,6 +1,24 @@
 #ifndef HEXLIB_H_
 #define HEXLIB_H_ 1
 
+struct HL_hex {
+       int x, y;
+};
+
+struct HL_isohex {
+       int i,j,k;
+};
+
+struct HL_point {
+       double x, y;
+};
+
+struct HL_hex HL_hex_xy(int x, int y);
+
+int HL_hex_cmp(struct HL_hex const *a, struct HL_hex const *b);
+
+int HL_hex_eq(struct HL_hex const *a, struct HL_hex const *b); 
+
 /*
  * this library implements a generic library for hexgrids for games.
  * it avoids display issues, other than some general provisions
@@ -25,7 +43,8 @@
  * on a hex boundary, the result will depend on how the machine
  * does the floating point math, but should be consistent.
  */
-int HL_hexbin(double width, double x, double y, int *i, int *j);
+struct HL_hex HL_hexbin(double width, double x, double y);
+struct HL_hex HL_bin(double x, double y);
 
 /* generate the cantor mapping of a hexes x,y coordinate.
  * See http://en.wikipedia.org/wiki/Cantor_pairing_function.
@@ -44,24 +63,10 @@ int HL_hexbin(double width, double x, double y, int *i, int *j);
  * is independent of the size of the grid.
  */
 
-/* Cartesian functions */
+/* Cantor encoding/decoding functions */
+int HL_cantor(struct HL_hex h);
 int HL_cantor_xy(int x, int y);
-int HL_cantor_xyp(int *xy);
-int HL_cantor_x(int cantor);
-int HL_cantor_y(int cantor);
-
-/* Isometric functions */
-int HL_cantor_ijk(int i, int j, int k);
-int HL_cantor_ijkp(int *ijk);
-int HL_cantor_i(int cantor);
-int HL_cantor_k(int cantor);
-int HL_cantor_j(int cantor);
-
-int HL_cantor_bin(double x, double y);
-
-/* A general decode function */
-int HL_cantor_decode(int can, int *x, int *y, int *i, int *j, int *k);
-int HL_cantor_arrays(int can, int *xy, int *ijk);
+struct HL_hex HL_uncantor(int cantor);
 
 /*
  * layout assistance functions
@@ -72,27 +77,23 @@ int HL_cantor_arrays(int can, int *xy, int *ijk);
  *
  * Similarly for HL_center_y() and HL_hexcenter()
  */
-double HL_center_x(int cantor);
-double HL_center_y(int cantor);
-int HL_hexcenter(int cantor, double *x, double *y);
+struct HL_point HL_hexcenter(struct HL_hex hex);
 
 /* find a point based on a unit hex, given angle and distance from center,
  * where a distance of 1 is on the hex side.  probably not useful
  * for points outside the hex, that is, distance should almost certainly
  * be less than or equal to 1.0
  */
-double HL_polar(double angle, double distance, double *x, double *y);
+struct HL_point HL_polar(double angle, double distance, double *d);
 
 /* how far is it on the hex grid */
-int HL_distance(int from_cantor, int to_cantor);
-
-/* returns 0 for <0 or >5 */
-int HL_adjacent_hex(int start, int dir);
+int HL_distance(struct HL_hex from, struct HL_hex to);
 
 /* module direction */
-int HL_adjhex(int start, int dir);
-int HL_hexes_at_range(int hex, int range, int *list, int size);
-int HL_hexes_within_range(int hex, int range, int *list, int size);
+struct HL_hex HL_adjhex(struct HL_hex, int dir);
+int HL_adjhexp(struct HL_hex, int dir, struct HL_hex *adj);
+int HL_hexes_at_range(struct HL_hex, int range, struct HL_hex *list, int size);
+int HL_hexes_within_range(struct HL_hex, int range, struct HL_hex *list, int size);
 
 typedef double (*HL_costfunc)(int start, int finish);
 
@@ -110,22 +111,14 @@ int HL_map_max_dimension(void);
 /*
  * Plotting support
  */
-void HL_trianglefan(int cantor, double *);
-
-struct HL_hex {
-       int x,y; /* hmm.  would be nice to be able to just point to a generic */
-};
-
-struct hl_point {
-       double x, y;
-};
+void HL_trianglefan(struct HL_hex hex, double *);
 
 /*
  * Pathfinding
  */
 
 struct HL_astar_hex {
-       int hex;
+       struct HL_hex hex;
        double f, g, h;
        struct HL_astar_hex *parent;
        int     open;
@@ -134,11 +127,11 @@ struct HL_astar_hex {
 };
 
 struct HL_astar {
-       int start, goal;
+       struct HL_hex start, goal;
        int pathlen;
-       double (*metric)(int,int);
-       double (*heuristic)(int,int);
-       int (*neighbor)(int,int);
+       double (*metric)(struct HL_hex,struct HL_hex);
+       double (*heuristic)(struct HL_hex,struct HL_hex);
+       int (*neighbor)(struct HL_hex,int dir, struct HL_hex *n);
        int nodes, allocated;
        struct HL_astar_hex *open;
        struct HL_astar_hex *closed;
@@ -151,7 +144,7 @@ int HL_findpath(struct HL_astar *s, int loops);
 void HL_astar_free(struct HL_astar *s);
 struct HL_astar *HL_astar_clear(struct HL_astar *s);
 struct HL_astar *HL_astar_init(struct HL_astar *s);
-void HL_vertices(int cantor, double *vc);
+void HL_vertices(struct HL_hex hex, double *vc);
 
 extern double HL_vertexv[12];
 extern double HL_fand[16];
index 411228805f34b6a1b3d92abbfc09f57175c6ac17..2f9d26ed670de9ef16d6ab3783f5763bb0933419 100644 (file)
@@ -3,18 +3,20 @@
 #include "ctap.h"
 
 int main(void) {
-       int hex, start, dist;
+       struct HL_hex hex, start;
+
+       int dist;
        int x, y, i;
 
        plan(294);
 
        for (x = -3 ; x <= 3; x++) {
                for (y = -3 ; y <= 3; y++) {
-                       start = HL_cantor_xy(x, y);
+                       start = HL_hex_xy(x, y);
                        for (i = 0; i < 6; i++) {
                                hex = HL_adjhex(start, i);
                                dist = HL_distance(hex, start);
-                               ok(dist == 1,
+                               is_int((long)dist, 1L,
                                        "%d, %d direction %d distance one",
                                        x, y, i);
                        }
index 729a7a864f8863391d453f8736a76f8bdd3ae482..5a447da42155a252c2cb8f61584571860f3766a5 100644 (file)
--- a/t/astar.c
+++ b/t/astar.c
@@ -5,10 +5,11 @@
 #include "ctap.h"
 
 void pcheck(struct HL_astar *p, int x1, int y1, int x2, int y2, int expect) {
-       int from, to, dist;
+       struct HL_hex from, to;
+       int dist;
 
-       from = HL_cantor_xy(x1,y1);
-       to = HL_cantor_xy(x2,y2);
+       from = HL_hex_xy(x1,y1);
+       to = HL_hex_xy(x2,y2);
 
 //     HL_astar_clear(p);
 
@@ -24,14 +25,21 @@ void pcheck(struct HL_astar *p, int x1, int y1, int x2, int y2, int expect) {
 }
 
 /* make hex 55 missing */
-int neighbor55(int hex, int dir) {
-       int neighbor;
-
-       do {
-               neighbor = HL_adjacent_hex(hex, dir++);
-       } while (neighbor == HL_cantor_xy(5,5));
-
-       return neighbor;
+int neighbor55(struct HL_hex hex, int dir, struct HL_hex *n) {
+       int valid;
+       struct HL_hex nh;
+
+       valid = HL_adjhexp(hex, dir, &nh);
+       if (valid && nh.x == 5 && nh.y == 5) {
+               valid = 0;
+       }
+               if (valid && n) {
+               *n = nh;
+       }
+       
+       return valid;
+
+       return 1;
 }
 
 int main(void) {
index 1e7dbf6e8c6358f46cafdc07ab622e786ba83b46..7362714c09e5ae9823acea24715059dbdfdb1c11 100644 (file)
@@ -5,21 +5,21 @@
 #include "ctap.h"
 
 int main(void) {
-       int xy[2];
-       int ijk[3];
        int hex;
+       struct HL_hex in;
+       struct HL_hex out;
        int x, y;
 
-       plan(81*4);
+       plan(81*2);
 
        for (x=-4;x<=4;x++) {
                for (y=-4;y<=4;y++) {
-                       hex = HL_cantor_xy(x,y);
-                       HL_cantor_arrays(hex, xy, ijk);
-                       ok(x == xy[0], "x check %d %d", x, y);
-                       ok(y == xy[1], "y check %d %d", x, y);
-                       ok(x == HL_cantor_x(hex), "reverse check x %d %d",hex,x);
-                       ok(x == HL_cantor_x(hex), "reverse check y %d %d",hex,y);
+                       in.x = x;
+                       in.y = y;
+                       hex = HL_cantor(in);
+                       out = HL_uncantor(hex);
+                       is_int(x, out.x, "x check %d %d", x, y);
+                       is_int(y, out.y, "y check %d %d", x, y);
                }
        }
 
index 1c039c9de97aa391e009fc2bf5c264886af94945..eecb80c3b0f6c8a828a0fb9c8659833f36ffcd6d 100644 (file)
@@ -4,27 +4,36 @@
 
 #include "ctap.h"
 
+#define EPS 0.00000001
+
 int main(void) {
-       int start, x, y;
+       int x, y;
+       struct HL_hex start;
+       struct HL_point center;
+       double stride;
+
+       stride = 1.5 / sqrt(3.0);
 
        plan(6);
 
        x = 0; y = 0;
-       start = HL_cantor_xy(x,y);
-       ok(HL_center_x(start) == x * 1.5 / sqrt(3.0), "%d %d center X", x, y);
-       ok(HL_center_y(start) == 0.0, "%d %d center Y", x, y);
+       start = HL_hex_xy(x,y);
+       center = HL_hexcenter(start);
+       is_double(center.x, x * stride, EPS, "%d %d center X", x, y);
+       is_double(center.y, 0.0, EPS, "%d %d center Y", x, y);
 
        x = 1; y = 1;
-       start = HL_cantor_xy(x,y);
-       ok(HL_center_x(start) == x * 1.5 / sqrt(3.0), "%d %d center X", x, y);
-       ok(HL_center_y(start) == 0.5, "%d %d center Y = %f", x, y,
-                       HL_center_y(start));
+       start = HL_hex_xy(x,y);
+       center = HL_hexcenter(start);
+       is_double(center.x, x * stride, EPS, "%d %d center X", x, y);
+       is_double(center.y, 0.5, EPS, "%d %d center Y", x, y);
+
 
        x = 2; y = 2;
-       start = HL_cantor_xy(x,y);
-       ok(HL_center_x(start) == x * 1.5 / sqrt(3.0), "%d %d center X", x, y);
-       ok(HL_center_y(start) == 2.0, "%d %d center Y = %f", x, y,
-                       HL_center_y(start));
+       start = HL_hex_xy(x,y);
+       center = HL_hexcenter(start);
+       is_double(center.x, x * stride, EPS, "%d %d center X", x, y);
+       is_double(center.y, 2.0, EPS, "%d %d center Y", x, y);
 
        return 0;
 }
index 0fa88f0bd59ec52bf7941dba63eb905437943973..55bfd5ce69ca06c3c41633ffad0be19791914d5e 100644 (file)
@@ -3,13 +3,18 @@
 #include "ctap.h"
 
 void dcheck(int x1, int y1, int x2, int y2, int expect) {
-       int from, to, dist;
-       from = HL_cantor_xy(x1,y1);
-       to = HL_cantor_xy(x2,y2);
+       int dist;
+       struct HL_hex from, to;
+
+       from.x = x1;
+       from.y = y1;
+       to.x = x2;
+       to.y = y2;
+
        dist = HL_distance(from,to);
-       ok(dist == expect,
-               "distance from (%02d, %02d) to (%02d, %02d) = %d (expect %d)",
-               x1, y1, x2, y2, dist, expect);
+       is_int(expect, dist,
+               "distance from (%02d, %02d) to (%02d, %02d)",
+               x1, y1, x2, y2);
 }
 
 int main(void) {
index 293d0f7782748e229071a980f4c4616aa9ca5950..7afe2700030efd7877bfbc4bbf42f2e1330009b2 100644 (file)
@@ -3,23 +3,30 @@
 #include "ctap.h"
 
 int main(void) {
-       int x, y;
-
-       plan(6);
-
-       HL_hexbin(1.0, 0.444194, -4.639363, &x, &y);
-       ok(x == 1 && y == 4, "hexbin 0.444194, 4.639363 = 1, 4, %d %d", x, y);
-
-        HL_hexbin(1.0, 0.0, 0.0, &x, &y);
-        ok(x == 0 && y == 0, "0.0 0.0 -> 0 0");
-
-        HL_hexbin(0.1111111, 0.288675, 0.500000, &x, &y);
-        ok(x == 3, "center bin X %d == 3", x);
-        ok(y == -5, "center bin Y %d == -5", y);
-
-        HL_hexbin(0.1111111, 0.866025, 0.500000, &x, &y);
-        ok(x == 9, "vertex bin X %d == 9", x);
-        ok(y == -5, "vertex bin Y %d == -5", y);
+       double px, py;
+       struct HL_hex h;
+
+       plan(8);
+
+       px = 0.444194; py = -4.639363;
+       h = HL_hexbin(1.0, px, py);
+       is_int(1, h.x, "hexbin x %f, %f", px, py);
+       is_int(4, h.y, "hexbin x %f, %f", px, py);
+
+       px = 0.0; py = 0.0;
+       h = HL_hexbin(1.0, px, py);
+       is_int(0, h.x, "hexbin x %f, %f", px, py);
+       is_int(0, h.y, "hexbin x %f, %f", px, py);
+
+       px = 0.288675; py = 0.5;
+       h = HL_hexbin(0.111111, px, py);
+       is_int(3, h.x, "center hexbin x %f, %f", px, py);
+       is_int(-5, h.y, "center hexbin x %f, %f", px, py);
+
+       px = 0.866025; py = 0.5;
+       h = HL_hexbin(0.1111111, px, py);
+       is_int(9, h.x, "vertex hexbin x %f, %f", px, py);
+       is_int(-5, h.y, "vertex hexbin y %f, %f", px, py);
 
        return 0;
 }
index 783a089f130cd87679b49e301cc001427bfa8dc4..76028454fecfc15e75ffd5ea41a35cef00979421 100644 (file)
--- a/t/range.c
+++ b/t/range.c
@@ -9,57 +9,62 @@
 #include "ctap.h"
 
 int icmp(const void *ap, const void *bp) {
-       int a;
-       int b;
+       struct HL_hex const *a;
+       struct HL_hex const *b;
        
-       a = *((int *)(ap));
-       b = *((int *)(bp));
+       a = ap;
+       b = bp;
 
-       return a-b;
+       if (a->x < b->x) return -1;
+       if (a->x > b->x) return 1;
+       if (a->y < b->y) return -1;
+       if (a->y > b->y) return 1;
+
+       return 0;
 }
 
-void sort(int *r, int ct) {
+void sort(struct HL_hex *r, int ct) {
        qsort(r, ct, sizeof *r, icmp);
 }
 
 int main(void) {
-       int start;
+       struct HL_hex start;
        int i, count;
-       int range[32];
-       int testrange[32];
+       struct HL_hex range[32];
+       struct HL_hex testrange[32];
 
        plan(7+4);
 
        /* printf("range = 1 from 3,3\n"); */
-       start = HL_cantor_xy(3,3);
+       start = HL_hex_xy(3,3);
        count = HL_hexes_at_range(start, 1, range, 0);
        ok(count == 6, "6 hexes at range 1");
        count = HL_hexes_at_range(start, 1, range, count);
        sort(range, 6);
-       testrange[0] = HL_cantor_xy(3,2);
-       testrange[1] = HL_cantor_xy(3,4);
-       testrange[2] = HL_cantor_xy(4,3);
-       testrange[3] = HL_cantor_xy(4,2);
-       testrange[4] = HL_cantor_xy(2,3);
-       testrange[5] = HL_cantor_xy(2,2);
+       testrange[0] = HL_hex_xy(3,2);
+       testrange[1] = HL_hex_xy(3,4);
+       testrange[2] = HL_hex_xy(4,3);
+       testrange[3] = HL_hex_xy(4,2);
+       testrange[4] = HL_hex_xy(2,3);
+       testrange[5] = HL_hex_xy(2,2);
        sort(testrange, 6);
        for (i = 0; i < count; i++) {
-               ok(range[i] == testrange[i], "3, 3 range 1 hex %d", testrange[i]);
+               ok(HL_hex_eq(&range[i], &testrange[i]), "3, 3 range 1 hex %d", testrange[i]);
        }
 
-       start = HL_cantor_xy(0,3);
+       start = HL_hex_xy(0,3);
        count = HL_hexes_at_range(start, 1, range, 0);
        ok(count == 6, "6 hexes at range1 from 0,3");
 
-       start = HL_cantor_xy(-1,5);
+       start = HL_hex_xy(-1,5);
        count = HL_hexes_at_range(start, 1, range, 0);
        ok(count == 6, "6 hexes at range1 from -1,5");
 
-       start = HL_cantor_xy(-2,3);
+       start = HL_hex_xy(-2,3);
        count = HL_hexes_at_range(start, 1, range, 0);
        ok(count == 6, "6 hexes at range1 from -2,3");
 
-       start = HL_cantor_xy(3,3);
+       start = HL_hex_xy(3,3);
        count = HL_hexes_at_range(start, 2, range, 0);
        ok(count == 12, "6 hexes at range1 from 3,3");
 
diff --git a/t/tap.3 b/t/tap.3
deleted file mode 100644 (file)
index 4b23c24..0000000
--- a/t/tap.3
+++ /dev/null
@@ -1,368 +0,0 @@
-.Dd December 20, 2004
-.Os
-.Dt TAP 3
-.Sh NAME
-.Nm tap
-.Nd write tests that implement the Test Anything Protocol
-.Sh SYNOPSIS
-.In tap.h
-.Sh DESCRIPTION
-The
-.Nm
-library provides functions for writing test scripts that produce output
-consistent with the Test Anything Protocol.  A test harness that parses
-this protocol can run these tests and produce useful reports indicating
-their success or failure.
-.Ss PRINTF STRINGS
-In the descriptions that follow, for any function that takes as the
-last two parameters
-.Dq Fa char * , Fa ...
-it can be assumed that the
-.Fa char *
-is a
-.Fn printf
--like format string, and the optional arguments are values to be placed
-in that string.
-.Ss TEST PLANS
-.Bl -tag -width indent
-.It Xo
-.Ft int
-.Fn plan_tests "unsigned int"
-.Xc
-.It Xo
-.Ft int
-.Fn plan_no_plan "void"
-.Xc
-.It Xo
-.Ft int
-.Fn plan_skip_all "char *" "..."
-.Xc
-.El
-.Pp
-You must first specify a test plan.  This indicates how many tests you
-intend to run, and allows the test harness to notice if any tests were
-missed, or if the test program exited prematurely.
-.Pp
-To do this, use
-.Fn plan_tests ,
-which always returns 0.  The function will cause your program to exit
-prematurely if you specify 0 tests.
-.Pp
-In some situations you may not know how many tests you will be running, or
-you are developing your test program, and do not want to update the
-.Fn plan_tests
-parameter every time you make a change.  For those situations use
-.Fn plan_no_plan .
-It returns 0, and indicates to the test harness that an indeterminate number
-of tests will be run.
-.Pp
-Both
-.Fn plan_tests
-and
-.Fn plan_no_plan
-will cause your test program to exit prematurely with a diagnostic
-message if they are called more than once.
-.Pp
-If your test program detects at run time that some required functionality
-is missing (for example, it relies on a database connection which is not
-present, or a particular configuration option that has not been included
-in the running kernel) use
-.Fn plan_skip_all ,
-passing as parameters a string to display indicating the reason for skipping
-the tests.
-.Ss SIMPLE TESTS
-.Bl -tag -width indent
-.It Xo
-.Ft unsigned int
-.Fn ok "expression" "char *" "..."
-.Xc
-.It Xo
-.Ft unsigned int
-.Fn ok1 "expression"
-.Xc
-.It Xo
-.Ft unsigned int
-.Fn pass "char *" "..."
-.Xc
-.It Xo
-.Ft unsigned int
-.Fn fail "char *" "..."
-.Xc
-.El
-.Pp
-Tests are implemented as expressions checked by calls to the
-.Fn ok
-and
-.Fn ok1
-macros.  In both cases
-.Fa expression
-should evaluate to true if the test succeeded.
-.Pp
-.Fn ok
-allows you to specify a name, or comment, describing the test which will
-be included in the output.
-.Fn ok1
-is for those times when the expression to be tested is self
-explanatory and does not need an associated comment.  In those cases
-the test expression becomes the comment.
-.Pp
-These four calls are equivalent:
-.Bd -literal -offset indent
-int i = 5;
-
-ok(i == 5, "i equals 5");      /* Overly verbose */
-ok(i == 5, "i equals %d", i);  /* Just to demonstrate printf-like
-                                  behaviour of the test name */
-ok(i == 5, "i == 5");          /* Needless repetition */
-ok1(i == 5);                   /* Just right */
-.Ed
-.Pp
-It is good practice to ensure that the test name describes the meaning
-behind the test rather than what you are testing.  Viz
-.Bd -literal -offset indent
-ok(db != NULL, "db is not NULL");            /* Not bad, but */
-ok(db != NULL, "Database conn. succeeded");  /* this is better */
-.Ed
-.Pp
-.Fn ok
-and
-.Fn ok1
-return 1 if the expression evaluated to true, and 0 if it evaluated to
-false.  This lets you chain calls from
-.Fn ok
-to
-.Fn diag
-to only produce diagnostic output if the test failed.  For example, this
-code will include diagnostic information about why the database connection
-failed, but only if the test failed.
-.Bd -literal -offset indent
-ok(db != NULL, "Database conn. succeeded") ||
-    diag("Database error code: %d", dberrno);
-.Ed
-.Pp
-You also have
-.Fn pass
-and
-.Fn fail .
-From the Test::More documentation:
-.Bd -literal -offset indent
-Sometimes you just want to say that the tests have passed.
-Usually the case is you've got some complicated condition
-that is difficult to wedge into an ok().  In this case,
-you can simply use pass() (to declare the test ok) or fail
-(for not ok).
-
-Use these very, very, very sparingly.
-.Ed
-.Pp
-These are synonyms for ok(1, ...) and ok(0, ...).
-.Ss SKIPPING TESTS
-.Bl -tag -width indent
-.It Xo
-.Ft int
-.Fn skip "unsigned int" "char *" "..."
-.Xc
-.It Xo
-.Fn skip_start "expression" "unsigned int" "char *" "..."
-.Xc
-.It Xo
-.Sy skip_end
-.Xc
-.El
-.Pp
-Sets of tests can be skipped.  Ordinarily you would do this because
-the test can't be run in this particular testing environment.
-.Pp
-For example, suppose some tests should be run as root.  If the test is
-not being run as root then the tests should be skipped.  In this 
-implementation, skipped tests are flagged as being ok, with a special
-message indicating that they were skipped.  It is your responsibility
-to ensure that the number of tests skipped (the first parameter to
-.Fn skip )
-is correct for the number of tests to skip.
-.Pp
-One way of implementing this is with a
-.Dq do { } while(0);
-loop, or an
-.Dq if( ) { } else { }
-construct, to ensure that there are no additional side effects from the
-skipped tests.
-.Bd -literal -offset indent
-if(getuid() != 0) {
-        skip(1, "because test only works as root");
-} else {
-        ok(do_something_as_root() == 0, "Did something as root");
-}
-.Ed
-.Pp
-Two macros are provided to assist with this.  The previous example could
-be re-written as follows.
-.Bd -literal -offset indent
-skip_start(getuid() != 0, 1, "because test only works as root");
-
-ok(do_something_as_root() == 0, "Did something as root");
-
-skip_end;    /* It's a macro, no parentheses */
-.Ed
-.Ss MARKING TESTS AS Dq TODO
-.Bl -tag -width indent
-.It Xo
-.Ft void
-.Fn todo_start "char *" "..."
-.Xc
-.It Xo
-.Ft void
-.Fn todo_end "void"
-.Xc
-.El
-.Pp
-Sets of tests can be flagged as being
-.Dq TODO .
-These are tests that you expect to fail, probably because you haven't
-fixed a bug, or finished a new feature yet.  These tests will still be
-run, but with additional output that indicates that they are expected
-to fail.  Should a test start to succeed unexpectedly, tools like
-.Xr prove 1
-will indicate this, and you can move the test out of the todo
-block.  This is much more useful than simply commenting out (or
-.Dq #ifdef 0 ... #endif )
-the tests.
-.Bd -literal -offset indent
-todo_start("dwim() not returning true yet");
-
-ok(dwim(), "Did what the user wanted");
-
-todo_end();
-.Ed
-.Pp
-Should
-.Fn dwim
-ever start succeeding you will know about it as soon as you run the
-tests.  Note that
-.Em unlike
-the
-.Fn skip_*
-family, additional code between
-.Fn todo_start
-and
-.Fn todo_end
-.Em is
-executed.
-.Ss SKIP vs. TODO
-From the Test::More documentation;
-.Bd -literal -offset indent
-If it's something the user might not be able to do, use SKIP.
-This includes optional modules that aren't installed, running
-under an OS that doesn't have some feature (like fork() or
-symlinks), or maybe you need an Internet connection and one
-isn't available.
-
-If it's something the programmer hasn't done yet, use TODO.
-This is for any code you haven't written yet, or bugs you have
-yet to fix, but want to put tests in your testing script 
-(always a good idea).
-.Ed
-.Ss DIAGNOSTIC OUTPUT
-.Bl -tag -width indent
-.It Xo
-.Fr unsigned int
-.Fn diag "char *" "..."
-.Xc
-.El
-.Pp
-If your tests need to produce diagnostic output, use
-.Fn diag .
-It ensures that the output will not be considered by the TAP test harness.
-.Fn diag
-adds the necessary trailing
-.Dq \en
-for you.
-.Bd -literal -offset indent
-diag("Expected return code 0, got return code %d", rcode);
-.Ed
-.Pp
-.Fn diag
-always returns 0.
-.Ss EXIT STATUS
-.Bl -tag -width indent
-.It Xo
-.Fr int
-.Fn exit_status void
-.Xc
-.El
-.Pp
-For maximum compatability your test program should return a particular
-exit code.  This is calculated by
-.Fn exit_status
-so it is sufficient to always return from
-.Fn main
-with either
-.Dq return exit_status();
-or
-.Dq exit(exit_status());
-as appropriate.
-.Sh EXAMPLES
-The
-.Pa tests
-directory in the source distribution contains numerous tests of
-.Nm
-functionality, written using
-.Nm .
-Examine them for examples of how to construct test suites.
-.Sh COMPATABILITY
-.Nm
-strives to be compatible with the Perl Test::More and Test::Harness 
-modules.  The test suite verifies that
-.Nm
-is bug-for-bug compatible with their behaviour.  This is why some
-functions which would more naturally return nothing return constant
-values.
-.Pp
-If the
-.Lb libpthread
-is found at compile time,
-.Nm
-.Em should
-be thread safe.  Indications to the contrary (and test cases that expose
-incorrect behaviour) are very welcome.
-.Sh SEE ALSO
-.Xr Test::More 1 ,
-.Xr Test::Harness 1 ,
-.Xr prove 1
-.Sh STANDARDS
-.Nm
-requires a
-.St -isoC-99
-compiler.  Some of the
-.Nm
-functionality is implemented as variadic macros, and that functionality
-was not formally codified until C99.  Patches to use
-.Nm
-with earlier compilers that have their own implementation of variadic
-macros will be gratefully received.
-.Sh HISTORY
-.Nm
-was written to help improve the quality and coverage of the FreeBSD
-regression test suite, and released in the hope that others find it
-a useful tool to help improve the quality of their code.
-.Sh AUTHORS
-.An "Nik Clayton" Aq nik@ngo.org.uk ,
-.Aq nik@FreeBSD.org
-.Pp
-.Nm
-would not exist without the efforts of
-.An "Michael G Schwern" Aq schqern@pobox.com ,
-.An "Andy Lester" Aq andy@petdance.com ,
-and the countless others who have worked on the Perl QA programme.
-.Sh BUGS
-Ideally, running the tests would have no side effects on the behaviour
-of the application you are testing.  However, it is not always possible
-to avoid them.  The following side effects of using
-.Nm
-are known.
-.Bl -bullet -offset indent
-.It
-stdout is set to unbuffered mode after calling any of the
-.Fn plan_*
-functions.
-.El
diff --git a/t/tap.c b/t/tap.c
deleted file mode 100644 (file)
index 475c55e..0000000
--- a/t/tap.c
+++ /dev/null
@@ -1,436 +0,0 @@
-/*-
- * Copyright (c) 2004 Nik Clayton
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#define _GNU_SOURCE
-#include <ctype.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "tap.h"
-
-static int no_plan = 0;
-static int skip_all = 0;
-static int have_plan = 0;
-static unsigned int test_count = 0; /* Number of tests that have been run */
-static unsigned int e_tests = 0; /* Expected number of tests to run */
-static unsigned int failures = 0; /* Number of tests that failed */
-static char *todo_msg = NULL;
-static char *todo_msg_fixed = "libtap malloc issue";
-static int todo = 0;
-static int test_died = 0;
-
-/* Encapsulate the pthread code in a conditional.  In the absence of
-   libpthread the code does nothing */
-#ifdef HAVE_LIBPTHREAD
-#include <pthread.h>
-static pthread_mutex_t M = PTHREAD_MUTEX_INITIALIZER;
-# define LOCK pthread_mutex_lock(&M);
-# define UNLOCK pthread_mutex_unlock(&M);
-#else
-# define LOCK
-# define UNLOCK
-#endif
-
-static void _expected_tests(unsigned int);
-static void _tap_init(void);
-static void _cleanup(void);
-
-/*
- * Generate a test result.
- *
- * ok -- boolean, indicates whether or not the test passed.
- * test_name -- the name of the test, may be NULL
- * test_comment -- a comment to print afterwards, may be NULL
- */
-unsigned int
-_gen_result(int ok, const char *func, char *file, unsigned int line, 
-           char *test_name, ...)
-{
-       va_list ap;
-       char *local_test_name = NULL;
-       char *c;
-       int name_is_digits;
-
-       LOCK;
-
-       test_count++;
-
-       /* Start by taking the test name and performing any printf()
-          expansions on it */
-       if(test_name != NULL) {
-               va_start(ap, test_name);
-               vasprintf(&local_test_name, test_name, ap);
-               va_end(ap);
-
-               /* Make sure the test name contains more than digits
-                  and spaces.  Emit an error message and exit if it
-                  does */
-               if(local_test_name) {
-                       name_is_digits = 1;
-                       for(c = local_test_name; *c != '\0'; c++) {
-                               if(!isdigit(*c) && !isspace(*c)) {
-                                       name_is_digits = 0;
-                                       break;
-                               }
-                       }
-
-                       if(name_is_digits) {
-                               diag("    You named your test '%s'.  You shouldn't use numbers for your test names.", local_test_name);
-                               diag("    Very confusing.");
-                       }
-               }
-       }
-
-       if(!ok) {
-               printf("not ");
-               failures++;
-       }
-
-       printf("ok %d", test_count);
-
-       if(test_name != NULL) {
-               printf(" - ");
-
-               /* Print the test name, escaping any '#' characters it
-                  might contain */
-               if(local_test_name != NULL) {
-                       flockfile(stdout);
-                       for(c = local_test_name; *c != '\0'; c++) {
-                               if(*c == '#')
-                                       fputc('\\', stdout);
-                               fputc((int)*c, stdout);
-                       }
-                       funlockfile(stdout);
-               } else {        /* vasprintf() failed, use a fixed message */
-                       printf("%s", todo_msg_fixed);
-               }
-       }
-
-       /* If we're in a todo_start() block then flag the test as being
-          TODO.  todo_msg should contain the message to print at this
-          point.  If it's NULL then asprintf() failed, and we should
-          use the fixed message.
-
-          This is not counted as a failure, so decrement the counter if
-          the test failed. */
-       if(todo) {
-               printf(" # TODO %s", todo_msg ? todo_msg : todo_msg_fixed);
-               if(!ok)
-                       failures--;
-       }
-
-       printf("\n");
-
-       if(!ok)
-               diag("    Failed %stest (%s:%s() at line %d)", 
-                    todo ? "(TODO) " : "", file, func, line);
-
-       free(local_test_name);
-
-       UNLOCK;
-
-       /* We only care (when testing) that ok is positive, but here we
-          specifically only want to return 1 or 0 */
-       return ok ? 1 : 0;
-}
-
-/*
- * Initialise the TAP library.  Will only do so once, however many times it's
- * called.
- */
-void
-_tap_init(void)
-{
-       static int run_once = 0;
-
-       LOCK;
-
-       if(!run_once) {
-               atexit(_cleanup);
-
-               /* stdout needs to be unbuffered so that the output appears
-                  in the same place relative to stderr output as it does 
-                  with Test::Harness */
-               setbuf(stdout, 0);
-               run_once = 1;
-       }
-
-       UNLOCK;
-}
-
-/*
- * Note that there's no plan.
- */
-int
-plan_no_plan(void)
-{
-
-       LOCK;
-
-       _tap_init();
-
-       if(have_plan != 0) {
-               fprintf(stderr, "You tried to plan twice!\n");
-               test_died = 1;
-               UNLOCK;
-               exit(255);
-       }
-
-       have_plan = 1;
-       no_plan = 1;
-
-       UNLOCK;
-
-       return 0;
-}
-
-/*
- * Note that the plan is to skip all tests
- */
-int
-plan_skip_all(char *reason)
-{
-
-       LOCK;
-
-       _tap_init();
-
-       skip_all = 1;
-
-       printf("1..0");
-
-       if(reason != NULL)
-               printf(" # Skip %s", reason);
-
-       printf("\n");
-
-       UNLOCK;
-
-       exit(0);
-}
-
-/*
- * Note the number of tests that will be run.
- */
-int
-plan_tests(unsigned int tests)
-{
-
-       LOCK;
-
-       _tap_init();
-
-       if(have_plan != 0) {
-               fprintf(stderr, "You tried to plan twice!\n");
-               test_died = 1;
-               UNLOCK;
-               exit(255);
-       }
-
-       if(tests == 0) {
-               fprintf(stderr, "You said to run 0 tests!  You've got to run something.\n");
-               test_died = 1;
-               UNLOCK;
-               exit(255);
-       }
-
-       have_plan = 1;
-
-       _expected_tests(tests);
-
-       UNLOCK;
-
-       return 0;
-}
-
-unsigned int
-diag(char *fmt, ...)
-{
-       va_list ap;
-
-       LOCK;
-
-       fputs("# ", stderr);
-
-       va_start(ap, fmt);
-       vfprintf(stderr, fmt, ap);
-       va_end(ap);
-
-       fputs("\n", stderr);
-
-       UNLOCK;
-
-       return 0;
-}
-
-void
-_expected_tests(unsigned int tests)
-{
-
-       LOCK;
-
-       printf("1..%d\n", tests);
-       e_tests = tests;
-
-       UNLOCK;
-}
-
-int
-skip(unsigned int n, char *fmt, ...)
-{
-       va_list ap;
-       char *skip_msg;
-
-       LOCK;
-
-       va_start(ap, fmt);
-       asprintf(&skip_msg, fmt, ap);
-       va_end(ap);
-
-       while(n-- > 0) {
-               test_count++;
-               printf("ok %d # skip %s\n", test_count, 
-                      skip_msg != NULL ? 
-                      skip_msg : "libtap():malloc() failed");
-       }
-
-       free(skip_msg);
-
-       UNLOCK;
-
-       return 1;
-}
-
-void
-todo_start(char *fmt, ...)
-{
-       va_list ap;
-
-       LOCK;
-
-       va_start(ap, fmt);
-       vasprintf(&todo_msg, fmt, ap);
-       va_end(ap);
-
-       todo = 1;
-
-       UNLOCK;
-}
-
-void
-todo_end(void)
-{
-
-       LOCK;
-
-       todo = 0;
-       free(todo_msg);
-
-       UNLOCK;
-}
-
-int
-exit_status(void)
-{
-       int r;
-
-       LOCK;
-
-       /* If there's no plan, just return the number of failures */
-       if(no_plan || !have_plan) {
-               UNLOCK;
-               return failures;
-       }
-
-       /* Ran too many tests?  Return the number of tests that were run
-          that shouldn't have been */
-       if(e_tests < test_count) {
-               r = test_count - e_tests;
-               UNLOCK;
-               return r;
-       }
-
-       /* Return the number of tests that failed + the number of tests 
-          that weren't run */
-       r = failures + e_tests - test_count;
-       UNLOCK;
-
-       return r;
-}
-
-/*
- * Cleanup at the end of the run, produce any final output that might be
- * required.
- */
-void
-_cleanup(void)
-{
-
-       LOCK;
-
-       /* If plan_no_plan() wasn't called, and we don't have a plan,
-          and we're not skipping everything, then something happened
-          before we could produce any output */
-       if(!no_plan && !have_plan && !skip_all) {
-               diag("Looks like your test died before it could output anything.");
-               UNLOCK;
-               return;
-       }
-
-       if(test_died) {
-               diag("Looks like your test died just after %d.", test_count);
-               UNLOCK;
-               return;
-       }
-
-
-       /* No plan provided, but now we know how many tests were run, and can
-          print the header at the end */
-       if(!skip_all && (no_plan || !have_plan)) {
-               printf("1..%d\n", test_count);
-       }
-
-       if((have_plan && !no_plan) && e_tests < test_count) {
-               diag("Looks like you planned %d tests but ran %d extra.",
-                    e_tests, test_count - e_tests);
-               UNLOCK;
-               return;
-       }
-
-       if((have_plan || !no_plan) && e_tests > test_count) {
-               diag("Looks like you planned %d tests but only ran %d.",
-                    e_tests, test_count);
-               UNLOCK;
-               return;
-       }
-
-       if(failures)
-               diag("Looks like you failed %d tests of %d.", 
-                    failures, test_count);
-
-       UNLOCK;
-}
diff --git a/t/tap.h b/t/tap.h
deleted file mode 100644 (file)
index e64f9d5..0000000
--- a/t/tap.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*-
- * Copyright (c) 2004 Nik Clayton
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/* '## __VA_ARGS__' is a gcc'ism. C99 doesn't allow the token pasting
-   and requires the caller to add the final comma if they've ommitted
-   the optional arguments */
-#ifdef __GNUC__
-# define ok(e, test, ...) ((e) ?                                       \
-                          _gen_result(1, __func__, __FILE__, __LINE__, \
-                                      test, ## __VA_ARGS__) :          \
-                          _gen_result(0, __func__, __FILE__, __LINE__, \
-                                      test, ## __VA_ARGS__))
-
-# define ok1(e) ((e) ?                                                 \
-                _gen_result(1, __func__, __FILE__, __LINE__, "%s", #e) : \
-                _gen_result(0, __func__, __FILE__, __LINE__, "%s", #e))
-
-# define pass(test, ...) ok(1, test, ## __VA_ARGS__);
-# define fail(test, ...) ok(0, test, ## __VA_ARGS__);
-
-# define skip_start(test, n, fmt, ...)                 \
-       do {                                            \
-               if((test)) {                            \
-                       skip(n, fmt, ## __VA_ARGS__);   \
-                       continue;                       \
-               }
-#elif __STDC_VERSION__ >= 199901L /* __GNUC__ */
-# define ok(e, ...) ((e) ?                                             \
-                    _gen_result(1, __func__, __FILE__, __LINE__,       \
-                                __VA_ARGS__) :                         \
-                    _gen_result(0, __func__, __FILE__, __LINE__,       \
-                                __VA_ARGS__))
-
-# define ok1(e) ((e) ?                                                 \
-                _gen_result(1, __func__, __FILE__, __LINE__, "%s", #e) : \
-                _gen_result(0, __func__, __FILE__, __LINE__, "%s", #e))
-
-# define pass(...) ok(1, __VA_ARGS__);
-# define fail(...) ok(0, __VA_ARGS__);
-
-# define skip_start(test, n, ...)                      \
-       do {                                            \
-               if((test)) {                            \
-                       skip(n,  __VA_ARGS__);          \
-                       continue;                       \
-               }
-#else /* __STDC_VERSION__ */
-# error "Needs gcc or C99 compiler for variadic macros."
-#endif /* __STDC_VERSION__ */
-
-# define skip_end } while(0);
-
-unsigned int _gen_result(int, const char *, char *, unsigned int, char *, ...);
-
-int plan_no_plan(void);
-int plan_skip_all(char *);
-int plan_tests(unsigned int);
-
-unsigned int diag(char *, ...);
-
-int skip(unsigned int, char *, ...);
-
-void todo_start(char *, ...);
-void todo_end(void);
-
-int exit_status(void);