@@@ man wip
authorMark Wooding <mdw@distorted.org.uk>
Tue, 12 Mar 2024 01:20:08 +0000 (01:20 +0000)
committerMark Wooding <mdw@distorted.org.uk>
Tue, 12 Mar 2024 01:20:27 +0000 (01:20 +0000)
76 files changed:
buf/lbuf.3
buf/pkbuf.3
codec/base64.3
codec/bincode.1
codec/codec.3
codec/url.3
hash/crc-mktab.1
hash/crc32.3
hash/t/hash-test.c
hash/unihash-mkstatic.1
hash/unihash.3
mem/alloc.3
mem/arena.3
mem/growbuf.3
mem/pool.3
mem/sub.3
sel/bres.3
sel/conn.3
sel/ident.3
sel/sel.3
sel/selbuf.3
sel/selpk.3
sel/sig.3
struct/assoc.3
struct/atom.3
struct/buf.3
struct/darray.3
struct/dspool.3
struct/dstr.3
struct/hash.3
struct/sym.3
sys/daemonize.3
sys/env.3
sys/fdflags.3
sys/fdpass.3
sys/fwatch.3
sys/lock.3
sys/mdup.3
sys/tv.3
test/Makefile.am
test/bench.3 [new file with mode: 0644]
test/t/tvec-test.c
test/testrig.3
test/tvec-adhoc.3 [new file with mode: 0644]
test/tvec-bench.3 [new file with mode: 0644]
test/tvec-bench.c
test/tvec-core.c
test/tvec-env.3 [new file with mode: 0644]
test/tvec-main.3 [new file with mode: 0644]
test/tvec-output.3 [new file with mode: 0644]
test/tvec-remote.3 [new file with mode: 0644]
test/tvec-remote.c
test/tvec-timeout.3 [new file with mode: 0644]
test/tvec-timeout.c
test/tvec-tyimpl.3 [new file with mode: 0644]
test/tvec-types.3 [new file with mode: 0644]
test/tvec-types.c
test/tvec.3
test/tvec.h
trace/trace.3
ui/mdwopt.3
ui/quis.3
ui/report.3
utils/align.3
utils/bits.3
utils/compiler.3
utils/control.3
utils/exc.3
utils/gprintf.3
utils/linreg.3
utils/macros.3
utils/maths.3
utils/str.3
utils/t/bits-test.c
utils/t/versioncmp-test.c
utils/versioncmp.3

index 0842cb8..001dc9a 100644 (file)
@@ -13,21 +13,21 @@ lbuf \- split lines out of asynchronously received blocks
 .nf
 .ta 2n
 .B "#include <mLib/lbuf.h>"
 .nf
 .ta 2n
 .B "#include <mLib/lbuf.h>"
-
+.PP
 .B "enum {"
 .B "   LBUF_CRLF,"
 .B "   LBUF_STRICTCRLF,"
 .B "   ..."
 .B "};"
 .B "#define LBUF_ENABLE ..."
 .B "enum {"
 .B "   LBUF_CRLF,"
 .B "   LBUF_STRICTCRLF,"
 .B "   ..."
 .B "};"
 .B "#define LBUF_ENABLE ..."
-
+.PP
 .B "typedef struct {"
 .B "   unsigned f;"
 .B "   ..."
 .B "} lbuf;"
 .B "typedef struct {"
 .B "   unsigned f;"
 .B "   ..."
 .B "} lbuf;"
-
+.PP
 .B "typedef void lbuf_func(char *" s ", size_t " len ", void *" p );
 .B "typedef void lbuf_func(char *" s ", size_t " len ", void *" p );
-
+.PP
 .BI "void lbuf_flush(lbuf *" b ", char *" p ", size_t " len );
 .BI "void lbuf_close(lbuf *" b );
 .BI "size_t lbuf_free(lbuf *" b ", char **" p );
 .BI "void lbuf_flush(lbuf *" b ", char *" p ", size_t " len );
 .BI "void lbuf_close(lbuf *" b );
 .BI "size_t lbuf_free(lbuf *" b ", char **" p );
index 50a30fd..dd48a33 100644 (file)
@@ -13,20 +13,20 @@ pkbuf \- split packets out of asynchronously received blocks
 .nf
 .ta 2n
 .B "#include <mLib/pkbuf.h>"
 .nf
 .ta 2n
 .B "#include <mLib/pkbuf.h>"
-
+.PP
 .B "enum {"
 .B "   PKBUF_ENABLE = ..."
 .B "};"
 .B "enum {"
 .B "   PKBUF_ENABLE = ..."
 .B "};"
-
+.PP
 .B "typedef struct {"
 .B "   unsigned f;"
 .B "   ..."
 .B "} pkbuf;"
 .B "typedef struct {"
 .B "   unsigned f;"
 .B "   ..."
 .B "} pkbuf;"
-
+.PP
 .ta \w'\fBtypedef void pkbuf_func('u
 .B "typedef void pkbuf_func(octet *" b ", size_t " sz ", pkbuf *" p ,
 .BI "  size_t *" keep ", void *" p );
 .ta \w'\fBtypedef void pkbuf_func('u
 .B "typedef void pkbuf_func(octet *" b ", size_t " sz ", pkbuf *" p ,
 .BI "  size_t *" keep ", void *" p );
-
+.PP
 .BI "void pkbuf_flush(pkbuf *" pk ", octet *" p ", size_t " len );
 .BI "void pkbuf_close(pkbuf *" pk );
 .BI "size_t pkbuf_free(pkbuf *" pk ", octet **" p );
 .BI "void pkbuf_flush(pkbuf *" pk ", octet *" p ", size_t " len );
 .BI "void pkbuf_close(pkbuf *" pk );
 .BI "size_t pkbuf_free(pkbuf *" pk ", octet **" p );
index 9c44d12..4d3a51a 100644 (file)
@@ -16,14 +16,14 @@ base64, base32, hex \- obsolete binary encoding functions
 .B "#include <mLib/base64.h>"
 .B "#include <mLib/base32.h>"
 .B "#include <mLib/hex.h>"
 .B "#include <mLib/base64.h>"
 .B "#include <mLib/base32.h>"
 .B "#include <mLib/hex.h>"
-
+.PP
 .ta 2n
 .B "typedef struct {"
 .B "   char *indent;"
 .B "   unsigned maxline;"
 .B "   ..."
 .B "} base64_ctx;"
 .ta 2n
 .B "typedef struct {"
 .B "   char *indent;"
 .B "   unsigned maxline;"
 .B "   ..."
 .B "} base64_ctx;"
-
+.PP
 .ta \w'\fBvoid base64_encode('u
 .BI "void base64_encode(base64_ctx *" ctx ,
 .BI "  const void *" p ", size_t " sz ,
 .ta \w'\fBvoid base64_encode('u
 .BI "void base64_encode(base64_ctx *" ctx ,
 .BI "  const void *" p ", size_t " sz ,
@@ -32,14 +32,14 @@ base64, base32, hex \- obsolete binary encoding functions
 .BI "  const void *" p ", size_t " sz ,
 .BI "  dstr *" d );
 .BI "void base64_init(base64_ctx *" ctx );
 .BI "  const void *" p ", size_t " sz ,
 .BI "  dstr *" d );
 .BI "void base64_init(base64_ctx *" ctx );
-
+.PP
 .ta 2n
 .B "typedef struct {"
 .B "   char *indent;"
 .B "   unsigned maxline;"
 .B "   ..."
 .B "} base32_ctx;"
 .ta 2n
 .B "typedef struct {"
 .B "   char *indent;"
 .B "   unsigned maxline;"
 .B "   ..."
 .B "} base32_ctx;"
-
+.PP
 .ta \w'\fBvoid base32_encode('u
 .BI "void base32_encode(base32_ctx *" ctx ,
 .BI "  const void *" p ", size_t " sz ,
 .ta \w'\fBvoid base32_encode('u
 .BI "void base32_encode(base32_ctx *" ctx ,
 .BI "  const void *" p ", size_t " sz ,
@@ -48,14 +48,14 @@ base64, base32, hex \- obsolete binary encoding functions
 .BI "  const void *" p ", size_t " sz ,
 .BI "  dstr *" d );
 .BI "void base32_init(base32_ctx *" ctx );
 .BI "  const void *" p ", size_t " sz ,
 .BI "  dstr *" d );
 .BI "void base32_init(base32_ctx *" ctx );
-
+.PP
 .ta 2n
 .B "typedef struct {"
 .B "   char *indent;"
 .B "   unsigned maxline;"
 .B "   ..."
 .B "} hex_ctx;"
 .ta 2n
 .B "typedef struct {"
 .B "   char *indent;"
 .B "   unsigned maxline;"
 .B "   ..."
 .B "} hex_ctx;"
-
+.PP
 .ta \w'\fBvoid hex_encode('u
 .BI "void hex_encode(hex_ctx *" ctx ,
 .BI "  const void *" p ", size_t " sz ,
 .ta \w'\fBvoid hex_encode('u
 .BI "void hex_encode(hex_ctx *" ctx ,
 .BI "  const void *" p ", size_t " sz ,
index 4e828b7..61fa6ca 100644 (file)
@@ -106,4 +106,4 @@ If an error is encountered, the output may be partially written.
 .BR codec (3).
 .SH "AUTHOR"
 Mark Wooding, <mdw@distorted.org.uk>
 .BR codec (3).
 .SH "AUTHOR"
 Mark Wooding, <mdw@distorted.org.uk>
-
+.PP
index 6f2ccd8..f2a0f29 100644 (file)
@@ -17,7 +17,7 @@ codec \- binary encoding and decoding
 .B "#include <mLib/base64.h>"
 .B "#include <mLib/base32.h>"
 .B "#include <mLib/hex.h>"
 .B "#include <mLib/base64.h>"
 .B "#include <mLib/base32.h>"
 .B "#include <mLib/hex.h>"
-
+.PP
 .B "#define CDCF_LOWERC ..."
 .B "#define CDCF_IGNCASE ..."
 .B "#define CDCF_NOEQPAD ..."
 .B "#define CDCF_LOWERC ..."
 .B "#define CDCF_IGNCASE ..."
 .B "#define CDCF_NOEQPAD ..."
@@ -28,7 +28,7 @@ codec \- binary encoding and decoding
 .B "#define CDCF_IGNINVCH ..."
 .B "#define CDCF_IGNSPC ..."
 .B "#define CDCF_IGNJUNK ..."
 .B "#define CDCF_IGNINVCH ..."
 .B "#define CDCF_IGNSPC ..."
 .B "#define CDCF_IGNJUNK ..."
-
+.PP
 .ta 2n
 .B "enum {"
 .B "   CDCERR_OK = ...,"
 .ta 2n
 .B "enum {"
 .B "   CDCERR_OK = ...,"
@@ -36,7 +36,7 @@ codec \- binary encoding and decoding
 .B "   CDCERR_INVEQPAD = ...,"
 .B "   CDCERR_INVZPAD = ..."
 .B "};"
 .B "   CDCERR_INVEQPAD = ...,"
 .B "   CDCERR_INVZPAD = ..."
 .B "};"
-
+.PP
 .B "typedef struct {"
 .B "   const char *name;"
 .ta 2n +\w'\fBcodec *(*encoder)('u
 .B "typedef struct {"
 .B "   const char *name;"
 .ta 2n +\w'\fBcodec *(*encoder)('u
@@ -45,22 +45,22 @@ codec \- binary encoding and decoding
 .BI "  codec *(*decoder)(unsigned " flags );
 .B "   ...\&"
 .B "} codec_class;"
 .BI "  codec *(*decoder)(unsigned " flags );
 .B "   ...\&"
 .B "} codec_class;"
-
+.PP
 .B "typedef struct {"
 .B "   const codec_ops *ops;"
 .B "} codec;"
 .B "typedef struct {"
 .B "   const codec_ops *ops;"
 .B "} codec;"
-
+.PP
 .B "typedef struct {"
 .B "   const codec_class *c;"
 .BI "  int (*code)(codec *" c ", const void *" p ", size_t " sz ", dstr *" d );
 .BI "  void (*destroy)(codec *" c );
 .B "} codec_ops;"
 .B "typedef struct {"
 .B "   const codec_class *c;"
 .BI "  int (*code)(codec *" c ", const void *" p ", size_t " sz ", dstr *" d );
 .BI "  void (*destroy)(codec *" c );
 .B "} codec_ops;"
-
+.PP
 .B "codec_class null_codec_class;"
 .B "codec_class base64_class, file64_class, base64url_class;"
 .B "codec_class base32_class, base32hex_class;"
 .B "codec_class hex_class;"
 .B "codec_class null_codec_class;"
 .B "codec_class base64_class, file64_class, base64url_class;"
 .B "codec_class base32_class, base32hex_class;"
 .B "codec_class hex_class;"
-
+.PP
 .BI "const char *codec_strerror(int " err ");"
 .fi
 .SH DESCRIPTION
 .BI "const char *codec_strerror(int " err ");"
 .fi
 .SH DESCRIPTION
index 9e8e880..0756808 100644 (file)
 .sp 1
 .fi
 ..
 .sp 1
 .fi
 ..
+.ie t \{\
+.  de VP
+.    sp .4v
+..
+\}
+.el \{\
+.  de VP
+.    sp
+..
+\}
 .TH url 3 "20 June 1999" "Straylight/Edgeware" "mLib utilities library"
 .SH NAME
 url \- manipulation of form-urlencoded strings
 .TH url 3 "20 June 1999" "Straylight/Edgeware" "mLib utilities library"
 .SH NAME
 url \- manipulation of form-urlencoded strings
@@ -21,27 +31,27 @@ url \- manipulation of form-urlencoded strings
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/url.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/url.h>"
-
+.PP
 .ta 2n
 .B "typedef struct {"
 .B "   unsigned f;"
 .B "   ..."
 .B "} url_ectx;"
 .ta 2n
 .B "typedef struct {"
 .B "   unsigned f;"
 .B "   ..."
 .B "} url_ectx;"
-
+.PP
 .B "typedef struct {"
 .B "   unsigned f;"
 .B "   ..."
 .B "} url_dctx;"
 .B "typedef struct {"
 .B "   unsigned f;"
 .B "   ..."
 .B "} url_dctx;"
-
+.PP
 .B "#define URLF_STRICT ..."
 .B "#define URLF_LAX ..."
 .B "#define URLF_SEMI ..."
 .B "#define URLF_STRICT ..."
 .B "#define URLF_LAX ..."
 .B "#define URLF_SEMI ..."
-
+.PP
 .BI "void url_initenc(url_ectx *" ctx );
 .ta \w'\fBvoid url_enc('u
 .BI "void url_enc(url_ectx *" ctx ", dstr *" d ,
 .BI "  const char *" name ", const char *" value );
 .BI "void url_initenc(url_ectx *" ctx );
 .ta \w'\fBvoid url_enc('u
 .BI "void url_enc(url_ectx *" ctx ", dstr *" d ,
 .BI "  const char *" name ", const char *" value );
-
+.PP
 .BI "void url_initdec(url_dctx *" ctx ", const char *" p );
 .BI "int url_dec(url_dctx *" ctx ", dstr *" n ", dstr *" v );
 .fi
 .BI "void url_initdec(url_dctx *" ctx ", const char *" p );
 .BI "int url_dec(url_dctx *" ctx ", dstr *" n ", dstr *" v );
 .fi
@@ -150,19 +160,19 @@ and a urlencoded representation.  The code is untested.
 #include <mLib/dstr.h>
 #include <mLib/sym.h>
 #include <mLib/url.h>
 #include <mLib/dstr.h>
 #include <mLib/sym.h>
 #include <mLib/url.h>
-
+.VP
 typedef struct {
        sym_base _b;
        char *v;
 } val;
 typedef struct {
        sym_base _b;
        char *v;
 } val;
-
+.VP
 void decode(sym_table *t, const char *p)
 {
        url_dctx c;
        dstr n = DSTR_INIT, v = DSTR_INIT;
        val *vv;
        unsigned f;
 void decode(sym_table *t, const char *p)
 {
        url_dctx c;
        dstr n = DSTR_INIT, v = DSTR_INIT;
        val *vv;
        unsigned f;
-
+.VP
        for (url_initdec(&c, p); url_dec(&c, &n, &v); ) {
                vv = sym_find(t, n.buf, -1, sizeof(*vv), &f);
                if (f) free(vv->v);
        for (url_initdec(&c, p); url_dec(&c, &n, &v); ) {
                vv = sym_find(t, n.buf, -1, sizeof(*vv), &f);
                if (f) free(vv->v);
@@ -172,13 +182,13 @@ void decode(sym_table *t, const char *p)
        }
        dstr_destroy(&n); dstr_destroy(&v);
 }
        }
        dstr_destroy(&n); dstr_destroy(&v);
 }
-
+.VP
 void encode(sym_table *t, dstr *d)
 {
        sym_iter i;
        url_ectx c;
        val *v;
 void encode(sym_table *t, dstr *d)
 {
        sym_iter i;
        url_ectx c;
        val *v;
-
+.VP
        url_initenc(&c);
        for (sym_mkiter(&i, t); (v = sym_next(&i)) != 0; )
                url_enc(&c, d, SYM_NAME(v), v->v);
        url_initenc(&c);
        for (sym_mkiter(&i, t); (v = sym_next(&i)) != 0; )
                url_enc(&c, d, SYM_NAME(v), v->v);
index bfbeb8a..d2d75e3 100644 (file)
@@ -169,4 +169,3 @@ an example of use, see the header file
 by Ross N. Williams.
 .SH "AUTHOR"
 Mark Wooding, <mdw@distorted.org.uk>
 by Ross N. Williams.
 .SH "AUTHOR"
 Mark Wooding, <mdw@distorted.org.uk>
-
index 6eca843..a03a208 100644 (file)
@@ -14,7 +14,7 @@ crc32 \- calculate 32-bit CRC
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/crc32.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/crc32.h>"
-
+.PP
 .BI "uint32 crc32(uint32 " crc ", const void *" buf ", size_t " sz );
 .BI CRC32( result ", " crc ", " buf ", " sz )
 .fi
 .BI "uint32 crc32(uint32 " crc ", const void *" buf ", size_t " sz );
 .BI CRC32( result ", " crc ", " buf ", " sz )
 .fi
index 3c637dc..57a6ce8 100644 (file)
@@ -111,20 +111,20 @@ static void run_step(struct tvec_state *tv, tvec_testfn *fn, void *ctx)
 static const struct tvec_env step_testenv = { 0, 0, 0, 0, run_step, 0, 0 };
 
 static const struct tvec_regdef unihash_regs[] = {
 static const struct tvec_env step_testenv = { 0, 0, 0, 0, run_step, 0, 0 };
 
 static const struct tvec_regdef unihash_regs[] = {
-  { "k", RK, &tvty_uint, 0, { &tvrange_u32 } },
-  { "m", RM, &tvty_bytes, 0 },
-  { "h", RH, &tvty_uint, 0, { &tvrange_u32 } },
+  { "k", &tvty_uint, RK, 0, { &tvrange_u32 } },
+  { "m", &tvty_bytes, RM, 0 },
+  { "h", &tvty_uint, RH, 0, { &tvrange_u32 } },
   TVEC_ENDREGS
 };
 
 static const struct tvec_regdef crc32_regs[] = {
   TVEC_ENDREGS
 };
 
 static const struct tvec_regdef crc32_regs[] = {
-  { "m", RM, &tvty_bytes, 0 },
-  { "h", RH, &tvty_uint, 0, { &tvrange_u32 } },
+  { "m", &tvty_bytes, RM, 0 },
+  { "h", &tvty_uint, RH, 0, { &tvrange_u32 } },
   TVEC_ENDREGS
 };
 
 static const struct tvec_regdef bench_regs[] = {
   TVEC_ENDREGS
 };
 
 static const struct tvec_regdef bench_regs[] = {
-  { "msz", RM, &tvty_buffer, TVRF_ID },
+  { "msz", &tvty_buffer, RM, TVRF_ID },
   TVEC_ENDREGS
 };
 
   TVEC_ENDREGS
 };
 
index 09da499..eb3f50b 100644 (file)
@@ -123,4 +123,3 @@ which is, as far as the author knows, as good as any other fixed value.
 .BR unihash (3).
 .SH "AUTHOR"
 Mark Wooding, <mdw@distorted.org.uk>
 .BR unihash (3).
 .SH "AUTHOR"
 Mark Wooding, <mdw@distorted.org.uk>
-
index 72467ac..86ea73b 100644 (file)
@@ -44,11 +44,11 @@ unihash \- simple and efficient universal hashing for hashtables
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/unihash.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/unihash.h>"
-
+.PP
 .B "typedef struct { ...\& } unihash_info;"
 .B "typedef struct { ...\& } unihash_info;"
-
+.PP
 .B "unihash_info unihash_global;"
 .B "unihash_info unihash_global;"
-
+.PP
 .BI "void unihash_setkey(unihash_info *" i ", uint32 " k );
 .BI "uint32 UNIHASH_INIT(const unihash_info *" i );
 .ta \w'\fBuint32 unihash_hash('u
 .BI "void unihash_setkey(unihash_info *" i ", uint32 " k );
 .BI "uint32 UNIHASH_INIT(const unihash_info *" i );
 .ta \w'\fBuint32 unihash_hash('u
index 06ad53d..d974ad8 100644 (file)
@@ -13,12 +13,12 @@ alloc \- mLib low-level memory allocation
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/alloc.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/alloc.h>"
-
+.PP
 .BI "void *x_alloc(arena *" a ", size_t " sz );
 .BI "char *x_strdup(arena *" a ", const char *" s );
 .BI "void *x_realloc(arena *" a ", void *" p ", size_t " sz ", size_t " osz );
 .BI "void x_free(arena *" a ", void *" p );
 .BI "void *x_alloc(arena *" a ", size_t " sz );
 .BI "char *x_strdup(arena *" a ", const char *" s );
 .BI "void *x_realloc(arena *" a ", void *" p ", size_t " sz ", size_t " osz );
 .BI "void x_free(arena *" a ", void *" p );
-
+.PP
 .BI "void *xmalloc(size_t " sz );
 .BI "void *xrealloc(void *" p ", size_t " sz ", size_t " osz );
 .BI "char *xstrdup(const char *" s );
 .BI "void *xmalloc(size_t " sz );
 .BI "void *xrealloc(void *" p ", size_t " sz ", size_t " osz );
 .BI "char *xstrdup(const char *" s );
@@ -66,4 +66,3 @@ allocation from the current arena
 .BR mLib (3).
 .SH AUTHOR
 Mark Wooding, <mdw@distorted.org.uk>
 .BR mLib (3).
 .SH AUTHOR
 Mark Wooding, <mdw@distorted.org.uk>
-
index 51c2227..b7b4d2a 100644 (file)
@@ -14,30 +14,30 @@ arena \- control of memory allocation
 .SH "SYNOPSIS"
 .nf
 .B "#include <mLib/arena.h>"
 .SH "SYNOPSIS"
 .nf
 .B "#include <mLib/arena.h>"
-
+.PP
 .ta 2n
 .B "typedef struct {"
 .B "   const struct arena_ops *ops";
 .B "} arena;"
 .ta 2n
 .B "typedef struct {"
 .B "   const struct arena_ops *ops";
 .B "} arena;"
-
+.PP
 .B "typedef struct {"
 .BI "  void *(*alloc)(arena *" a ", size_t " sz );
 .BI "  void *(*realloc)(arena *" a ", void *" p ", size_t " sz ", size_t " osz );
 .BI "  void *(*free)(arena *" a ", void *" p );
 .BI "  void *(*purge)(arena *" a );
 .B "} arena_ops;"
 .B "typedef struct {"
 .BI "  void *(*alloc)(arena *" a ", size_t " sz );
 .BI "  void *(*realloc)(arena *" a ", void *" p ", size_t " sz ", size_t " osz );
 .BI "  void *(*free)(arena *" a ", void *" p );
 .BI "  void *(*purge)(arena *" a );
 .B "} arena_ops;"
-
+.PP
 .BI "arena *arena_global;"
 .BI "arena arena_stdlib;"
 .BI "arena *arena_global;"
 .BI "arena arena_stdlib;"
-
+.PP
 .ta \w'\fBvoid *arena_fakerealloc('u
 .BI "void *arena_fakerealloc(arena *" a ", void *" p ,
 .BI "  size_t " sz ", size_t " osz );
 .ta \w'\fBvoid *arena_fakerealloc('u
 .BI "void *arena_fakerealloc(arena *" a ", void *" p ,
 .BI "  size_t " sz ", size_t " osz );
-
+.PP
 .BI "void *a_alloc(arena *" a ", size_t " sz );
 .BI "void *a_realloc(arena *" a ", void *" p ", size_t " sz ", size_t " osz );
 .BI "void a_free(arena *" a );
 .BI "void *a_alloc(arena *" a ", size_t " sz );
 .BI "void *a_realloc(arena *" a ", void *" p ", size_t " sz ", size_t " osz );
 .BI "void a_free(arena *" a );
-
+.PP
 .BI "void *A_ALLOC(arena *" a ", size_t " sz );
 .BI "void *A_REALLOC(arena *" a ", void *" p ", size_t " sz ", size_t " osz );
 .BI "void A_FREE(arena *" a );
 .BI "void *A_ALLOC(arena *" a ", size_t " sz );
 .BI "void *A_REALLOC(arena *" a ", void *" p ", size_t " sz ", size_t " osz );
 .BI "void A_FREE(arena *" a );
index c31f27c..bb964a9 100644 (file)
@@ -10,10 +10,10 @@ growbuf \- extend buffers efficiently
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/growbuf.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/growbuf.h>"
-
+.PP
 .BI "GROWBUF_SIZE(size_t " sz ", size_t " want ", " \c
 .BI "size_t " init ", size_t " granule ");"
 .BI "GROWBUF_SIZE(size_t " sz ", size_t " want ", " \c
 .BI "size_t " init ", size_t " granule ");"
-
+.PP
 .ds mT \fBGROWBUF_EXTEND(
 .BI "\*(mTarena *" a ", " type " *" buf ", size_t " sz ", size_t " want ","
 .BI "\h'\w'\*(mT'u'size_t " init ", size_t " granule ");"
 .ds mT \fBGROWBUF_EXTEND(
 .BI "\*(mTarena *" a ", " type " *" buf ", size_t " sz ", size_t " want ","
 .BI "\h'\w'\*(mT'u'size_t " init ", size_t " granule ");"
index 38538a8..1885874 100644 (file)
@@ -28,20 +28,20 @@ pool \- resource pool management
 .SH "SYNOPSIS"
 .nf
 .B "#include <mLib/pool.h>"
 .SH "SYNOPSIS"
 .nf
 .B "#include <mLib/pool.h>"
-
+.PP
 .B "typedef struct { ...\& } pool;"
 .B "typedef struct { ...\& } pool;"
-
+.PP
 .ta 2n
 .B "typedef struct {"
 .B "   pool_resource *next;"
 .BI "  void (*destroy)(pool_resource *" r );
 .B "} pool_resource;"
 .ta 2n
 .B "typedef struct {"
 .B "   pool_resource *next;"
 .BI "  void (*destroy)(pool_resource *" r );
 .B "} pool_resource;"
-
+.PP
 .B "typedef struct {"
 .B "   FILE *fp;"
 .B "   ..."
 .B "} pool_file;"
 .B "typedef struct {"
 .B "   FILE *fp;"
 .B "   ..."
 .B "} pool_file;"
-
+.PP
 .BI "void pool_init(pool *" p ", arena *" a );
 .BI "pool *pool_create(arena *" a );
 .BI "pool *pool_sub(pool *" p );
 .BI "void pool_init(pool *" p ", arena *" a );
 .BI "pool *pool_create(arena *" a );
 .BI "pool *pool_sub(pool *" p );
@@ -54,7 +54,7 @@ pool \- resource pool management
 .BI "pool_file *pool_fopen(pool *" p ", const char *" file ", const char *" how );
 .BI "int pool_fclose(pool_file *" pf );
 .BI "subarena *pool_subarena(pool *" p );
 .BI "pool_file *pool_fopen(pool *" p ", const char *" file ", const char *" how );
 .BI "int pool_fclose(pool_file *" pf );
 .BI "subarena *pool_subarena(pool *" p );
-
+.PP
 .ta \w'\fBvoid POOL_ADD('u
 .BI "void POOL_ADD(pool *" p ", pool_resource *" r ,
 .BI "  void (*" dfn ")(pool_resource *" r ));
 .ta \w'\fBvoid POOL_ADD('u
 .BI "void POOL_ADD(pool *" p ", pool_resource *" r ,
 .BI "  void (*" dfn ")(pool_resource *" r ));
