chiark / gitweb /
@@@ 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 0842cb8325a65812004d84aacc8e92b18ddcc46b..001dc9a152417507d16f9ab4c86078ed57d11acf 100644 (file)
@@ -13,21 +13,21 @@ lbuf \- split lines out of asynchronously received blocks
 .nf
 .ta 2n
 .B "#include <mLib/lbuf.h>"
-
+.PP
 .B "enum {"
 .B "   LBUF_CRLF,"
 .B "   LBUF_STRICTCRLF,"
 .B "   ..."
 .B "};"
 .B "#define LBUF_ENABLE ..."
-
+.PP
 .B "typedef struct {"
 .B "   unsigned f;"
 .B "   ..."
 .B "} lbuf;"
-
+.PP
 .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 );
index 50a30fd709eb7449b0c26dfa8c2e6544c21cec00..dd48a336cfd85bf7a5d358e18d928e88355b2222 100644 (file)
@@ -13,20 +13,20 @@ pkbuf \- split packets out of asynchronously received blocks
 .nf
 .ta 2n
 .B "#include <mLib/pkbuf.h>"
-
+.PP
 .B "enum {"
 .B "   PKBUF_ENABLE = ..."
 .B "};"
-
+.PP
 .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 );
-
+.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 );
index 9c44d12207fba6dc1d19fedcef62c30c5e5e9f76..4d3a51a3e14d9a24f3ba449d5703fac7d329be49 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>"
-
+.PP
 .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 ,
@@ -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 );
-
+.PP
 .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 ,
@@ -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 );
-
+.PP
 .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 ,
index 4e828b71edda503bb63388650d05cc2dba8fc4ea..61fa6cac61756fe9ceeea3e8ce990a3306b7c839 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>
-
+.PP
index 6f2ccd82477c24106fd03ae17aaace186babb2a0..f2a0f29ce54551feb7b0873b9293af5fad88f760 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>"
-
+.PP
 .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 ..."
-
+.PP
 .ta 2n
 .B "enum {"
 .B "   CDCERR_OK = ...,"
@@ -36,7 +36,7 @@ codec \- binary encoding and decoding
 .B "   CDCERR_INVEQPAD = ...,"
 .B "   CDCERR_INVZPAD = ..."
 .B "};"
-
+.PP
 .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;"
-
+.PP
 .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;"
-
+.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;"
-
+.PP
 .BI "const char *codec_strerror(int " err ");"
 .fi
 .SH DESCRIPTION
index 9e8e8804cdf085eb4b2c078eef64dfb0ad504b06..07568087dd11c1d71aa90235f4ec1cc9f93cbd3a 100644 (file)
 .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
@@ -21,27 +31,27 @@ url \- manipulation of form-urlencoded strings
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/url.h>"
-
+.PP
 .ta 2n
 .B "typedef struct {"
 .B "   unsigned f;"
 .B "   ..."
 .B "} url_ectx;"
-
+.PP
 .B "typedef struct {"
 .B "   unsigned f;"
 .B "   ..."
 .B "} url_dctx;"
-
+.PP
 .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 );
-
+.PP
 .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>
-
+.VP
 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;
-
+.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);
@@ -172,13 +182,13 @@ void decode(sym_table *t, const char *p)
        }
        dstr_destroy(&n); dstr_destroy(&v);
 }
-
+.VP
 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);
index bfbeb8a65410be18ed36999c69408a45d7cf40a0..d2d75e357356732f99d666f68950ce279dcea686 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>
-
index 6eca843c785c78cafde1b86d00a25dc2e7a44a58..a03a2089a375c40b42c1a1ed597198f78aafd1f7 100644 (file)
@@ -14,7 +14,7 @@ crc32 \- calculate 32-bit CRC
 .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
