From d056fbdff1c5a26be055c38eee4c273ee6a0cba7 Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Tue, 12 Mar 2024 01:20:08 +0000 Subject: [PATCH] @@@ man wip --- buf/lbuf.3 | 8 +- buf/pkbuf.3 | 8 +- codec/base64.3 | 12 +- codec/bincode.1 | 2 +- codec/codec.3 | 14 +- codec/url.3 | 30 ++- hash/crc-mktab.1 | 1 - hash/crc32.3 | 2 +- hash/t/hash-test.c | 12 +- hash/unihash-mkstatic.1 | 1 - hash/unihash.3 | 6 +- mem/alloc.3 | 5 +- mem/arena.3 | 12 +- mem/growbuf.3 | 4 +- mem/pool.3 | 10 +- mem/sub.3 | 8 +- sel/bres.3 | 4 +- sel/conn.3 | 8 +- sel/ident.3 | 8 +- sel/sel.3 | 22 +-- sel/selbuf.3 | 4 +- sel/selpk.3 | 4 +- sel/sig.3 | 4 +- struct/assoc.3 | 10 +- struct/atom.3 | 12 +- struct/buf.3 | 34 ++-- struct/darray.3 | 30 +-- struct/dspool.3 | 6 +- struct/dstr.3 | 10 +- struct/hash.3 | 149 +++++++------- struct/sym.3 | 40 ++-- sys/daemonize.3 | 2 +- sys/env.3 | 2 +- sys/fdflags.3 | 2 +- sys/fdpass.3 | 2 +- sys/fwatch.3 | 4 +- sys/lock.3 | 4 +- sys/mdup.3 | 23 ++- sys/tv.3 | 4 +- test/Makefile.am | 14 +- test/bench.3 | 495 ++++++++++++++++++++++++++++++++++++++++++++++ test/t/tvec-test.c | 43 ++-- test/testrig.3 | 14 +- test/tvec-adhoc.3 | 91 +++++++++ test/tvec-bench.3 | 65 ++++++ test/tvec-bench.c | 2 +- test/tvec-core.c | 44 ++--- test/tvec-env.3 | 178 +++++++++++++++++ test/tvec-main.3 | 64 ++++++ test/tvec-output.3 | 96 +++++++++ test/tvec-remote.3 | 109 ++++++++++ test/tvec-remote.c | 25 +-- test/tvec-timeout.3 | 52 +++++ test/tvec-timeout.c | 4 +- test/tvec-tyimpl.3 | 103 ++++++++++ test/tvec-types.3 | 323 ++++++++++++++++++++++++++++++ test/tvec-types.c | 8 +- test/tvec.3 | 129 +++++++++++- test/tvec.h | 200 ++++++++++--------- trace/trace.3 | 8 +- ui/mdwopt.3 | 20 +- ui/quis.3 | 2 +- ui/report.3 | 2 +- utils/align.3 | 2 +- utils/bits.3 | 17 +- utils/compiler.3 | 2 +- utils/control.3 | 6 +- utils/exc.3 | 2 +- utils/gprintf.3 | 36 ++-- utils/linreg.3 | 4 +- utils/macros.3 | 14 +- utils/maths.3 | 2 +- utils/str.3 | 14 +- utils/t/bits-test.c | 24 +-- utils/t/versioncmp-test.c | 6 +- utils/versioncmp.3 | 2 +- 76 files changed, 2263 insertions(+), 482 deletions(-) create mode 100644 test/bench.3 create mode 100644 test/tvec-adhoc.3 create mode 100644 test/tvec-bench.3 create mode 100644 test/tvec-env.3 create mode 100644 test/tvec-main.3 create mode 100644 test/tvec-output.3 create mode 100644 test/tvec-remote.3 create mode 100644 test/tvec-timeout.3 create mode 100644 test/tvec-tyimpl.3 create mode 100644 test/tvec-types.3 diff --git a/buf/lbuf.3 b/buf/lbuf.3 index 0842cb8..001dc9a 100644 --- a/buf/lbuf.3 +++ b/buf/lbuf.3 @@ -13,21 +13,21 @@ lbuf \- split lines out of asynchronously received blocks .nf .ta 2n .B "#include " - +.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 ); diff --git a/buf/pkbuf.3 b/buf/pkbuf.3 index 50a30fd..dd48a33 100644 --- a/buf/pkbuf.3 +++ b/buf/pkbuf.3 @@ -13,20 +13,20 @@ pkbuf \- split packets out of asynchronously received blocks .nf .ta 2n .B "#include " - +.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 ); diff --git a/codec/base64.3 b/codec/base64.3 index 9c44d12..4d3a51a 100644 --- a/codec/base64.3 +++ b/codec/base64.3 @@ -16,14 +16,14 @@ base64, base32, hex \- obsolete binary encoding functions .B "#include " .B "#include " .B "#include " - +.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 , diff --git a/codec/bincode.1 b/codec/bincode.1 index 4e828b7..61fa6ca 100644 --- a/codec/bincode.1 +++ b/codec/bincode.1 @@ -106,4 +106,4 @@ If an error is encountered, the output may be partially written. .BR codec (3). .SH "AUTHOR" Mark Wooding, - +.PP diff --git a/codec/codec.3 b/codec/codec.3 index 6f2ccd8..f2a0f29 100644 --- a/codec/codec.3 +++ b/codec/codec.3 @@ -17,7 +17,7 @@ codec \- binary encoding and decoding .B "#include " .B "#include " .B "#include " - +.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 diff --git a/codec/url.3 b/codec/url.3 index 9e8e880..0756808 100644 --- a/codec/url.3 +++ b/codec/url.3 @@ -11,6 +11,16 @@ .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 " - +.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 #include #include - +.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); diff --git a/hash/crc-mktab.1 b/hash/crc-mktab.1 index bfbeb8a..d2d75e3 100644 --- a/hash/crc-mktab.1 +++ b/hash/crc-mktab.1 @@ -169,4 +169,3 @@ an example of use, see the header file by Ross N. Williams. .SH "AUTHOR" Mark Wooding, - diff --git a/hash/crc32.3 b/hash/crc32.3 index 6eca843..a03a208 100644 --- a/hash/crc32.3 +++ b/hash/crc32.3 @@ -14,7 +14,7 @@ crc32 \- calculate 32-bit CRC .SH SYNOPSIS .nf .B "#include " - +.PP .BI "uint32 crc32(uint32 " crc ", const void *" buf ", size_t " sz ); .BI CRC32( result ", " crc ", " buf ", " sz ) .fi diff --git a/hash/t/hash-test.c b/hash/t/hash-test.c index 3c637dc..57a6ce8 100644 --- a/hash/t/hash-test.c +++ b/hash/t/hash-test.c @@ -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 }; diff --git a/hash/unihash-mkstatic.1 b/hash/unihash-mkstatic.1 index 09da499..eb3f50b 100644 --- a/hash/unihash-mkstatic.1 +++ b/hash/unihash-mkstatic.1 @@ -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, - diff --git a/hash/unihash.3 b/hash/unihash.3 index 72467ac..86ea73b 100644 --- a/hash/unihash.3 +++ b/hash/unihash.3 @@ -44,11 +44,11 @@ unihash \- simple and efficient universal hashing for hashtables .SH SYNOPSIS .nf .B "#include " - +.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 diff --git a/mem/alloc.3 b/mem/alloc.3 index 06ad53d..d974ad8 100644 --- a/mem/alloc.3 +++ b/mem/alloc.3 @@ -13,12 +13,12 @@ alloc \- mLib low-level memory allocation .SH SYNOPSIS .nf .B "#include " - +.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, - diff --git a/mem/arena.3 b/mem/arena.3 index 51c2227..b7b4d2a 100644 --- a/mem/arena.3 +++ b/mem/arena.3 @@ -14,30 +14,30 @@ arena \- control of memory allocation .SH "SYNOPSIS" .nf .B "#include " - +.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 ); diff --git a/mem/growbuf.3 b/mem/growbuf.3 index c31f27c..bb964a9 100644 --- a/mem/growbuf.3 +++ b/mem/growbuf.3 @@ -10,10 +10,10 @@ growbuf \- extend buffers efficiently .SH SYNOPSIS .nf .B "#include " - +.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 ");" diff --git a/mem/pool.3 b/mem/pool.3 index 38538a8..1885874 100644 --- a/mem/pool.3 +++ b/mem/pool.3 @@ -28,20 +28,20 @@ pool \- resource pool management .SH "SYNOPSIS" .nf .B "#include " - +.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 )); diff --git a/mem/sub.3 b/mem/sub.3 index c41041f..23e751d 100644 --- 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 " - +.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 ); diff --git a/sel/bres.3 b/sel/bres.3 index b5539b0..cce20c2 100644 --- a/sel/bres.3 +++ b/sel/bres.3 @@ -10,9 +10,9 @@ bres \- background name resolver .SH SYNOPSIS .nf .B "#include " - +.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 ), diff --git a/sel/conn.3 b/sel/conn.3 index 1ff936f..d02a711 100644 --- a/sel/conn.3 +++ b/sel/conn.3 @@ -8,20 +8,20 @@ conn \- selector for nonblocking connections .SH SYNOPSIS .nf .B "#include " - +.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 diff --git a/sel/ident.3 b/sel/ident.3 index aebf903..69b3fe7 100644 --- a/sel/ident.3 +++ b/sel/ident.3 @@ -8,16 +8,16 @@ ident \- identd (RFC931) client .SH "SYNOPSIS" .nf .B "#include " - +.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 , diff --git a/sel/sel.3 b/sel/sel.3 index e312277..da55fe8 100644 --- 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 " - +.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" diff --git a/sel/selbuf.3 b/sel/selbuf.3 index 5db9a71..a2d345a 100644 --- a/sel/selbuf.3 +++ b/sel/selbuf.3 @@ -10,9 +10,9 @@ selbuf \- line-buffering input selector .SH SYNOPSIS .nf .B "#include " - +.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 ); diff --git a/sel/selpk.3 b/sel/selpk.3 index 5a3a0ff..e945c82 100644 --- a/sel/selpk.3 +++ b/sel/selpk.3 @@ -10,9 +10,9 @@ selpk \- packet-buffering input selector .SH SYNOPSIS .nf .B "#include " - +.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 ); diff --git a/sel/sig.3 b/sel/sig.3 index 725f859..511b96d 100644 --- a/sel/sig.3 +++ b/sel/sig.3 @@ -8,9 +8,9 @@ sig \- more controlled signal handling .SH SYNOPSIS .nf .B "#include " - +.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 ); diff --git a/struct/assoc.3 b/struct/assoc.3 index cbec2c2..9f65b8e 100644 --- a/struct/assoc.3 +++ b/struct/assoc.3 @@ -26,18 +26,18 @@ assoc \- tables indexed by atoms .SH SYNOPSIS .nf .B "#include " - +.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 diff --git a/struct/atom.3 b/struct/atom.3 index e5ecf00..35d30f9 100644 --- a/struct/atom.3 +++ b/struct/atom.3 @@ -35,29 +35,29 @@ atom \- atom table manager .SH SYNOPSIS .nf .B "#include " - +.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 diff --git a/struct/buf.3 b/struct/buf.3 index 3b3ef7c..ccb8dc1 100644 --- a/struct/buf.3 +++ b/struct/buf.3 @@ -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 " - +.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 diff --git a/struct/darray.3 b/struct/darray.3 index 6037c74..c01a594 100644 --- a/struct/darray.3 +++ b/struct/darray.3 @@ -57,51 +57,51 @@ darray \- dense, dynamically resizing arrays .SH "SYNOPSIS" .nf .B "#include " - +.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 diff --git a/struct/dspool.3 b/struct/dspool.3 index 9d2ab00..dd6dbd9 100644 --- a/struct/dspool.3 +++ b/struct/dspool.3 @@ -25,14 +25,14 @@ dspool \- pools of preallocated dynamic strings .SH SYNOPSIS .nf .B "#include " - +.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 diff --git a/struct/dstr.3 b/struct/dstr.3 index 1aadd35..8608d55 100644 --- a/struct/dstr.3 +++ b/struct/dstr.3 @@ -52,17 +52,17 @@ dstr \- a simple dynamic string type .SH SYNOPSIS .nf .B "#include " - +.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 ); diff --git a/struct/hash.3 b/struct/hash.3 index c067275..fdde662 100644 --- a/struct/hash.3 +++ b/struct/hash.3 @@ -17,8 +17,18 @@ \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 " - +.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 diff --git a/struct/sym.3 b/struct/sym.3 index a2afcaf..a683e20 100644 --- a/struct/sym.3 +++ b/struct/sym.3 @@ -11,6 +11,16 @@ .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 " - +.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. diff --git a/sys/daemonize.3 b/sys/daemonize.3 index 1482bed..fba258e 100644 --- a/sys/daemonize.3 +++ b/sys/daemonize.3 @@ -7,7 +7,7 @@ daemonize \- become a background process .SH SYNOPSIS .nf .B "#include " - +.PP .B "void detachtty(void);" .B "int daemonize(void);" .fi diff --git a/sys/env.3 b/sys/env.3 index 1818b37..2c5b5af 100644 --- a/sys/env.3 +++ b/sys/env.3 @@ -10,7 +10,7 @@ env \- efficient fiddling with environment variables .SH "SYNOPSIS" .nf .B "#include " - +.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 ); diff --git a/sys/fdflags.3 b/sys/fdflags.3 index 2ed2fa9..25fb3f6 100644 --- a/sys/fdflags.3 +++ b/sys/fdflags.3 @@ -18,7 +18,7 @@ fdflags \- set file and file descriptor flags .SH "SYNOPSIS" .nf .B "#include " - +.PP .ta \w'\fBint fdflags('u .BI "int fdflags(int " fd , .BI " unsigned " fbic ", unsigned " fxor , diff --git a/sys/fdpass.3 b/sys/fdpass.3 index b643bde..449b6bf 100644 --- a/sys/fdpass.3 +++ b/sys/fdpass.3 @@ -7,7 +7,7 @@ fdpass \- file descriptor passing .SH SYNOPSIS .nf .B "#include " - +.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 diff --git a/sys/fwatch.3 b/sys/fwatch.3 index 9afe273..c461733 100644 --- a/sys/fwatch.3 +++ b/sys/fwatch.3 @@ -9,9 +9,9 @@ fwatch \- watch a file for changes .SH SYNOPSIS .nf .B "#include " - +.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 ); diff --git a/sys/lock.3 b/sys/lock.3 index d7b18e5..46be546 100644 --- a/sys/lock.3 +++ b/sys/lock.3 @@ -6,14 +6,14 @@ lock \- oversimplified file locking interface .SH SYNOPSIS .nf .B "#include " - +.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 diff --git a/sys/mdup.3 b/sys/mdup.3 index f08c13e..567da6a 100644 --- a/sys/mdup.3 +++ b/sys/mdup.3 @@ -17,21 +17,31 @@ \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 " - +.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, - diff --git a/sys/tv.3 b/sys/tv.3 index 62d9189..f24892d 100644 --- a/sys/tv.3 +++ b/sys/tv.3 @@ -17,7 +17,7 @@ tv \- arithmetic on \fBstruct timeval\fR objects .SH SYNOPSIS .nf .B "#include " - +.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 , diff --git a/test/Makefile.am b/test/Makefile.am index 5a4b2ff..f3805ad 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -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 index 0000000..2a9e60f --- /dev/null +++ b/test/bench.3 @@ -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 " +.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 "" +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, diff --git a/test/t/tvec-test.c b/test/t/tvec-test.c index b6ba605..04759cd 100644 --- a/test/t/tvec-test.c +++ b/test/t/tvec-test.c @@ -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, { ®_enum } }, + { "rc", &tvty_int, RRC, TVRF_OPT, { &tvrange_int } }, + { "serialized", &tvty_bytes, RSEROUT, TVRF_OPT }, + { "sabotage", &tvty_ienum, RSAB, TVRF_OPT, { ®_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 }; diff --git a/test/testrig.3 b/test/testrig.3 index b6e30f3..e33bbb0 100644 --- a/test/testrig.3 +++ b/test/testrig.3 @@ -18,37 +18,37 @@ testrig \- generic test rig .SH SYNOPSIS .nf .B "#include " - +.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 index 0000000..1756486 --- /dev/null +++ b/test/tvec-adhoc.3 @@ -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 " +.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 index 0000000..687c8ff --- /dev/null +++ b/test/tvec-bench.3 @@ -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 " +.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 diff --git a/test/tvec-bench.c b/test/tvec-bench.c index dda5713..bff3c3a 100644 --- a/test/tvec-bench.c +++ b/test/tvec-bench.c @@ -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) diff --git a/test/tvec-core.c b/test/tvec-core.c index 6a98f73..ca71dd2 100644 --- a/test/tvec-core.c +++ b/test/tvec-core.c @@ -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 = ""; 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 index 0000000..9a4a32f --- /dev/null +++ b/test/tvec-env.3 @@ -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 " +.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 index 0000000..67a31d2 --- /dev/null +++ b/test/tvec-main.3 @@ -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 " +.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 index 0000000..1a0a036 --- /dev/null +++ b/test/tvec-output.3 @@ -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 " +.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 index 0000000..d7ae260 --- /dev/null +++ b/test/tvec-remote.3 @@ -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 " +.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 diff --git a/test/tvec-remote.c b/test/tvec-remote.c index c167618..3c25282 100644 --- a/test/tvec-remote.c +++ b/test/tvec-remote.c @@ -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(®->v, rd); rc = rd->ty->frombuf(b, ®->v, rd); if (!rc) tvec_dumpreg(tv, v, ®->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 index 0000000..fd4568e --- /dev/null +++ b/test/tvec-timeout.3 @@ -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 " +.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 diff --git a/test/tvec-timeout.c b/test/tvec-timeout.c index a1800db..5e386e2 100644 --- a/test/tvec-timeout.c +++ b/test/tvec-timeout.c @@ -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 index 0000000..0e3dce7 --- /dev/null +++ b/test/tvec-tyimpl.3 @@ -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 " +.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 index 0000000..4c682dc --- /dev/null +++ b/test/tvec-types.3 @@ -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 " +.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 diff --git a/test/tvec-types.c b/test/tvec-types.c index 20c2930..87748eb 100644 --- a/test/tvec-types.c +++ b/test/tvec-types.c @@ -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@ --- * * diff --git a/test/tvec.3 b/test/tvec.3 index c0cb3c3..23eded3 100644 --- a/test/tvec.3 +++ b/test/tvec.3 @@ -1,14 +1,129 @@ .\" -*-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 " - +.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 diff --git a/test/tvec.h b/test/tvec.h index d16df58..293dccc 100644 --- a/test/tvec.h +++ b/test/tvec.h @@ -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@ --- * * diff --git a/trace/trace.3 b/trace/trace.3 index 1a40587..d0e4fcf 100644 --- a/trace/trace.3 +++ b/trace/trace.3 @@ -15,12 +15,12 @@ trace \- configurable tracing output .SH "SYNOPSIS" .nf .B "#include " - +.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 diff --git a/ui/mdwopt.3 b/ui/mdwopt.3 index 253b635..9b87323 100644 --- a/ui/mdwopt.3 +++ b/ui/mdwopt.3 @@ -6,31 +6,31 @@ mdwopt \- command-line option parser .SH "SYNOPSIS" .nf .B "#include " - +.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 , diff --git a/ui/quis.3 b/ui/quis.3 index bd19698..50a0203 100644 --- 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 " - +.PP .BI "void ego(const char *" p ); .B "const char *quis(void);" .B "const char *QUIS;" diff --git a/ui/report.3 b/ui/report.3 index 1ccecb6..19fda9a 100644 --- a/ui/report.3 +++ b/ui/report.3 @@ -7,7 +7,7 @@ report \- report errors .SH SYNOPSIS .nf .B "#include " - +.PP .BI "void moan(const char *" f ", ...);" .BI "void die(int " status ", const char *" f ", ...);" .fi diff --git a/utils/align.3 b/utils/align.3 index 9ee2377..55a4040 100644 --- a/utils/align.3 +++ b/utils/align.3 @@ -6,7 +6,7 @@ align \- alignment utilities .SH SYNOPSIS .nf .B "#include " - +.PP .BI "size_t ALIGN(size_t " sz ");" .fi .SH DESCRIPTION diff --git a/utils/bits.3 b/utils/bits.3 index a002e24..3b09b65 100644 --- a/utils/bits.3 +++ b/utils/bits.3 @@ -175,34 +175,34 @@ bits \- portable bit manipulation macros .SH SYNOPSIS .nf .B "#include " - +.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, - diff --git a/utils/compiler.3 b/utils/compiler.3 index 1920be4..424ca0e 100644 --- a/utils/compiler.3 +++ b/utils/compiler.3 @@ -7,7 +7,7 @@ compiler \- detect compiler version .SH SYNOPSIS .nf .B "#include " - +.PP .BI "int GCC_VERSION_P(" maj ", " min ");" .BI "int CLANG_VERSION_P(" maj ", " min ");" .fi diff --git a/utils/control.3 b/utils/control.3 index be83be9..65f31d6 100644 --- a/utils/control.3 +++ b/utils/control.3 @@ -34,7 +34,7 @@ control \- control structure metaprogramming .SH SYNOPSIS .nf .B "#include " - +.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 ) diff --git a/utils/exc.3 b/utils/exc.3 index d4c7eb9..92b65c3 100644 --- a/utils/exc.3 +++ b/utils/exc.3 @@ -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 ); diff --git a/utils/gprintf.3 b/utils/gprintf.3 index c7f8652..13d2a1a 100644 --- a/utils/gprintf.3 +++ b/utils/gprintf.3 @@ -17,8 +17,18 @@ \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 " - +.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"); diff --git a/utils/linreg.3 b/utils/linreg.3 index 20f74ca..422adae 100644 --- a/utils/linreg.3 +++ b/utils/linreg.3 @@ -8,10 +8,10 @@ .SH SYNOPSIS .nf .B "#include " - +.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 diff --git a/utils/macros.3 b/utils/macros.3 index d481a47..23af69b 100644 --- a/utils/macros.3 +++ b/utils/macros.3 @@ -42,12 +42,12 @@ macros \- useful macros .SH SYNOPSIS .nf .B "#include " - +.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 diff --git a/utils/maths.3 b/utils/maths.3 index 0d6afa5..a6f6b40 100644 --- a/utils/maths.3 +++ b/utils/maths.3 @@ -7,7 +7,7 @@ .SH SYNOPSIS .nf .B "#include " - +.PP .BI "int NANP(" floatish " " x ); .BI "int INFP(" floatish " " x ); .BI "int NEGP(" floatish " " x ); diff --git a/utils/str.3 b/utils/str.3 index 09a6f24..4b48e82 100644 --- a/utils/str.3 +++ b/utils/str.3 @@ -11,6 +11,16 @@ .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 " - +.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 diff --git a/utils/t/bits-test.c b/utils/t/bits-test.c index b4a515b..4967fd6 100644 --- a/utils/t/bits-test.c +++ b/utils/t/bits-test.c @@ -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 }; diff --git a/utils/t/versioncmp-test.c b/utils/t/versioncmp-test.c index fb462d0..c9090a3 100644 --- a/utils/t/versioncmp-test.c +++ b/utils/t/versioncmp-test.c @@ -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 }; diff --git a/utils/versioncmp.3 b/utils/versioncmp.3 index 15d1593..2b1c303 100644 --- a/utils/versioncmp.3 +++ b/utils/versioncmp.3 @@ -7,7 +7,7 @@ versioncmp \- compare Debian-format version numbers .SH SYNOPSIS .nf .B "#include " - +.PP .BI "int versioncmp(const char *" va ", const char *" vb ");" .BI "int VERSIONCMP(const char *" va ", " op ", const char *" vb ");" .fi -- 2.11.0