index c41041f..23e751d 100644 (file)
--- a/mem/sub.3
+++ b/mem/sub.3
@@ -30,18 +30,18 @@ sub \- efficient allocation and freeing of small blocks
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/sub.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/sub.h>"
-
+.PP
 .B "typedef struct { ...\& } subarena;"
 .B "typedef struct { ...\& } subarena;"
-
+.PP
 .BI "void subarena_create(subarena *" s ", arena *" a );
 .BI "void subarena_destroy(subarena *" s );
 .BI "void subarena_alloc(subarena *" s ", size_t " sz );
 .BI "void subarena_free(subarena *" s ", void *" p ", size_t " sz );
 .BI "void subarena_create(subarena *" s ", arena *" a );
 .BI "void subarena_destroy(subarena *" s );
 .BI "void subarena_alloc(subarena *" s ", size_t " sz );
 .BI "void subarena_free(subarena *" s ", void *" p ", size_t " sz );
-
+.PP
 .B "void sub_init(void);"
 .BI "void *sub_alloc(size_t " sz );
 .BI "void sub_free(void *" p ", size_t " sz );
 .B "void sub_init(void);"
 .BI "void *sub_alloc(size_t " sz );
 .BI "void sub_free(void *" p ", size_t " sz );
-
+.PP
 .BI "void *A_CREATE(subarena *" s ", " type );
 .BI "void A_DESTROY(subarena *" s ", " type " *" p );
 .BI "void *CREATE(" type );
 .BI "void *A_CREATE(subarena *" s ", " type );
 .BI "void A_DESTROY(subarena *" s ", " type " *" p );
 .BI "void *CREATE(" type );
index b5539b0..cce20c2 100644 (file)
@@ -10,9 +10,9 @@ bres \- background name resolver
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/bres.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/bres.h>"
-
+.PP
 .B "typedef struct { ...\& } bres_client;"
 .B "typedef struct { ...\& } bres_client;"
-
+.PP
 .ta \w'\fBvoid bres_byname('u
 .BI "void bres_byname(bres_client *" rc ", const char *" name ,
 .BI "  void (*" func ")(struct hostent *" h ", void *" p ),
 .ta \w'\fBvoid bres_byname('u
 .BI "void bres_byname(bres_client *" rc ", const char *" name ,
 .BI "  void (*" func ")(struct hostent *" h ", void *" p ),
index 1ff936f..d02a711 100644 (file)
@@ -8,20 +8,20 @@ conn \- selector for nonblocking connections
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/conn.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/conn.h>"
-
+.PP
 .B "typedef struct { ...\& } conn;"
 .B "typedef struct { ...\& } conn;"
-
+.PP
 .ta \w'\fBint conn_fd('u
 .BI "int conn_fd(conn *" c ", sel_state *" s ", int " fd ,
 .BI "  void (*" func ")(int " fd ", void *" p ),
 .BI "  void *" p );
 .ta \w'\fBint conn_fd('u
 .BI "int conn_fd(conn *" c ", sel_state *" s ", int " fd ,
 .BI "  void (*" func ")(int " fd ", void *" p ),
 .BI "  void *" p );
-
+.PP
 .ta \w'\fBint conn_init('u
 .BI "int conn_init(conn *" c ", sel_state *" s ", int " fd ,
 .BI "  struct sockaddr *" dst ", int " dsz ,
 .BI "  void (*" func ")(int " fd ", void *" p ),
 .BI "  void *" p );
 .ta \w'\fBint conn_init('u
 .BI "int conn_init(conn *" c ", sel_state *" s ", int " fd ,
 .BI "  struct sockaddr *" dst ", int " dsz ,
 .BI "  void (*" func ")(int " fd ", void *" p ),
 .BI "  void *" p );
-
+.PP
 .BI "void conn_kill(conn *" c );
 .fi
 .SH DESCRIPTION
 .BI "void conn_kill(conn *" c );
 .fi
 .SH DESCRIPTION
index aebf903..69b3fe7 100644 (file)
@@ -8,16 +8,16 @@ ident \- identd (RFC931) client
 .SH "SYNOPSIS"
 .nf
 .B "#include <mLib/ident>"
 .SH "SYNOPSIS"
 .nf
 .B "#include <mLib/ident>"
-
+.PP
 .B "typedef struct { ...\& } ident_request;"
 .B "typedef struct { ...\& } ident_request;"
-
+.PP
 .ta 2n +2n
 .B "enum ["
 .B "   IDENT_USERID = ...,"
 .B "   IDENT_ERROR = ...,"
 .B "   IDENT_BAD = ..."
 .B "};"
 .ta 2n +2n
 .B "enum ["
 .B "   IDENT_USERID = ...,"
 .B "   IDENT_ERROR = ...,"
 .B "   IDENT_BAD = ..."
 .B "};"
-
+.PP
 .B "typedef struct {"
 .B "   unsigned short sport, dport;"
 .B "   unsigned type;"
 .B "typedef struct {"
 .B "   unsigned short sport, dport;"
 .B "   unsigned type;"
@@ -26,7 +26,7 @@ ident \- identd (RFC931) client
 .B "           char *error;"
 .B "   } u;"
 .B "} ident_reply;"
 .B "           char *error;"
 .B "   } u;"
 .B "} ident_reply;"
-
+.PP
 .BI "void ident_abort(ident_request *" rq );
 .ta \w'\fBvoid ident('u
 .BI "void ident(ident_request *" rq ", sel_state *" s ,
 .BI "void ident_abort(ident_request *" rq );
 .ta \w'\fBvoid ident('u
 .BI "void ident(ident_request *" rq ", sel_state *" s ,
index e312277..da55fe8 100644 (file)
--- a/sel/sel.3
+++ b/sel/sel.3
@@ -16,7 +16,7 @@ sel \- low level interface for waiting for I/O
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/sel.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/sel.h>"
-
+.PP
 .ta 2n
 .B "enum {"
 .B "   SEL_READ = ...,"
 .ta 2n
 .B "enum {"
 .B "   SEL_READ = ...,"
@@ -24,27 +24,27 @@ sel \- low level interface for waiting for I/O
 .B "   SEL_EXC = ...,"
 .B "   SEL_MODES = ..."
 .B "};"
 .B "   SEL_EXC = ...,"
 .B "   SEL_MODES = ..."
 .B "};"
-
+.PP
 .B "typedef struct { ...\& } sel_state;"
 .B "typedef struct { ...\& } sel_timer;"
 .B "typedef struct { ...\& } sel_hook;"
 .B "typedef struct { ...\& } sel_state;"
 .B "typedef struct { ...\& } sel_timer;"
 .B "typedef struct { ...\& } sel_hook;"
-
+.PP
 .B "typedef struct {"
 .B "   int fd;"
 .B "   ..."
 .B "} sel_file;"
 .B "typedef struct {"
 .B "   int fd;"
 .B "   ..."
 .B "} sel_file;"
-
+.PP
 .B "typedef struct {"
 .B "   int maxfd;"
 .B "   fd_set fd[SEL_MODES];"
 .B "   struct timeval tv, *tvp;"
 .B "   struct timeval now;"
 .B "} sel_args;"
 .B "typedef struct {"
 .B "   int maxfd;"
 .B "   fd_set fd[SEL_MODES];"
 .B "   struct timeval tv, *tvp;"
 .B "   struct timeval now;"
 .B "} sel_args;"
-
+.PP
 .BI "typedef void (*sel_hookfn)(sel_state *" s ", sel_args *" a ", void *" p );
 .BI "typedef void (*sel_hookfn)(sel_state *" s ", sel_args *" a ", void *" p );
-
+.PP
 .BI "void sel_init(sel_state *" s );
 .BI "void sel_init(sel_state *" s );
-
+.PP
 .ta \w'\fBvoid sel_initfile('u
 .BI "void sel_initfile(sel_state *" s ", sel_file *" f ,
 .BI "  int " fd ", unsigned " mode ,
 .ta \w'\fBvoid sel_initfile('u
 .BI "void sel_initfile(sel_state *" s ", sel_file *" f ,
 .BI "  int " fd ", unsigned " mode ,
@@ -53,22 +53,22 @@ sel \- low level interface for waiting for I/O
 .BI "void sel_addfile(sel_file *" f );
 .BI "void sel_force(sel_file *" f );
 .BI "void sel_rmfile(sel_file *" f );
 .BI "void sel_addfile(sel_file *" f );
 .BI "void sel_force(sel_file *" f );
 .BI "void sel_rmfile(sel_file *" f );
-
+.PP
 .ta \w'\fBvoid sel_addtimer('u
 .BI "void sel_addtimer(sel_state *" s ", sel_timer *" t ,
 .BI "  struct timeval *" tv ,
 .BI "  void (*" func ")(struct timeval *" tv ", void *" p ),
 .BI "  void *" p );
 .BI "void sel_rmtimer(sel_timer *" t );
 .ta \w'\fBvoid sel_addtimer('u
 .BI "void sel_addtimer(sel_state *" s ", sel_timer *" t ,
 .BI "  struct timeval *" tv ,
 .BI "  void (*" func ")(struct timeval *" tv ", void *" p ),
 .BI "  void *" p );
 .BI "void sel_rmtimer(sel_timer *" t );
-
+.PP
 .ta \w'\fBvoid sel_addhook('u
 .BI "void sel_addtimer(sel_state *" s ", sel_hook *" h ,
 .BI "  sel_hookfn " before ", sel_hookfn " after ,
 .BI "  void *" p );
 .BI "void sel_rmhook(sel_hook *" h );
 .ta \w'\fBvoid sel_addhook('u
 .BI "void sel_addtimer(sel_state *" s ", sel_hook *" h ,
 .BI "  sel_hookfn " before ", sel_hookfn " after ,
 .BI "  void *" p );
 .BI "void sel_rmhook(sel_hook *" h );
-
+.PP
 .BI "int sel_fdmerge(fd_set *" dest ", fd_set *" fd ", int " maxfd );
 .BI "int sel_fdmerge(fd_set *" dest ", fd_set *" fd ", int " maxfd );
-
+.PP
 .BI "int sel_select(sel_state *" s );
 .fi
 .SH "OVERVIEW"
 .BI "int sel_select(sel_state *" s );
 .fi
 .SH "OVERVIEW"
index 5db9a71..a2d345a 100644 (file)
@@ -10,9 +10,9 @@ selbuf \- line-buffering input selector
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/selbuf.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/selbuf.h>"
-
+.PP
 .B "typedef struct { ...\& } selbuf;"
 .B "typedef struct { ...\& } selbuf;"
-
+.PP
 .BI "void selbuf_enable(selbuf *" b );
 .BI "void selbuf_disable(selbuf *" b );
 .BI "void selbuf_setsize(selbuf *" b ", size_t " sz );
 .BI "void selbuf_enable(selbuf *" b );
 .BI "void selbuf_disable(selbuf *" b );
 .BI "void selbuf_setsize(selbuf *" b ", size_t " sz );
index 5a3a0ff..e945c82 100644 (file)
@@ -10,9 +10,9 @@ selpk \- packet-buffering input selector
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/selpk.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/selpk.h>"
-
+.PP
 .B "typedef struct { ...\& } selpk;"
 .B "typedef struct { ...\& } selpk;"
-
+.PP
 .BI "void selpk_enable(selpk *" pk );
 .BI "void selpk_disable(selpk *" pk );
 .BI "void selpk_want(selpk *" pk ", size_t " sz );
 .BI "void selpk_enable(selpk *" pk );
 .BI "void selpk_disable(selpk *" pk );
 .BI "void selpk_want(selpk *" pk ", size_t " sz );
index 725f859..511b96d 100644 (file)
--- a/sel/sig.3
+++ b/sel/sig.3
@@ -8,9 +8,9 @@ sig \- more controlled signal handling
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/sig.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/sig.h>"
-
+.PP
 .B "typedef struct { ...\& } sig;"
 .B "typedef struct { ...\& } sig;"
-
+.PP
 .ta \w'\fBvoid sig_add('u
 .BI "void sig_add(sig *" s ", int " n ,
 .BI "  void (*" proc ")(int " n ", void *" p "), void *" p );
 .ta \w'\fBvoid sig_add('u
 .BI "void sig_add(sig *" s ", int " n ,
 .BI "  void (*" proc ")(int " n ", void *" p "), void *" p );
index cbec2c2..9f65b8e 100644 (file)
@@ -26,18 +26,18 @@ assoc \- tables indexed by atoms
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/assoc.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/assoc.h>"
-
+.PP
 .B "typedef struct { ...\& } assoc_table;"
 .B "typedef struct { ...\& } assoc_base;"
 .B "typedef struct { ...\& } assoc_table;"
 .B "typedef struct { ...\& } assoc_base;"
-
+.PP
 .BI "void assoc_create(assoc_table *" t );
 .BI "void assoc_destroy(assoc_table *" t );
 .BI "void assoc_create(assoc_table *" t );
 .BI "void assoc_destroy(assoc_table *" t );
-
+.PP
 .BI "void *assoc_find(assoc_table *" t ", atom *" a ", size_t " sz ", unsigned *" f );
 .BI "void assoc_remove(assoc_table *" t ", void *" b );
 .BI "void *assoc_find(assoc_table *" t ", atom *" a ", size_t " sz ", unsigned *" f );
 .BI "void assoc_remove(assoc_table *" t ", void *" b );
-
+.PP
 .BI "atom *ASSOC_ATOM(const void *" p );
 .BI "atom *ASSOC_ATOM(const void *" p );
-
+.PP
 .BI "void assoc_mkiter(assoc_iter *" i ", assoc_table *" t );
 .BI "void *assoc_next(assoc_iter *" i );
 .fi
 .BI "void assoc_mkiter(assoc_iter *" i ", assoc_table *" t );
 .BI "void *assoc_next(assoc_iter *" i );
 .fi
index e5ecf00..35d30f9 100644 (file)
@@ -35,29 +35,29 @@ atom \- atom table manager
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/atom.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/atom.h>"
-
+.PP
 .B "typedef struct { ...\& } atom_table;"
 .B "typedef struct { ...\& } atom;"
 .B "typedef struct { ...\& } atom_table;"
 .B "typedef struct { ...\& } atom;"
-
+.PP
 .BI "void atom_createtable(atom_table *" t );
 .BI "void atom_destroytable(atom_table *" t );
 .BI "void atom_createtable(atom_table *" t );
 .BI "void atom_destroytable(atom_table *" t );
-
+.PP
 .BI "atom *atom_intern(atom_table *" t ", const char *" p );
 .BI "atom *atom_nintern(atom_table *" t ", const char *" p ", size_t " n );
 .BI "atom *atom_gensym(atom_table *" t );
 .BI "atom *INTERN(const char *" p );
 .BI "atom *GENSYM;"
 .BI "atom *atom_intern(atom_table *" t ", const char *" p );
 .BI "atom *atom_nintern(atom_table *" t ", const char *" p ", size_t " n );
 .BI "atom *atom_gensym(atom_table *" t );
 .BI "atom *INTERN(const char *" p );
 .BI "atom *GENSYM;"
-
+.PP
 .BI "const char *atom_name(const atom *" a );
 .BI "size_t atom_len(const atom *" a );
 .BI "uint32 atom_hash(const atom *" a );
 .BI "const char *ATOM_NAME(const atom *" a );
 .BI "size_t ATOM_LEN(const atom *" a );
 .BI "uint32 ATOM_HASH(const atom *" a );
 .BI "const char *atom_name(const atom *" a );
 .BI "size_t atom_len(const atom *" a );
 .BI "uint32 atom_hash(const atom *" a );
 .BI "const char *ATOM_NAME(const atom *" a );
 .BI "size_t ATOM_LEN(const atom *" a );
 .BI "uint32 ATOM_HASH(const atom *" a );
-
+.PP
 .BI "void atom_mkiter(atom_iter *" i ", atom_table *" t );
 .BI "atom *atom_next(atom_iter *" i );
 .BI "void atom_mkiter(atom_iter *" i ", atom_table *" t );
 .BI "atom *atom_next(atom_iter *" i );
-
+.PP
 .BI "extern atom_table *ATOM_GLOBAL;"
 .fi
 .SH DESCRIPTION
 .BI "extern atom_table *ATOM_GLOBAL;"
 .fi
 .SH DESCRIPTION
index 3b3ef7c..ccb8dc1 100644 (file)
@@ -34,7 +34,7 @@ buf \- reading and writing stuff in buffers
 .\" @BBAD
 .\" @BOK
 .\" @BENSURE
 .\" @BBAD
 .\" @BOK
 .\" @BENSURE
-
+.
 .\" @DBBASE
 .\" @DBLIM
 .\" @DBCUR
 .\" @DBBASE
 .\" @DBLIM
 .\" @DBCUR
@@ -459,10 +459,10 @@ buf \- reading and writing stuff in buffers
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/dstr.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/dstr.h>"
-
+.PP
 .B "typedef struct { ...\& } buf;"
 .B "typedef struct { ...\& } dbuf;"
 .B "typedef struct { ...\& } buf;"
 .B "typedef struct { ...\& } dbuf;"
-
+.PP
 .BI "void buf_init(buf *" b ", void *" p ", size_t " sz );
 .BI "void dbuf_create(dbuf *" db );
 .BI "void dbuf_reset(dbuf *" db );
 .BI "void buf_init(buf *" b ", void *" p ", size_t " sz );
 .BI "void dbuf_create(dbuf *" db );
 .BI "void dbuf_reset(dbuf *" db );
@@ -472,7 +472,7 @@ buf \- reading and writing stuff in buffers
 .BI "void DBRESET(dbuf *" db );
 .BI "void DBDESTROY(dbuf *" db );
 .B "#define DBUF_INIT ..."
 .BI "void DBRESET(dbuf *" db );
 .BI "void DBDESTROY(dbuf *" db );
 .B "#define DBUF_INIT ..."
-
+.PP
 .fi
 All of the following functions and macros exist in two variants:
 one with a name beginning
 .fi
 All of the following functions and macros exist in two variants:
 one with a name beginning
@@ -490,7 +490,7 @@ or
 and taking a first argument of type
 .BR "dbuf *" .
 .nf
 and taking a first argument of type
 .BR "dbuf *" .
 .nf
-
+.PP
 .BI "void buf_flip(buf *" b );
 .BI "octet *BBASE(buf *" b );
 .BI "octet *BLIM(buf *" b );
 .BI "void buf_flip(buf *" b );
 .BI "octet *BBASE(buf *" b );
 .BI "octet *BLIM(buf *" b );
@@ -499,26 +499,26 @@ and taking a first argument of type
 .BI "ptrdiff_t BLEN(buf *" b );
 .BI "ptrdiff_t BLEFT(buf *" b );
 .BI "void BFLIP(buf *" b );
 .BI "ptrdiff_t BLEN(buf *" b );
 .BI "ptrdiff_t BLEFT(buf *" b );
 .BI "void BFLIP(buf *" b );
-
+.PP
 .BI "int buf_break(buf *" b );
 .BI "int BBREAK(buf *" b );
 .BI "int BBAD(buf *" b );
 .BI "int BOK(buf *" b );
 .BI "int buf_break(buf *" b );
 .BI "int BBREAK(buf *" b );
 .BI "int BBAD(buf *" b );
 .BI "int BOK(buf *" b );
-
+.PP
 .BI "int buf_ensure(buf *" b ", size_t " sz );
 .BI "int buf_tryextend(buf *" b ", size_t " sz );
 .BI "int BENSURE(buf *" b ", size_t " sz );
 .BI "octet *BSTEP(buf *" b ", size_t " sz );
 .BI "int buf_ensure(buf *" b ", size_t " sz );
 .BI "int buf_tryextend(buf *" b ", size_t " sz );
 .BI "int BENSURE(buf *" b ", size_t " sz );
 .BI "octet *BSTEP(buf *" b ", size_t " sz );
-
+.PP
 .BI "void *buf_get(buf *" b ", size_t " sz );
 .BI "void *buf_put(buf *" b ", const void *" p ", size_t " sz );
 .BI "void *buf_get(buf *" b ", size_t " sz );
 .BI "void *buf_put(buf *" b ", const void *" p ", size_t " sz );
-
+.PP
 .BI "int buf_getbyte(buf *" b );
 .BI "int buf_putbyte(buf *" b ", int " ch );
 .BI "int buf_getbyte(buf *" b );
 .BI "int buf_putbyte(buf *" b ", int " ch );
-
+.PP
 .BI "int buf_putstr(buf *" b ", const char *" p ", ...);"
 .BI "int buf_vputstr(buf *" b ", const char *" p ", va_list *" ap );
 .BI "int buf_putstr(buf *" b ", const char *" p ", ...);"
 .BI "int buf_vputstr(buf *" b ", const char *" p ", va_list *" ap );
-
+.PP
 .fi
 For
 .I suff
 .fi
 For
 .I suff
@@ -542,7 +542,7 @@ and
 .nf
 .BI "int buf_putu" suff "(buf *" b ", uint" suff " " w );
 .BI "int buf_getu" suff "(buf *" b ", uint" suff " *" w );
 .nf
 .BI "int buf_putu" suff "(buf *" b ", uint" suff " " w );
 .BI "int buf_getu" suff "(buf *" b ", uint" suff " *" w );
-
+.PP
 .fi
 For
 .I suff
 .fi
 For
 .I suff
@@ -554,7 +554,7 @@ and
 .nf
 .BI "int buf_putk" suff "(buf *" b ", kludge64 " w );
 .BI "int buf_getk" suff "(buf *" b ", kludge64 *" w );
 .nf
 .BI "int buf_putk" suff "(buf *" b ", kludge64 " w );
 .BI "int buf_getk" suff "(buf *" b ", kludge64 *" w );
-
+.PP
 .ta 2n
 .BI "BUF_ENCLOSETAG(" tag ", buf *" b ", size_t " mk ", " check ", " poke ", size_t " lensz )
 .I "   body"
 .ta 2n
 .BI "BUF_ENCLOSETAG(" tag ", buf *" b ", size_t " mk ", " check ", " poke ", size_t " lensz )
 .I "   body"
@@ -564,7 +564,7 @@ and
 .I "   body"
 .BI "BUF_ENCLOSEZTAG(" tag ", buf *" b )
 .I "   body"
 .I "   body"
 .BI "BUF_ENCLOSEZTAG(" tag ", buf *" b )
 .I "   body"
-
+.PP
 .fi
 For
 .I suff
 .fi
 For
 .I suff
@@ -587,10 +587,10 @@ and
 .ta 2n
 .BI "BUF_ENCLOSE" suff "(buf *" b ", size_t " mk )
 .I "   body"
 .ta 2n
 .BI "BUF_ENCLOSE" suff "(buf *" b ", size_t " mk )
 .I "   body"
-
+.PP
 .BI "BUF_ENCLOSEZ(buf *" b )
 .I "   body"
 .BI "BUF_ENCLOSEZ(buf *" b )
 .I "   body"
-
+.PP
 .fi
 For
 .I suff
 .fi
 For
 .I suff
@@ -629,7 +629,7 @@ and
 .BI "int dbuf_putmem" suff "(dbuf *" db ", const void *" p ", size_t " sz );
 .BI "void *buf_getmem" suff "(buf *" b ", size_t *" sz );
 .BI "void d*buf_getmem" suff "(dbuf *" db ", size_t *" sz );
 .BI "int dbuf_putmem" suff "(dbuf *" db ", const void *" p ", size_t " sz );
 .BI "void *buf_getmem" suff "(buf *" b ", size_t *" sz );
 .BI "void d*buf_getmem" suff "(dbuf *" db ", size_t *" sz );
-
+.PP
 .fi
 For
 .I suff
 .fi
 For
 .I suff
index 6037c74..c01a594 100644 (file)
@@ -57,51 +57,51 @@ darray \- dense, dynamically resizing arrays
 .SH "SYNOPSIS"
 .nf
 .B "#include <mLib/darray.h>"
 .SH "SYNOPSIS"
 .nf
 .B "#include <mLib/darray.h>"
-
+.PP
 .ta 2n
 .B "typedef struct {"
 .B "   size_t sz, len, off;"
 .B "   unsigned push, unshift;"
 .B "   arena *a;"
 .B "} da_base;"
 .ta 2n
 .B "typedef struct {"
 .B "   size_t sz, len, off;"
 .B "   unsigned push, unshift;"
 .B "   arena *a;"
 .B "} da_base;"
-
+.PP
 .B "#define DA_INIT ..."
 .B "#define DA_INIT ..."
-
+.PP
 .B "#define DAEXC_UFLOW EXC_ALLOCN(EXC_MLIB, ...)"
 .B "#define DAEXC_OFLOW EXC_ALLOCN(EXC_MLIB, ...)"
 .B "#define DAEXC_UFLOW EXC_ALLOCN(EXC_MLIB, ...)"
 .B "#define DAEXC_OFLOW EXC_ALLOCN(EXC_MLIB, ...)"
-
+.PP
 .BI DA_DECL( type_v ", " type );
 .BI "void DA_CREATE(" type_v " *" a );
 .BI "void DA_DESTROY(" type_v " *" a );
 .BI DA_DECL( type_v ", " type );
 .BI "void DA_CREATE(" type_v " *" a );
 .BI "void DA_DESTROY(" type_v " *" a );
-
+.PP
 .BI "void DA_ENSURE(" type_v " *" a ", size_t " n );
 .BI "void DA_SHUNT(" type_v " *" a ", size_t " n );
 .BI "void DA_TIDY(" type_v " *" a );
 .BI "void DA_RESET(" type_v " *" a );
 .BI "void DA_ENSURE(" type_v " *" a ", size_t " n );
 .BI "void DA_SHUNT(" type_v " *" a ", size_t " n );
 .BI "void DA_TIDY(" type_v " *" a );
 .BI "void DA_RESET(" type_v " *" a );
-
+.PP
 .IB type " *DA(" type_v " *" a );
 .BI "size_t DA_LEN(" type_v " *" a );
 .BI "size_t DA_SPARE(" type_v " *" a );
 .BI "size_t DA_OFFSET(" type_v " *" a );
 .BI "void DA_INCLUDE(" type_v " *" a ", size_t " i );
 .IB type " *DA(" type_v " *" a );
 .BI "size_t DA_LEN(" type_v " *" a );
 .BI "size_t DA_SPARE(" type_v " *" a );
 .BI "size_t DA_OFFSET(" type_v " *" a );
 .BI "void DA_INCLUDE(" type_v " *" a ", size_t " i );
-
+.PP
 .BI "void DA_EXTEND(" type_v " *" a ", long " n );
 .BI "void DA_SHRINK(" type_v " *" a ", long " n );
 .BI "void DA_SLIDE(" type_v " *" a ", long " n );
 .BI "void DA_UNSLIDE(" type_v " *" a ", long " n );
 .BI "void DA_EXTEND(" type_v " *" a ", long " n );
 .BI "void DA_SHRINK(" type_v " *" a ", long " n );
 .BI "void DA_SLIDE(" type_v " *" a ", long " n );
 .BI "void DA_UNSLIDE(" type_v " *" a ", long " n );
-
+.PP
 .BI "void DA_UNSAFE_EXTEND(" type_v " *" a ", long " n );
 .BI "void DA_UNSAFE_SHRINK(" type_v " *" a ", long " n );
 .BI "void DA_UNSAFE_SLIDE(" type_v " *" a ", long " n );
 .BI "void DA_UNSAFE_UNSLIDE(" type_v " *" a ", long " n );
 .BI "void DA_UNSAFE_EXTEND(" type_v " *" a ", long " n );
 .BI "void DA_UNSAFE_SHRINK(" type_v " *" a ", long " n );
 .BI "void DA_UNSAFE_SLIDE(" type_v " *" a ", long " n );
 .BI "void DA_UNSAFE_UNSLIDE(" type_v " *" a ", long " n );
-
+.PP
 .IB type " DA_FIRST(" type_v " *" a );
 .IB type " DA_LAST(" type_v " *" a );
 .BI "void DA_PUSH(" type_v " *" a ", " type " " x );
 .IB type " DA_POP(" type_v " *" a );
 .BI "void DA_UNSHIFT(" type_v " *" a ", " type " " x );
 .IB type " DA_SHIFT(" type_v " *" a );
 .IB type " DA_FIRST(" type_v " *" a );
 .IB type " DA_LAST(" type_v " *" a );
 .BI "void DA_PUSH(" type_v " *" a ", " type " " x );
 .IB type " DA_POP(" type_v " *" a );
 .BI "void DA_UNSHIFT(" type_v " *" a ", " type " " x );
 .IB type " DA_SHIFT(" type_v " *" a );