index 3c637dc9ce9eb05c59bc591369392cd365292f64..57a6ce8273ac27113a192732eb64bda35c69276f 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[] = {
-  { "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[] = {
-  { "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[] = {
-  { "msz", RM, &tvty_buffer, TVRF_ID },
+  { "msz", &tvty_buffer, RM, TVRF_ID },
   TVEC_ENDREGS
 };
 
index 09da499e6117eec9ab0c9fd93481e9d9f663e893..eb3f50bcf98498478aeba34dadc6b7a5f8ad91e4 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>
-
index 72467acf909b3762ff03338a529cca49511cd2b6..86ea73b64c7531d740052aa49ceb0be297f5a721 100644 (file)
@@ -44,11 +44,11 @@ unihash \- simple and efficient universal hashing for hashtables
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/unihash.h>"
-
+.PP
 .B "typedef struct { ...\& } unihash_info;"
-
+.PP
 .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
index 06ad53df33636ac28a28578d94ae8a2db537f195..d974ad8af41b8a1be84ef30e45bbd7dd9057aaa1 100644 (file)
@@ -13,12 +13,12 @@ alloc \- mLib low-level memory allocation
 .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 );
-
+.PP
 .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>
-
index 51c2227dc5d7217c626c8847ff1f5b150bf50035..b7b4d2aa027007ed2b26603213c47ac4535ffae1 100644 (file)
@@ -14,30 +14,30 @@ arena \- control of memory allocation
 .SH "SYNOPSIS"
 .nf
 .B "#include <mLib/arena.h>"
-
+.PP
 .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;"
-
+.PP
 .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 );
-
+.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 );
-
+.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 );
index c31f27c6a1931a2121ca141528d9ed2c797ee88a..bb964a91770ff589da21dc08e6c98cffd0f37883 100644 (file)
@@ -10,10 +10,10 @@ growbuf \- extend buffers efficiently
 .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 ");"
-
+.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 ");"
index 38538a8204634fc3ccee68f20871f5f72dc47e47..18858740860cebf4a2f0aed9d41cc4f77d6cd921 100644 (file)
@@ -28,20 +28,20 @@ pool \- resource pool management
 .SH "SYNOPSIS"
 .nf
 .B "#include <mLib/pool.h>"
-
+.PP
 .B "typedef struct { ...\& } pool;"
-
+.PP
 .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;"
-
+.PP
 .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 );
-
+.PP
 .ta \w'\fBvoid POOL_ADD('u
 .BI "void POOL_ADD(pool *" p ", pool_resource *" r ,
 .BI "  void (*" dfn ")(pool_resource *" r ));
index c41041f6d820eaab7b8190d2980ca71788f3eaa8..23e751d017f1988967cf118a5b9afb8d8cc86302 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>"
-
+.PP
 .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 );
-
+.PP
 .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 );
index b5539b09d7b2e2ce88648035335effcf8fbf5086..cce20c2303b39bec1ec5cb041b5077c71fef1aa6 100644 (file)
@@ -10,9 +10,9 @@ bres \- background name resolver
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/bres.h>"
-
+.PP
 .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 ),
index 1ff936fcc6684b9271926694cf5224d6b978c569..d02a711a68da665f0245220b7663a93c676a1b41 100644 (file)
@@ -8,20 +8,20 @@ conn \- selector for nonblocking connections
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/conn.h>"
-
+.PP
 .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 );
-
+.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 );
-
+.PP
 .BI "void conn_kill(conn *" c );
 .fi
 .SH DESCRIPTION
index aebf9034f282efdf802011eac1bfffd29176f5f2..69b3fe7ed0cbfdacca234ba62d59cb09534eb799 100644 (file)
@@ -8,16 +8,16 @@ ident \- identd (RFC931) client
 .SH "SYNOPSIS"
 .nf
 .B "#include <mLib/ident>"
-
+.PP
 .B "typedef struct { ...\& } ident_request;"
-
+.PP
 .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;"
@@ -26,7 +26,7 @@ ident \- identd (RFC931) client
 .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 ,
index e31227727c2eeedbf3bd38fb8c75dc9a7584543e..da55fe862ae2a73775f8237cc05c2df50e5c6983 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>"
-
+.PP
 .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 "};"
-
+.PP
 .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;"
-
+.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;"
-
+.PP
 .BI "typedef void (*sel_hookfn)(sel_state *" s ", sel_args *" a ", void *" p );
-
+.PP
 .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 ,
@@ -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 );
-
+.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 );
-
+.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 );
-
+.PP
 .BI "int sel_fdmerge(fd_set *" dest ", fd_set *" fd ", int " maxfd );
-
+.PP
 .BI "int sel_select(sel_state *" s );
 .fi
 .SH "OVERVIEW"
index 5db9a71907c81ea5af6dca95abcaff37db3cd1aa..a2d345acfebdf6f7d365b5373d40493c78c5c750 100644 (file)
@@ -10,9 +10,9 @@ selbuf \- line-buffering input selector
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/selbuf.h>"
-
+.PP
 .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 );
index 5a3a0ffb1760841656e78f7453184eaa3c232e01..e945c823df8fb66978dfce19a02444c12c402137 100644 (file)
@@ -10,9 +10,9 @@ selpk \- packet-buffering input selector
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/selpk.h>"
-
+.PP
 .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 );
index 725f859291bcb161962e67124876814824391bd8..511b96d2ddf66e22513c7dad526a1377f210545b 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>"
-
+.PP
 .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 );
index cbec2c228357c581f825759a007cd8082e47a439..9f65b8ee76b84125d1bdf61a83db63187f91dafc 100644 (file)
@@ -26,18 +26,18 @@ assoc \- tables indexed by atoms
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/assoc.h>"
-
+.PP
 .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 );
-
+.PP
 .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 );
-
+.PP
 .BI "void assoc_mkiter(assoc_iter *" i ", assoc_table *" t );
 .BI "void *assoc_next(assoc_iter *" i );
 .fi
index e5ecf004de59584d114bbfc314c483cf7c56249c..35d30f9c7e8eb6901eba859475fa90cf875e810a 100644 (file)
@@ -35,29 +35,29 @@ atom \- atom table manager
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/atom.h>"
-
+.PP
 .B "typedef struct { ...\& } atom_table;"
 .B "typedef struct { ...\& } atom;"
-
+.PP
 .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;"
-
+.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 );
-
+.PP
 .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
index 3b3ef7ce2edf854f889a46b71319e74079e0d83d..ccb8dc197ca353014a45c95a8074b323642334ea 100644 (file)
@@ -34,7 +34,7 @@ buf \- reading and writing stuff in buffers
 .\" @BBAD
 .\" @BOK
 .\" @BENSURE
-
+.
 .\" @DBBASE
 .\" @DBLIM
 .\" @DBCUR
@@ -459,10 +459,10 @@ buf \- reading and writing stuff in buffers
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/dstr.h>"
-
+.PP
 .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 );
@@ -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 ..."
-
+.PP
 .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
-
+.PP
 .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 );
-
+.PP
 .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 );
-
+.PP
 .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 );
-
+.PP
 .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
@@ -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 );
-
+.PP
 .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 );
-
+.PP
 .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"
-
+.PP
 .fi
 For
 .I suff
@@ -587,10 +587,10 @@ and
 .ta 2n
 .BI "BUF_ENCLOSE" suff "(buf *" b ", size_t " mk )
 .I "   body"
-
+.PP
 .BI "BUF_ENCLOSEZ(buf *" b )
 .I "   body"
-
+.PP
 .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 );
-
+.PP
 .fi
 For
 .I suff
index 6037c74c06b17720ab0a19e55cffec66db4bcfa8..c01a5943e670fc1604d40643525fe1aeb82bd2be 100644 (file)
@@ -57,51 +57,51 @@ darray \- dense, dynamically resizing arrays
 .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;"
-
+.PP
 .B "#define DA_INIT ..."
-
+.PP
 .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 );
-
+.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 );
-
+.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 );
-
+.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 );
-
+.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 );
-
+.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 );
-
+.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 );
@@ -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
+.ta 2n
 #ifndef FOO_V
-#  define FOO_V
-   DA_DECL(foo_v, foo);
+#      define FOO_V
+       DA_DECL(foo_v, foo);
 #endif
 .VE
 The macro