-
+.PP
 .BI "void *da_ensure(da_base *" b ", void *" v ", size_t " sz ", size_t " n );
 .BI "void *da_shunt(da_base *" b ", void *" v ", size_t " sz ", size_t " n );
 .BI "void *da_tidy(da_base *" b ", void *" v ", size_t " sz );
 .BI "void *da_ensure(da_base *" b ", void *" v ", size_t " sz ", size_t " n );
 .BI "void *da_shunt(da_base *" b ", void *" v ", size_t " sz ", size_t " n );
 .BI "void *da_tidy(da_base *" b ", void *" v ", size_t " sz );
@@ -134,9 +134,10 @@ declared separately from the array, it's also conventional to declare a
 macro with the same name as the array type only in uppercase which may
 be used to prevent multiple declarations, e.g.,
 .VS
 macro with the same name as the array type only in uppercase which may
 be used to prevent multiple declarations, e.g.,
 .VS
+.ta 2n
 #ifndef FOO_V
 #ifndef FOO_V
-#  define FOO_V
-   DA_DECL(foo_v, foo);
+#      define FOO_V
+       DA_DECL(foo_v, foo);
 #endif
 .VE
 The macro
 #endif
 .VE
 The macro
@@ -360,9 +361,10 @@ miss.
 .PP
 Dynamic arrays are structures with the format
 .VS
 .PP
 Dynamic arrays are structures with the format
 .VS
+.ta 2n
 .BI "typedef struct " type_v " {"
 .BI "typedef struct " type_v " {"
-.B "  da_base b;"
-.BI "  " type " *v;"
+.B "   da_base b;"
+.BI "  " type " *v;"
 .BI "} " type_v ";"
 .VE
 The pointer
 .BI "} " type_v ";"
 .VE
 The pointer
index 9d2ab00..dd6dbd9 100644 (file)
@@ -25,14 +25,14 @@ dspool \- pools of preallocated dynamic strings
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/dspool.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/dspool.h>"
-
+.PP
 .B "typedef struct { ...\& } dspool;"
 .B "typedef struct { ...\& } dspool;"
-
+.PP
 .BI "void dspool_create(dspool *" p ", size_t " isz );
 .BI "void dspool_destroy(dspool *" p );
 .BI "dstr *dspool_get(dspool *" p );
 .BI "void dspool_put(dspool *" p ", dstr *" d );
 .BI "void dspool_create(dspool *" p ", size_t " isz );
 .BI "void dspool_destroy(dspool *" p );
 .BI "dstr *dspool_get(dspool *" p );
 .BI "void dspool_put(dspool *" p ", dstr *" d );
-
+.PP
 .BI "void DSGET(dspool *" p ", " d );
 .BI "void DSPUT(dspool *" p ", dstr *" d );
 .fi
 .BI "void DSGET(dspool *" p ", " d );
 .BI "void DSPUT(dspool *" p ", dstr *" d );
 .fi
index 1aadd35..8608d55 100644 (file)
@@ -52,17 +52,17 @@ dstr \- a simple dynamic string type
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/dstr.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/dstr.h>"
-
+.PP
 .B "typedef struct { ...\& } dstr;"
 .B "#define DSTR_INIT ..."
 .B "typedef struct { ...\& } dstr;"
 .B "#define DSTR_INIT ..."
-
+.PP
 .BI "void dstr_create(dstr *" d );
 .BI "void dstr_destroy(dstr *" d );
 .BI "void dstr_reset(dstr *" d );
 .BI "void dstr_create(dstr *" d );
 .BI "void dstr_destroy(dstr *" d );
 .BI "void dstr_reset(dstr *" d );
-
+.PP
 .BI "void dstr_ensure(dstr *" d ", size_t " sz );
 .BI "void dstr_tidy(dstr *" d );
 .BI "void dstr_ensure(dstr *" d ", size_t " sz );
 .BI "void dstr_tidy(dstr *" d );
-
+.PP
 .BI "void dstr_putc(dstr *" d ", int " ch );
 .BI "void dstr_putz(dstr *" d );
 .BI "void dstr_puts(dstr *" d ", const char *" s );
 .BI "void dstr_putc(dstr *" d ", int " ch );
 .BI "void dstr_putz(dstr *" d );
 .BI "void dstr_puts(dstr *" d ", const char *" s );
@@ -72,7 +72,7 @@ dstr \- a simple dynamic string type
 .BI "void dstr_putm(dstr *" d ", const void *" p ", size_t " sz );
 .BI "int dstr_putline(dstr *" d ", FILE *" fp );
 .BI "size_t dstr_write(const dstr *" d ", FILE *" fp );
 .BI "void dstr_putm(dstr *" d ", const void *" p ", size_t " sz );
 .BI "int dstr_putline(dstr *" d ", FILE *" fp );
 .BI "size_t dstr_write(const dstr *" d ", FILE *" fp );
-
+.PP
 .BI "void DCREATE(dstr *" d );
 .BI "void DDESTROY(dstr *" d );
 .BI "void DRESET(dstr *" d );
 .BI "void DCREATE(dstr *" d );
 .BI "void DDESTROY(dstr *" d );
 .BI "void DRESET(dstr *" d );
index c067275..fdde662 100644 (file)
 \h'-\w'\\$1\ 'u'\\$1\ \c
 .ft P
 ..
 \h'-\w'\\$1\ 'u'\\$1\ \c
 .ft P
 ..
-.ie t .ds o \(bu
-.el .ds o o
+.ie t \{\
+.  ds o \(bu
+.  de VP
+.    sp .4v
+..
+\}
+.el \{\
+.  ds o o
+.  de VP
+.    sp
+..
+\}
 .TH hash 3 "2 August 1999" "Straylight/Edgeware" "mLib utilities library"
 .SH "NAME"
 hash \- low-level hashtable implementation
 .TH hash 3 "2 August 1999" "Straylight/Edgeware" "mLib utilities library"
 .SH "NAME"
 hash \- low-level hashtable implementation
@@ -37,21 +47,21 @@ hash \- low-level hashtable implementation
 .SH "SYNOPSIS"
 .nf
 .B "#include <mLib/hash.h>"
 .SH "SYNOPSIS"
 .nf
 .B "#include <mLib/hash.h>"
-
+.PP
 .ta 2n
 .B "typedef struct {"
 .B "   uint32 mask;"
 .B "   hash_base **v;"
 .B "   arena *a;"
 .B "} hash_table;"
 .ta 2n
 .B "typedef struct {"
 .B "   uint32 mask;"
 .B "   hash_base **v;"
 .B "   arena *a;"
 .B "} hash_table;"
-
+.PP
 .B "typedef struct {"
 .B "   hash_base *next;"
 .B "   uint32 hash;"
 .B "} hash_base;"
 .B "typedef struct {"
 .B "   hash_base *next;"
 .B "   uint32 hash;"
 .B "} hash_base;"
-
+.PP
 .B "typedef struct { ...\& } hash_iter;"
 .B "typedef struct { ...\& } hash_iter;"
-
+.PP
 .BI "void hash_create(hash_table *" t ", size_t " n );
 .BI "void hash_destroy(hash_table *" t );
 .BI "hash_base **hash_bin(hash_table *" t ", uint32 " hash );
 .BI "void hash_create(hash_table *" t ", size_t " n );
 .BI "void hash_destroy(hash_table *" t );
 .BI "hash_base **hash_bin(hash_table *" t ", uint32 " hash );
@@ -59,7 +69,7 @@ hash \- low-level hashtable implementation
 .BI "void hash_remove(hash_table *" t ", hash_base *" b );
 .BI "void hash_mkiter(hash_iter *" i ", hash_table *" t );
 .BI "hash_base *hash_next(hash_iter *" i );
 .BI "void hash_remove(hash_table *" t ", hash_base *" b );
 .BI "void hash_mkiter(hash_iter *" i ", hash_table *" t );
 .BI "hash_base *hash_next(hash_iter *" i );
-
+.PP
 .BI "hash_base **HASH_BIN(hash_table *" t ", uint32 " hash );
 .BI "void HASH_MKITER(hash_iter *" i ", hash_table *" t );
 .BI "void HASH_NEXT(hash_iter *" i ", " b );
 .BI "hash_base **HASH_BIN(hash_table *" t ", uint32 " hash );
 .BI "void HASH_MKITER(hash_iter *" i ", hash_table *" t );
 .BI "void HASH_NEXT(hash_iter *" i ", " b );
@@ -135,19 +145,20 @@ This section describes the functions and macros provided for building
 hashtables.  Code examples are given throughout.  They assume the
 following definitions:
 .VS
 hashtables.  Code examples are given throughout.  They assume the
 following definitions:
 .VS
+.ta 2n
 /* --- A table of items --- */
 /* --- A table of items --- */
-
+.VP
 typedef struct item_table {
 typedef struct item_table {
-  hash_table t;
-  size_t load;
+       hash_table t;
+       size_t load;
 };
 };
-
+.VP
 /* --- An item --- */
 /* --- An item --- */
-
+.VP
 typedef struct item {
 typedef struct item {
-  hash_base b;
-  const char *k;
-  /* ... */
+       hash_base b;
+       const char *k;
+       /* ... */
 } item;
 .VE
 The implementation presented here is simple but relatively bad.  The
 } item;
 .VE
 The implementation presented here is simple but relatively bad.  The
@@ -163,10 +174,11 @@ structure to be filled in and the initial number of hash bins to create.
 .PP
 For example, an item table might be initialized like this:
 .VS
 .PP
 For example, an item table might be initialized like this:
 .VS
+.ta 2n
 void item_createtab(item_table *t)
 {
 void item_createtab(item_table *t)
 {
-  hash_create(&t->t, ITEM_INITSZ);
-  t->load = ITEM_INITLOAD;
+       hash_create(&t->t, ITEM_INITSZ);
+       t->load = ITEM_INITLOAD;
 }
 .VE
 A hashtable can be destroyed by calling
 }
 .VE
 A hashtable can be destroyed by calling
@@ -179,17 +191,18 @@ that must be done beforehand.
 The usual way to deallocate the individual hashtable items is using the
 iteration constructs described below.
 .VS
 The usual way to deallocate the individual hashtable items is using the
 iteration constructs described below.
 .VS
+.ta 2n +2n
 void item_destroytab(item_table *t)
 {
 void item_destroytab(item_table *t)
 {
-  hash_iter i;
-  hash_base *b;
-  for (hash_mkiter(&i, &t->t); (b = hash_next(&i)) != 0; ) {
-    item *ii = (item *)b;
-    free(ii->k);
-    /* ... */
-    DESTROY(ii);
-  }
-  hash_destroy(&t->t);
+       hash_iter i;
+       hash_base *b;
+       for (hash_mkiter(&i, &t->t); (b = hash_next(&i)) != 0; ) {
+               item *ii = (item *)b;
+               free(ii->k);
+               /* ... */
+               DESTROY(ii);
+       }
+       hash_destroy(&t->t);
 }
 .VE
 .sp -1
 }
 .VE
 .sp -1
@@ -208,17 +221,18 @@ arguments multiple times.
 Once the bin list has been found, it's fairly easy to search for an
 exact match.  A simple search might look something like this:
 .VS
 Once the bin list has been found, it's fairly easy to search for an
 exact match.  A simple search might look something like this:
 .VS
+.ta 2n +2n +2n 20m
 item *lookup(item_table *t, const char *k)
 {
 item *lookup(item_table *t, const char *k)
 {
-  uint32 h = hash(k);          /* Hash @k@ somehow */
-  hash_base **bin = HASH_BIN(&t->t, h);
-  hash_base *b;
-  for (b = *bin; b; b = b->next) {
-    item *i = (item *)b;
-    if (h == i->b.hash && strcmp(k, i->k) == 0)
-      return (i);
-  }
-  return (0);
+       uint32 h = hash(k);                     /* Hash \fIk\fP somehow */
+       hash_base **bin = HASH_BIN(&t->t, h);
+       hash_base *b;
+       for (b = *bin; b; b = b->next) {
+               item *i = (item *)b;
+               if (h == i->b.hash && strcmp(k, i->k) == 0)
+                       return (i);
+       }
+       return (0);
 }
 .VE
 Insertion is also relatively trivial given the bin list head.  Insertion
 }
 .VE
 Insertion is also relatively trivial given the bin list head.  Insertion
@@ -228,40 +242,41 @@ it.  Extension is performed by
 which is passed only the address of the hashtable.  It returns nonzero
 if extension was successful.
 .VS
 which is passed only the address of the hashtable.  It returns nonzero
 if extension was successful.
 .VS
+.ta 2n +2n
 item *add(item_table *t, const char *k, /* ... */)
 {
 item *add(item_table *t, const char *k, /* ... */)
 {
-  item *i;
-  uint32 h;
-  hash_base **bin;
-
-  /* --- See if the item is already there --- */
-
-  if ((i =  = lookup(t, k)) != 0)
-    return (i);
-
-  /* --- Make a new hashtable item --- */
-
-  i = CREATE(item);
-  i->k = xstrdup(k);
-  /* ... */
-
-  /* --- Link it into the bin list --- */
-
-  h = i->b.hash = hash(k);
-  bin = HASH_BIN(&t->t, h);
-  i->b.next = *bin;
-  *bin = &i->b.next;
-
-  /* --- Maybe extend the hashtable --- */
-
-  if (t->load)
-    t->load--;
-  else if (hash_extend(&t->t))
-    t->load = recalc_load(t);
-
-  /* --- Done --- */
-
-  return (i);
+       item *i;
+       uint32 h;
+       hash_base **bin;
+.VP
+       /* --- See if the item is already there --- */
+.VP
+       if ((i = lookup(t, k)) != 0)
+               return (i);
+.VP
+       /* --- Make a new hashtable item --- */
+.VP
+       i = CREATE(item);
+       i->k = xstrdup(k);
+       /* ... */
+.VP
+       /* --- Link it into the bin list --- */
+.VP
+       h = i->b.hash = hash(k);
+       bin = HASH_BIN(&t->t, h);
+       i->b.next = *bin;
+       *bin = &i->b.next;
+.VP
+       /* --- Maybe extend the hashtable --- */
+.VP
+       if (t->load)
+               t->load--;
+       else if (hash_extend(&t->t))
+               t->load = recalc_load(t);
+.VP
+       /* --- Done --- */
+.VP
+       return (i);
 }
 .VE
 The
 }
 .VE
 The
index a2afcaf..a683e20 100644 (file)
 .RE
 .sp 1
 ..
 .RE
 .sp 1
 ..
+.ie t \{\
+.  de VP
+.    sp .4v
+..
+\}
+.el \{\
+.  de VP
+.    sp
+..
+\}
 .TH sym 3 "8 May 1999" "Straylight/Edgeware" "mLib utilities library"
 .SH NAME
 sym \- symbol table manager
 .TH sym 3 "8 May 1999" "Straylight/Edgeware" "mLib utilities library"
 .SH NAME
 sym \- symbol table manager
@@ -28,24 +38,24 @@ sym \- symbol table manager
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/sym.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/sym.h>"
-
+.PP
 .B "type struct { ...\& } sym_table;"
 .B "type struct { ...\& } sym_base;"
 .B "type struct { ...\& } sym_iter;"
 .B "type struct { ...\& } sym_table;"
 .B "type struct { ...\& } sym_base;"
 .B "type struct { ...\& } sym_iter;"
-
+.PP
 .BI "void sym_create(sym_table *" t );
 .BI "void sym_destroy(sym_table *" t );
 .BI "void sym_create(sym_table *" t );
 .BI "void sym_destroy(sym_table *" t );
-
+.PP
 .ta \w'\fBvoid *sym_find('u
 .BI "void *sym_find(sym_table *" t ,
 .BI "  const char *" n ", long " l ,
 .BI "  size_t " sz ", unsigned *" f );
 .BI "void sym_remove(sym_table *" t ", void *" b );
 .ta \w'\fBvoid *sym_find('u
 .BI "void *sym_find(sym_table *" t ,
 .BI "  const char *" n ", long " l ,
 .BI "  size_t " sz ", unsigned *" f );
 .BI "void sym_remove(sym_table *" t ", void *" b );
-
+.PP
 .BI "const char *SYM_NAME(const void *" p );
 .BI "size_t SYM_LEN(const void *" p );
 .BI "uint32 SYM_HASH(const void *" p );
 .BI "const char *SYM_NAME(const void *" p );
 .BI "size_t SYM_LEN(const void *" p );
 .BI "uint32 SYM_HASH(const void *" p );
-
+.PP
 .BI "void sym_mkiter(sym_iter *" i ", sym_table *" t );
 .BI "void *sym_next(sym_iter *" i );
 .fi
 .BI "void sym_mkiter(sym_iter *" i ", sym_table *" t );
 .BI "void *sym_next(sym_iter *" i );
 .fi
@@ -189,11 +199,12 @@ information about types and values.
 In this case, you'd define something like the following structure for
 your values:
 .VS
 In this case, you'd define something like the following structure for
 your values:
 .VS
+.ta 2 20m
 typedef struct val {
 typedef struct val {
-  sym_base _base;      /* Symbol header */
-  unsigned type;       /* Type of this symbol */
-  int dispoff;         /* Which display variable is in */
-  size_t frameoff;     /* Offset of variable in frame */
+       sym_base _base; /* Symbol header */
+       unsigned type;  /* Type of this symbol */
+       int dispoff;    /* Which display variable is in */
+       size_t frameoff;        /* Offset of variable in frame */
 } val;
 .VE
 Given a pointer
 } val;
 .VE
 Given a pointer
@@ -205,26 +216,29 @@ you can find the variable's name by calling
 .PP
 You can look up a name in the table by saying something like:
 .VS
 .PP
 You can look up a name in the table by saying something like:
 .VS
+.ta 2n
 val *v = sym_find(t, name, -1, 0, 0);
 if (!v)
 val *v = sym_find(t, name, -1, 0, 0);
 if (!v)
-  error("unknown variable `%s'", name);
+       error("unknown variable `%s'", name);
 .VE
 You can add in a new variable by saying something like
 .VS
 .VE
 You can add in a new variable by saying something like
 .VS
+.ta 2n
 unsigned f;
 val *v = sym_find(t, name, -1, sizeof(val), &f);
 if (f)
 unsigned f;
 val *v = sym_find(t, name, -1, sizeof(val), &f);
 if (f)
-  error("variable `%s' already exists", name);
+       error("variable `%s' already exists", name);
 /* fill in v */
 .VE
 You can examine all the variables in your symbol table by saying
 something like:
 .VS
 /* fill in v */
 .VE
 You can examine all the variables in your symbol table by saying
 something like:
 .VS
+.ta 2n
 sym_iter i;
 val *v;
 sym_iter i;
 val *v;
-
+.VP
 for (sym_mkiter(&i, t); (v = sym_next(&i)) != 0; ) {
 for (sym_mkiter(&i, t); (v = sym_next(&i)) != 0; ) {
-  /* ... */
+       /* ... */
 }
 .VE
 That ought to be enough examples to be getting on with.
 }
 .VE
 That ought to be enough examples to be getting on with.
index 1482bed..fba258e 100644 (file)
@@ -7,7 +7,7 @@ daemonize \- become a background process
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/daemonize.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/daemonize.h>"
-
+.PP
 .B "void detachtty(void);"
 .B "int daemonize(void);"
 .fi
 .B "void detachtty(void);"
 .B "int daemonize(void);"
 .fi
index 1818b37..2c5b5af 100644 (file)
--- a/sys/env.3
+++ b/sys/env.3
@@ -10,7 +10,7 @@ env \- efficient fiddling with environment variables
 .SH "SYNOPSIS"
 .nf
 .B "#include <mLib/env.h>"
 .SH "SYNOPSIS"
 .nf
 .B "#include <mLib/env.h>"
-
+.PP
 .BI "char *env_get(sym_table *" t ", const char *" name );
 .BI "void env_put(sym_table *" t ,
 .BI "             const char *" name ", const char *" value );
 .BI "char *env_get(sym_table *" t ", const char *" name );
 .BI "void env_put(sym_table *" t ,
 .BI "             const char *" name ", const char *" value );
index 2ed2fa9..25fb3f6 100644 (file)
@@ -18,7 +18,7 @@ fdflags \- set file and file descriptor flags
 .SH "SYNOPSIS"
 .nf
 .B "#include <mLib/fdflags.h>"
 .SH "SYNOPSIS"
 .nf
 .B "#include <mLib/fdflags.h>"
-
+.PP
 .ta \w'\fBint fdflags('u
 .BI "int fdflags(int " fd ,
 .BI "  unsigned " fbic ", unsigned " fxor ,
 .ta \w'\fBint fdflags('u
 .BI "int fdflags(int " fd ,
 .BI "  unsigned " fbic ", unsigned " fxor ,
index b643bde..449b6bf 100644 (file)
@@ -7,7 +7,7 @@ fdpass \- file descriptor passing
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/fdpass.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/fdpass.h>"
-
+.PP
 .BI "ssize_t fdpass_send(int " sock ", int " fd ", const void *" p ", size_t " sz );
 .BI "ssize_t fdpass_recv(int " sock ", int *" fd ", void *" p ", size_t " sz );
 .fi
 .BI "ssize_t fdpass_send(int " sock ", int " fd ", const void *" p ", size_t " sz );
 .BI "ssize_t fdpass_recv(int " sock ", int *" fd ", void *" p ", size_t " sz );
 .fi
index 9afe273..c461733 100644 (file)
@@ -9,9 +9,9 @@ fwatch \- watch a file for changes
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/fwatch.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/fwatch.h>"
-
+.PP
 .B "typedef struct { ...\& } fwatch;"
 .B "typedef struct { ...\& } fwatch;"
-
+.PP
 .BI "void fwatch_init(fwatch *" f ", const char *" name );
 .BI "void fwatch_initfd(fwatch *" f ", int " fd );
 .BI "int fwatch_update(fwatch *" f ", const char *" name );
 .BI "void fwatch_init(fwatch *" f ", const char *" name );
 .BI "void fwatch_initfd(fwatch *" f ", int " fd );
 .BI "int fwatch_update(fwatch *" f ", const char *" name );
index d7b18e5..46be546 100644 (file)
@@ -6,14 +6,14 @@ lock \- oversimplified file locking interface
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/lock.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/lock.h>"
-
+.PP
 .ta 2n
 .B "enum {"
 .B "   LOCK_UNLOCK = ...,"
 .B "   LOCK_EXCL = ...,"
 .B "   LOCK_NONEXCL = ..."
 .B "};"
 .ta 2n
 .B "enum {"
 .B "   LOCK_UNLOCK = ...,"
 .B "   LOCK_EXCL = ...,"
 .B "   LOCK_NONEXCL = ..."
 .B "};"
-
+.PP
 .BI "int lock_file(int " fd ", unsigned " how );
 .fi
 .SH DESCRIPTION
 .BI "int lock_file(int " fd ", unsigned " how );
 .fi
 .SH DESCRIPTION
index f08c13e..567da6a 100644 (file)
 \h'-\w'\\$1\ 'u'\\$1\ \c
 .ft P
 ..
 \h'-\w'\\$1\ 'u'\\$1\ \c
 .ft P
 ..
-.ie t .ds o \(bu
-.el .ds o o
+.ie t \{\
+.  ds o \(bu
+.  de VP
+.    sp .4v
+..
+\}
+.el \{\
+.  ds o o
+.  de VP
+.    sp
+..
+\}
 .TH mdup 3 "4 January" "Straylight/Edgeware" "mLib utilities library"
 .SH NAME
 mdup \- renumber file descriptors
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/mdup.h>"
 .TH mdup 3 "4 January" "Straylight/Edgeware" "mLib utilities library"
 .SH NAME
 mdup \- renumber file descriptors
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/mdup.h>"
-
+.PP
 .ta 2n
 .B "typedef struct {"
 .B "   int cur;"
 .B "   int want;"
 .B "} mdup_fd;"
 .ta 2n
 .B "typedef struct {"
 .B "   int cur;"
 .B "   int want;"
 .B "} mdup_fd;"
-
+.PP
 .BI "int mdup(mdup_fd *" v ", size_t " n ");"
 .fi
 .SH DESCRIPTION
 .BI "int mdup(mdup_fd *" v ", size_t " n ");"
 .fi
 .SH DESCRIPTION
@@ -113,7 +123,7 @@ this.
 int p_in[2] = P_INIT, p_out[2] = P_INIT, p_err[2] = P_INIT;
 pid_t kid = -1;
 int i;
 int p_in[2] = P_INIT, p_out[2] = P_INIT, p_err[2] = P_INIT;
 pid_t kid = -1;
 int i;
-
+.VP
 if (pipe(p_in) || pipe(p_out) || pipe(p_err)) goto error;
 if ((kid = fork()) < 0) goto error;
 if (!kid) {
 if (pipe(p_in) || pipe(p_out) || pipe(p_err)) goto error;
 if ((kid = fork()) < 0) goto error;
 if (!kid) {
@@ -153,7 +163,7 @@ int p_in[2] = P_INIT, p_out[2] = P_INIT, p_err[2] = P_INIT;
 pid_t kid = -1;
 mdup_fd md[3];
 int i;
 pid_t kid = -1;
 mdup_fd md[3];
 int i;
-
+.VP
 if (pipe(p_in) || pipe(p_out) || pipe(p_err)) goto error;
 if ((kid = fork()) < 0) goto error;
 if (!kid) {
 if (pipe(p_in) || pipe(p_out) || pipe(p_err)) goto error;
 if ((kid = fork()) < 0) goto error;
 if (!kid) {
@@ -184,4 +194,3 @@ wanted ends of the pipes.
 .BR mLib (3).
 .SH AUTHOR
 Mark Wooding, <mdw@distorted.org.uk>
 .BR mLib (3).
 .SH AUTHOR
 Mark Wooding, <mdw@distorted.org.uk>
-
index 62d9189..f24892d 100644 (file)
--- a/sys/tv.3
+++ b/sys/tv.3
@@ -17,7 +17,7 @@ tv \- arithmetic on \fBstruct timeval\fR objects
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/tv.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/tv.h>"
-
+.PP
 .BI "void tv_add(struct timeval *" dst ,
 .BI "            const struct timeval *" a ,
 .BI "            const struct timeval *" b );
 .BI "void tv_add(struct timeval *" dst ,
 .BI "            const struct timeval *" a ,
 .BI "            const struct timeval *" b );
@@ -32,7 +32,7 @@ tv \- arithmetic on \fBstruct timeval\fR objects
 .BI "             time_t " sec ", unsigned long " usec );
 .BI "int tv_cmp(const struct timeval *" a ,
 .BI "           const struct timeval *" b );
 .BI "             time_t " sec ", unsigned long " usec );
 .BI "int tv_cmp(const struct timeval *" a ,
 .BI "           const struct timeval *" b );
-
+.PP
 .B "int MILLION;"
 .BI "void TV_ADD(struct timeval *" dst ,
 .BI "            const struct timeval *" a ,
 .B "int MILLION;"
 .BI "void TV_ADD(struct timeval *" dst ,
 .BI "            const struct timeval *" a ,
index 5a4b2ff..f3805ad 100644 (file)
@@ -35,6 +35,7 @@ libtest_la_SOURCES     =
 ## Benchmarking.
 pkginclude_HEADERS     += bench.h
 libtest_la_SOURCES     += bench.c
 ## Benchmarking.
 pkginclude_HEADERS     += bench.h
 libtest_la_SOURCES     += bench.c
+LIBMANS                        += bench.3
 
 ## Old `testrig' testing framework.
 pkginclude_HEADERS     += testrig.h
 
 ## Old `testrig' testing framework.
 pkginclude_HEADERS     += testrig.h
@@ -47,11 +48,22 @@ libtest_la_SOURCES  += tvec-core.c
 libtest_la_SOURCES     += tvec-output.c
 libtest_la_SOURCES     += tvec-types.c
 libtest_la_SOURCES     += tvec-main.c
 libtest_la_SOURCES     += tvec-output.c
 libtest_la_SOURCES     += tvec-types.c
 libtest_la_SOURCES     += tvec-main.c
-#LIBMANS               += tvec.3
+LIBMANS                        += tvec.3
+LIBMANS                        += tvec-types.3
+LIBMANS                        += tvec-adhoc.3
+LIBMANS                        += tvec-main.3
+LIBMANS                        += tvec-env.3
+LIBMANS                        += tvec-tyimpl.3
+LIBMANS                        += tvec-output.3
 
 libtest_la_SOURCES     += tvec-bench.c
 
 libtest_la_SOURCES     += tvec-bench.c
+LIBMANS                        += tvec-bench.3
+
 libtest_la_SOURCES     += tvec-remote.c
 libtest_la_SOURCES     += tvec-remote.c
+LIBMANS                        += tvec-remote.3
+
 libtest_la_SOURCES     += tvec-timeout.c
 libtest_la_SOURCES     += tvec-timeout.c
+LIBMANS                        += tvec-timeout.3
 
 check_PROGRAMS         += t/tvec.t
 t_tvec_t_SOURCES        = t/tvec-test.c
 
 check_PROGRAMS         += t/tvec.t
 t_tvec_t_SOURCES        = t/tvec-test.c
diff --git a/test/bench.3 b/test/bench.3
new file mode 100644 (file)
index 0000000..2a9e60f
--- /dev/null
@@ -0,0 +1,495 @@
+.\" -*-nroff-*-
+.ie t .ds , \h'\w'\ 'u/2u'
+.el .ds , \ \"
+.TH bench 3 "9 March 2024" "Straylight/Edgeware" "mLib utilities library"
+.\" @bench_createtimer
+.\" @bench_init
+.\" @bench_destroy
+.\" @bench_calibrate
+.\" @bench_measure
+.
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/bench.h>"
+.PP
+.ta 2n
+.B "struct bench_time {"
+.B "   unsigned f;"
+.B "   kludge64 s;"
+.B "   uint32 ns;"
+.B "   kludge64 cy;"
+.B "};"
+.PP
+.B "struct bench_timing {"
+.B "   unsigned f;"
+.B "   double n;"
+.B "   double t;"
+.B "   double cy;"
+.B "};"
+.PP
+.B "struct bench_timerops {"
+.BI "  void (*describe)(struct bench_timer *" bt ", dstr *" d );
+.BI "  void (*now)(struct bench_timer *" bt ", struct bench_time *" t_out );
+.BI "  void (*destroy)(struct bench_timer *" bt );
+.B "};"
+.B "struct bench_timer {"
+.B "   const struct bench_timerops *ops;"
+.B "};"
+.PP
+.B "struct bench_state {"
+.B "   unsigned f;"
+.B "   double target_s;"
+.B "   ..."
+.B "}";
+.PP
+.BI "typedef void bench_fn(unsigned long " n ", void *" ctx );
+.PP
+.B "#define BTF_TIMEOK ..."
+.B "#define BTF_CYOK ..."
+.B "#define BTF_CLB ..."
+.B "#define BTF_ANY (BTF_TIMEOK | BTF_CYOK)"
+.PP
+.B "struct bench_timer *bench_createtimer(void);"
+.PP
+.BI "int bench_init(struct bench_state *" b ", struct bench_timer *" tm );
+.BI "void bench_destroy(struct bench_state *" b );
+.BI "int bench_calibrate(struct bench_state *" b );
+.ta \w'\fBint bench_measure('u
+.BI "int bench_measure(struct bench_state *" b ", struct bench_timing *" t_out ,
+.BI "  double " base ", bench_fn *" fn ", void *" ctx );
+.fi
+.
+.SH DESCRIPTION
+The header file
+.B "<mLib/bench.h>"
+provides declarations and defintions
+for performing low-level benchmarks.
+.PP
+The `main event' is
+.BR bench_measure .
+This function will be described in detail later,
+but, in brief,
+it calls a caller-provided function,
+instructing it to run adaptively chosen numbers of iterations,
+in order to get a reasonably reliable measurement of its running time,
+and then reports its results by filling in a structure.
+.PP
+With understanding this function as our objective,
+we must examine all of the pieces involved in making it work.
+.
+.SS Timers in general
+A
+.I timer
+is a gadget which is capable of reporting the current time,
+in seconds (ideally precise to tiny fractions of a second),
+and/or in CPU cycles.
+A timer is represented by a pointer to an object of type
+.BR "struct bench_timer" .
+This structure has a single member,
+.BR ops ,
+pointing to a
+.BR "struct bench_timerops" ,
+which is a table of function pointers;
+typically, a timer has more data following this,
+but this fact is not exposed to applications.
+.PP
+The function pointers in
+.B "struct bench_timerops"
+are as follows.
+The first argument,
+named
+.I tm
+must always point to the timer object itself.
+.TP
+.IB tm ->ops->describe( tm ", " d)
+Write a description of the timer to the dynamic string
+.IR d .
+.TP
+.IB tm ->ops->now( tm ", " t_out)
+Store the current time in
+.IR t_out .
+The
+.B struct bench_time
+used to represent the time reported by a timer
+is described in detail below.
+.TP
+.IB tm ->ops->destroy( tm )
+Destroy the timer,
+releasing all of the resources that it holds.
+.PP
+A time, a reported by a timer, is represented by the
+.BR "struct bench_time" .
+A passage-of-time measurement is stored in the
+.B s
+and
+.B ns
+members, holding seconds and nanoseconds respectively.
+(A timer need not have nanosecond precision.
+The exact interpretation of the time \(en
+e.g., whether it measures wallclock time,
+user-mode CPU time,
+or total thread CPU time \(en
+is a matter for the specific timer implementation.)
+A cycle count is stored in the
+.B cy
+member.
+The
+.B f
+member stores flags:
+.B BTF_TIMEOK
+is set if the passage-of-time measurement
+.B s
+and
+.B ns
+are valid; and
+.B BTF_CYOK
+is set if the cycle count
+.B cy
+is valid.
+Neither the time nor the cycle count need be measured
+relative to any particular origin.
+The mask
+.B BTF_ANY
+covers the
+.B BTF_TIMEOK
+and
+.B BTF_CYOK
+bits:
+hence,
+.IB f &BTF_ANY
+is nonzero (true)
+if the timer returned any valid timing information.
+.
+.SS The built-in timer
+The function
+.B bench_createtimer
+constructs and returns a timer.
+It takes a single argument,
+a string
+.IR config ,
+from which it reads configuration information.
+If
+.B bench_createtimer
+fails, it returns a null pointer.
+.PP
+The
+.I config
+pointer may safely be null,
+in which case a default configuration will be used.
+Applications
+.I should only
+set this pointer to a value supplied by a user,
+e.g., through a command-line argument,
+environment variable, or
+configuration file.
+.PP
+The built-in timer makes use of one or two
+.IR subtimers :
+a `clock' subtimer to measure the passage of time,
+and possibly a `cycle' subtimer to count CPU cycles.
+.PP
+The configuration string consists of a sequence of words
+separated by whitespace.
+There may be additional whitespace at the start and end of the string.
+The words recognized are as follows.
+.TP
+.B list
+Prints a list of the available clock and cycle subtimers
+to standard output.
+.TP
+.BI clock= t , ...
+Use the first of the listed clock subtimers
+to initialize successfully
+as the clock subtimer.
+If none of the subtimers can be initialized,
+then construction of the timer as a whole fails.
+.TP
+.BI cycle= t , ...
+Use the first of the listed subtimers
+to initialize successfully
+as the cycle subtimer.
+If none of the subtimers can be initialized,
+then construction of the timer as a whole fails.
+.PP
+The clock subtimers are as follows.
+Not all of them will be available on every platform.
+.TP
+.B posix-thread-cputime
+Measures the passage of time using
+.BR clock_gettime (2),
+specifying the
+.B CLOCK_\%THREAD_\%CPUTIME_\%ID
+clock.
+.TP
+.B stdc-clock
+Measures the passage of time using
+.BR clock (3).
+Since
+.BR clock (3)
+is part of the original ANSI\ C standard,
+this subtimer should always be available.
+However, it may produce unhelpful results
+if other threads are running.
+.PP
+The cycle subtimers are as follows.
+Not all of them will be available on every platform.
+.TP
+.B linux-perf-event
+Counts CPU cycles using the Linux-specific 
+.BR perf_event_open (2)
+function to read the
+.BR PERF_\%COUNT_\%HW_\%CPU_\%CYCLES
+counter.
+Only available on Linux.
+It will fail to initialize
+if access to performance counters is restricted,
+e.g., because the
+.B /proc/sys/kernel/perf_event_paranoid
+level is too high.
+.TP
+.B x86-rdtsc
+Counts CPU cycles using the x86
+.B rdtsc
+instruction.
+This instruction is not really suitable for performance measurement:
+it gives misleading results on CPUs with variable clock frequency.
+.TP
+.B null
+A dummy cycle counter,
+which will initialize successfully
+and then fail to report cycle counts.
+This is a reasonable fallback in many situations.
+.PP
+The built-in preference order for clock subtimers,
+from most to least preferred, is
+.B posix-thread-cputime
+followed by
+.BR stdc-clock .
+The built-in preference order for cycle subtimers,
+from most to least preferred, is
+.B linux-perf-event
+followed by
+.BR x86-rdtsc ,
+and then
+.BR null .
+.
+.SS The benchmark state
+A
+.I benchmark state
+tracks the information needed to measure performance of functions.
+It is represented by a
+.B struct bench_state
+structure.
+.PP
+The benchmark state is initialized by calling
+.BR bench_init ,
+passing the address of the state structure to be initialized,
+and a pointer to a timer.
+If
+.B bench_init
+is called with a non-null timer pointer,
+then it will not fail;
+the benchmark state will be initialized,
+and the function returns zero.
+If the timer pointer is null,
+then
+.B bench_init
+attempts to construct a timer for itself
+by calling
+.BR bench_createtimer .
+If this succeeds,
+then the benchmark state will be initialized,
+and the function returns zero.
+In both cases,
+the timer becomes owned by the benchmark state:
+calling
+.B bench_destroy
+on the benchmark state will destroy the timer.
+If
+.B bench_init
+is called with a null timer pointer,
+and its attempt to create a timer for itself fails,
+then
+.B bench_init
+returns \-1;
+the benchmark state is not initialized
+and can safely be discarded;
+calling
+safe to call
+.B bench_destroy
+on the unsuccessfully benchmark state is safe and has no effect.
+.PP
+Calling
+.B bench_destroy
+on a benchmark state
+releases any resources it holds,
+most notably its timer, if any.
+.PP
+Although
+.B struct bench_state
+is defined in the header file,
+only two members are available for use by applications.
+.TP
+.B f
+A word containing flags.
+.TP
+.B target_s
+The target time for which to try run a benchmark, in seconds.
+After initialization, this is set to 1.0,
+though applications can override it.
+.PP
+Before the benchmark state can be used in measurements,
+it must be
+.IR calibrated .
+This is performed by calling
+.B bench_calibrate
+on the benchmark state.
+Calibration takes a noticeable amount of time
+(currently about 0.25\*,s),
+so it makes sense to defer it until it's known to be necessary.
+.PP
+Calibration is carried out separately, but in parallel,
+for the timer's passage-of-time measurement and cycle counter.
+Either or both of these calibrations can succeed or fail;
+if passage-of-time calibration fails,
+then cycle count calibration is impossible.
+.PP
+When it completes,
+.B bench_calibrate
+sets flag in the benchmark state's
+.B f
+member:
+if passage-of-time calibration succeeded,
+.B BTF_TIMEOK
+is set;
+if cycle-count calibration succeeded,
+.B BTF_CYOK
+is set;
+and the flag
+.B BTF_CLB
+is set unconditionally,
+as a persistent indication that calibration has been attempted.
+.PP
+The
+.B bench_calibrate
+function returns zero if it successfully calibrated
+at least the passage-of-time measurement;
+otherwise, it returns \-1.
+If
+.B bench_calibrate
+is called for a second or subsequent time on the same benchmark state,
+it returns immediately,
+either returning 0 or \-1
+according to whether passage-of-time had previously been calibrated.
+.
+.SS Timing functions
+A
+.I benchmark function
+has the signature
+.IP
+.BI "void " fn "(unsigned long " n ", void *" ctx );
+.PP
+When called, it should perform the operation to be measured
+.I n
+times.
+The
+.I ctx
+argument is a pointer passed into
+.B bench_measure
+for the benchmark function's own purposes.
+.PP
+The function
+.B bench_measure
+receives five arguments.
+.TP
+.I b
+points to the benchmark state to be used.
+.TP
+.I t_out
+is the address of a
+.BR struct bench_timing
+in which the measurement should be left.
+This structure is described below.
+.TP
+.I base
+is a count of the number of operations performed
+by each iteration of the benchmark function.
+.TP
+.I fn
+is a benchmark function, described above.
+.TP
+.I ctx
+is a pointer to be passed to the benchmark function.
+.B bench_measure
+does not interpret this pointer in any way.
+.PP
+The
+.B bench_measure
+function calls its benchark function repeatedly
+with different iteration counts
+.IR n ,
+with the objective that the call take approximately
+.B target_s
+seconds, as established in the benchmark state.
+(Currently, if
+.B target_s
+holds the value
+.IR t ,
+then
+.B bench_measure
+is satisfied when a call takes at least
+.IR t /\(sr2\*,s.)
+Once the function finds a satisfactory number of iterations,
+it stores the results in
+.BI * t_out \fR.
+If measurement succeeds, then
+.B bench_measure
+returns zero.
+If it fails \(en
+most likely because the timer failed \(en
+then it returns \-1.
+.PP
+A
+.B bench_timing
+structure reports the outcome of a successful measurement.
+It has four members.
+.TP
+.B f
+A flags word.
+.B BTF_TIMEOK
+is set if the passage-of-time measurement in 
+.B t
+is valid;
+.B BTF_CYOK
+is set if the cycle count in
+.B cy
+is valid.
+.TP
+.B n
+The number of iterations performed by the benchmark function
+on its satisfactory run,
+multiplied by
+.IR base .
+.TP
+.B t
+The time taken for the satisfactory run of the benchmark function,
+in seconds.
+Only valid if
+.B BTF_TIMEOK
+is set in
+.BR f .
+.TP
+.B cy
+The number of CPU cycles used
+in the satisfactory run of the benchmark function,
+in seconds.
+Only valid if
+.B BTF_CYOK
+is set in
+.BR f .
+.
+.SH "SEE ALSO"
+.BR mLib (3).
+.
+.SH AUTHOR
+Mark Wooding, <mdw@distorted.org.uk>
index b6ba605..04759cd 100644 (file)
@@ -190,7 +190,7 @@ static int common_setvar(struct tvec_state *tv, const char *var,
 
 static const struct tvec_vardef show_var =
   { sizeof(struct tvec_reg), common_setvar,
 
 static const struct tvec_vardef show_var =
   { sizeof(struct tvec_reg), common_setvar,
-    { "@show", -1, &tvty_ienum, 0, { &tvenum_bool } } };
+    { "@show", &tvty_ienum, -1, 0, { &tvenum_bool } } };
 
 static const struct tvec_vardef *common_findvar
   (struct tvec_state *tv, const char *var, void **ctx_out, void *ctx)
 
 static const struct tvec_vardef *common_findvar
   (struct tvec_state *tv, const char *var, void **ctx_out, void *ctx)
@@ -256,7 +256,7 @@ static void test_copy_buffer
 
 #define COPYREG(name, i, ty, argslot, argval)                          \
        static DSGINIT(const) struct tvec_regdef name##_copyregs[] = {  \
 
 #define COPYREG(name, i, ty, argslot, argval)                          \
        static DSGINIT(const) struct tvec_regdef name##_copyregs[] = {  \
-         { #name, RVOUT, &tvty_##ty, 0, DSGINIT({ .argslot = argval }) }, \
+         { #name, &tvty_##ty, RVOUT, 0, DSGINIT({ .argslot = argval }) }, \
          { 0 }                                                         \
        };
 TYPEREGS(COPYREG)
          { 0 }                                                         \
        };
 TYPEREGS(COPYREG)
@@ -314,16 +314,21 @@ static void test_single_deserialize
 
 #define SERREG(name, i, ty, argslot, argval)                           \
        static DSGINIT(const) struct tvec_regdef name##_serregs[] = {   \
 
 #define SERREG(name, i, ty, argslot, argval)                           \
        static DSGINIT(const) struct tvec_regdef name##_serregs[] = {   \
-         { #name, RV,  &tvty_##ty, 0, DSGINIT({ .argslot = argval }) }, \
-         { "buf", RSEROUT, &tvty_bytes },                              \
-         { "rc", RRC,  &tvty_int,      TVRF_OPT,       { &tvrange_int } }, \
+         { #name,      &tvty_##ty,     RV,     0,                      \
+                                     DSGINIT({ .argslot = argval }) }, \
+         { "buf",      &tvty_bytes,    RSEROUT, 0 },                   \
+         { "rc",       &tvty_int,      RRC,    TVRF_OPT,               \
+                                                   { &tvrange_int } }, \
          TVEC_ENDREGS                                                  \
        };                                                              \
        static DSGINIT(const) struct tvec_regdef name##_deserregs[] = { \
          TVEC_ENDREGS                                                  \
        };                                                              \
        static DSGINIT(const) struct tvec_regdef name##_deserregs[] = { \
-         { "buf", RSER, &tvty_bytes },                                 \
-         { #name, RVOUT, &tvty_##ty, 0, DSGINIT({ .argslot = argval }) }, \
-         { "left", RLEFT, &tvty_uint,  TVRF_OPT,      { &tvrange_size } }, \
-         { "rc", RRC,  &tvty_int,      TVRF_OPT,       { &tvrange_int } }, \
+         { "buf",      &tvty_bytes,    RSER,   0 },                    \
+         { #name,      &tvty_##ty,     RVOUT,  0,                      \
+                                     DSGINIT({ .argslot = argval }) }, \
+         { "left",     &tvty_uint,     RLEFT,  TVRF_OPT,               \
+                                                  { &tvrange_size } }, \
+         { "rc",       &tvty_int,      RRC,    TVRF_OPT,               \
+                                                   { &tvrange_int } }, \
          TVEC_ENDREGS                                                  \
        };
 TYPEREGS(SERREG)
          TVEC_ENDREGS                                                  \
        };
 TYPEREGS(SERREG)
@@ -423,14 +428,14 @@ static const struct tvec_ienuminfo reg_enum = { "reg", reg_assocs, 0 };
 
 static DSGINIT(const) struct tvec_regdef multi_serialize_regs[] = {
 #define DEFREG(name, i, ty, argslot, argval)                           \
 
 static DSGINIT(const) struct tvec_regdef multi_serialize_regs[] = {
 #define DEFREG(name, i, ty, argslot, argval)                           \
-  { #name,     i,      &tvty_##ty,     TVRF_OPT,                       \
-                                           DSGINIT({ .argslot = argval }) },
+  { #name,     &tvty_##ty,     i,      TVRF_OPT,                       \
+                                     DSGINIT({ .argslot = argval }) },
   TYPEREGS(DEFREG)
 #undef DEFREG
 
   TYPEREGS(DEFREG)
 #undef DEFREG
 
-  { "rc",      RRC,    &tvty_int,      TVRF_OPT,       { &tvrange_int } },
-  { "serialized", RSEROUT, &tvty_bytes,        TVRF_OPT },
-  { "sabotage",        RSAB,   &tvty_ienum,    TVRF_OPT,       { &reg_enum } },
+  { "rc",      &tvty_int,      RRC,    TVRF_OPT,       { &tvrange_int } },
+  { "serialized", &tvty_bytes, RSEROUT, TVRF_OPT },
+  { "sabotage",        &tvty_ienum,    RSAB,   TVRF_OPT,       { &reg_enum } },
 
   TVEC_ENDREGS
 };
 
   TVEC_ENDREGS
 };
@@ -463,9 +468,9 @@ static const struct tvec_remotefork crash_testenv =
   { TVEC_REMOTEFORK(0, 0) };
 
 static const struct tvec_regdef crash_regs[] = {
   { TVEC_REMOTEFORK(0, 0) };
 
 static const struct tvec_regdef crash_regs[] = {
-  { "crash",   RSAB,   &tvty_ienum,    0,              { &tvenum_bool } },
-  { "x",       RV,     &tvty_uint,     0,              { &tvrange_uint } },
-  { "z",       RVOUT,  &tvty_uint,     0,              { &tvrange_uint } },
+  { "crash",   &tvty_ienum,    RSAB,   0,              { &tvenum_bool } },
+  { "x",       &tvty_uint,     RV,     0,              { &tvrange_uint } },
+  { "z",       &tvty_uint,     RVOUT,  0,              { &tvrange_uint } },
   TVEC_ENDREGS
 };
 
   TVEC_ENDREGS
 };
 
@@ -496,8 +501,8 @@ static const struct tvec_remotefork sleep_testenv =
   { TVEC_REMOTEFORK(&sleep_subenv._env, 0) };
 
 static const struct tvec_regdef sleep_regs[] = {
   { TVEC_REMOTEFORK(&sleep_subenv._env, 0) };
 
 static const struct tvec_regdef sleep_regs[] = {
-  { "time",    RV,     &tvty_duration, 0,              { &tvflt_nonneg } },
-  { "z",       RVOUT,  &tvty_float,    0,              { &tvflt_nonneg } },
+  { "time",    &tvty_duration, RV,     0,              { &tvflt_nonneg } },
+  { "z",       &tvty_float,    RVOUT,  0,              { &tvflt_nonneg } },
   TVEC_ENDREGS
 };
 
   TVEC_ENDREGS
 };
 
index b6e30f3..e33bbb0 100644 (file)
@@ -18,37 +18,37 @@ testrig \- generic test rig
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/testrig.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/testrig.h>"
-
+.PP
 .B "#define TEST_FIELDMAX ..."
 .B "#define TEST_FIELDMAX ..."
-
+.PP
 .ta 2n
 .B "typedef struct {"
 .B "   unsigned tests, failed;"
 .B "} test_results";
 .ta 2n
 .B "typedef struct {"
 .B "   unsigned tests, failed;"
 .B "} test_results";
-
+.PP
 .B "typedef struct {"
 .BI "  void (*cvt)(const char *" buf ", dstr *" d );
 .BI "  void (*dump)(dstr *" d ", FILE *" fp );
 .B "} test_type";
 .B "typedef struct {"
 .BI "  void (*cvt)(const char *" buf ", dstr *" d );
 .BI "  void (*dump)(dstr *" d ", FILE *" fp );
 .B "} test_type";
-
+.PP
 .B "typedef struct {"
 .B "   const char *name;"
 .BI "  void (*test)(dstr " dv "[]);"
 .B "   const test_type *f[TEST_FIELDMAX];"
 .B "} test_chunk";
 .B "typedef struct {"
 .B "   const char *name;"
 .BI "  void (*test)(dstr " dv "[]);"
 .B "   const test_type *f[TEST_FIELDMAX];"
 .B "} test_chunk";
-
+.PP
 .B "typedef struct {"
 .B "   const char *name;"
 .B "   const test_chunk *chunks;"
 .B "} test_suite";
 .B "typedef struct {"
 .B "   const char *name;"
 .B "   const test_chunk *chunks;"
 .B "} test_suite";
-
+.PP
 .B "const test_type type_hex;"
 .B "const test_type type_string;"
 .B "const test_type type_int;"
 .B "const test_type type_long;"
 .B "const test_type type_ulong;"
 .B "const test_type type_uint32;"
 .B "const test_type type_hex;"
 .B "const test_type type_string;"
 .B "const test_type type_int;"
 .B "const test_type type_long;"
 .B "const test_type type_ulong;"
 .B "const test_type type_uint32;"
-
+.PP
 .ta \w'\fBint test_do('u
 .BI "int test_do(const test_suite " suite [],
 .BI "  FILE *" fp ", test_results *" results );
 .ta \w'\fBint test_do('u
 .BI "int test_do(const test_suite " suite [],
 .BI "  FILE *" fp ", test_results *" results );
diff --git a/test/tvec-adhoc.3 b/test/tvec-adhoc.3
new file mode 100644 (file)
index 0000000..1756486
--- /dev/null
@@ -0,0 +1,91 @@
+.\" -*-nroff-*-
+.de VS
+.sp 1
+.RS
+.nf
+.ft B
+..
+.de VE
+.ft R
+.fi
+.RE
+.sp 1
+..
+.de hP
+.IP
+.ft B
+\h'-\w'\\$1\ 'u'\\$1\ \c
+.ft P
+..
+.ie t \{\
+.  ds o \(bu
+.  de VP
+.    sp .4v
+..
+\}
+.el \{\
+.  ds o o
+.  de VP
+.    sp
+..
+\}
+..
+.TH tvec-adhoc 3 "11 March 2024" "Straylight/Edgeware" "mLib utilities library"
+.SH NAME
+tvec-adhoc \- ad-hoc testing with the test vector framework
+.\" @tvec_adhocconfig
+.\" @tvec_adhoc
+.
+.\" @tvec_begingroup
+.\" @TVEC_BEGINGROUP
+.\" @tvec_endgroup
+.\" @TVEC_TESTGROUP
+.\" @TVEC_TESTGROUP_TAG
+.\" @tvec_begintest
+.\" @TVEC_BEGINTEST
+.\" @tvec_endtest
+.\" @TVEC_TEST
+.\" @TVEC_TEST_TAG
+.
+.\" @tvec_claim
+.\" @TVEC_CLAIM
+.\" @tvec_claim_eq
+.
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/tvec.h>"
+.PP
+.BI "const struct tvec_config tvec_adhocconfig;"
+.BI "void tvec_adhoc(struct tvec_state *" tv ", struct tvec_test *" t );
+.PP
+.ta \w'\fBvoid tvec_begingroup('u
+.BI "void tvec_begingroup(struct tvec_state *" tv ", const char *" name ,
+.BI "  const char *" file ", unsigned " lno );
+.BI "void TVEC_BEGINGROUP(struct tvec_state *" tv ", const char *" name );
+.BI "void tvec_endgroup(struct tvec_state *" tv );
+.BI "TVEC_TESTGROUP(" tv ", " name ") " body
+.BI "TVEC_TESTGROUP_TAG(" tag ", " tv ", " name ") " body
+.ta \w'\fBvoid tvec_begintest('u
+.BI "void tvec_begintest(struct tvec_state *" tv ,
+.BI "  const char *" file ", unsigned " lno );
+.BI "void TVEC_BEGINTEST(struct tvec_state *" tv );
+.BI "void tvec_endtest(struct tvec_state *" tv );
+.BI "TVEC_TEST(" tv ") " body
+.BI "TVEC_TEST_TAG(" tag ", " tv ") " body
+.PP
+.ta \w'\fBint tvec_claim('u
+.BI "int tvec_claim(struct tvec_state *" tv ", int " ok ,
+.BI "  const char *" file ", unsigned " lno ,
+.BI "  const char *" msg ", ...);"
+.ta \w'\fBint tvec_claim_v('u
+.BI "int tvec_claim_v(struct tvec_state *" tv ", int " ok ,
+.BI "  const char *" file ", unsigned " lno ,
+.BI "  const char *" msg ", va_list *" ap );
+.BI "int TVEC_CLAIM(struct tvec_state *" tv ", int " cond );
+.ta \w'\fBint tvec_claim_eq('u
+.BI "int tvec_claim_eq(struct tvec_state *" tv ,
+.BI "  const struct tvec_regty *" ty ,
+.BI "  const union tvec_misc *" arg ,
+.BI "  const char *" file ", unsigned " lno ,
+.BI "  const char *" expr );
+.fi
diff --git a/test/tvec-bench.3 b/test/tvec-bench.3
new file mode 100644 (file)
index 0000000..687c8ff
--- /dev/null
@@ -0,0 +1,65 @@
+.\" -*-nroff-*-
+.de VS
+.sp 1
+.RS
+.nf
+.ft B
+..
+.de VE
+.ft R
+.fi
+.RE
+.sp 1
+..
+.de hP
+.IP
+.ft B
+\h'-\w'\\$1\ 'u'\\$1\ \c
+.ft P
+..
+.ie t \{\
+.  ds o \(bu
+.  de VP
+.    sp .4v
+..
+\}
+.el \{\
+.  ds o o
+.  de VP
+.    sp
+..
+\}
+..
+.TH tvec-bench 3 "11 March 2024" "Straylight/Edgeware" "mLib utilities library"
+.SH NAME
+tvec-bench \- benchmarking with the test vector framework
+.\" @TVEC_BENCHENV
+.\" @TVEC_BENCHINIT
+.\" @tvec_benchreport
+.
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/tvec.h>"
+.PP
+.ta 2n
+.B "struct tvec_benchenv {"
+.B "   struct tvec_env _env;"
+.B "   struct bench_state **bst;"
+.B "   unsigned long niter;"
+.B "   int riter, rbuf;"
+.B "   const struct tvec_env *env;"
+.B "};"
+.B "struct bench_state *tvec_benchstate;"
+.B "#define TVEC_BENCHENV ..."
+.B "#define TVEC_BENCHINIT ..."
+.B "enum {"
+.B "   TVBU_OP = ...,"
+.B "   TVBU_BYTE = ...,"
+.B "   ...,"
+.B "   TVBU_LIMIT"
+.B "};"
+.PP
+.ta \w'\fBvoid tvec_benchreport('u
+.BI "void tvec_benchreport(const struct gprintf_ops *" gops ", void *" go ,
+.BI "  unsigned " unit ", const struct bench_timing *" tm );
+.fi
index dda5713..bff3c3a 100644 (file)
@@ -294,7 +294,7 @@ static int setvar(struct tvec_state *tv, const char *var,
 }
 
 static const struct tvec_vardef target_var =
 }
 
 static const struct tvec_vardef target_var =
-  { sizeof(struct tvec_reg), setvar, { "@target", -1, &tvty_duration, 0 } };
+  { sizeof(struct tvec_reg), setvar, { "@target", &tvty_duration, -1, 0 } };
 
 const struct tvec_vardef *tvec_benchfindvar
   (struct tvec_state *tv, const char *var, void **ctx_out, void *ctx)
 
 const struct tvec_vardef *tvec_benchfindvar
   (struct tvec_state *tv, const char *var, void **ctx_out, void *ctx)
index 6a98f73..ca71dd2 100644 (file)
@@ -256,7 +256,7 @@ void tvec_mismatch(struct tvec_state *tv, unsigned f)
   const struct tvec_reg *rin, *rout;
 
   for (rd = tv->test->regs; rd->name; rd++) {
   const struct tvec_reg *rin, *rout;
 
   for (rd = tv->test->regs; rd->name; rd++) {
-    if (rd->i >= tv->nrout) {
+    if (rd->i >= tv->cfg.nrout) {
       if (!(f&TVMF_IN)) continue;
       rin = TVEC_REG(tv, in, rd->i);
       tvec_dumpreg(tv, TVRD_INPUT, rin->f&TVRF_LIVE ? &rin->v : 0, rd);
       if (!(f&TVMF_IN)) continue;
       rin = TVEC_REG(tv, in, rd->i);
       tvec_dumpreg(tv, TVRD_INPUT, rin->f&TVRF_LIVE ? &rin->v : 0, rd);
@@ -572,9 +572,9 @@ void tvec_initregs(struct tvec_state *tv)
   struct tvec_reg *r;
 
   for (rd = tv->test->regs; rd->name; rd++) {
   struct tvec_reg *r;
 
   for (rd = tv->test->regs; rd->name; rd++) {
-    assert(rd->i < tv->nreg); r = TVEC_REG(tv, in, rd->i);
+    assert(rd->i < tv->cfg.nreg); r = TVEC_REG(tv, in, rd->i);
     rd->ty->init(&r->v, rd); r->f = 0;
     rd->ty->init(&r->v, rd); r->f = 0;
-    if (rd->i < tv->nrout)
+    if (rd->i < tv->cfg.nrout)
       { r = TVEC_REG(tv, out, rd->i); rd->ty->init(&r->v, rd); r->f = 0; }
   }
 }
       { r = TVEC_REG(tv, out, rd->i); rd->ty->init(&r->v, rd); r->f = 0; }
   }
 }
@@ -585,9 +585,9 @@ void tvec_releaseregs(struct tvec_state *tv)
   struct tvec_reg *r;
 
   for (rd = tv->test->regs; rd->name; rd++) {
   struct tvec_reg *r;
 
   for (rd = tv->test->regs; rd->name; rd++) {
-    assert(rd->i < tv->nreg); r = TVEC_REG(tv, in, rd->i);
+    assert(rd->i < tv->cfg.nreg); r = TVEC_REG(tv, in, rd->i);
     rd->ty->release(&r->v, rd); r->f = 0;
     rd->ty->release(&r->v, rd); r->f = 0;
-    if (rd->i < tv->nrout)
+    if (rd->i < tv->cfg.nrout)
       { r = TVEC_REG(tv, out, rd->i); rd->ty->release(&r->v, rd); r->f = 0; }
   }
 }
       { r = TVEC_REG(tv, out, rd->i); rd->ty->release(&r->v, rd); r->f = 0; }
   }
 }
@@ -611,8 +611,8 @@ void tvec_resetoutputs(struct tvec_state *tv)
   struct tvec_reg *r;
 
   for (rd = tv->test->regs; rd->name; rd++) {
   struct tvec_reg *r;
 
   for (rd = tv->test->regs; rd->name; rd++) {
-    assert(rd->i < tv->nreg);
-    if (rd->i >= tv->nrout) continue;
+    assert(rd->i < tv->cfg.nreg);
+    if (rd->i >= tv->cfg.nrout) continue;
     r = TVEC_REG(tv, out, rd->i);
     rd->ty->release(&r->v, rd);
     rd->ty->init(&r->v, rd);
     r = TVEC_REG(tv, out, rd->i);
     rd->ty->release(&r->v, rd);
     rd->ty->init(&r->v, rd);
@@ -643,7 +643,7 @@ int tvec_checkregs(struct tvec_state *tv)
   const struct tvec_reg *rin, *rout;
 
   for (rd = tv->test->regs; rd->name; rd++) {
   const struct tvec_reg *rin, *rout;
 
   for (rd = tv->test->regs; rd->name; rd++) {
-    if (rd->i >= tv->nrout) continue;
+    if (rd->i >= tv->cfg.nrout) continue;
     rin = TVEC_REG(tv, in, rd->i); rout = TVEC_REG(tv, out, rd->i);
     if (!rin->f&TVRF_LIVE) continue;
     if (!(rout->f&TVRF_LIVE) || !rd->ty->eq(&rin->v, &rout->v, rd))
     rin = TVEC_REG(tv, in, rd->i); rout = TVEC_REG(tv, out, rd->i);
     if (!rin->f&TVRF_LIVE) continue;
     if (!(rout->f&TVRF_LIVE) || !rd->ty->eq(&rin->v, &rout->v, rd))
@@ -790,9 +790,10 @@ static void check(struct tvec_state *tv, struct groupstate *g)
   if (!(tv->f&TVSF_OPEN)) return;
 
   for (rd = t->regs; rd->name; rd++) {
   if (!(tv->f&TVSF_OPEN)) return;
 
   for (rd = t->regs; rd->name; rd++) {
-    if (TVEC_REG(tv, in, rd->i)->f&TVRF_LIVE)
-      { if (rd->i < tv->nrout) TVEC_REG(tv, out, rd->i)->f |= TVRF_LIVE; }
-    else if (!(rd->f&TVRF_OPT)) {
+    if (TVEC_REG(tv, in, rd->i)->f&TVRF_LIVE) {
+      if (rd->i < tv->cfg.nrout)
+       TVEC_REG(tv, out, rd->i)->f |= TVRF_LIVE;
+    } else if (!(rd->f&TVRF_OPT)) {
       tvec_error(tv, "required register `%s' not set in test `%s'",
                 rd->name, t->name);
       f |= f_err;
       tvec_error(tv, "required register `%s' not set in test `%s'",
                 rd->name, t->name);
       f |= f_err;