@@ -360,9 +361,10 @@ miss.
 .PP
 Dynamic arrays are structures with the format
 .VS
+.ta 2n
 .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
index 9d2ab00f4fca42143f5892c2256ab0c974500b97..dd6dbd9e6c3c1fd1b4c78ad35377b5f9e05e0b45 100644 (file)
@@ -25,14 +25,14 @@ dspool \- pools of preallocated dynamic strings
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/dspool.h>"
-
+.PP
 .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 );
-
+.PP
 .BI "void DSGET(dspool *" p ", " d );
 .BI "void DSPUT(dspool *" p ", dstr *" d );
 .fi
index 1aadd35c28afc24319f74be5cdcea2234ad766ad..8608d557b0b658366e9be030143c5b04061f57f2 100644 (file)
@@ -52,17 +52,17 @@ dstr \- a simple dynamic string type
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/dstr.h>"
-
+.PP
 .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 );
-
+.PP
 .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 );
@@ -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 );
-
+.PP
 .BI "void DCREATE(dstr *" d );
 .BI "void DDESTROY(dstr *" d );
 .BI "void DRESET(dstr *" d );
index c06727516ed58322867dc12cc7789d471b95696d..fdde662a7309fb2c2c91650cd654fead46aba0a6 100644 (file)
 \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
@@ -37,21 +47,21 @@ hash \- low-level hashtable implementation
 .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;"
-
+.PP
 .B "typedef struct {"
 .B "   hash_base *next;"
 .B "   uint32 hash;"
 .B "} hash_base;"
-
+.PP
 .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 );
@@ -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 );
-
+.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 );
@@ -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
+.ta 2n
 /* --- A table of items --- */
-
+.VP
 typedef struct item_table {
-  hash_table t;
-  size_t load;
+       hash_table t;
+       size_t load;
 };
-
+.VP
 /* --- An item --- */
-
+.VP
 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
@@ -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
+.ta 2n
 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
@@ -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
+.ta 2n +2n
 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
@@ -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
+.ta 2n +2n +2n 20m
 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
@@ -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
+.ta 2n +2n
 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
index a2afcaf87285d6167344d370cc8c9ca3c5cd59e8..a683e20149675cdcc216e4326112ee2d9423a8f1 100644 (file)
 .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
@@ -28,24 +38,24 @@ sym \- symbol table manager
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/sym.h>"
-
+.PP
 .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 );
-
+.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 );
-
+.PP
 .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
@@ -189,11 +199,12 @@ information about types and values.
 In this case, you'd define something like the following structure for
 your values:
 .VS
+.ta 2 20m
 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
@@ -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
+.ta 2n
 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
+.ta 2n
 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
+.ta 2n
 sym_iter i;
 val *v;
-
+.VP
 for (sym_mkiter(&i, t); (v = sym_next(&i)) != 0; ) {
-  /* ... */
+       /* ... */
 }
 .VE
 That ought to be enough examples to be getting on with.
index 1482bed157b5a80a3060eb71eba7f09595051ad3..fba258e21194f99906d3dd58948968dc70da6c4f 100644 (file)
@@ -7,7 +7,7 @@ daemonize \- become a background process
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/daemonize.h>"
-
+.PP
 .B "void detachtty(void);"
 .B "int daemonize(void);"
 .fi
index 1818b372ac1d7db4c92e0ca461ce65825cf13498..2c5b5af3c0fb4e93422eb6b8b6db2e2629b9f4b5 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>"
-
+.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 );
index 2ed2fa9470258457f0eae69e6048ad92dcf04cc2..25fb3f673cb49b302940044b9078ebeae26a6920 100644 (file)
@@ -18,7 +18,7 @@ fdflags \- set file and file descriptor flags
 .SH "SYNOPSIS"
 .nf
 .B "#include <mLib/fdflags.h>"
-
+.PP
 .ta \w'\fBint fdflags('u
 .BI "int fdflags(int " fd ,
 .BI "  unsigned " fbic ", unsigned " fxor ,