@@ -957,7 +958,7 @@ static const struct tvec_uenuminfo outcome_enum =
   { "test-outcome", outcome_assoc, &outcome_range };
 static const struct tvec_vardef outcome_vardef =
   { sizeof(struct tvec_reg), core_setvar,
   { "test-outcome", outcome_assoc, &outcome_range };
 static const struct tvec_vardef outcome_vardef =
   { sizeof(struct tvec_reg), core_setvar,
-    { "@outcome", 0, &tvty_uenum, 0, { &outcome_enum } } };
+    { "@outcome", &tvty_uenum, -1, 0, { &outcome_enum } } };
 
 static const struct tvec_vardef *core_findvar
   (struct tvec_state *tv, const char *name, void **ctx_out, void *ctx)
 
 static const struct tvec_vardef *core_findvar
   (struct tvec_state *tv, const char *name, void **ctx_out, void *ctx)
@@ -1023,7 +1024,7 @@ int tvec_read(struct tvec_state *tv, const char *infile, FILE *fp)
        ch = getc(tv->fp); if (ch != ']') tvec_syntax(tv, ch, "`]'");
 
        /* Find the matching test definition. */
        ch = getc(tv->fp); if (ch != ']') tvec_syntax(tv, ch, "`]'");
 
        /* Find the matching test definition. */
-       for (test = tv->tests; test->name; test++)
+       for (test = tv->cfg.tests; test->name; test++)
          if (STRCMP(d.buf, ==, test->name)) goto found_test;
 
        /* There wasn't one.  Report the error.  Muffle errors about the
          if (STRCMP(d.buf, ==, test->name)) goto found_test;
 
        /* There wasn't one.  Report the error.  Muffle errors about the
@@ -1211,19 +1212,18 @@ void tvec_begin(struct tvec_state *tv_out,
   tv_out->f = 0;
 
   assert(config->nrout <= config->nreg);
   tv_out->f = 0;
 
   assert(config->nrout <= config->nreg);
-  tv_out->nrout = config->nrout; tv_out->nreg = config->nreg;
-  tv_out->regsz = config->regsz;
-  tv_out->in = xmalloc(tv_out->nreg*tv_out->regsz);
-  tv_out->out = xmalloc(tv_out->nrout*tv_out->regsz);
-  for (i = 0; i < tv_out->nreg; i++) {
+  tv_out->cfg = *config;
+  tv_out->in = xmalloc(tv_out->cfg.nreg*tv_out->cfg.regsz);
+  tv_out->out = xmalloc(tv_out->cfg.nrout*tv_out->cfg.regsz);
+  for (i = 0; i < tv_out->cfg.nreg; i++) {
     TVEC_REG(tv_out, in, i)->f = 0;
     TVEC_REG(tv_out, in, i)->f = 0;
-    if (i < tv_out->nrout) TVEC_REG(tv_out, out, i)->f = 0;
+    if (i < tv_out->cfg.nrout) TVEC_REG(tv_out, out, i)->f = 0;
   }
 
   for (i = 0; i < TVOUT_LIMIT; i++)
     tv_out->curr[i] = tv_out->all[i] = tv_out->grps[i] = 0;
 
   }
 
   for (i = 0; i < TVOUT_LIMIT; i++)
     tv_out->curr[i] = tv_out->all[i] = tv_out->grps[i] = 0;
 
-  tv_out->tests = config->tests; tv_out->test = 0;
+  tv_out->test = 0;
   tv_out->infile = 0; tv_out->lno = 0; tv_out->fp = 0;
   tv_out->output = o; tv_out->output->ops->bsession(tv_out->output, tv_out);
 }
   tv_out->infile = 0; tv_out->lno = 0; tv_out->fp = 0;
   tv_out->output = o; tv_out->output->ops->bsession(tv_out->output, tv_out);
 }
@@ -1367,7 +1367,7 @@ static void fakefn(const struct tvec_reg *in, struct tvec_reg *out, void *p)
 void tvec_adhoc(struct tvec_state *tv, struct tvec_test *t)
 {
   t->name = "<unset>"; t->regs = &no_regs; t->env = 0; t->fn = fakefn;
 void tvec_adhoc(struct tvec_state *tv, struct tvec_test *t)
 {
   t->name = "<unset>"; t->regs = &no_regs; t->env = 0; t->fn = fakefn;
-  tv->tests = t;
+  tv->cfg.tests = t;
 }
 
 /* --- @tvec_begingroup@ --- *
 }
 
 /* --- @tvec_begingroup@ --- *
@@ -1387,7 +1387,7 @@ void tvec_adhoc(struct tvec_state *tv, struct tvec_test *t)
 void tvec_begingroup(struct tvec_state *tv, const char *name,
                     const char *file, unsigned lno)
 {
 void tvec_begingroup(struct tvec_state *tv, const char *name,
                     const char *file, unsigned lno)
 {
-  struct tvec_test *t = (/*unconst*/ struct tvec_test *)tv->tests;
+  struct tvec_test *t = (/*unconst*/ struct tvec_test *)tv->cfg.tests;
 
   t->name = name; tv->test = t;
   tv->infile = file; tv->lno = tv->test_lno = lno;
 
   t->name = name; tv->test = t;
   tv->infile = file; tv->lno = tv->test_lno = lno;
diff --git a/test/tvec-env.3 b/test/tvec-env.3
new file mode 100644 (file)
index 0000000..9a4a32f
--- /dev/null
@@ -0,0 +1,178 @@
+.\" -*-nroff-*-
+.de VS
+.sp 1
+.RS
+.nf
+.ft B
+..
+.de VE
+.ft R
+.fi
+.RE
+.sp 1
+..
+.de hP
+.IP
+.ft B
+\h'-\w'\\$1\ 'u'\\$1\ \c
+.ft P
+..
+.ie t \{\
+.  ds o \(bu
+.  de VP
+.    sp .4v
+..
+\}
+.el \{\
+.  ds o o
+.  de VP
+.    sp
+..
+\}
+..
+.TH tvec-env 3 "11 March 2024" "Straylight/Edgeware" "mLib utilities library"
+.SH NAME
+tvec-env \- test vector framework environments
+.\" @TVEG_GREG
+.\" @TVEG_REG
+.
+.\" @tvec_skipgroup
+.\" @tvec_skipgroup_v
+.\" @tvec_skip
+.\" @tvec_skip_v
+.\" @tvec_fail
+.\" @tvec_fail_v
+.\" @tvec_dumpreg
+.
+.\" @tvec_checkregs
+.\" @tvec_mismatch
+.\" @tvec_check
+.\" @tvec_check_v
+.
+.\" @tvec_report
+.\" @tvec_report_v
+.\" @tvec_error
+.\" @tvec_notice
+.\" @tvec_unkreg
+.\" @tvec_dupreg
+.
+.\" @tvec_serialize
+.\" @tvec_deserialize
+.
+.\" @tvec_initregs
+.\" @tvec_releaseregs
+.\" @tvec_releaseoutputs
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/tvec.h>"
+.PP
+.ta 2n
+.B "enum {"
+.B "   TVRD_INPUT,"
+.B "   TVRD_OUTPUT,"
+.B "   TVRD_MATCH,"
+.B "   TVRD_FOUND,"
+.B "   TVRD_EXPECT,"
+.B "   TVRD_LIMIT"
+.B "};"
+.B "struct tvec_state {"
+.B "   unsigned f;"
+.B "   struct tvec_config cfg;"
+.B "   struct tvec_reg *in, *out;"
+.B "   const struct tvec_test *test;"
+.B "   ..."
+.B "};"
+.B "#define TVSF_SKIP ..."
+.B "#define TVSF_ACTIVE ..."
+.B "#define TVSF_OUTMASK ..."
+.B "#define TVSF_OUTSHIFT ..."
+.B "#define TVSF_XFAIL ..."
+.PP
+.ta \w'\fBtypedef int tvec_setvarfn('u
+.BI "typedef int tvec_setvarfn(struct tvec_state *" tv ", const char *" var ,
+.BI "  const union tvec_regval *" rv ", void *" ctx );
+.ta \w'\fBtypedef int tvec_envsetupfn('u
+.BI "typedef void tvec_envsetupfn(struct tvec_state *" tv ,
+.BI "  const struct tvec_env *" env ,
+.BI "  void *" pctx ", void *" ctx );
+.ta 2n +\w'\fB('u
+.B "typedef const struct tvec_vardef *tvec_envfindvarfn"
+.BI "  (struct tvec_state *" tv ", const char *" name ,
+.BI "          void **" ctx_out ", void *" ctx );
+.BI "typedef void tvec_envbeforefn(struct tvec_state *" tv ", void *" ctx );
+.ta \w'\fBtypedef void tvec_envrunfn('u
+.BI "typedef void tvec_envrunfn(struct tvec_state *" tv ,
+.BI "  tvec_testfn *" fn ", void *" ctx );
+.BI "typedef void tvec_envafterfn(struct tvec_state *" tv ", void *" ctx );
+.BI "typedef void tvec_envteardownfn(struct tvec_state *" tv ", void *" ctx );
+.ta 2n
+.B "struct tvec_env {"
+.B "   size_t ctxsz;"
+.B "   tvec_envsetupfn *setup;"
+.B "   tvec_envfindvarfn *findvar;"
+.B "   tvec_envbeforefn *before;"
+.B "   tvec_envrunfn *run;"
+.B "   tvec_envafterfn *after;"
+.B "   tvec_envteardownfn *teardown;"
+.B "};"
+.PP
+.ta \w'\fBstruct tvec_reg *TVEC_GREG('u
+.BI "struct tvec_reg *TVEC_GREG(struct tvec_reg *" vec ,
+.BI "  unsigned " i ", size_t " regsz );
+.ta \w'\fBstruct tvec_reg *TVEC_REG('u
+.BI "struct tvec_reg *TVEC_REG(struct tvec_state *" tv ", " vec ", unsigned " i );
+.PP
+.BI "void tvec_skipgroup(struct tvec_state *" tv ", const char *" excuse ", ...);"
+.ta \w'\fBvoid tvec_skipgroup_v('u
+.BI "void tvec_skipgroup_v(struct tvec_state *" tv ,
+.BI "  const char *" excuse ", va_list *" ap );
+.BI "void tvec_skip(struct tvec_state *" tv ", const char *" excuse ", ...);"
+.ta \w'\fBvoid tvec_skip_v('u
+.BI "void tvec_skip_v(struct tvec_state *" tv ,
+.BI "  const char *" excuse ", va_list *" ap );
+.BI "void tvec_fail(struct tvec_state *" tv ", const char *" detail ", ...);"
+.ta \w'\fBvoid tvec_fail_v('u
+.BI "void tvec_fail_v(struct tvec_state *" tv ,
+.BI "  const char *" detail ", va_list *" ap );
+.ta \w'\fBvoid tvec_dumpreg('u
+.BI "void tvec_dumpreg(struct tvec_state *" tv ,
+.BI "  unsigned " disp ", const union tvec_regval *" rv ,
+.BI "  const struct tvec_regdef *" rd );
+.PP
+.BI "void tvec_checkregs(struct tvec_state *" tv );
+.BI "void tvec_mismatch(struct tvec_state *" tv ", unsigned " f );
+.BI "void tvec_check(struct tvec_state *" tv ", const char *" detail ", ...);"
+.ta \w'\fBvoid tvec_check_v('u
+.BI "void tvec_check_v(struct tvec_state *" tv ,
+.B "#define TVMF_IN ..."
+.B "#define TVMF_OUT ..."
+.PP
+.B "enum {"
+.B "   TVLEV_NOTE = ...,"
+.B "   TVLEV_ERR = ...,"
+.B "   ..."
+.B "};"
+.ta \w'\fBvoid tvec_report('u
+.BI "void tvec_report(struct tvec_state *" tv ", unsigned " level ,
+.BI "  const char *" msg ", ...);"
+.ta \w'\fBvoid tvec_report_v('u
+.BI "void tvec_report_v(struct tvec_state *" tv ", unsigned " level ,
+.BI "  const char *" msg ", va_list *" ap );
+.BI "int tvec_error(struct tvec_state *" tv ", const char *" msg ", ...);"
+.BI "void tvec_notice(struct tvec_state *" tv ", const char *" msg ", ...);"
+.BI "int tvec_unkreg(struct tvec_state *" tv ", const char *" name );
+.BI "int tvec_dupreg(struct tvec_state *" tv ", const char *" name );
+.PP
+.ta \w'\fBint tvec_serialize('u
+.BI "int tvec_serialize(const struct tvec_reg *" rv ", buf *" b ,
+.BI "  const struct tvec_regdef *" regs ,
+.BI "  unsigned " nr ", size_t " regsz );
+.ta \w'\fBint tvec_deserialize('u
+.BI "int tvec_deserialize(struct tvec_reg *" rv ", buf *" b ,
+.BI "  const struct tvec_regdef *" regs ,
+.BI "  unsigned " nr ", size_t " regsz );
+.PP
+.BI "void tvec_initregs(struct tvec_state *" tv );
+.BI "void tvec_releaseregs(struct tvec_state *" tv );
+.BI "void tvec_releaseoutputs(struct tvec_state *" tv );
+.fi
diff --git a/test/tvec-main.3 b/test/tvec-main.3
new file mode 100644 (file)
index 0000000..67a31d2
--- /dev/null
@@ -0,0 +1,64 @@
+.\" -*-nroff-*-
+.de VS
+.sp 1
+.RS
+.nf
+.ft B
+..
+.de VE
+.ft R
+.fi
+.RE
+.sp 1
+..
+.de hP
+.IP
+.ft B
+\h'-\w'\\$1\ 'u'\\$1\ \c
+.ft P
+..
+.ie t \{\
+.  ds o \(bu
+.  de VP
+.    sp .4v
+..
+\}
+.el \{\
+.  ds o o
+.  de VP
+.    sp
+..
+\}
+..
+.TH tvec-main 3 "11 March 2024" "Straylight/Edgeware" "mLib utilities library"
+.SH NAME
+tvec-main \- test vector framework program frontend
+.\" @tvec_parseargs
+.\" @tvec_readstdin
+.\" @tvec_readfile
+.\" @tvec_readarg
+.\" @tvec_readdflt
+.\" @tvec_readargs
+.\" @tvec_main
+.
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/tvec.h>"
+.PP
+.ta \w'\fBvoid tvec_parseargs('u
+.BI "void tvec_parseargs(int " argc ", char *" argv "[],"
+.BI "  struct tvec_state *" tv_out ,
+.BI "  int *" argpos_out ,
+.BI "  const struct tvec_config *" config );
+.BI "int tvec_readstdin(struct tvec_state *" tv );
+.BI "int tvec_readfile(struct tvec_state *" tv ", const char *" file );
+.BI "int tvec_readarg(struct tvec_state *" tv ", const char *" arg );
+.BI "int tvec_readdflt(struct tvec_state *" tv ", const char *" file );
+.ta \w'\fBvoid tvec_readargs('u
+.BI "void tvec_readargs(int " argc ", char *" argv "[],"
+.BI "  struct tvec_state *" tv ,
+.BI "  int *" argpos_out ", const char *" dflt );
+.ta \w'\fBvoid tvec_main('u
+.BI "void tvec_main(int " argc ", char *" argv "[],"
+.BI "  const struct tvec_config *" config ", const char *" dflt );
+.fi
diff --git a/test/tvec-output.3 b/test/tvec-output.3
new file mode 100644 (file)
index 0000000..1a0a036
--- /dev/null
@@ -0,0 +1,96 @@
+.\" -*-nroff-*-
+.de VS
+.sp 1
+.RS
+.nf
+.ft B
+..
+.de VE
+.ft R
+.fi
+.RE
+.sp 1
+..
+.de hP
+.IP
+.ft B
+\h'-\w'\\$1\ 'u'\\$1\ \c
+.ft P
+..
+.ie t \{\
+.  ds o \(bu
+.  de VP
+.    sp .4v
+..
+\}
+.el \{\
+.  ds o o
+.  de VP
+.    sp
+..
+\}
+..
+.TH tvec-output 3 "11 March 2024" "Straylight/Edgeware" "mLib utilities library"
+.SH NAME
+tvec-output \- test vector framework output driver interface
+.\" @tvec_strlevel
+.
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/tvec.h>"
+.PP
+.ta 2n
+.B "enum {"
+.B "   TVOUT_LOSE,"
+.B "   TVOUT_SKIP,"
+.B "   TVOUT_WIN,"
+.B "   TVOUT_XFAIL,"
+.B "   TVOUT_LIMIT"
+.B "};"
+.PP
+.B "struct tvec_state {"
+.B "   unsigned f;"
+.B "   const struct tvec_test *test;"
+.B "   unsigned curr[TVOUT_LIMIT], all[TVOUT_LIMIT], grps[TVOUT_LIMIT];"
+.B "   ..."
+.B "};"
+.B "#define TVSF_ERROR ..."
+.PP
+.B "struct tvec_output {"
+.B "   const struct tvec_outops *ops;"
+.B "};"
+.B "struct tvec_outops {"
+.BI "  void (*" bsession ")(struct tvec_output *" o ", struct tvec_state *" tv );
+.BI "  int (*" esession ")(struct tvec_output *" o );
+.BI "  void (*" bgroup ")(struct tvec_output *" o );
+.ta 2n +\w'\fBvoid (*\,\fIskipgroup\/\fB)('u
+.BI "  void (*" skipgroup ")(struct tvec_output *" o ,
+.BI "          const char *" excuse ", void *" ap );
+.BI "  void (*" egroup ")(struct tvec_output *" o );
+.BI "  void (*" btest ")(struct tvec_output *" o );
+.ta 2n +\w'\fBvoid (*\,\fIskip\/\fB)('u
+.BI "  void (*" skip ")(struct tvec_output *" o ,
+.BI "          const char *" excuse ", void *" ap );
+.ta 2n +\w'\fBvoid (*\,\fIfail\/\fB)('u
+.BI "  void (*" fail ")(struct tvec_output *" o ,
+.BI "          const char *" fail ", void *" ap );
+.ta 2n +\w'\fBvoid (*\,\fIdumpreg\/\fB)('u
+.BI "  void (*" dumpreg ")(struct tvec_output *" o ,
+.BI "          unsigned " disp ", const union tvec_regval *" rv ,
+.BI "          const struct tvec_regdef *" rd );
+.BI "  void (*" etest ")(struct tvec_output *" o ", unsigned " outcome );
+.ta 2n +\w'\fBvoid (*\,\fIbbench\/\fB)('u
+.BI "  void (*" bbench ")(struct tvec_output *" o ,
+.BI "          const char *" ident ", unsigned " unit );
+.ta 2n +\w'\fBvoid (*\,\fIebench\/\fB)('u
+.BI "  void (*" ebench ")(struct tvec_output *" o ,
+.BI "          const char *" ident ", unsigned " unit ,
+.BI "          const struct bench_timing *" tm );
+.ta 2n +\w'\fBvoid (*\,\fIreport\/\fB)('u
+.BI "  void (*" report ")(struct tvec_output *" o ", unsigned " level ,
+.BI "          const char *" msg ", va_list *" ap );
+.BI "  void (*" level ")(struct tvec_output *" o );
+.B "};"
+.PP
+.B "const char *tvec_strlevel(unsigned " level );
+.fi
diff --git a/test/tvec-remote.3 b/test/tvec-remote.3
new file mode 100644 (file)
index 0000000..d7ae260
--- /dev/null
@@ -0,0 +1,109 @@
+.\" -*-nroff-*-
+.de VS
+.sp 1
+.RS
+.nf
+.ft B
+..
+.de VE
+.ft R
+.fi
+.RE
+.sp 1
+..
+.de hP
+.IP
+.ft B
+\h'-\w'\\$1\ 'u'\\$1\ \c
+.ft P
+..
+.ie t \{\
+.  ds o \(bu
+.  de VP
+.    sp .4v
+..
+\}
+.el \{\
+.  ds o o
+.  de VP
+.    sp
+..
+\}
+..
+.TH tvec-remote 3 "11 March 2024" "Straylight/Edgeware" "mLib utilities library"
+.SH NAME
+tvec-remote \- test vector framework remote invocation
+.\" @TVEC_REMOTEENV
+.\" @TVEC_FORK
+.\" @TVEC_EXEC
+.\" @tvec_fork
+.\" @tvec_exec
+.
+.\" @tvec_setprogress
+.\" @tvec_setprogress_v
+.
+.\" @tvec_remoteserver
+.
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/tvec.h>"
+.PP
+.ta \w'\fBtypedef int tvec_connectfn('u
+.BI "typedef int tvec_connectfn(pid_t *" kid_out ", int *" infd_out ,
+.BI "  int *" outfd_out ", int *" errfd_out ,
+.BI "  struct tvec_state *" tv ,
+.BI "  const struct tvec_remoteenv *" env );
+.PP
+.ta 2n
+.B "struct tvec_remoteenv_slots {"
+.B "   tvec_connectfn *connect;"
+.B "   const struct tvec_env *env;"
+.B "   unsigned dflt_reconn;"
+.B "};"
+.B "struct tvec_remoteenv {"
+.B "   struct tvec_env _env;"
+.B "   struct tvec_remoteenv_slots r;"
+.B "};"
+.B "#define TVEC_REMOTEENV ..."
+.PP
+.B "#define TVXF_VALMASK ..."
+.B "#define TVXF_SIG ..."
+.B "#define TVXF_CAUSEMASK ..."
+.B "#define TVXST_RUN ..."
+.B "#define TVXST_EXIT ..."
+.B "#define TVXST_KILL ..."
+.B "#define TVXST_CONT ..."
+.B "#define TVXST_STOP ..."
+.B "#define TVXST_DISCONN ..."
+.B "#define TVXST_UNK ..."
+.B "#define TVXST_ERR ..."
+.PP
+.B "struct tvec_remotefork_slots {"
+.B "   const struct tvec_test *tests;"
+.B "};"
+.B "struct tvec_remotefork {"
+.B "   struct tvec_env _env;"
+.B "   struct tvec_remoteenv_slots r;"
+.B "   struct tvec_remotefork_slots f;"
+.B "};"
+.B "tvec_connectfn tvec_fork;"
+.BI "#define TVEC_REMOTEFORK(" subenv ", " tests ") ..."
+.PP
+.B "struct tvec_remoteexec_slots {"
+.B "   const char *const *args;"
+.B "};"
+.B "struct tvec_remoteexec {"
+.B "   struct tvec_env _env;"
+.B "   struct tvec_remoteenv_slots r;"
+.B "   struct tvec_remoteexec_slots x;"
+.B "};"
+.B "tvec_connectfn tvec_exec;"
+.BI "#define TVEC_REMOTEEXEC(" subenv ", " args ") ..."
+.PP
+.BI "void tvec_setprogress(const char *" status ", ...);"
+.BI "void tvec_setprogress_v(const char *" status ", va_list *" ap );
+.PP
+.ta \w'\fBint tvec_remoteserver('u
+.BI "int tvec_remoteserver(int " infd ", int " outfd ,
+.BI "  const struct tvec_config *" config );
+.fi
index c167618..3c25282 100644 (file)
@@ -645,7 +645,7 @@ int tvec_remoteserver(int infd, int outfd, const struct tvec_config *config)
        if (BLEFT(&b)) goto bad;
 
        /* Find the group given its name. */
        if (BLEFT(&b)) goto bad;
 
        /* Find the group given its name. */
-       for (t = srvtv.tests; t->name; t++)
+       for (t = srvtv.cfg.tests; t->name; t++)
          if (strlen(t->name) == sz && MEMCMP(t->name, ==, p, sz))
            goto found_group;
        rc = ioerr(&srvtv, &srvrc, "unknown test group `%.*s'",
          if (strlen(t->name) == sz && MEMCMP(t->name, ==, p, sz))
            goto found_group;
        rc = ioerr(&srvtv, &srvrc, "unknown test group `%.*s'",
@@ -731,7 +731,7 @@ int tvec_remoteserver(int infd, int outfd, const struct tvec_config *config)
 
              /* Parse the packet payload. */
              if (tvec_deserialize(srvtv.in, &b, srvtv.test->regs,
 
              /* Parse the packet payload. */
              if (tvec_deserialize(srvtv.in, &b, srvtv.test->regs,
-                                  srvtv.nreg, srvtv.regsz))
+                                  srvtv.cfg.nreg, srvtv.cfg.regsz))
                goto bad;
              if (BLEFT(&b)) goto bad;
 
                goto bad;
              if (BLEFT(&b)) goto bad;
 
@@ -743,7 +743,7 @@ int tvec_remoteserver(int infd, int outfd, const struct tvec_config *config)
                /* Prepare the output registers and reset the test outcome.
                 * (The environment may force a skip.)
                 */
                /* Prepare the output registers and reset the test outcome.
                 * (The environment may force a skip.)
                 */
-               for (i = 0; i < srvtv.nrout; i++)
+               for (i = 0; i < srvtv.cfg.nrout; i++)
                  if (TVEC_REG(&srvtv, in, i)->f&TVRF_LIVE)
                    TVEC_REG(&srvtv, out, i)->f |= TVRF_LIVE;
                srvtv.f |= TVSF_ACTIVE; srvtv.f &= ~TVSF_OUTMASK;
                  if (TVEC_REG(&srvtv, in, i)->f&TVRF_LIVE)
                    TVEC_REG(&srvtv, out, i)->f |= TVRF_LIVE;
                srvtv.f |= TVSF_ACTIVE; srvtv.f &= ~TVSF_OUTMASK;
@@ -1289,13 +1289,13 @@ static const struct tvec_flaginfo exit_flaginfo =
   { "exit-status", exit_flags, &tvrange_uint };
 static const struct tvec_vardef exit_var =
   { sizeof(struct tvec_reg), setvar_local,
   { "exit-status", exit_flags, &tvrange_uint };
 static const struct tvec_vardef exit_var =
   { sizeof(struct tvec_reg), setvar_local,
-    { "@exit", -1, &tvty_flags, 0, { &exit_flaginfo } } };
+    { "@exit", &tvty_flags, -1, 0, { &exit_flaginfo } } };
 
 /* Progress. */
 
 static const struct tvec_vardef progress_var =
   { sizeof(struct tvec_reg), setvar_local,
 
 /* Progress. */
 
 static const struct tvec_vardef progress_var =
   { sizeof(struct tvec_reg), setvar_local,
-    { "@progress", -1, &tvty_text, 0 } };
+    { "@progress", &tvty_text, -1, 0 } };
 
 /* Reconnection. */
 
 
 /* Reconnection. */
 
@@ -1309,7 +1309,7 @@ static const struct tvec_uenuminfo reconn_enuminfo =
   { "remote-reconnection", reconn_assocs, &tvrange_uint };
 static const struct tvec_vardef reconn_var =
   { sizeof(struct tvec_reg), setvar_local,
   { "remote-reconnection", reconn_assocs, &tvrange_uint };
 static const struct tvec_vardef reconn_var =
   { sizeof(struct tvec_reg), setvar_local,
-    { "@reconnect", -1, &tvty_uenum, 0, { &reconn_enuminfo } } };
+    { "@reconnect", &tvty_uenum, -1, 0, { &reconn_enuminfo } } };
 
 /*----- Client ------------------------------------------------------------*/
 
 
 /*----- Client ------------------------------------------------------------*/
 
@@ -1361,7 +1361,7 @@ static int handle_packets(struct tvec_state *tv, struct tvec_remotectx *r,
   buf *b = b_out;
   const struct tvec_regdef *rd;
   struct bench_timing bt;
   buf *b = b_out;
   const struct tvec_regdef *rd;
   struct bench_timing bt;
-  struct tvec_reg *reg = 0;
+  struct tvec_reg *reg = 0; size_t rsz = 0;
   unsigned i;
   int rc;
 
   unsigned i;
   int rc;
 
@@ -1476,7 +1476,8 @@ static int handle_packets(struct tvec_state *tv, struct tvec_remotectx *r,
        if (!rc)
          tvec_dumpreg(tv, v, 0, rd);
        else {
        if (!rc)
          tvec_dumpreg(tv, v, 0, rd);
        else {
-         if (!reg) reg = xmalloc(tv->regsz);
+         GROWBUF_REPLACE(&arena_stdlib, reg, rsz, tv->cfg.regsz,
+                         8*sizeof(void *), 1);
          rd->ty->init(&reg->v, rd);
          rc = rd->ty->frombuf(b, &reg->v, rd);
          if (!rc) tvec_dumpreg(tv, v, &reg->v, rd);
          rd->ty->init(&reg->v, rd);
          rc = rd->ty->frombuf(b, &reg->v, rd);
          if (!rc) tvec_dumpreg(tv, v, &reg->v, rd);
@@ -2046,7 +2047,7 @@ void tvec_remoterun(struct tvec_state *tv, tvec_testfn *fn, void *ctx)
   /* Send the command to the server and handle output. */
   QUEUEPK(tv, &r->rc, QF_FORCE, TVPK_TEST)
     tvec_serialize(tv->in, DBUF_BUF(&r->rc.bout),
   /* Send the command to the server and handle output. */
   QUEUEPK(tv, &r->rc, QF_FORCE, TVPK_TEST)
     tvec_serialize(tv->in, DBUF_BUF(&r->rc.bout),
-                  tv->test->regs, tv->nreg, tv->regsz);
+                  tv->test->regs, tv->cfg.nreg, tv->cfg.regsz);
   else { goto fail; }
   rc = handle_packets(tv, r, RCVF_ALLOWEOF, TVPK_TEST | TVPF_ACK, &b);
 
   else { goto fail; }
   rc = handle_packets(tv, r, RCVF_ALLOWEOF, TVPK_TEST | TVPF_ACK, &b);
 
@@ -2286,9 +2287,9 @@ int tvec_fork(pid_t *kid_out, int *infd_out, int *outfd_out, int *errfd_out,
   if (fork_common(&kid, &infd, &outfd, &errfd, tv)) { rc = -1; goto end; }
   if (!kid) {
     if (tv->fp) fclose(tv->fp);
   if (fork_common(&kid, &infd, &outfd, &errfd, tv)) { rc = -1; goto end; }
   if (!kid) {
     if (tv->fp) fclose(tv->fp);
-    config.tests = rf->f.tests ? rf->f.tests : tv->tests;
-    config.nrout = tv->nrout; config.nreg = tv->nreg;
-    config.regsz = tv->regsz;
+    config.tests = rf->f.tests ? rf->f.tests : tv->cfg.tests;
+    config.nrout = tv->cfg.nrout; config.nreg = tv->cfg.nreg;
+    config.regsz = tv->cfg.regsz;
     _exit(tvec_remoteserver(infd, outfd, &config));
   }
 
     _exit(tvec_remoteserver(infd, outfd, &config));
   }
 
diff --git a/test/tvec-timeout.3 b/test/tvec-timeout.3
new file mode 100644 (file)
index 0000000..fd4568e
--- /dev/null
@@ -0,0 +1,52 @@
+.\" -*-nroff-*-
+.de VS
+.sp 1
+.RS
+.nf
+.ft B
+..
+.de VE
+.ft R
+.fi
+.RE
+.sp 1
+..
+.de hP
+.IP
+.ft B
+\h'-\w'\\$1\ 'u'\\$1\ \c
+.ft P
+..
+.ie t \{\
+.  ds o \(bu
+.  de VP
+.    sp .4v
+..
+\}
+.el \{\
+.  ds o o
+.  de VP
+.    sp
+..
+\}
+..
+.TH tvec-timeout 3 "11 March 2024" "Straylight/Edgeware" "mLib utilities library"
+.SH NAME
+tvec-timeout \- test vector framework timeouts
+.\" @TVEC_TIMEOUTENV
+.\" @TVEC_TIMEOUTINIT
+.
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/tvec.h>"
+.PP
+.ta 2n
+.B "struct tvec_timeoutenv {"
+.B "   struct tvec_env _env;"
+.B "   int timer;"
+.B "   double t;"
+.B "   const struct tvec_env *env;"
+.B "};"
+.B "#define TVEC_TIMEOUTENV ..."
+.BI "#define TVEC_TIMEOUTINIT(" timer ", " t ") ..."
+.fi
index a1800db..5e386e2 100644 (file)
@@ -118,7 +118,7 @@ static int setvar(struct tvec_state *tv, const char *var,
 
 static const struct tvec_vardef timeout_var =
   { sizeof(struct tvec_reg), setvar,
 
 static const struct tvec_vardef timeout_var =
   { sizeof(struct tvec_reg), setvar,
-    { "@timeout", -1, &tvty_duration, 0 } };
+    { "@timeout", &tvty_duration, -1, 0 } };
 
 static const struct tvec_iassoc timer_assocs[] = {
   { "REAL",    ITIMER_REAL },
 
 static const struct tvec_iassoc timer_assocs[] = {
   { "REAL",    ITIMER_REAL },
@@ -130,7 +130,7 @@ static const struct tvec_ienuminfo timer_enum =
   { "interval-timer", timer_assocs, &tvrange_int };
 static const struct tvec_vardef timer_var =
   { sizeof(struct tvec_reg), setvar,
   { "interval-timer", timer_assocs, &tvrange_int };
 static const struct tvec_vardef timer_var =
   { sizeof(struct tvec_reg), setvar,
-    { "@timer", -1, &tvty_ienum, 0, { &timer_enum } } };
+    { "@timer", &tvty_ienum, -1, 0, { &timer_enum } } };
 
 const struct tvec_vardef *tvec_timeoutfindvar
   (struct tvec_state *tv, const char *var, void **ctx_out, void *ctx)
 
 const struct tvec_vardef *tvec_timeoutfindvar
   (struct tvec_state *tv, const char *var, void **ctx_out, void *ctx)
diff --git a/test/tvec-tyimpl.3 b/test/tvec-tyimpl.3
new file mode 100644 (file)
index 0000000..0e3dce7
--- /dev/null
@@ -0,0 +1,103 @@
+.\" -*-nroff-*-
+.de VS
+.sp 1
+.RS
+.nf
+.ft B
+..
+.de VE
+.ft R
+.fi
+.RE
+.sp 1
+..
+.de hP
+.IP
+.ft B
+\h'-\w'\\$1\ 'u'\\$1\ \c
+.ft P
+..
+.ie t \{\
+.  ds o \(bu
+.  de VP
+.    sp .4v
+..
+\}
+.el \{\
+.  ds o o
+.  de VP
+.    sp
+..
+\}
+..
+.TH tvec-tyimpl 3 "11 March 2024" "Straylight/Edgeware" "mLib utilities library"
+.SH NAME
+tvec-tyimpl \- test vector framework type implementation
+.\" @tvec_syntax
+.\" @tvec_syntax_v
+.
+.\" @tvec_skipspc
+.\" @tvec_flushtoeol
+.\" @tvec_nexttoken
+.\" @tvec_readword
+.\" @tvec_readword_v
+.
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/tvec.h>"
+.PP
+.B "struct tvec_state {"
+.B "   unsigned f;"
+.B "   const char *infile; unsigned lno, test_lno;"
+.B "   FILE *fp;"
+.B "   ..."
+.B "};"
+.PP
+.B "struct tvec_regty {"
+.ta 2n +\w'\fBvoid (*init)('u
+.BI "  void (*init)(union tvec_regval *" rv ,
+.BI "          const struct tvec_regdef *" rd );
+.ta 2n +\w'\fBvoid (*release)('u
+.BI "  void (*release)(union tvec_regval *" rv ,
+.BI "          const struct tvec_regdef *" rd );
+.ta 2n +\w'\fBint (*eq)('u
+.BI "  int (*eq)(const union tvec_regval *" rv0 ,
+.BI "          const union tvec_regval *" rv1 ,
+.BI "          const struct tvec_regdef *" rd );
+.ta 2n +\w'\fBint (*tobuf)('u
+.BI "  int (*tobuf)(buf *" b ", const union tvec_regval *" rv ,
+.BI "          const struct tvec_regdef *" rd );
+.ta 2n +\w'\fBint (*frombuf)('u
+.BI "  int (*frombuf)(buf *" b ", union tvec_regval *" rv ,
+.BI "          const struct tvec_regdef *" rd );
+.ta 2n +\w'\fBint (*parse)('u
+.BI "  int (*parse)(union tvec_regval *" rv ", const struct tvec_regdef *" rd ,
+.BI "          struct tvec_state *" tv );
+.ta 2n +\w'\fBvoid (*dump)('u
+.BI "  void (*dump)(const union tvec_regval *" rv ,
+.BI "          const struct tvec_regdef *" rd ,
+.BI "          unsigned " style ,
+.BI "          const struct gprintf_ops *" gops ", void *" go );
+.B "};"
+.B "#define TVSF_COMPACT ..."
+.PP
+.ta \w'\fBint tvec_syntax('u
+.BI "int tvec_syntax(struct tvec_state *" tv ", int " ch ,
+.BI "  const char *" expect ", ...);"
+.ta \w'\fBint tvec_syntax_v('u
+.BI "int tvec_syntax(struct tvec_state *" tv ", int " ch ,
+.BI "  const char *" expect ", va_list *" ap );
+.PP
+.B "#define TVFF_ALLOWANY ..."
+.B "void tvec_skipspc(struct tvec_state *" tv );
+.B "int tvec_flushtoeol(struct tvec_state *" tv );
+.B "int tvec_nexttoken(struct tvec_state *" tv );
+.ta \w'\fBint tvec_readword('u
+.BI "int tvec_readword(struct tvec_state *" tv ", dstr *" d ,
+.BI "  const char **" p_inout ", const char *" delims ,
+.BI "  const char *" expect ", ...);"
+.ta \w'\fBint tvec_readword_v('u
+.BI "int tvec_readword_v(struct tvec_state *" tv ", dstr *" d ,
+.BI "  const char **" p_inout ", const char *" delims ,
+.BI "  const char *" expect ", va_list *" ap );
+.fi
diff --git a/test/tvec-types.3 b/test/tvec-types.3
new file mode 100644 (file)
index 0000000..4c682dc
--- /dev/null
@@ -0,0 +1,323 @@
+.\" -*-nroff-*-
+.de VS
+.sp 1
+.RS
+.nf
+.ft B
+..
+.de VE
+.ft R
+.fi
+.RE
+.sp 1
+..
+.de hP
+.IP
+.ft B
+\h'-\w'\\$1\ 'u'\\$1\ \c
+.ft P
+..
+.ie t \{\
+.  ds o \(bu
+.  de VP
+.    sp .4v
+..
+\}
+.el \{\
+.  ds o o
+.  de VP
+.    sp
+..
+\}
+..
+.TH tvec-types 3 "11 March 2024" "Straylight/Edgeware" "mLib utilities library"
+.SH NAME
+tvec-types \- test vector framework provided register types
+.\" @tvty_int
+.\" @tvty_uint
+.\" @tvty_float
+.\" @tvty_duration
+.\" @tvty_ienum
+.\" @tvty_uenum
+.\" @tvty_fenum
+.\" @tvty_penum
+.\" @tvty_flags
+.\" @tvty_char
+.\" @tvty_text
+.\" @tvty_bytes
+.\" @tvty_buffer
+.
+.\" @tvrange_schar
+.\" @tvrange_short
+.\" @tvrange_int
+.\" @tvrange_long
+.\" @tvrange_sbyte
+.\" @tvrange_i16
+.\" @tvrange_i32
+.\" @tvrange_uchar
+.\" @tvrange_ushort
+.\" @tvrange_uint
+.\" @tvrange_ulong
+.\" @tvrange_size
+.\" @tvrange_byte
+.\" @tvrange_u16
+.\" @tvrange_u32
+.
+.\" @tvflt_finite
+.\" @tvflt_nonneg
+.
+.\" @tvenum_bool
+.\" @tvenum_cmp
+.
+.\" @tvec_claimeq_int
+.\" @tvec_claimeq_uint
+.\" @tvec_claimeqish_float
+.\" @tvec_claimeq_float
+.\" @tvec_claimeq_ienum
+.\" @tvec_claimeq_uenum
+.\" @tvec_claimeq_fenum
+.\" @tvec_claimeq_penum
+.\" @tvec_claimeq_flags
+.\" @tvec_claimeq_char
+.\" @tvec_claimeq_text
+.\" @tvec_claimeq_textz
+.\" @tvec_claimeq_bytes
+.\" @TVEC_CLAIMEQ_INT
+.\" @TVEC_CLAIMEQ_UINT
+.\" @TVEC_CLAIMEQISH_FLOAT
+.\" @TVEC_CLAIMEQ_FLOAT
+.\" @TVEC_CLAIMEQ_IENUM
+.\" @TVEC_CLAIMEQ_UENUM
+.\" @TVEC_CLAIMEQ_FENUM
+.\" @TVEC_CLAIMEQ_PENUM
+.\" @TVEC_CLAIMEQ_FLAGS
+.\" @TVEC_CLAIMEQ_CHAR
+.\" @TVEC_CLAIMEQ_TEXT
+.\" @TVEC_CLAIMEQ_TEXTZ
+.\" @TVEC_CLAIMEQ_BYTES
+.
+.\" @tvec_parsedurunit
+.\" @tvec_alloctext
+.\" @tvec_allocbytes
+.\" @tvec_initbuffer
+.\" @tvec_allocbuffer
+.
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/tvec.h>"
+.PP
+.B "const struct tvec_regty tvty_int, tvty_uint;"
+.PP
+.B "struct tvec_irange { long min, max; };"
+.B "struct tvec_urange { unsigned long min, max; };"
+.PP
+.ta 2n
+.B "const struct tvec_irange"
+.B "   tvrange_schar, tvrange_short, tvrange_int, tvrange_long,"
+.B "   tvrange_sbyte, tvrange_i16, tvrange_i32;"
+.B "const struct tvec_urange"
+.B "   tvrange_uchar, tvrange_ushort, tvrange_uint,"
+.B "   tvrange_ulong, tvrange_size,"
+.B "   tvrange_byte, tvrange_u16, tvrange_u32;"
+.PP
+.ta \w'\fBint tvec_claimeq_int('u
+.BI "int tvec_claimeq_int(struct tvec_state *" tv ,
+.BI "  long " i0 ", long " i1 ,
+.BI "  const char *" file ", unsigned " lno ,
+.BI "  const char *" expr );
+.BI "int TVEC_CLAIMEQ_INT(struct tvec_state *" tv ", long " i0 ", long " i1 );
+.ta \w'\fBint tvec_claimeq_uint('u
+.BI "int tvec_claimeq_uint(struct tvec_state *" tv ,
+.BI "  unsigned long " u0 ", unsigned long " u1 ,
+.BI "  const char *" file ", unsigned " lno ,
+.BI "  const char *" expr );
+.ta \w'\fBint TVEC_CLAIMEQ_UINT('u
+.BI "int TVEC_CLAIMEQ_UINT(struct tvec_state *" tv ,
+.BI "  unsigned long " u0 ", unsigned long " u1 );
+.PP
+.B "const struct tvec_regty tvty_float;"
+.PP
+.ta 2n
+.B "struct tvec_floatinfo {"
+.B "   unsigned f;"
+.B "   double min, max;"
+.B "   double delta;"
+.B "};"
+.B "#define TVFF_NOMIN ..."
+.B "#define TVFF_NOMAX ..."
+.B "#define TVFF_NANOK ..."
+.B "#define TVFF_EQMASK ..."
+.B "#define TVFF_EXACT ..."
+.B "#define TVFF_ABSDELTA ..."
+.B "#define TVFF_RELDELTA ..."
+.PP
+.B "const struct tvec_floatinfo tvflt_finite, tvflt_nonneg;"
+.PP
+.ta \w'\fBint tvec_claimeqish_float('u
+.BI "int tvec_claimeqish_float(struct tvec_state *" tv ,
+.BI "  double " f0 ", double " f1 ,
+.BI "  unsigned " f ", double " delta ,
+.BI "  const char *" file ", unsigned " lno ,
+.BI "  const char *" expr );
+.ta \w'\fBint TVEC_CLAIMEQISH_FLOAT('u
+.BI "int TVEC_CLAIMEQISH_FLOAT(struct tvec_state *" tv ,
+.BI "  double " f0 ", double " f1 ,
+.BI "  unsigned " f ", double " delta );
+.ta \w'\fBint tvec_claimeq_float('u
+.BI "int tvec_claimeq_float(struct tvec_state *" tv ,
+.BI "  double " f0 ", double " f1 ,
+.BI "  const char *" file ", unsigned " lno ,
+.BI "  const char *" expr );
+.ta \w'\fBint TVEC_CLAIMEQ_FLOAT('u
+.BI "int TVEC_CLAIMEQ_FLOAT(struct tvec_state *" tv ,
+.BI "  double " f0 ", double " f1 );
+.PP
+.B "const struct tvec_regty tvty_duration;"
+.PP
+.BI "int tvec_parsedurunit(double *" scale_out ", const char **" p_inout );
+.PP
+.B "const struct tvec_regty tvty_ienum, tvty_uenum, tvty_fenum, tvty_penum;"
+.PP
+.B "struct tvec_iassoc { const char *tag; long i; };"
+.B "struct tvec_uassoc { const char *tag; unsigned long u; };"
+.B "struct tvec_fassoc { const char *tag; double f; };"
+.B "struct tvec_passoc { const char *tag; void *p; };"
+.B "#define TVEC_ENDENUM ..."
+.PP
+.ta 2n
+.B "struct tvec_ienuminfo {"
+.B "   const char *name;"
+.B "   const struct tvec_iassoc *av;"
+.B "   const struct tvec_irange *ir;"
+.B "};"
+.B "struct tvec_uenuminfo {"
+.B "   const char *name;"
+.B "   const struct tvec_uassoc *av;"
+.B "   const struct tvec_urange *ur;"
+.B "};"
+.B "struct tvec_fenuminfo {"
+.B "   const char *name;"
+.B "   const struct tvec_fassoc *av;"
+.B "   const struct tvec_floatinfo *fi;"
+.B "};"
+.B "struct tvec_penuminfo {"
+.B "   const char *name;"
+.B "   const struct tvec_passoc *av;"
+.B "};"
+.B "const struct tvec_ienuminfo tvenum_bool;"
+.B "const struct tvec_ienuminfo tvenum_cmp;"
+.PP
+.ta \w'\fBint tvec_claimeq_ienum('u
+.BI "int tvec_claimeq_ienum(struct tvec_state *" tv ,
+.BI "  const struct tvec_uenuminfo *" ei ,
+.BI "  long " i0 ", long " i1 ,
+.BI "  const char *" file ", unsigned " lno ,
+.BI "  const char *" expr );
+.ta \w'\fBint TVEC_CLAIMEQ_IENUM('u
+.BI "int TVEC_CLAIMEQ_IENUM(struct tvec_state *" tv ,
+.BI "  const struct tvec_uenuminfo *" ei ,
+.BI "  long " i0 ", long " i1 );
+.ta \w'\fBint tvec_claimeq_uenum('u
+.BI "int tvec_claimeq_uenum(struct tvec_state *" tv ,
+.BI "  const struct tvec_uenuminfo *" ei ,
+.BI "  unsigned long " u0 ", unsigned long " u1 ,
+.BI "  const char *" file ", unsigned " lno ,
+.BI "  const char *" expr );
+.ta \w'\fBint TVEC_CLAIMEQ_UENUM('u
+.BI "int TVEC_CLAIMEQ_UENUM(struct tvec_state *" tv ,
+.BI "  const struct tvec_uenuminfo *" ei ,
+.BI "  unsigned long " u0 ", unsigned long " u1 );
+.ta \w'\fBint tvec_claimeq_fenum('u
+.BI "int tvec_claimeq_fenum(struct tvec_state *" tv ,
+.BI "  const struct tvec_fenuminfo *" ei ,
+.BI "  double " f0 ", double " f1 ,
+.BI "  const char *" file ", unsigned " lno ,
+.BI "  const char *" expr );
+.ta \w'\fBint TVEC_CLAIMEQ_FENUM('u
+.BI "int TVEC_CLAIMEQ_FENUM(struct tvec_state *" tv ,
+.BI "  const struct tvec_fenuminfo *" ei ,
+.BI "  double " f0 ", double " f1 );
+.ta \w'\fBint tvec_claimeq_penum('u
+.BI "int tvec_claimeq_penum(struct tvec_state *" tv ,
+.BI "  const struct tvec_penuminfo *" ei ,
+.BI "  const void *" p0 ", const void *" p1 ,
+.BI "  const char *" file ", unsigned " lno ,
+.BI "  const char *" expr );
+.ta \w'\fBint TVEC_CLAIMEQ_PENUM('u
+.BI "int TVEC_CLAIMEQ_PENUM(struct tvec_state *" tv ,
+.BI "  const struct tvec_penuminfo *" ei ,
+.BI "  const void *" p0 ", const void *" p1 );
+.PP
+.B "const struct tvec_regty tvty_flags;"
+.PP
+.B "struct tvec_flag { const char *name; unsigned long m, v; };"
+.B "#define TVEC_ENDFLAGS ..."
+.PP
+.ta 2n
+.B "struct tvec_flaginfo {"
+.B "   const char *name;"
+.B "   const struct tvec_flag *fv;"
+.B "   const struct tvec_urange *range;"
+.B "};"
+.PP
+.ta \w'\fBint tvec_claimeq_flags('u
+.BI "int tvec_claimeq_flags(struct tvec_state *" tv ,
+.BI "  const struct tvec_flaginfo *" fi ,
+.BI "  unsigned long " f0 ", unsigned long " f1 ,
+.BI "  const char *" file ", unsigned " lno ,
+.BI "  const char *" expr );
+.ta \w'\fBint TVEC_CLAIMEQ_FLAGS('u
+.BI "int TVEC_CLAIMEQ_UENUM(struct tvec_state *" tv ,
+.BI "  const struct tvec_flaginfo *" fi ,
+.BI "  unsigned long " f0 ", unsigned long " f1 );
+.PP
+.B "const struct tvec_regty tvty_char;"
+.PP
+.ta \w'\fBint tvec_claimeq_char('u
+.BI "int tvec_claimeq_char(struct tvec_state *" tv ,
+.BI "  int " ch0 ", int " ch1 ,
+.BI "  const char *" file ", unsigned " lno ,
+.BI "  const char *" expr );
+.BI "int TVEC_CLAIMEQ_CHAR(struct tvec_state *" tv ", int " ch0 ", int " ch1 );
+.PP
+.B "const struct tvec_regty tvty_text, tvty_bytes;"
+.PP
+.BI "void tvec_alloctext(union tvec_regval *" rv ", size_t " sz );
+.BI "void tvec_allocbytes(union tvec_regval *" rv ", size_t " sz );
+.PP
+.ta \w'\fBint tvec_claimeq_text('u
+.BI "int tvec_claimeq_text(struct tvec_state *" tv ,
+.BI "  const char *" p0 ", size_t " sz0 ,
+.BI "  const char *" p1 ", size_t " sz1 ,
+.BI "  const char *" file ", unsigned " lno ,
+.BI "  const char *" expr );
+.ta \w'\fBint TVEC_CLAIMEQ_TEXT('u
+.BI "int TVEC_CLAIMEQ_TEXT(struct tvec_state *" tv ,
+.BI "  const char *" p0 ", size_t " sz0 ,
+.BI "  const char *" p1 ", size_t " sz1 );
+.ta \w'\fBint tvec_claimeq_textz('u
+.BI "int tvec_claimeq_textz(struct tvec_state *" tv ,
+.BI "  const char *" p0 ", const char *" p1 ,
+.BI "  const char *" file ", unsigned " lno ,
+.BI "  const char *" expr );
+.ta \w'\fBint TVEC_CLAIMEQ_TEXTZ('u
+.BI "int TVEC_CLAIMEQ_TEXTZ(struct tvec_state *" tv ,
+.BI "  const char *" p0 " const char *" p1 );
+.ta \w'\fBint tvec_claimeq_bytes('u
+.BI "int tvec_claimeq_bytes(struct tvec_state *" tv ,
+.BI "  const void *" p0 ", size_t " sz0 ,
+.BI "  const void *" p1 ", size_t " sz1 ,
+.BI "  const char *" file ", unsigned " lno ,
+.BI "  const char *" expr );
+.ta \w'\fBint TVEC_CLAIMEQ_BYTES('u
+.BI "int TVEC_CLAIMEQ_BYTES(struct tvec_state *" tv ,
+.BI "  const void *" p0 ", size_t " sz0 ,
+.BI "  const void *" p1 ", size_t " sz1 );
+.PP
+.B "const struct tvec_regty tvty_buffer;"
+.PP
+.ta \w'\fBvoid tvec_initbuffer('
+.BI "void tvec_initbuffer(union tvec_regval *" rv ,
+.BI "  const union tvec_regval *" ref ", size_t " sz );
+.BI "void tvec_allocbuffer(union tvec_regval *" rv );
+.fi
index 20c2930..87748eb 100644 (file)
@@ -3516,18 +3516,18 @@ const struct tvec_regty tvty_buffer = {
 /* --- @tvec_initbuffer@ --- *
  *
  * Arguments:  @union tvec_regval *rv@ = register value
 /* --- @tvec_initbuffer@ --- *
  *
  * Arguments:  @union tvec_regval *rv@ = register value
- *             @const union tvec_regval *src@ = source buffer
+ *             @const union tvec_regval *ref@ = source buffer
  *             @size_t sz@ = size to allocate
  *
  * Returns:    ---
  *
  *             @size_t sz@ = size to allocate
  *
  * Returns:    ---
  *
- * Use:                Initialize the alignment parameters in @rv@ to match @src@,
+ * Use:                Initialize the alignment parameters in @rv@ to match @ref@,
  *             and the size to @sz@.
  */
 
 void tvec_initbuffer(union tvec_regval *rv,
  *             and the size to @sz@.
  */
 
 void tvec_initbuffer(union tvec_regval *rv,
-                    const union tvec_regval *src, size_t sz)
-  { rv->buf.sz = sz; rv->buf.a = src->buf.a; rv->buf.m = src->buf.m; }
+                    const union tvec_regval *ref, size_t sz)
+  { rv->buf.sz = sz; rv->buf.a = ref->buf.a; rv->buf.m = ref->buf.m; }
 
 /* --- @tvec_allocbuffer@ --- *
  *
 
 /* --- @tvec_allocbuffer@ --- *
  *
index c0cb3c3..23eded3 100644 (file)
 .\" -*-nroff-*-
 .\" -*-nroff-*-
-.TH tvec 3 "10 May 2023" "Straylight/Edgeware" "mLib utilities library"
+.de VS
+.sp 1
+.RS
+.nf
+.ft B
+..
+.de VE
+.ft R
+.fi
+.RE
+.sp 1
+..
+.de hP
+.IP
+.ft B
+\h'-\w'\\$1\ 'u'\\$1\ \c
+.ft P
+..
+.ie t \{\
+.  ds o \(bu
+.  de VP
+.    sp .4v
+..
+\}
+.el \{\
+.  ds o o
+.  de VP
+.    sp
+..
+\}
+..
+.TH tvec 3 "11 March 2024" "Straylight/Edgeware" "mLib utilities library"
 .SH NAME
 tvec \- test vector framework
 .SH NAME
 tvec \- test vector framework
-
-
-
-
+.\" @tvec_begin
+.\" @tvec_end
+.\" @tvec_read
+.\" @tvec_humanoutput
+.\" @tvec_tapoutput
+.\" @tvec_dfltoutput
+.
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/tvec.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/tvec.h>"
-
+.PP
+.ta 2n
 .B "union tvec_misc {"
 .B "union tvec_misc {"
-.B 
+.B "   const void *p;"
+.B "   long i;"
+.B "   unsigned long u;"
+.B "   double f;"
+.B "};"
+.B "enum {"
+.B "   TVMISC_PTR,"
+.B "   TVMISC_INT,"
+.B "   TVMISC_UINT,"
+.B "   TVMISC_FLT,"
+.B "   ...,"
+.B "   TVMISC_LIMIT,"
+.B "};"
+.PP
+.ta 2n +2n
+.B "union tvec_regval {"
+.B "   long i;"
+.B "   unsigned long u;"
+.B "   void *p;"
+.B "   double f;"
+.B "   struct { char *p; size_t sz; } text;"
+.B "   struct { unsigned char *p; size_t sz; } bytes;"
+.B "   struct {"
+.B "           unsigned char *p; size_t sz;"
+.B "           size_t a, m;"
+.B "           size_t off;"
+.B "   } buf;"
+.B "   TVEC_REGSLOTS"
+.B "};"
+.B "struct tvec_reg {"
+.B "   unsigned f;"
+.B "   union tvec_regval v;"
+.B "};"
+.B "#define TVRF_LIVE ..."
+.PP
+.ta 2n
+.B "struct tvec_regdef {"
+.B "   const char *name;"
+.B "   const struct tvec_regty *ty;"
+.B "   unsigned i;"
+.B "   unsigned f;"
+.B "   union tvec_misc arg;"
+.B "};"
+.B "#define TVRF_OPT ..."
+.B "#define TVRF_ID ..."
+.B "#define TVEC_ENDREGS ..."
+.PP
+.B "struct tvec_state;"
+.PP
+.B "struct tvec_env;"
+.ta \w'\fBtypedef void tvec_testfn('u
+.BI "typedef void tvec_testfn(const struct tvec_reg *" in ,
+.BI "  struct tvec_reg *" out ,
+.BI "  void *" ctx );
+.B "struct tvec_test {"
+.B "   const char *name;"
+.B "   const struct tvec_regdef *regs;"
+.B "   const struct tvec_env *env;"
+.B "   tvec_testfn *fn;"
+.B "};"
+.B "#define TVEC_ENDTESTS ..."
+.PP
+.ta 2n
+.B "struct tvec_config {"
+.B "   const struct tvec_test *tests;"
+.B "   unsigned nrout, nreg;"
+.B "   size_t regsz;"
+.B "};"
+.B "struct tvec_output;"
+.PP
+.ta \w'\fBvoid tvec_begin('u
+.BI "void tvec_begin(struct tvec_state *" tv_out ,
+.BI "  const struct tvec_config *" config ,
+.BI "  struct tvec_output *" o );
+.BI "int tvec_end(struct tvec_state *" tv );
+.BI "int tvec_read(struct tvec_state *" tv ", const char *" infile ", FILE *" fp );
+.PP
+.BI "extern struct tvec_output *tvec_humanoutput(FILE *" fp );
+.BI "extern struct tvec_output *tvec_tapoutput(FILE *" fp );
+.BI "extern struct tvec_output *tvec_dfltoutput(FILE *" fp );
+.fi
index d16df58..293dccc 100644 (file)
@@ -192,8 +192,8 @@ union tvec_regval {
   unsigned long u;                     /* unsigned integer */
   void *p;                             /* pointer */
   double f;                            /* floating point */
   unsigned long u;                     /* unsigned integer */
   void *p;                             /* pointer */
   double f;                            /* floating point */
-  struct { unsigned char *p; size_t sz; } bytes; /* binary string of bytes */
   struct { char *p; size_t sz; } text; /* text string */
   struct { char *p; size_t sz; } text; /* text string */
+  struct { unsigned char *p; size_t sz; } bytes; /* binary string of bytes */
   struct {                             /* buffer */
     unsigned char *p; size_t sz;       /* binary string */
     size_t a, m;                       /* residue and modulus */
   struct {                             /* buffer */
     unsigned char *p; size_t sz;       /* binary string */
     size_t a, m;                       /* residue and modulus */
@@ -236,8 +236,8 @@ struct tvec_regdef {
    */
 
   const char *name;                    /* register name (for input files) */
    */
 
   const char *name;                    /* register name (for input files) */
-  unsigned i;                          /* register index */
   const struct tvec_regty *ty;         /* register type descriptor */
   const struct tvec_regty *ty;         /* register type descriptor */
+  unsigned i;                          /* register index */
   unsigned f;                          /* flags */
 #define TVRF_OPT 1u                    /*   optional register */
 #define TVRF_ID 2u                     /*   part of test identity  */
   unsigned f;                          /* flags */
 #define TVRF_OPT 1u                    /*   optional register */
 #define TVRF_ID 2u                     /*   part of test identity  */
@@ -321,6 +321,8 @@ struct tvec_regty {
 
 /*----- Test descriptions -------------------------------------------------*/
 
 
 /*----- Test descriptions -------------------------------------------------*/
 
+struct tvec_env;
+
 typedef void tvec_testfn(const struct tvec_reg */*in*/,
                         struct tvec_reg */*out*/,
                         void */*ctx*/);
 typedef void tvec_testfn(const struct tvec_reg */*in*/,
                         struct tvec_reg */*out*/,
                         void */*ctx*/);
@@ -340,8 +342,6 @@ typedef void tvec_testfn(const struct tvec_reg */*in*/,
    * anything to do with the test function's context.
    */
 
    * anything to do with the test function's context.
    */
 
-struct tvec_env;
-
 typedef int tvec_setvarfn(struct tvec_state */*tv*/, const char */*var*/,
                          const union tvec_regval */*rv*/, void */*ctx*/);
   /* Called after a variable is read.  Return zero on success or %$-1$% on
 typedef int tvec_setvarfn(struct tvec_state */*tv*/, const char */*var*/,
                          const union tvec_regval */*rv*/, void */*ctx*/);
   /* Called after a variable is read.  Return zero on success or %$-1$% on
@@ -435,17 +435,6 @@ struct tvec_test {
 };
 #define TVEC_ENDTESTS { 0, 0, 0, 0 }
 
 };
 #define TVEC_ENDTESTS { 0, 0, 0, 0 }
 
-enum {
-  /* Register output dispositions. */
-
-  TVRD_INPUT,                          /* input-only register */
-  TVRD_OUTPUT,                         /* output-only (input is dead) */
-  TVRD_MATCH,                          /* matching (equal) registers */
-  TVRD_FOUND,                          /* mismatching output register */
-  TVRD_EXPECT,                         /* mismatching input register */
-  TVRD_LIMIT                           /* (number of dispositions) */
-};
-
 /*----- Test state --------------------------------------------------------*/
 
 enum {
 /*----- Test state --------------------------------------------------------*/
 
 enum {
@@ -458,9 +447,18 @@ enum {
   TVOUT_LIMIT                          /* (number of possible outcomes) */
 };
 
   TVOUT_LIMIT                          /* (number of possible outcomes) */
 };
 
+struct tvec_config {
+  /* An overall test configuration. */
+
+  const struct tvec_test *tests;       /* the tests to be performed */
+  unsigned nrout, nreg;                        /* number of output/total regs */
+  size_t regsz;                                /* size of a register */
+};
+
 struct tvec_state {
   /* The primary state structure for the test vector machinery. */
 
 struct tvec_state {
   /* The primary state structure for the test vector machinery. */
 
+  /* Flags.  Read-only for all callers. */
   unsigned f;                          /* flags */
 #define TVSF_SKIP 0x0001u              /*   skip this test group */
 #define TVSF_OPEN 0x0002u              /*   test is open */
   unsigned f;                          /* flags */
 #define TVSF_SKIP 0x0001u              /*   skip this test group */
 #define TVSF_OPEN 0x0002u              /*   test is open */
@@ -471,13 +469,17 @@ struct tvec_state {
 #define TVSF_XFAIL 0x0100u             /*   test expected to fail */
 #define TVSF_MUFFLE 0x0200u            /*   muffle errors */
 
 #define TVSF_XFAIL 0x0100u             /*   test expected to fail */
 #define TVSF_MUFFLE 0x0200u            /*   muffle errors */
 
-  /* Registers.  Available to execution environments. */
-  unsigned nrout, nreg;                       /* number of output/total registers */
-  size_t regsz;                                /* size of register entry */
+  /* Test configuration.  Read-only for all callers. */
+  struct tvec_config cfg;              /* test configuration */
+
+  /* Registers.  Available to execution environments, which may modify the
+   * contents of the active registers, as defined by the current test group,
+   * but not the vector pointers themselves or inactive registers.
+   */
   struct tvec_reg *in, *out;           /* register vectors */
 
   struct tvec_reg *in, *out;           /* register vectors */
 
-  /* Test groups state.  Available to output formatters. */
-  const struct tvec_test *tests, *test;        /* all tests and current test */
+  /* Test group state.  Read-only for all callers. */
+  const struct tvec_test *test;                /* current test */
 
   /* Test scoreboard.  Available to output formatters. */
   unsigned curr[TVOUT_LIMIT], all[TVOUT_LIMIT], grps[TVOUT_LIMIT];
 
   /* Test scoreboard.  Available to output formatters. */
   unsigned curr[TVOUT_LIMIT], all[TVOUT_LIMIT], grps[TVOUT_LIMIT];
@@ -496,15 +498,7 @@ struct tvec_state {
  * @out@, and @i@ is an integer, then this evaluates to the address of the
  * @i@th register in the selected vector.
  */
  * @out@, and @i@ is an integer, then this evaluates to the address of the
  * @i@th register in the selected vector.
  */
-#define TVEC_REG(tv, vec, i) TVEC_GREG((tv)->vec, (i), (tv)->regsz)
-
-struct tvec_config {
-  /* An overall test configuration. */
-
-  const struct tvec_test *tests;       /* the tests to be performed */
-  unsigned nrout, nreg;                        /* number of output/total regs */
-  size_t regsz;                                /* size of a register */
-};
+#define TVEC_REG(tv, vec, i) TVEC_GREG((tv)->vec, (i), (tv)->cfg.regsz)
 
 /*----- Output formatting -------------------------------------------------*/
 
 
 /*----- Output formatting -------------------------------------------------*/
 
@@ -513,6 +507,27 @@ struct tvec_output {
   const struct tvec_outops *ops;       /* pointer to operations */
 };
 
   const struct tvec_outops *ops;       /* pointer to operations */
 };
 
+enum {
+  /* Register output dispositions. */
+
+  TVRD_INPUT,                          /* input-only register */
+  TVRD_OUTPUT,                         /* output-only (input is dead) */
+  TVRD_MATCH,                          /* matching (equal) registers */
+  TVRD_FOUND,                          /* mismatching output register */
+  TVRD_EXPECT,                         /* mismatching input register */
+  TVRD_LIMIT                           /* (number of dispositions) */
+};
+
+#define TVEC_LEVELS(_)                                                 \
+       _(NOTE, "notice", 4)                                            \
+       _(ERR, "ERROR", 8)
+enum {
+#define TVEC_DEFLEVEL(tag, name, val) TVLEV_##tag = val,
+  TVEC_LEVELS(TVEC_DEFLEVEL)
+#undef TVEC_DEFLEVEL
+  TVLEV_LIMIT
+};
+
 /* Benchmarking details. */
 enum {
   TVBU_OP,                            /* counting operations of some kind */
 /* Benchmarking details. */
 enum {
   TVBU_OP,                            /* counting operations of some kind */
@@ -620,17 +635,6 @@ struct tvec_outops {
     /* Release any resources acquired by the driver. */
 };
 
     /* Release any resources acquired by the driver. */
 };
 
-#define TVEC_LEVELS(_)                                                 \
-       _(NOTE, "notice", 4)                                            \
-       _(ERR, "ERROR", 8)
-
-enum {
-#define TVEC_DEFLEVEL(tag, name, val) TVLEV_##tag = val,
-  TVEC_LEVELS(TVEC_DEFLEVEL)
-#undef TVEC_DEFLEVEL
-  TVLEV_LIMIT
-};
-
 /*----- Session lifecycle -------------------------------------------------*/
 
 /* --- @tvec_begin@ --- *
 /*----- Session lifecycle -------------------------------------------------*/
 
 /* --- @tvec_begin@ --- *
@@ -1204,6 +1208,8 @@ extern void tvec_benchreport
 
 /*----- Remote execution --------------------------------------------------*/
 
 
 /*----- Remote execution --------------------------------------------------*/
 
+struct tvec_remoteenv;
+
 struct tvec_remotecomms {
   int infd, outfd;                     /* input and output descriptors */
   dbuf bout;                           /* output buffer */
 struct tvec_remotecomms {
   int infd, outfd;                     /* input and output descriptors */
   dbuf bout;                           /* output buffer */
@@ -1397,7 +1403,7 @@ extern tvec_connectfn tvec_fork, tvec_exec;
 
 struct tvec_timeoutenv {
   struct tvec_env _env;
 
 struct tvec_timeoutenv {
   struct tvec_env _env;
-  int timer;                   /* the timer (@ITIMER_...@) */
+  int timer;                           /* the timer (@ITIMER_...@) */
   double t;                            /* time to wait (in seconds) */
   const struct tvec_env *env;          /* subsidiary environment */
 };
   double t;                            /* time to wait (in seconds) */
   const struct tvec_env *env;          /* subsidiary environment */
 };
@@ -1442,7 +1448,7 @@ extern tvec_envteardownfn tvec_timeoutteardown;
  *             message.
  */
 
  *             message.
  */
 
-extern  const char *tvec_strlevel(unsigned /*level*/);
+extern const char *tvec_strlevel(unsigned /*level*/);
 
 /* --- @tvec_report@, @tvec_report_v@ --- *
  *
 
 /* --- @tvec_report@, @tvec_report_v@ --- *
  *
@@ -1481,6 +1487,32 @@ extern PRINTF_LIKE(2, 3)
 extern PRINTF_LIKE(2, 3)
   void tvec_notice(struct tvec_state */*tv*/, const char */*msg*/, ...);
 
 extern PRINTF_LIKE(2, 3)
   void tvec_notice(struct tvec_state */*tv*/, const char */*msg*/, ...);
 
+/* --- @tvec_unkreg@ --- *
+ *
+ * Arguments:  @struct tvec_state *tv@ = test-vector state
+ *             @const char *name@ = register or pseudoregister name
+ *
+ * Returns:    %$-1$%.
+ *
+ * Use:                Reports an error that the register or pseudoregister is
+ *             unrecognized.
+ */
+
+extern int tvec_unkreg(struct tvec_state */*tv*/, const char */*name*/);
+
+/* --- @tvec_dupreg@ --- *
+ *
+ * Arguments:  @struct tvec_state *tv@ = test-vector state
+ *             @const char *name@ = register or pseudoregister name
+ *
+ * Returns:    %$-1$%.
+ *
+ * Use:                Reports an error that the register or pseudoregister has been
+ *             assigned already in the current test.
+ */
+
+extern int tvec_dupreg(struct tvec_state */*tv*/, const char */*name*/);
+
 /* --- @tvec_humanoutput@ --- *
  *
  * Arguments:  @FILE *fp@ = output file to write on
 /* --- @tvec_humanoutput@ --- *
  *
  * Arguments:  @FILE *fp@ = output file to write on
@@ -1643,32 +1675,6 @@ extern PRINTF_LIKE(3, 4)
 extern int tvec_syntax_v(struct tvec_state */*tv*/, int /*ch*/,
                         const char */*expect*/, va_list */*ap*/);
 
 extern int tvec_syntax_v(struct tvec_state */*tv*/, int /*ch*/,
                         const char */*expect*/, va_list */*ap*/);
 
-/* --- @tvec_unkreg@ --- *
- *
- * Arguments:  @struct tvec_state *tv@ = test-vector state
- *             @const char *name@ = register or pseudoregister name
- *
- * Returns:    %$-1$%.
- *
- * Use:                Reports an error that the register or pseudoregister is
- *             unrecognized.
- */
-
-extern int tvec_unkreg(struct tvec_state */*tv*/, const char */*name*/);
-
-/* --- @tvec_dupreg@ --- *
- *
- * Arguments:  @struct tvec_state *tv@ = test-vector state
- *             @const char *name@ = register or pseudoregister name
- *
- * Returns:    %$-1$%.
- *
- * Use:                Reports an error that the register or pseudoregister has been
- *             assigned already in the current test.
- */
-
-extern int tvec_dupreg(struct tvec_state */*tv*/, const char */*name*/);
-
 /* --- @tvec_skipspc@ --- *
  *
  * Arguments:  @struct tvec_state *tv@ = test-vector state
 /* --- @tvec_skipspc@ --- *
  *
  * Arguments:  @struct tvec_state *tv@ = test-vector state
@@ -1902,6 +1908,8 @@ struct tvec_floatinfo {
   double delta;                                /* maximum tolerable difference */
 };
 
   double delta;                                /* maximum tolerable difference */
 };
 
+extern const struct tvec_floatinfo tvflt_finite, tvflt_nonneg;
+
 /* --- @tvec_claimeqish_float@, @TVEC_CLAIMEQISH_FLOAT@ --- *
  *
  * Arguments:  @struct tvec_state *tv@ = test-vector state
 /* --- @tvec_claimeqish_float@, @TVEC_CLAIMEQISH_FLOAT@ --- *
  *
  * Arguments:  @struct tvec_state *tv@ = test-vector state
@@ -1980,8 +1988,6 @@ extern int tvec_claimeq_float(struct tvec_state */*tv*/,
 #define TVEC_CLAIMEQ_FLOAT(tv, f0, f1)                                 \
        (tvec_claimeq_float(tv, f0, f1, __FILE__, __LINE__, #f0 " /= " #f1))
 
 #define TVEC_CLAIMEQ_FLOAT(tv, f0, f1)                                 \
        (tvec_claimeq_float(tv, f0, f1, __FILE__, __LINE__, #f0 " /= " #f1))
 
-extern const struct tvec_floatinfo tvflt_finite, tvflt_nonneg;
-
 /*----- Durations ---------------------------------------------------------*/
 
 /* A duration measures a time interval in seconds.  The input format consists
 /*----- Durations ---------------------------------------------------------*/
 
 /* A duration measures a time interval in seconds.  The input format consists
@@ -2335,6 +2341,30 @@ extern int tvec_claimeq_char(struct tvec_state */*tv*/,
 
 extern const struct tvec_regty tvty_text, tvty_bytes;
 
 
 extern const struct tvec_regty tvty_text, tvty_bytes;
 
+/* --- @tvec_alloctext@, @tvec_allocbytes@ --- *
+ *
+ * Arguments:  @union tvec_regval *rv@ = register value
+ *             @size_t sz@ = required size
+ *
+ * Returns:    ---
+ *
+ * Use:                Allocated space in a text or binary string register.  If the
+ *             current register size is sufficient, its buffer is left
+ *             alone; otherwise, the old buffer, if any, is freed and a
+ *             fresh buffer allocated.  These functions are not intended to
+ *             be used to adjust a buffer repeatedly, e.g., while building
+ *             output incrementally: (a) they will perform badly, and (b)
+ *             the old buffer contents are simply discarded if reallocation
+ *             is necessary.  Instead, use a @dbuf@ or @dstr@.
+ *
+ *             The @tvec_alloctext@ function sneakily allocates an extra
+ *             byte for a terminating zero.  The @tvec_allocbytes@ function
+ *             doesn't do this.
+ */
+
+extern void tvec_alloctext(union tvec_regval */*rv*/, size_t /*sz*/);
+extern void tvec_allocbytes(union tvec_regval */*rv*/, size_t /*sz*/);
+
 /* --- @tvec_claimeq_text@, @TVEC_CLAIMEQ_TEXT@ --- *
  *
  * Arguments:  @struct tvec_state *tv@ = test-vector state
 /* --- @tvec_claimeq_text@, @TVEC_CLAIMEQ_TEXT@ --- *
  *
  * Arguments:  @struct tvec_state *tv@ = test-vector state
@@ -2424,30 +2454,6 @@ extern int tvec_claimeq_bytes(struct tvec_state */*tv*/,
        (tvec_claimeq(tv, p0, sz0, p1, sz1, __FILE__, __LINE__,         \
                      #p0 "[" #sz0 "] /= " #p1 "[" #sz1 "]"))
 
        (tvec_claimeq(tv, p0, sz0, p1, sz1, __FILE__, __LINE__,         \
                      #p0 "[" #sz0 "] /= " #p1 "[" #sz1 "]"))
 
-/* --- @tvec_alloctext@, @tvec_allocbytes@ --- *
- *
- * Arguments:  @union tvec_regval *rv@ = register value
- *             @size_t sz@ = required size
- *
- * Returns:    ---
- *
- * Use:                Allocated space in a text or binary string register.  If the
- *             current register size is sufficient, its buffer is left
- *             alone; otherwise, the old buffer, if any, is freed and a
- *             fresh buffer allocated.  These functions are not intended to
- *             be used to adjust a buffer repeatedly, e.g., while building
- *             output incrementally: (a) they will perform badly, and (b)
- *             the old buffer contents are simply discarded if reallocation
- *             is necessary.  Instead, use a @dbuf@ or @dstr@.
- *
- *             The @tvec_alloctext@ function sneakily allocates an extra
- *             byte for a terminating zero.  The @tvec_allocbytes@ function
- *             doesn't do this.
- */
-
-extern void tvec_alloctext(union tvec_regval */*rv*/, size_t /*sz*/);
-extern void tvec_allocbytes(union tvec_regval */*rv*/, size_t /*sz*/);
-
 /*----- Buffer type -------------------------------------------------------*/
 
 /* Buffer registers are primarily used for benchmarking.  Only a buffer's
 /*----- Buffer type -------------------------------------------------------*/
 
 /* Buffer registers are primarily used for benchmarking.  Only a buffer's
@@ -2479,17 +2485,17 @@ extern const struct tvec_regty tvty_buffer;
 /* --- @tvec_initbuffer@ --- *
  *
  * Arguments:  @union tvec_regval *rv@ = register value
 /* --- @tvec_initbuffer@ --- *
  *
  * Arguments:  @union tvec_regval *rv@ = register value
- *             @const union tvec_regval *src@ = source buffer
+ *             @const union tvec_regval *ref@ = reference buffer
  *             @size_t sz@ = size to allocate
  *
  * Returns:    ---
  *
  *             @size_t sz@ = size to allocate
  *
  * Returns:    ---
  *
- * Use:                Initialize the alignment parameters in @rv@ to match @src@,
+ * Use:                Initialize the alignment parameters in @rv@ to match @ref@,
  *             and the size to @sz@.
  */
 
 extern void tvec_initbuffer(union tvec_regval */*rv*/,
  *             and the size to @sz@.
  */
 
 extern void tvec_initbuffer(union tvec_regval */*rv*/,
-                           const union tvec_regval */*src*/, size_t /*sz*/);
+                           const union tvec_regval */*ref*/, size_t /*sz*/);
 
 /* --- @tvec_allocbuffer@ --- *
  *
 
 /* --- @tvec_allocbuffer@ --- *
  *
index 1a40587..d0e4fcf 100644 (file)
@@ -15,12 +15,12 @@ trace \- configurable tracing output
 .SH "SYNOPSIS"
 .nf
 .B "#include <mLib/trace.h>"
 .SH "SYNOPSIS"
 .nf
 .B "#include <mLib/trace.h>"
-
+.PP
 .BI "void trace(unsigned " l ", const char *" f ", ...);"
 .ta \w'\fBvoid trace_block('u
 .BI "void trace_block(unsigned " l ", const char *" s ,
 .BI "  const void *" b ", size_t " sz );
 .BI "void trace(unsigned " l ", const char *" f ", ...);"
 .ta \w'\fBvoid trace_block('u
 .BI "void trace_block(unsigned " l ", const char *" s ,
 .BI "  const void *" b ", size_t " sz );
-
+.PP
 .BI "void trace_on(FILE *" fp ", unsigned " l );
 .ta \w'\fBvoid trace_custom('u +\w'\fBvoid (*\,\fIfunc\/\fB)('u
 .BI "void trace_custom(void (*" func ")(const char *" buf ,
 .BI "void trace_on(FILE *" fp ", unsigned " l );
 .ta \w'\fBvoid trace_custom('u +\w'\fBvoid (*\,\fIfunc\/\fB)('u
 .BI "void trace_custom(void (*" func ")(const char *" buf ,
@@ -28,11 +28,11 @@ trace \- configurable tracing output
 .BI "  void *" v );
 .BI "void trace_level(unsigned " l );
 .BI "unsigned tracing(void);"
 .BI "  void *" v );
 .BI "void trace_level(unsigned " l );
 .BI "unsigned tracing(void);"
-
+.PP
 .ta \w'\fBunsigned traceopt('u
 .BI "unsigned traceopt(const trace_opt *" t ", const char *" p ,
 .BI "  unsigned " f ", unsigned " bad );
 .ta \w'\fBunsigned traceopt('u
 .BI "unsigned traceopt(const trace_opt *" t ", const char *" p ,
 .BI "  unsigned " f ", unsigned " bad );
-
+.PP
 .BI T( statements\fR... )
 .BI "IF_TRACING(unsigned " l ", " statements\fR... )
 .fi
 .BI T( statements\fR... )
 .BI "IF_TRACING(unsigned " l ", " statements\fR... )
 .fi
index 253b635..9b87323 100644 (file)
@@ -6,31 +6,31 @@ mdwopt \- command-line option parser
 .SH "SYNOPSIS"
 .nf
 .B "#include <mLib/mdwopt.h>"
 .SH "SYNOPSIS"
 .nf
 .B "#include <mLib/mdwopt.h>"
-
+.PP
 .ta 2n
 .B "typedef struct {"
 .B "   char *arg, *prog;"
 .B "   int opt, ind, err;"
 .B "   ..."
 .B "} mdwopt_data;"
 .ta 2n
 .B "typedef struct {"
 .B "   char *arg, *prog;"
 .B "   int opt, ind, err;"
 .B "   ..."
 .B "} mdwopt_data;"
-
+.PP
 .B "char *optarg, optprog;"
 .B "int optopt, opterr, optind;"
 .B "char *optarg, optprog;"
 .B "int optopt, opterr, optind;"
-
+.PP
 .B "struct option {"
 .B "   const char *name;"
 .B "   int has_arg;"
 .B "   int *flag;"
 .B "   int val;"
 .B "};"
 .B "struct option {"
 .B "   const char *name;"
 .B "   int has_arg;"
 .B "   int *flag;"
 .B "   int val;"
 .B "};"
-
+.PP
 .B "#define OPTF_NOARG = ..."
 .B "#define OPTF_ARGREQ = ..."
 .B "#define OPTF_ARGOPT = ..."
 .B "#define OPTF_ARG = ..."
 .B "#define OPTF_SWITCH = ..."
 .B "#define OPTF_NEGATE = ..."
 .B "#define OPTF_NOARG = ..."
 .B "#define OPTF_ARGREQ = ..."
 .B "#define OPTF_ARGOPT = ..."
 .B "#define OPTF_ARG = ..."
 .B "#define OPTF_SWITCH = ..."
 .B "#define OPTF_NEGATE = ..."
-
+.PP
 .B "#define OPTF_NOLONGS = ..."
 .B "#define OPTF_NOSHORTS = ..."
 .B "#define OPTF_NUMBERS = ..."
 .B "#define OPTF_NOLONGS = ..."
 .B "#define OPTF_NOSHORTS = ..."
 .B "#define OPTF_NUMBERS = ..."
@@ -38,22 +38,22 @@ mdwopt \- command-line option parser
 .B "#define OPTF_ENVVAR = ..."
 .B "#define OPTF_NOPROGNAME = ..."
 .B "#define OPTF_NEGNUMBER = ..."
 .B "#define OPTF_ENVVAR = ..."
 .B "#define OPTF_NOPROGNAME = ..."
 .B "#define OPTF_NEGNUMBER = ..."
-
+.PP
 .B "#define OPTF_NEGATED = ..."
 .B "#define OPTF_NEGATED = ..."
-
+.PP
 .ta \w'\fBint mdwopt('u
 .BI "int mdwopt(int " argc ", char *const *" argv ,
 .BI "  const char *" shortopt ,
 .BI "  const struct option *" longopt ", int *" longind ,
 .BI "  mdwopt_data *" data ", int " flags );
 .ta \w'\fBint mdwopt('u
 .BI "int mdwopt(int " argc ", char *const *" argv ,
 .BI "  const char *" shortopt ,
 .BI "  const struct option *" longopt ", int *" longind ,
 .BI "  mdwopt_data *" data ", int " flags );
-
+.PP
 .BI "int getopt(int " argc ", char *const *" argv ", const char *" o );
 .BI "int getopt(int " argc ", char *const *" argv ", const char *" o );
-
+.PP
 .ta \w'\fBint getopt_long('u
 .BI "int getopt_long(int " argc ", char *const *" argv ,
 .BI "  const char * "shortopt ,
 .BI "  const struct option *" longopt ", int *" longind );
 .ta \w'\fBint getopt_long('u
 .BI "int getopt_long(int " argc ", char *const *" argv ,
 .BI "  const char * "shortopt ,
 .BI "  const struct option *" longopt ", int *" longind );
-
+.PP
 .ta \w'\fBint getopt_long_only('u
 .BI "int getopt_long_only(int " argc ", char *const *" argv ,
 .BI "  const char * "shortopt ,
 .ta \w'\fBint getopt_long_only('u
 .BI "int getopt_long_only(int " argc ", char *const *" argv ,
 .BI "  const char * "shortopt ,
index bd19698..50a0203 100644 (file)
--- a/ui/quis.3
+++ b/ui/quis.3
@@ -9,7 +9,7 @@ quis \- remember the program's name for use in messages
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/quis.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/quis.h>"
-
+.PP
 .BI "void ego(const char *" p );
 .B "const char *quis(void);"
 .B "const char *QUIS;"
 .BI "void ego(const char *" p );
 .B "const char *quis(void);"
 .B "const char *QUIS;"
index 1ccecb6..19fda9a 100644 (file)
@@ -7,7 +7,7 @@ report \- report errors
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/report.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/report.h>"
-
+.PP
 .BI "void moan(const char *" f ", ...);"
 .BI "void die(int " status ", const char *" f ", ...);"
 .fi
 .BI "void moan(const char *" f ", ...);"
 .BI "void die(int " status ", const char *" f ", ...);"
 .fi
index 9ee2377..55a4040 100644 (file)
@@ -6,7 +6,7 @@ align \- alignment utilities
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/align.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/align.h>"
-
+.PP
 .BI "size_t ALIGN(size_t " sz ");"
 .fi
 .SH DESCRIPTION
 .BI "size_t ALIGN(size_t " sz ");"
 .fi
 .SH DESCRIPTION
index a002e24..3b09b65 100644 (file)
@@ -175,34 +175,34 @@ bits \- portable bit manipulation macros
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/bits.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/bits.h>"
-
+.PP
 .BR "typedef " ... " octet;"
 .BR "typedef " ... " uint16;"
 .BR "typedef " ... " uint24;"
 .BR "typedef " ... " uint32;"
 .BR "typedef " ... " uint64;"
 .BR "typedef " ... " kludge64;"
 .BR "typedef " ... " octet;"
 .BR "typedef " ... " uint16;"
 .BR "typedef " ... " uint24;"
 .BR "typedef " ... " uint32;"
 .BR "typedef " ... " uint64;"
 .BR "typedef " ... " kludge64;"
-
+.PP
 .BI "#define TY_" we " " type
 .BI "#define SZ_" we " \fR..."
 .BI "#define MASK_" we " \fR..."
 .BI "#define TY_" we " " type
 .BI "#define SZ_" we " \fR..."
 .BI "#define MASK_" we " \fR..."
-
+.PP
 .BI "#define DOUINTSZ(" f ") \fR..."
 .BI "#define DOUINTCONV(" f ") \fR..."
 .BI "#define DOUINTSZ(" f ") \fR..."
 .BI "#define DOUINTCONV(" f ") \fR..."
-
+.PP
 .IB type " U" w ( v );
 .IB type " U" w ( v );
-
+.PP
 .IB type " LSL" w ( type " " v ", int " s );
 .IB type " LSR" w ( type " " v ", int " s );
 .IB type " ROL" w ( type " " v ", int " s );
 .IB type " ROR" w ( type " " v ", int " s );
 .IB type " LSL" w ( type " " v ", int " s );
 .IB type " LSR" w ( type " " v ", int " s );
 .IB type " ROL" w ( type " " v ", int " s );
 .IB type " ROR" w ( type " " v ", int " s );
-
+.PP
 .BI "octet GETBYTE(void *" p ", size_t " o );
 .BI "void PUTBYTE(void *" p ", size_t " o ", octet " v );
 .BI "octet GETBYTE(void *" p ", size_t " o );
 .BI "void PUTBYTE(void *" p ", size_t " o ", octet " v );
-
+.PP
 .IB type " LOAD" we "(void *" p );
 .BI "void STORE" we "(void *" p ", " type " " v );
 .IB type " LOAD" we "(void *" p );
 .BI "void STORE" we "(void *" p ", " type " " v );
-
+.PP
 .BI "void SET64(kludge64 &" d ", uint32 " h ", uint32 " l );
 .BI "kludge64 X64(" hexh ", " hexl );
 .BI "void ASSIGN64(kludge64 &" d ", " x );
 .BI "void SET64(kludge64 &" d ", uint32 " h ", uint32 " l );
 .BI "kludge64 X64(" hexh ", " hexl );
 .BI "void ASSIGN64(kludge64 &" d ", " x );
@@ -710,4 +710,3 @@ is exactly zero.
 .BR mLib (3).
 .SH AUTHOR
 Mark Wooding, <mdw@distorted.org.uk>
 .BR mLib (3).
 .SH AUTHOR
 Mark Wooding, <mdw@distorted.org.uk>
-
index 1920be4..424ca0e 100644 (file)
@@ -7,7 +7,7 @@ compiler \- detect compiler version
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/compiler.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/compiler.h>"
-
+.PP
 .BI "int GCC_VERSION_P(" maj ", " min ");"
 .BI "int CLANG_VERSION_P(" maj ", " min ");"
 .fi
 .BI "int GCC_VERSION_P(" maj ", " min ");"
 .BI "int CLANG_VERSION_P(" maj ", " min ");"
 .fi
index be83be9..65f31d6 100644 (file)
@@ -34,7 +34,7 @@ control \- control structure metaprogramming
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/control.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/control.h>"
-
+.PP
 .BI MC_BEFORE( tag ", " stmts ") " body
 .BI MC_AFTER( tag ", " stmts ") " body
 .BI MC_WRAP( tag ", " before_stmt ", " onend_stmt ", " onbreak_stmt ") " body
 .BI MC_BEFORE( tag ", " stmts ") " body
 .BI MC_AFTER( tag ", " stmts ") " body
 .BI MC_WRAP( tag ", " before_stmt ", " onend_stmt ", " onbreak_stmt ") " body
@@ -43,12 +43,12 @@ control \- control structure metaprogramming
 .BI MC_DECL( tag ", " decl ") " body
 .BI MC_LOOPELSE( tag ", " head ") " loop_body " \fR[\fBelse " else_body \fR]
 .BI MC_LOOPBETWEEN( tag ", " setup ", " cond ", " step ") " loop_body " \fR[\fBelse " else_body \fR]
 .BI MC_DECL( tag ", " decl ") " body
 .BI MC_LOOPELSE( tag ", " head ") " loop_body " \fR[\fBelse " else_body \fR]
 .BI MC_LOOPBETWEEN( tag ", " setup ", " cond ", " step ") " loop_body " \fR[\fBelse " else_body \fR]
-
+.PP
 .BI MC_TARGET( tag ", " stmt ") " body
 .BI MC_GOTARGET( tag );
 .BI MC_ALLOWELSE( tag ") " main_body " \fR[\fBelse " else_body \fR]
 .BI MC_GOELSE( tag );
 .BI MC_TARGET( tag ", " stmt ") " body
 .BI MC_GOTARGET( tag );
 .BI MC_ALLOWELSE( tag ") " main_body " \fR[\fBelse " else_body \fR]
 .BI MC_GOELSE( tag );
-
+.PP
 .BI MC_ACT( stmt )
 .BI MC_LABEL( tag )
 .BI MC_GOTO( tag )
 .BI MC_ACT( stmt )
 .BI MC_LABEL( tag )
 .BI MC_GOTO( tag )
index d4c7eb9..92b65c3 100644 (file)
@@ -49,7 +49,7 @@ exc \- exception handling for C programs
 .nf
 .B "typedef void (*exc__uncaught)(exc_extype, exc_exval);"
 .BI "exc__uncaught exc_uncaught(exc__uncaught " proc );
 .nf
 .B "typedef void (*exc__uncaught)(exc_extype, exc_exval);"
 .BI "exc__uncaught exc_uncaught(exc__uncaught " proc );
-
+.PP
 .BI "exc_extype EXC_PAIR(unsigned char " x ", unsigned char " y );
 .BI "exc_extype EXC_ALLOC(exc_extype " owner ", exc_extype " type );
 .BI "exc_extype EXC_ALLOCN(exc_extype " owner ", exc_extype " type );
 .BI "exc_extype EXC_PAIR(unsigned char " x ", unsigned char " y );
 .BI "exc_extype EXC_ALLOC(exc_extype " owner ", exc_extype " type );
 .BI "exc_extype EXC_ALLOCN(exc_extype " owner ", exc_extype " type );
index c7f8652..13d2a1a 100644 (file)
 \h'-\w'\\$1\ 'u'\\$1\ \c
 .ft P
 ..
 \h'-\w'\\$1\ 'u'\\$1\ \c
 .ft P
 ..
-.ie t .ds o \(bu
-.el .ds o o
+.ie t \{\
+.  ds o \(bu
+.  de VP
+.    sp .4v
+..
+\}
+.el \{\
+.  ds o o
+.  de VP
+.    sp
+..
+\}
 .
 .TH gprintf 3 "9 March 2024" "Straylight/Edgeware" "mLib utilities library"
 .
 .
 .TH gprintf 3 "9 March 2024" "Straylight/Edgeware" "mLib utilities library"
 .
@@ -28,25 +38,25 @@ gprintf \- generalized output formatting
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/gprintf.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/gprintf.h>"
-
+.PP
 .ta 2n
 .B "struct gprintf_ops {"
 .BI "  int (*putch)(void *" out ", int " ch ");"
 .BI "  int (*putm)(void *" out ", const char *" p ", size_t " sz ");"
 .BI "  int (*nputf)(void *" out ", size_t " maxsz ", const char *" p ", ...);"
 .B "};"
 .ta 2n
 .B "struct gprintf_ops {"
 .BI "  int (*putch)(void *" out ", int " ch ");"
 .BI "  int (*putm)(void *" out ", const char *" p ", size_t " sz ");"
 .BI "  int (*nputf)(void *" out ", size_t " maxsz ", const char *" p ", ...);"
 .B "};"
-
+.PP
 .BI "int gprintf(const struct gprintf_ops *" ops ", void *" out ","
 .ta \w'\fBint gprintf('u
 .BI "  const char *" p ", ...);"
 .BI "int vgprintf(const struct gprintf_ops *" ops ", void *" out ","
 .ta \w'\fBint vgprintf('u
 .BI "  const char *" p ", va_list *" ap ");"
 .BI "int gprintf(const struct gprintf_ops *" ops ", void *" out ","
 .ta \w'\fBint gprintf('u
 .BI "  const char *" p ", ...);"
 .BI "int vgprintf(const struct gprintf_ops *" ops ", void *" out ","
 .ta \w'\fBint vgprintf('u
 .BI "  const char *" p ", va_list *" ap ");"
-
+.PP
 .BI "int gprintf_memputf(char **" buf_inout ", size_t *" sz_inout ","
 .ta \w'\fBint gprintf_memputf('u
 .BI "  size_t " maxsz ", const char *" p ", va_list " ap ");"
 .BI "int gprintf_memputf(char **" buf_inout ", size_t *" sz_inout ","
 .ta \w'\fBint gprintf_memputf('u
 .BI "  size_t " maxsz ", const char *" p ", va_list " ap ");"
-
+.PP
 .B "const struct gprintf_ops file_printops;"
 .fi
 .
 .B "const struct gprintf_ops file_printops;"
 .fi
 .
@@ -189,28 +199,28 @@ struct my_output {
        size_t sz;
        /* ...\& other members ...\& */
 };
        size_t sz;
        /* ...\& other members ...\& */
 };
-
+.VP
 /* ...\& define putch and putm ...\& */
 /* ...\& define putch and putm ...\& */
-
+.VP
 static int nputf(void *out, size_t maxsz, const char *p, ...)
 {
        struct my_output *myout = out;
        va_list ap;
        int n;
 static int nputf(void *out, size_t maxsz, const char *p, ...)
 {
        struct my_output *myout = out;
        va_list ap;
        int n;
-
+.VP
        va_start(ap, p);
        n = gprintf_memputf(&myout->buf, &myout->sz, maxsz, p, ap);
        va_end(ap);
        if (n > 0) n = putm(myout, myout->buf, n);
        return (n);
 }
        va_start(ap, p);
        n = gprintf_memputf(&myout->buf, &myout->sz, maxsz, p, ap);
        va_end(ap);
        if (n > 0) n = putm(myout, myout->buf, n);
        return (n);
 }
-
+.VP
 const struct gprintf_ops my_output_ops = { putch, putm, nputf };
 const struct gprintf_ops my_output_ops = { putch, putm, nputf };
-
+.VP
 /* ...\& */
 /* ...\& */
-
+.VP
 struct my_output myout;
 struct my_output myout;
-
+.VP
 myout.buf = 0; myout.sz = 0;
 /* ...\& other initialization ...\& */
 gprintf(&my_output_ops, &myout, "Hello, %s!", "world");
 myout.buf = 0; myout.sz = 0;
 /* ...\& other initialization ...\& */
 gprintf(&my_output_ops, &myout, "Hello, %s!", "world");
index 20f74ca..422adae 100644 (file)
@@ -8,10 +8,10 @@
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/linreg.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/linreg.h>"
-
+.PP
 .B "struct linreg { ...\& };"
 .B "#define LINREG_INIT ..."
 .B "struct linreg { ...\& };"
 .B "#define LINREG_INIT ..."
-
+.PP
 .BI "void linreg_init(struct linreg *" lr );
 .BI "void linreg_update(struct linreg *" lr ", double " x ", double " y );
 .ta \w'void linreg_fit('u
 .BI "void linreg_init(struct linreg *" lr );
 .BI "void linreg_update(struct linreg *" lr ", double " x ", double " y );
 .ta \w'void linreg_fit('u
index d481a47..23af69b 100644 (file)
@@ -42,12 +42,12 @@ macros \- useful macros
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/macros.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/macros.h>"
-
+.PP
 .BI "size_t N(" array ");"
 .BI "STR(" tokens\fR... ")"
 .BI "GLUE(" tokens\fR... ", " tokens\fR... ")"
 .BI "STATIC_ASSERT(" cond ", " msg ");"
 .BI "size_t N(" array ");"
 .BI "STR(" tokens\fR... ")"
 .BI "GLUE(" tokens\fR... ", " tokens\fR... ")"
 .BI "STATIC_ASSERT(" cond ", " msg ");"
-
+.PP
 .BI "ISALNUM(int " ch ");"
 .BI "ISALPHA(int " ch ");"
 .BI "ISASCII(int " ch ");"
 .BI "ISALNUM(int " ch ");"
 .BI "ISALPHA(int " ch ");"
 .BI "ISASCII(int " ch ");"
@@ -64,14 +64,14 @@ macros \- useful macros
 .BI "TOASCII(int " ch ");"
 .BI "TOLOWER(int " ch ");"
 .BI "TOUPPER(int " ch ");"
 .BI "TOASCII(int " ch ");"
 .BI "TOLOWER(int " ch ");"
 .BI "TOUPPER(int " ch ");"
-
+.PP
 .BI "MEMCMP(const void *" x ", " op ", const void *" y ", size_t " n ");"
 .BI "STRCMP(const char *" x ", " op ", const char *" y ");"
 .BI "STRNCMP(const char *" x ", " op ", const char *" y ", size_t " n ");"
 .BI "MEMCMP(const void *" x ", " op ", const void *" y ", size_t " n ");"
 .BI "STRCMP(const char *" x ", " op ", const char *" y ");"
 .BI "STRNCMP(const char *" x ", " op ", const char *" y ", size_t " n ");"
-
+.PP
 .BI "void DISCARD(" scalar ");"
 .BI "void IGNORE(" variable ");"
 .BI "void DISCARD(" scalar ");"
 .BI "void IGNORE(" variable ");"
-
+.PP
 .BI "DEPRECATED(" msg ")"
 .BI "EXECL_LIKE(" ntrail ")"
 .BI "IGNORABLE"
 .BI "DEPRECATED(" msg ")"
 .BI "EXECL_LIKE(" ntrail ")"
 .BI "IGNORABLE"
@@ -79,11 +79,11 @@ macros \- useful macros
 .BI "NORETURN"
 .BI "PRINTF_LIKE(" fmt-index ", " arg-index ")"
 .BI "SCANF_LIKE(" fmt-index ", " arg-index ")"
 .BI "NORETURN"
 .BI "PRINTF_LIKE(" fmt-index ", " arg-index ")"
 .BI "SCANF_LIKE(" fmt-index ", " arg-index ")"
-
+.PP
 .BI "MUFFLE_WARNINGS_DECL(" warns ", " decls ")"
 .BI "MUFFLE_WARNINGS_EXPR(" warns ", " expr ")"
 .BI "MUFFLE_WARNINGS_STMT(" warns ", " stmt ")"
 .BI "MUFFLE_WARNINGS_DECL(" warns ", " decls ")"
 .BI "MUFFLE_WARNINGS_EXPR(" warns ", " expr ")"
 .BI "MUFFLE_WARNINGS_STMT(" warns ", " stmt ")"
-
+.PP
 .BI "GCC_WARNING(" option ")"
 .BI "CLANG_WARNING(" option ")"
 .fi
 .BI "GCC_WARNING(" option ")"
 .BI "CLANG_WARNING(" option ")"
 .fi
index 0d6afa5..a6f6b40 100644 (file)
@@ -7,7 +7,7 @@
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/maths.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/maths.h>"
-
+.PP
 .BI "int NANP(" floatish " " x );
 .BI "int INFP(" floatish " " x );
 .BI "int NEGP(" floatish " " x );
 .BI "int NANP(" floatish " " x );
 .BI "int INFP(" floatish " " x );
 .BI "int NEGP(" floatish " " x );
index 09a6f24..4b48e82 100644 (file)
 .sp 1
 .fi
 ..
 .sp 1
 .fi
 ..
+.ie t \{\
+.  de VP
+.    sp .4v
+..
+\}
+.el \{\
+.  de VP
+.    sp
+..
+\}
 .TH str 3 "20 June 1999" "Straylight/Edgeware" "mLib utilities library"
 .SH NAME
 str \- small string utilities
 .TH str 3 "20 June 1999" "Straylight/Edgeware" "mLib utilities library"
 .SH NAME
 str \- small string utilities
@@ -24,7 +34,7 @@ str \- small string utilities
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/str.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/str.h>"
-
+.PP
 .BI "char *str_qword(char **" pp ", unsigned " f );
 .BI "size_t str_qsplit(char *" p ", char *" v "[], size_t " c ,
 .BI "                  char **" rest ", unsigned " f );
 .BI "char *str_qword(char **" pp ", unsigned " f );
 .BI "size_t str_qsplit(char *" p ", char *" v "[], size_t " c ,
 .BI "                  char **" rest ", unsigned " f );