index b643bde19a4a2b933862666a894569a0b952918d..449b6bf8f8a5d8453b2f6c0c2cb896df3b6f9845 100644 (file)
@@ -7,7 +7,7 @@ fdpass \- file descriptor passing
 .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
index 9afe273f15c3bdb739e00af4b18738911c0f4509..c4617339fd4841d790729bbeae0d450c3ab52206 100644 (file)
@@ -9,9 +9,9 @@ fwatch \- watch a file for changes
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/fwatch.h>"
-
+.PP
 .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 );
index d7b18e5cce91dd405ed4179bb7e373cd10419597..46be54641275df11885d70b705edb78e279e96cc 100644 (file)
@@ -6,14 +6,14 @@ lock \- oversimplified file locking interface
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/lock.h>"
-
+.PP
 .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
index f08c13e7171b599d0b62c99a3f94240cba05c2ed..567da6ae486b4af689c7196ab33b85fec714df2b 100644 (file)
 \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>"
-
+.PP
 .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
@@ -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;
-
+.VP
 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;
-
+.VP
 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>
-
index 62d918943b8df89298c1c8fd3c46423ad1a72293..f24892d03cbc661790f94301ef4e6ff2170405ed 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>"
-
+.PP
 .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 );
-
+.PP
 .B "int MILLION;"
 .BI "void TV_ADD(struct timeval *" dst ,
 .BI "            const struct timeval *" a ,
index 5a4b2ffd7f0cea49aa648bc1af820cbd9dadd9d1..f3805ad3c3b204ea9974fc156de23671744c6341 100644 (file)
@@ -35,6 +35,7 @@ libtest_la_SOURCES     =
 ## Benchmarking.
 pkginclude_HEADERS     += bench.h
 libtest_la_SOURCES     += bench.c
+LIBMANS                        += bench.3
 
 ## 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
-#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
+LIBMANS                        += tvec-bench.3
+
 libtest_la_SOURCES     += tvec-remote.c
+LIBMANS                        += tvec-remote.3
+
 libtest_la_SOURCES     += tvec-timeout.c
+LIBMANS                        += tvec-timeout.3
 
 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 b6ba60578cd8b63468d0c8337096014fd7b23a07..04759cdac9e729e2c5b62988573c72609ec6e107 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,
-    { "@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)
@@ -256,7 +256,7 @@ static void test_copy_buffer
 
 #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)
@@ -314,16 +314,21 @@ static void test_single_deserialize
 
 #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[] = { \
-         { "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)
@@ -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)                           \
-  { #name,     i,      &tvty_##ty,     TVRF_OPT,                       \
-                                           DSGINIT({ .argslot = argval }) },
+  { #name,     &tvty_##ty,     i,      TVRF_OPT,                       \
+                                     DSGINIT({ .argslot = argval }) },
   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
 };
@@ -463,9 +468,9 @@ static const struct tvec_remotefork crash_testenv =
   { 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
 };
 
@@ -496,8 +501,8 @@ static const struct tvec_remotefork sleep_testenv =
   { 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
 };
 
index b6e30f305d0d4cad5e2e48c6e00a3593966f2ec7..e33bbb0f8434fb08ed839971d241a4928d94a3ad 100644 (file)
@@ -18,37 +18,37 @@ testrig \- generic test rig
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/testrig.h>"
-
+.PP
 .B "#define TEST_FIELDMAX ..."
-
+.PP
 .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";
-
+.PP
 .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";
-
+.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;"
-
+.PP
 .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 dda57137b72e14ada9ef653cc355c79221f47126..bff3c3a2fa01805210a8d0526a2107003ca46742 100644 (file)
@@ -294,7 +294,7 @@ static int setvar(struct tvec_state *tv, const char *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)
index 6a98f7368f02936307cb9139425837e86ca1ca70..ca71dd2b258de6de27c7a9a1fe27560d4a34593e 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++) {
-    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);
@@ -572,9 +572,9 @@ void tvec_initregs(struct tvec_state *tv)
   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;
-    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; }
   }
 }
@@ -585,9 +585,9 @@ void tvec_releaseregs(struct tvec_state *tv)
   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;
-    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; }
   }
 }
@@ -611,8 +611,8 @@ void tvec_resetoutputs(struct tvec_state *tv)
   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);
@@ -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++) {
-    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))
@@ -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 (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;
@@ -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,
-    { "@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)
@@ -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. */
-       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
@@ -1211,19 +1212,18 @@ void tvec_begin(struct tvec_state *tv_out,
   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;
-    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;
 
-  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);
 }
@@ -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;
-  tv->tests = t;
+  tv->cfg.tests = t;
 }
 
 /* --- @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)
 {
-  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;
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 c167618217b777ac49d38e8553b1286e7669d275..3c25282fb5f3a142bee655e30e1b1f6afe53d809 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. */
-       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'",
@@ -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,
-                                  srvtv.nreg, srvtv.regsz))
+                                  srvtv.cfg.nreg, srvtv.cfg.regsz))
                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.)
                 */
-               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;
@@ -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", -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", -1, &tvty_text, 0 } };
+    { "@progress", &tvty_text, -1, 0 } };
 
 /* 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,
-    { "@reconnect", -1, &tvty_uenum, 0, { &reconn_enuminfo } } };
+    { "@reconnect", &tvty_uenum, -1, 0, { &reconn_enuminfo } } };
 
 /*----- 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;
-  struct tvec_reg *reg = 0;
+  struct tvec_reg *reg = 0; size_t rsz = 0;
   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 (!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);
@@ -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),
-                  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);
 
@@ -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);
-    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));
   }
 
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 a1800db258b988d719f47e00b5b50e111e80d5b3..5e386e2da9dbcf4a7352af48dc97f603c7dd198f 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,
-    { "@timeout", -1, &tvty_duration, 0 } };
+    { "@timeout", &tvty_duration, -1, 0 } };
 
 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,
-    { "@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)
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 20c29301dcfef5911fc0c1840b5673d09701d246..87748ebf62c0528af39f78640d876ac91d9da828 100644 (file)
@@ -3516,18 +3516,18 @@ const struct tvec_regty tvty_buffer = {
 /* --- @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:    ---
  *
- * 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,
-                    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@ --- *
  *
index c0cb3c3ecd822b325f169f82c0c9c86657eab9c0..23eded3bcc288be2f9d93565ad62b366c721a01a 100644 (file)
 .\" -*-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
-
-
-
-
+.\" @tvec_begin
+.\" @tvec_end
+.\" @tvec_read
+.\" @tvec_humanoutput
+.\" @tvec_tapoutput
+.\" @tvec_dfltoutput
+.
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/tvec.h>"
-
+.PP
+.ta 2n
 .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 d16df58be3579dfcc941f5e74c9340af0e0053c1..293dccc0a90e70eb4a308033e40d9290c312f262 100644 (file)
@@ -192,8 +192,8 @@ union tvec_regval {
   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 { 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 */