@@ -170,7 +180,7 @@ char p[] = " alpha  beta gamma   delta ";
 char *v[3];
 size_t n;
 char *q;
 char *v[3];
 size_t n;
 char *q;
-
+.VP
 n = str_split(p, v, 3, &q);
 .VE
 following the call to
 n = str_split(p, v, 3, &q);
 .VE
 following the call to
index b4a515b..4967fd6 100644 (file)
@@ -72,25 +72,25 @@ TARITH(SUB)
 static const struct tvec_urange ur_eight = { 8, 8 };
 static const struct tvec_urange ur_shift = { 0, 63 };
 static const struct tvec_regdef shift_regs[] = {
 static const struct tvec_urange ur_eight = { 8, 8 };
 static const struct tvec_urange ur_shift = { 0, 63 };
 static const struct tvec_regdef shift_regs[] = {
-  { "x", RX, &tvty_bytes, 0, { &ur_eight } },
-  { "n", RN, &tvty_uint, 0, { &ur_shift } },
-  { "z", RZ, &tvty_bytes, 0, { &ur_eight } },
+  { "x",       &tvty_bytes,    RX,     0,              { &ur_eight } },
+  { "n",       &tvty_uint,     RN,     0,              { &ur_shift } },
+  { "z",       &tvty_bytes,    RZ,     0,              { &ur_eight } },
   TVEC_ENDREGS
 };
 static const struct tvec_regdef arith_regs[] = {
   TVEC_ENDREGS
 };
 static const struct tvec_regdef arith_regs[] = {
-  { "x", RX, &tvty_bytes, 0, { &ur_eight } },
-  { "y", RY, &tvty_bytes, 0, { &ur_eight } },
-  { "z", RZ, &tvty_bytes, 0, { &ur_eight } },
+  { "x",       &tvty_bytes,    RX,     0,              { &ur_eight } },
+  { "y",       &tvty_bytes,    RY,     0,              { &ur_eight } },
+  { "z",       &tvty_bytes,    RZ,     0,              { &ur_eight } },
   TVEC_ENDREGS
 };
 
 static const struct tvec_test tests[] = {
   TVEC_ENDREGS
 };
 
 static const struct tvec_test tests[] = {
-  { "lsl64", shift_regs, 0, test_LSL },
-  { "lsr64", shift_regs, 0, test_LSR },
-  { "rol64", shift_regs, 0, test_ROL },
-  { "ror64", shift_regs, 0, test_ROR },
-  { "add64", arith_regs, 0, test_ADD },
-  { "sub64", arith_regs, 0, test_SUB },
+  { "lsl64",   shift_regs,     0,              test_LSL },
+  { "lsr64",   shift_regs,     0,              test_LSR },
+  { "rol64",   shift_regs,     0,              test_ROL },
+  { "ror64",   shift_regs,     0,              test_ROR },
+  { "add64",   arith_regs,     0,              test_ADD },
+  { "sub64",   arith_regs,     0,              test_SUB },
   TVEC_ENDTESTS
 };
 
   TVEC_ENDTESTS
 };
 