@@ -236,8 +236,8 @@ struct tvec_regdef {
    */
 
   const char *name;                    /* register name (for input files) */
-  unsigned i;                          /* register index */
   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  */
@@ -321,6 +321,8 @@ struct tvec_regty {
 
 /*----- Test descriptions -------------------------------------------------*/
 
+struct tvec_env;
+
 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.
    */
 
-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
@@ -435,17 +435,6 @@ struct tvec_test {
 };
 #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 {
@@ -458,9 +447,18 @@ enum {
   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. */
 
+  /* Flags.  Read-only for all callers. */
   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 */
 
-  /* 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 */
 
-  /* 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];
@@ -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.
  */
-#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 -------------------------------------------------*/
 
@@ -513,6 +507,27 @@ struct tvec_output {
   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 */
@@ -620,17 +635,6 @@ struct tvec_outops {
     /* 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@ --- *
@@ -1204,6 +1208,8 @@ extern void tvec_benchreport
 
 /*----- Remote execution --------------------------------------------------*/
 
+struct tvec_remoteenv;
+
 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;
-  int timer;                   /* the timer (@ITIMER_...@) */
+  int timer;                           /* the timer (@ITIMER_...@) */
   double t;                            /* time to wait (in seconds) */
   const struct tvec_env *env;          /* subsidiary environment */
 };
@@ -1442,7 +1448,7 @@ extern tvec_envteardownfn tvec_timeoutteardown;
  *             message.
  */
 
-extern  const char *tvec_strlevel(unsigned /*level*/);
+extern const char *tvec_strlevel(unsigned /*level*/);
 
 /* --- @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*/, ...);
 
+/* --- @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
@@ -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*/);
 
-/* --- @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
@@ -1902,6 +1908,8 @@ struct tvec_floatinfo {
   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
@@ -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))
 
-extern const struct tvec_floatinfo tvflt_finite, tvflt_nonneg;
-
 /*----- 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;
 
+/* --- @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
@@ -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_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
@@ -2479,17 +2485,17 @@ extern const struct tvec_regty tvty_buffer;
 /* --- @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:    ---
  *
- * 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*/,
-                           const union tvec_regval */*src*/, size_t /*sz*/);
+                           const union tvec_regval */*ref*/, size_t /*sz*/);
 
 /* --- @tvec_allocbuffer@ --- *
  *
index 1a405871c4849f7b550710e32077fe9b7ba66533..d0e4fcf9b4446aa49bc708988fbdc6a8559fc07d 100644 (file)
@@ -15,12 +15,12 @@ trace \- configurable tracing output
 .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 );
-
+.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 ,
@@ -28,11 +28,11 @@ trace \- configurable tracing output
 .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 );
-
+.PP
 .BI T( statements\fR... )
 .BI "IF_TRACING(unsigned " l ", " statements\fR... )
 .fi
index 253b63523a3f489c6f7355a8e9ec2cd1be9b2ece..9b87323a859f453702104b270110fcde7ec027e2 100644 (file)
@@ -6,31 +6,31 @@ mdwopt \- command-line option parser
 .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;"
-
+.PP
 .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 "};"
-
+.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 = ..."
-
+.PP
 .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 = ..."
-
+.PP
 .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 );
-
+.PP
 .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 );
-
+.PP
 .ta \w'\fBint getopt_long_only('u
 .BI "int getopt_long_only(int " argc ", char *const *" argv ,
 .BI "  const char * "shortopt ,
index bd1969808560fd85f261530fdf0942b4c1eeec58..50a0203d10fb004f59df95367a9fec3d66f91821 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>"
-
+.PP
 .BI "void ego(const char *" p );
 .B "const char *quis(void);"
 .B "const char *QUIS;"
index 1ccecb68bab602e52a4476a5b133169e440b8da8..19fda9a6ddb1796053efb02e0158f4858e3acd5c 100644 (file)
@@ -7,7 +7,7 @@ report \- report errors
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/report.h>"
-
+.PP
 .BI "void moan(const char *" f ", ...);"
 .BI "void die(int " status ", const char *" f ", ...);"
 .fi
index 9ee237705aa1a5c3f626b492e6ca721f6e6870aa..55a4040a9cfdf75d28f784574ef6eba73f38efbe 100644 (file)
@@ -6,7 +6,7 @@ align \- alignment utilities
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/align.h>"
-
+.PP
 .BI "size_t ALIGN(size_t " sz ");"
 .fi
 .SH DESCRIPTION
index a002e2438ec34a297a267f27584de22ac8e28b53..3b09b65dd66e7243b0bd86ba3060659566ec5ce3 100644 (file)
@@ -175,34 +175,34 @@ bits \- portable bit manipulation macros
 .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;"
-
+.PP
 .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..."
-
+.PP
 .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 );
-
+.PP
 .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 );
-
+.PP
 .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>
-
index 1920be40572807d61bc3b5ea39f5cc6590d5ebbe..424ca0ea18e572a0cf13393f6ccfc2a8d4377f76 100644 (file)
@@ -7,7 +7,7 @@ compiler \- detect compiler version
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/compiler.h>"
-
+.PP
 .BI "int GCC_VERSION_P(" maj ", " min ");"
 .BI "int CLANG_VERSION_P(" maj ", " min ");"
 .fi
index be83be91fe4cdb067ef725857dafe99e8445aaac..65f31d634608e1391c7e6b4345efb45867aa7c2a 100644 (file)
@@ -34,7 +34,7 @@ control \- control structure metaprogramming
 .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
@@ -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]
-
+.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 );
-
+.PP
 .BI MC_ACT( stmt )
 .BI MC_LABEL( tag )
 .BI MC_GOTO( tag )
index d4c7eb9e7cb92408bc90e69ed554dca792ffcdae..92b65c30873c404c4d5bef11f875e1e48466f2f5 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 );
-
+.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 );
index c7f86522aa0831b0c740a715644ce2717cd17e24..13d2a1adb553c71ac210c7dd3c19152de02c9a86 100644 (file)
 \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"
 .
@@ -28,25 +38,25 @@ gprintf \- generalized output formatting
 .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 "};"
-
+.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 ");"
-
+.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 ");"
-
+.PP
 .B "const struct gprintf_ops file_printops;"
 .fi
 .
@@ -189,28 +199,28 @@ struct my_output {
        size_t sz;
        /* ...\& other members ...\& */
 };