index fb462d0..c9090a3 100644 (file)
@@ -50,9 +50,9 @@ static void swap_test(struct tvec_state *tv, tvec_testfn *fn, void *ctx)
 static const struct tvec_env swap_testenv = { 0, 0, 0, 0, swap_test, 0, 0 };
 
 static const struct tvec_regdef versioncmp_regs[] = {
 static const struct tvec_env swap_testenv = { 0, 0, 0, 0, swap_test, 0, 0 };
 
 static const struct tvec_regdef versioncmp_regs[] = {
-  { "v0", RV0, &tvty_text, 0 },
-  { "v1", RV1, &tvty_text, 0 },
-  { "rc", RRC, &tvty_ienum, 0, { &tvenum_cmp } },
+  { "v0",      &tvty_text,     RV0,    0 },
+  { "v1",      &tvty_text,     RV1,    0 },
+  { "rc",      &tvty_ienum,    RRC,    0,              { &tvenum_cmp } },
   TVEC_ENDREGS
 };
 
   TVEC_ENDREGS
 };
 
index 15d1593..2b1c303 100644 (file)
@@ -7,7 +7,7 @@ versioncmp \- compare Debian-format version numbers
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/versioncmp.h>"
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/versioncmp.h>"
-
+.PP
 .BI "int versioncmp(const char *" va ", const char *" vb ");"
 .BI "int VERSIONCMP(const char *" va ", " op ", const char *" vb ");"
 .fi
 .BI "int versioncmp(const char *" va ", const char *" vb ");"
 .BI "int VERSIONCMP(const char *" va ", " op ", const char *" vb ");"
 .fi