-
+.VP
 /* ...\& 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;
-
+.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);
 }
-
+.VP
 const struct gprintf_ops my_output_ops = { putch, putm, nputf };
-
+.VP
 /* ...\& */
-
+.VP
 struct my_output myout;
-
+.VP
 myout.buf = 0; myout.sz = 0;
 /* ...\& other initialization ...\& */
 gprintf(&my_output_ops, &myout, "Hello, %s!", "world");
index 20f74cad1b734cb81e96162637427e75b712aba8..422adae05c580bb9347dad1370b2480ba5b825df 100644 (file)
@@ -8,10 +8,10 @@
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/linreg.h>"
-
+.PP
 .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
index d481a47f28c9e6d8958242b8a10730bc6a1fc310..23af69bce8a0a7bb86d5e3b103ca749cccd154bc 100644 (file)
@@ -42,12 +42,12 @@ macros \- useful macros
 .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 ");"
-
+.PP
 .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 ");"
-
+.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 ");"
-
+.PP
 .BI "void DISCARD(" scalar ");"
 .BI "void IGNORE(" variable ");"
-
+.PP
 .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 ")"
-
+.PP
 .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
index 0d6afa55b66cda0460e3acb1e0e4b57f403bd39d..a6f6b40e43fe8bace3939cce7275c69f5a1d9966 100644 (file)
@@ -7,7 +7,7 @@
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/maths.h>"
-
+.PP
 .BI "int NANP(" floatish " " x );
 .BI "int INFP(" floatish " " x );
 .BI "int NEGP(" floatish " " x );
index 09a6f242c0621483530572c61e85fb9a8555dc24..4b48e8265b893cfd975bbe1146da5237204d7868 100644 (file)
 .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
@@ -24,7 +34,7 @@ str \- small string utilities
 .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 );
@@ -170,7 +180,7 @@ char p[] = " alpha  beta gamma   delta ";
 char *v[3];
 size_t n;
 char *q;
-
+.VP
 n = str_split(p, v, 3, &q);
 .VE
 following the call to
index b4a515b0278544141b1bfce7572e2bec8d302a20..4967fd67fd90ee04296e28b9fead32f7aa04da5d 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[] = {
-  { "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[] = {
-  { "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[] = {
-  { "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
 };
 
index fb462d04df02893847de01669f2ef343267bf388..c9090a3899908269e6b5ff6b809882f6cd0b9c3f 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[] = {
-  { "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
 };
 
index 15d159379d8c6ab87763d57c281297046de898cd..2b1c303fad19b772d79dc0d33e6657e89b114cc6 100644 (file)
@@ -7,7 +7,7 @@ versioncmp \- compare Debian-format version numbers
 .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