X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/mLib/blobdiff_plain/bca75e8d0ad7ce51192de3ef053ec63d0c79cfaa..31d0247cc58abc0b0720aa7e9972011c5a66995c:/test/tvec.h diff --git a/test/tvec.h b/test/tvec.h index 123743e..38c462b 100644 --- a/test/tvec.h +++ b/test/tvec.h @@ -57,8 +57,8 @@ * -> @tvec_mismatch@ * -> output @dumpreg@ * -> type @dump@ - * -> env @after@ * -> output @etest@ + * -> env @after@ * finally * -> output @egroup@ * -> env @teardown@ @@ -177,16 +177,16 @@ enum { */ union tvec_regval { - /* The actual register value. This is what the type handler sees. - * Additional members can be added by setting `TVEC_REGSLOTS' before - * including this file. - * - * A register value can be /initialized/, which simply means that its - * contents represent a valid value according to its type -- the - * register can be compared, dumped, serialized, parsed into, etc. - * You can't do anything safely to an uninitialized register value - * other than initialize it. - */ + /* The actual register value. This is what the type handler sees. + * Additional members can be added by setting `TVEC_REGSLOTS' before + * including this file. + * + * A register value can be /initialized/, which simply means that its + * contents represent a valid value according to its type -- the register + * can be compared, dumped, serialized, parsed into, etc. You can't do + * anything safely to an uninitialized register value other than initialize + * it. + */ long i; /* signed integer */ unsigned long u; /* unsigned integer */ @@ -200,24 +200,22 @@ union tvec_regval { }; struct tvec_reg { - /* A register. - * - * Note that all of the registers listed as being used by a - * particular test group are initialized at all times[1] while that - * test group is being processed. (The other register slots don't - * even have types associated with them, so there's nothing useful we - * could do with them.) - * - * The `TVRF_LIVE' flag indicates that the register was assigned a - * value by the test vector file: it's the right thing to use to - * check whether an optional register is actually present. Even - * `dead' registers are still initialized, though. - * - * [1] This isn't quite true. Between individual tests, the - * registers are released and reinitialized in order to reset - * them to known values ready for the next test. But you won't - * see them at this point. - */ + /* A register. + * + * Note that all of the registers listed as being used by a particular test + * group are initialized at all times[1] while that test group is being + * processed. (The other register slots don't even have types associated + * with them, so there's nothing useful we could do with them.) + * + * The `TVRF_LIVE' flag indicates that the register was assigned a value by + * the test vector file: it's the right thing to use to check whether an + * optional register is actually present. Even `dead' registers are still + * initialized, though. + * + * [1] This isn't quite true. Between individual tests, the registers are + * released and reinitialized in order to reset them to known values + * ready for the next test. But you won't see them at this point. + */ unsigned f; /* flags */ #define TVRF_LIVE 1u /* used in current test */ @@ -225,13 +223,12 @@ struct tvec_reg { }; struct tvec_regdef { - /* A register definition. Register definitions list the registers - * which are used by a particular test group (see `struct tvec_test' - * below). - * - * A vector of register definitions is terminated by a definition - * whose `name' slot is null. - */ + /* A register definition. Register definitions list the registers which + * are used by a particular test group (see `struct tvec_test' below). + * + * A vector of register definitions is terminated by a definition whose + * `name' slot is null. + */ const char *name; /* register name (for input files) */ unsigned i; /* register index */ @@ -266,55 +263,55 @@ struct tvec_regty { /* A register type. */ void (*init)(union tvec_regval */*rv*/, const struct tvec_regdef */*rd*/); - /* Initialize the value in @*rv@. This will be called before any - * other function acting on the value, including @release@. - */ + /* Initialize the value in @*rv@. This will be called before any other + * function acting on the value, including @release@. + */ void (*release)(union tvec_regval */*rv*/, const struct tvec_regdef */*rd*/); - /* Release any resources associated with the value in @*rv@. */ + /* Release any resources associated with the value in @*rv@. */ int (*eq)(const union tvec_regval */*rv0*/, const union tvec_regval */*rv1*/, const struct tvec_regdef */*rd*/); - /* Return nonzero if @*rv0@ and @*rv1@ are equal values. - * Asymmetric criteria are permitted: @tvec_checkregs@ calls @eq@ - * with the input register as @rv0@ and the output as @rv1@. - */ + /* Return nonzero if @*rv0@ and @*rv1@ are equal values. Asymmetric + * criteria are permitted: @tvec_checkregs@ calls @eq@ with the input + * register as @rv0@ and the output as @rv1@. + */ int (*tobuf)(buf */*b*/, const union tvec_regval */*rv*/, const struct tvec_regdef */*rd*/); - /* Serialize the value @*rv@, writing the result to @b@. Return - * zero on success, or @-1@ on error. - */ + /* Serialize the value @*rv@, writing the result to @b@. Return zero on + * success, or %$-1$% on error. + */ int (*frombuf)(buf */*b*/, union tvec_regval */*rv*/, const struct tvec_regdef */*rd*/); - /* Deserialize a value from @b@, storing it in @*rv@. Return zero on - * success, or @-1@ on error. - */ + /* Deserialize a value from @b@, storing it in @*rv@. Return zero on + * success, or %$-1$% on error. + */ int (*parse)(union tvec_regval */*rv*/, const struct tvec_regdef */*rd*/, struct tvec_state */*tv*/); - /* Parse a value from @tv->fp@, storing it in @*rv@. Return zero on - * success, or @-1@ on error, having reported one or more errors via - * @tvec_error@ or @tvec_syntax@. A successful return should leave - * the input position at the start of the next line; the caller will - * flush the remainder of the line itself. - */ + /* Parse a value from @tv->fp@, storing it in @*rv@. Return zero on + * success, or %$-1$% on error, having reported one or more errors via + * @tvec_error@ or @tvec_syntax@. A successful return should leave the + * input position at the start of the next line; the caller will flush + * the remainder of the line itself. + */ void (*dump)(const union tvec_regval */*rv*/, const struct tvec_regdef */*rd*/, unsigned /*style*/, const struct gprintf_ops */*gops*/, void */*go*/); #define TVSF_COMPACT 1u - /* Write a human-readable representation of the value @*rv@ using - * @gprintf@ on @gops@ and @go@. The @style@ is a collection of - * flags: if @TVSF_COMPACT@ is set, then output should be minimal, - * and must fit on a single line; otherwise, output may consist of - * multiple lines and may contain redundant information if that is - * likely to be useful to a human reader. - */ + /* Write a human-readable representation of the value @*rv@ using + * @gprintf@ on @gops@ and @go@. The @style@ is a collection of flags: + * if @TVSF_COMPACT@ is set, then output should be minimal, and must fit + * on a single line; otherwise, output may consist of multiple lines and + * may contain redundant information if that is likely to be useful to a + * human reader. + */ }; /*----- Test descriptions -------------------------------------------------*/ @@ -346,12 +343,13 @@ typedef void tvec_envsetupfn(struct tvec_state */*tv*/, /* Initialize the context; called at the start of a test group; @pctx@ is * null for environments called by the core, but may be non-null for * subordinate environments. If setup fails, the function should call - * @tvec_skipgroup@ with a suitable excuse. The @set@ and @teardown@ entry - * points will still be called, but @before@, @run@, and @after@ will not. + * @tvec_skipgroup@ with a suitable excuse. The @set@, @after@, and + * @teardown@ entry points will still be called, but @before@ and @run@ + * will not. */ -typedef int tvec_envsetfn(struct tvec_state */*tv*/, const char */*var*/, - const struct tvec_env */*env*/, void */*ctx*/); +typedef int tvec_envsetfn(struct tvec_state */*tv*/, + const char */*var*/, void */*ctx*/); /* Called when the parser finds a %|@var|%' setting to parse and store the * value. If @setup@ failed, this is still called (so as to skip the * value), but @ctx@ is null. @@ -376,8 +374,10 @@ typedef void tvec_envrunfn(struct tvec_state */*tv*/, typedef void tvec_envafterfn(struct tvec_state */*tv*/, void */*ctx*/); /* Called after running or skipping a test. Typical actions involve - * resetting whatever things were established by @set@. This function is - * never called if the test group is skipped. + * resetting whatever things were established by @set@. This function + * %%\emph{is}%% called if the test group is skipped, so that the test + * environment can reset variables set by the @set@ entry point. It should + * check the @TVSF_SKIP@ flag if necessary. */ typedef void tvec_envteardownfn(struct tvec_state */*tv*/, void */*ctx*/); @@ -447,6 +447,7 @@ struct tvec_state { #define TVSF_OUTMASK 0x00f0u /* test outcome (@TVOUT_...@) */ #define TVSF_OUTSHIFT 4 /* shift applied to outcome */ #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 */ @@ -502,106 +503,110 @@ struct tvec_outops { /* Output operations. */ void (*bsession)(struct tvec_output */*o*/, struct tvec_state */*tv*/); - /* Begin a test session. The output driver will probably want to - * save @tv@, because this isn't provided to any other methods. - */ + /* Begin a test session. The output driver will probably want to + * save @tv@, because this isn't provided to any other methods. + */ int (*esession)(struct tvec_output */*o*/); - /* End a session, and return the suggested exit code. */ + /* End a session, and return the suggested exit code. */ void (*bgroup)(struct tvec_output */*o*/); - /* Begin a test group. The test group description is @tv->test@. */ + /* Begin a test group. The test group description is @tv->test@. */ void (*skipgroup)(struct tvec_output */*o*/, const char */*excuse*/, va_list */*ap*/); - /* The group is being skipped; @excuse@ may be null or a format - * string explaining why. The @egroup@ method will not be called - * separately. - */ + /* The group is being skipped; @excuse@ may be null or a format + * string explaining why. The @egroup@ method will not be called + * separately. + */ void (*egroup)(struct tvec_output */*o*/); - /* End a test group. At least one test was attempted or @skipgroup@ - * would have been called instead. If @tv->curr[TVOUT_LOSE]@ is - * nonzero then the test group as a whole failed; otherwise it - * passed. - */ + /* End a test group. At least one test was attempted or @skipgroup@ + * would have been called instead. If @tv->curr[TVOUT_LOSE]@ is nonzero + * then the test group as a whole failed; otherwise it passed. + */ void (*btest)(struct tvec_output */*o*/); - /* Begin a test case. */ + /* Begin a test case. */ void (*skip)(struct tvec_output */*o*/, const char */*excuse*/, va_list */*ap*/); - /* The test case is being skipped; @excuse@ may be null or a format - * string explaining why. The @etest@ function will still be called - * (so this works differently from @skipgroup@ and @egroup@). A test - * case can be skipped at most once, and, if skipped, it cannot fail. - */ + /* The test case is being skipped; @excuse@ may be null or a format + * string explaining why. The @etest@ function will still be called (so + * this works differently from @skipgroup@ and @egroup@). A test case + * can be skipped at most once, and, if skipped, it cannot fail. + */ void (*fail)(struct tvec_output */*o*/, const char */*detail*/, va_list */*ap*/); - /* The test case failed. - * - * The output driver should preferably report the filename (@infile@) - * and line number (@test_lno@, not @lno@) for the failing test. - * - * The @detail@ may be null or a format string describing detail - * about how the failing test was run which can't be determined from - * the registers; a @detail@ is usually provided when (and only when) - * the test environment potentially invokes the test function more - * than once. - * - * A single test case can fail multiple times! - */ + /* The test case failed. + * + * The output driver should preferably report the filename (@infile@) and + * line number (@test_lno@, not @lno@) for the failing test. + * + * The @detail@ may be null or a format string describing detail about + * how the failing test was run which can't be determined from the + * registers; a @detail@ is usually provided when (and only when) the + * test environment potentially invokes the test function more than once. + * + * A single test case can fail multiple times! + */ void (*dumpreg)(struct tvec_output */*o*/, unsigned /*disp*/, const union tvec_regval */*rv*/, const struct tvec_regdef */*rd*/); - /* Dump a register. The `disposition' @disp@ explains what condition - * the register is in; see @tvec_dumpreg@ and the @TVRD_...@ codes. - * The register value is at @rv@, and its definition, including its - * type, at @rd@. Note that this function may be called on virtual - * registers which aren't in either of the register vectors or - * mentioned by the test description. It may also be called with - * @rv@ null, indicating that the register is not live. - */ + /* Dump a register. The `disposition' @disp@ explains what condition the + * register is in; see @tvec_dumpreg@ and the @TVRD_...@ codes. The + * register value is at @rv@, and its definition, including its type, at + * @rd@. Note that this function may be called on virtual registers + * which aren't in either of the register vectors or mentioned by the + * test description. It may also be called with @rv@ null, indicating + * that the register is not live. + */ void (*etest)(struct tvec_output */*o*/, unsigned /*outcome*/); - /* The test case concluded with the given @outcome@ (one of the - * @TVOUT_...@ codes. - */ + /* The test case concluded with the given @outcome@ (one of the + * @TVOUT_...@ codes. + */ void (*bbench)(struct tvec_output */*o*/, const char */*ident*/, unsigned /*unit*/); - /* Begin a benchmark. The @ident@ is a formatted string identifying - * the benchmark based on the values of the input registered marked - * @TVRF_ID@; the output driver is free to use this or come up with - * its own way to identify the test, e.g., by inspecting the register - * values for itself. The @unit@ is one of the @TVBU_...@ constants - * explaining what sort of thing is being measured. - */ + /* Begin a benchmark. The @ident@ is a formatted string identifying the + * benchmark based on the values of the input registered marked + * @TVRF_ID@; the output driver is free to use this or come up with its + * own way to identify the test, e.g., by inspecting the register values + * for itself. The @unit@ is one of the @TVBU_...@ constants explaining + * what sort of thing is being measured. + */ void (*ebench)(struct tvec_output */*o*/, const char */*ident*/, unsigned /*unit*/, const struct bench_timing */*tm*/); - /* End a benchmark. The @ident@ and @unit@ arguments are as for - * @bbench@. If @tm@ is zero then the measurement failed; otherwise - * @tm->n@ counts total number of things (operations or bytes, as - * indicated by @unit@) processed in the indicated time. - */ + /* End a benchmark. The @ident@ and @unit@ arguments are as for + * @bbench@. If @tm@ is zero then the measurement failed; otherwise + * @tm->n@ counts total number of things (operations or bytes, as + * indicated by @unit@) processed in the indicated time. + */ void (*report)(struct tvec_output */*o*/, unsigned /*level*/, const char */*msg*/, va_list */*ap*/); - /* Report a message. The driver should ideally report the filename - * (@infile@) and line number (@lno@) prompting the error. - */ + /* Report a message. The driver should ideally report the filename + * (@infile@) and line number (@lno@) prompting the error. + */ void (*destroy)(struct tvec_output */*o*/); - /* Release any resources acquired by the driver. */ + /* Release any resources acquired by the driver. */ }; +#define TVEC_LEVELS(_) \ + _(NOTE, "notice", 4) \ + _(ERR, "ERROR", 8) + enum { - TVLEV_NOTE = 4, /* notice */ - TVLEV_ERR = 8 /* error */ +#define TVEC_DEFLEVEL(tag, name, val) TVLEV_##tag = val, + TVEC_LEVELS(TVEC_DEFLEVEL) +#undef TVEC_DEFLEVEL + TVLEV_LIMIT }; /*----- Session lifecycle -------------------------------------------------*/ @@ -640,7 +645,7 @@ extern int tvec_end(struct tvec_state */*tv*/); * @const char *infile@ = the name of the input file * @FILE *fp@ = stream to read from * - * Returns: Zero on success, @-1@ on error. + * Returns: Zero on success, %$-1$% on error. * * Use: Read test vector data from @fp@ and exercise test functions. * THe return code doesn't indicate test failures: it's only @@ -684,7 +689,7 @@ extern void tvec_parseargs(int /*argc*/, char */*argv*/[], * @const char *file@ = pathname of file to read * @const char *arg@ = argument to interpret * - * Returns: Zero on success, @-1@ on error. + * Returns: Zero on success, %$-1$% on error. * * Use: Read test vector data from stdin or a named file. The * @tvec_readarg@ function reads from stdin if @arg@ is `%|-|%', @@ -700,7 +705,7 @@ extern int tvec_readarg(struct tvec_state */*tv*/, const char */*arg*/); * Arguments: @struct tvec_state *tv@ = test vector state * @const char *dflt@ = defsault filename or null * - * Returns: Zero on success, @-1@ on error. + * Returns: Zero on success, %$-1$% on error. * * Use: Reads from the default test vector data. If @file@ is null, * then read from standard input, unless that's a terminal; if @@ -719,7 +724,7 @@ extern int tvec_readdflt(struct tvec_state */*tv*/, const char */*file*/); * @int *argpos_inout@ = current argument position (updated) * @const char *dflt@ = default filename or null * - * Returns: Zero on success, @-1@ on error. + * Returns: Zero on success, %$-1$% on error. * * Use: Reads from the sources indicated by the command-line * arguments, in order, interpreting each as for @tvec_readarg@; @@ -764,8 +769,9 @@ extern int tvec_main(int /*argc*/, char */*argv*/[], * the @setup@ function fails. */ -extern void PRINTF_LIKE(2, 3) - tvec_skipgroup(struct tvec_state */*tv*/, const char */*excuse*/, ...); +extern PRINTF_LIKE(2, 3) + void tvec_skipgroup(struct tvec_state */*tv*/, + const char */*excuse*/, ...); extern void tvec_skipgroup_v(struct tvec_state */*tv*/, const char */*excuse*/, va_list */*ap*/); @@ -781,46 +787,11 @@ extern void tvec_skipgroup_v(struct tvec_state */*tv*/, * the @before@ function fails. */ -extern void PRINTF_LIKE(2, 3) - tvec_skip(struct tvec_state */*tv*/, const char */*excuse*/, ...); +extern PRINTF_LIKE(2, 3) + void tvec_skip(struct tvec_state */*tv*/, const char */*excuse*/, ...); extern void tvec_skip_v(struct tvec_state */*tv*/, const char */*excuse*/, va_list */*ap*/); -/* --- @tvec_resetoutputs@ --- * - * - * Arguments: @struct tvec_state *tv@ = test-vector state - * - * Returns: --- - * - * Use: Reset (releases and reinitializes) the output registers in - * the test state. This is mostly of use to test environment - * @run@ functions, between invocations of the test function. - */ - -extern void tvec_resetoutputs(struct tvec_state */*tv*/); - -extern void tvec_initregs(struct tvec_state */*tv*/); -extern void tvec_releaseregs(struct tvec_state */*tv*/); - -/* --- @tvec_checkregs@ --- * - * - * Arguments: @struct tvec_state *tv@ = test-vector state - * - * Returns: Zero on success, @-1@ on mismatch. - * - * Use: Compare the active output registers (according to the current - * test group definition) with the corresponding input register - * values. A mismatch occurs if the two values differ - * (according to the register type's @eq@ method), or if the - * input is live but the output is dead. - * - * This function only checks for a mismatch and returns the - * result; it takes no other action. In particular, it doesn't - * report a failure, or dump register values. - */ - -extern int tvec_checkregs(struct tvec_state */*tv*/); - /* --- @tvec_fail@, @tvec_fail_v@ --- * * * Arguments: @struct tvec_state *tv@ = test-vector state @@ -838,8 +809,8 @@ extern int tvec_checkregs(struct tvec_state */*tv*/); * safely be left null if the test function is run only once. */ -extern void PRINTF_LIKE(2, 3) - tvec_fail(struct tvec_state */*tv*/, const char */*detail*/, ...); +extern PRINTF_LIKE(2, 3) + void tvec_fail(struct tvec_state */*tv*/, const char */*detail*/, ...); extern void tvec_fail_v(struct tvec_state */*tv*/, const char */*detail*/, va_list */*ap*/); @@ -865,6 +836,55 @@ extern void tvec_dumpreg(struct tvec_state */*tv*/, unsigned /*disp*/, const union tvec_regval */*rv*/, const struct tvec_regdef */*rd*/); +/* --- @tvec_initregs@, @tvec_releaseregs@ --- * + * + * Arguments: @struct tvec_state *tv@ = test-vector state + * + * Returns: --- + * + * Use: Initialize or release, respectively, the registers required + * by the current test. All of the registers, both input and + * output, are effected. Initialized registers are not marked + * live. + */ + +extern void tvec_initregs(struct tvec_state */*tv*/); +extern void tvec_releaseregs(struct tvec_state */*tv*/); + +/* --- @tvec_resetoutputs@ --- * + * + * Arguments: @struct tvec_state *tv@ = test-vector state + * + * Returns: --- + * + * Use: Reset (releases and reinitializes) the output registers in + * the test state. This is mostly of use to test environment + * @run@ functions, between invocations of the test function. + * Output registers are marked live if and only if the + * corresponding input register is live. + */ + +extern void tvec_resetoutputs(struct tvec_state */*tv*/); + +/* --- @tvec_checkregs@ --- * + * + * Arguments: @struct tvec_state *tv@ = test-vector state + * + * Returns: Zero on success, %$-1$% on mismatch. + * + * Use: Compare the active output registers (according to the current + * test group definition) with the corresponding input register + * values. A mismatch occurs if the two values differ + * (according to the register type's @eq@ method), or if the + * input is live but the output is dead. + * + * This function only checks for a mismatch and returns the + * result; it takes no other action. In particular, it doesn't + * report a failure, or dump register values. + */ + +extern int tvec_checkregs(struct tvec_state */*tv*/); + /* --- @tvec_mismatch@ --- * * * Arguments: @struct tvec_state *tv@ = test-vector state @@ -896,8 +916,8 @@ extern void tvec_mismatch(struct tvec_state */*tv*/, unsigned /*f*/); * obvious way. */ -extern void PRINTF_LIKE(2, 3) - tvec_check(struct tvec_state */*tv*/, const char */*detail*/, ...); +extern PRINTF_LIKE(2, 3) + void tvec_check(struct tvec_state */*tv*/, const char */*detail*/, ...); extern void tvec_check_v(struct tvec_state */*tv*/, const char */*detail*/, va_list */*ap*/); @@ -994,13 +1014,13 @@ extern void tvec_begintest(struct tvec_state */*tv*/, #define TVEC_BEGINTEST(tv) \ do tvec_begintest(tv, __FILE__, __LINE__); while (0) -/* --- *tvec_endtest@ --- * +/* --- @tvec_endtest@ --- * * * Arguments: @struct tvec_state *tv@ = test-vector state * * Returns: --- * - * Use: End a ad-hoc test case, The statistics are updated and the + * Use: End an ad-hoc test case, The statistics are updated and the * outcome is reported to the output formatter. */ @@ -1053,10 +1073,10 @@ extern void tvec_endtest(struct tvec_state */*tv*/); * the failure message. */ -extern int PRINTF_LIKE(5, 6) - tvec_claim(struct tvec_state */*tv*/, int /*ok*/, - const char */*file*/, unsigned /*lno*/, - const char */*msg*/, ...); +extern PRINTF_LIKE(5, 6) + int tvec_claim(struct tvec_state */*tv*/, int /*ok*/, + const char */*file*/, unsigned /*lno*/, + const char */*msg*/, ...); extern int tvec_claim_v(struct tvec_state */*tv*/, int /*ok*/, const char */*file*/, unsigned /*lno*/, const char */*msg*/, va_list */*ap*/); @@ -1106,6 +1126,9 @@ struct tvec_benchctx { const struct tvec_benchenv *be; /* environment configuration */ struct bench_state *bst; /* benchmark state */ double dflt_target; /* default time in seconds */ + unsigned f; /* flags */ +#define TVBF_SETTRG 1u /* set `@target' */ +#define TVBF_SETMASK (TVBF_SETTRG)) /* mask of @TVBF_SET...@ */ void *subctx; /* subsidiary environment context */ }; @@ -1161,12 +1184,14 @@ extern void tvec_benchreport struct tvec_remotecomms { int infd, outfd; /* input and output descriptors */ - dbuf bin, bout; /* input and output buffers */ + dbuf bout; /* output buffer */ + unsigned char *bin; /* input buffer */ + size_t binoff, binlen, binsz; /* input offset, length, and size */ + size_t t; /* temporary offset */ unsigned f; /* flags */ #define TVRF_BROKEN 0x0001u /* communications have failed */ - /* bits 8--15 for upper layer */ }; -#define TVEC_REMOTECOMMS_INIT { -1, -1, DBUF_INIT, DBUF_INIT, 0 } +#define TVEC_REMOTECOMMS_INIT { -1, -1, DBUF_INIT, 0, 0, 0, 0, 0, 0 } struct tvec_remotectx { struct tvec_state *tv; /* test vector state */ @@ -1183,6 +1208,11 @@ struct tvec_remotectx { #define TVRCN_DEMAND 0x0100u /* connect on demand */ #define TVRCN_FORCE 0x0200u /* force reconnection */ #define TVRF_MUFFLE 0x0400u /* muffle child stderr */ +#define TVRF_SETEXIT 0x0800u /* set `@exit' */ +#define TVRF_SETPRG 0x1000u /* set `@progress' */ +#define TVRF_SETRCN 0x2000u /* set `@reconnect' */ +#define TVRF_SETMASK (TVRF_SETEXIT | TVRF_SETPRG | TVRF_SETRCN) + /* mask of @TVTF_SET...@ */ }; typedef int tvec_connectfn(pid_t */*kid_out*/, int */*infd_out*/, @@ -1241,21 +1271,69 @@ extern tvec_envteardownfn tvec_remoteteardown; tvec_remoteafter, \ tvec_remoteteardown } -extern int tvec_setprogress(const char */*status*/); +extern PRINTF_LIKE(1, 2) int tvec_setprogress(const char */*status*/, ...); +extern int tvec_setprogress_v(const char */*status*/, va_list */*ap*/); extern int tvec_remoteserver(int /*infd*/, int /*outfd*/, const struct tvec_config */*config*/); extern tvec_connectfn tvec_fork, tvec_exec; -#define TVEC_REMOTEFORK( subenv, tests) \ +#define TVEC_REMOTEFORK(subenv, tests) \ TVEC_REMOTEENV, { tvec_fork, subenv }, { tests } #define TVEC_REMOTEEXEC(subenv, args) \ TVEC_REMOTEENV, { tvec_exec, subenv }, { args } +/*----- Timeouts ----------------------------------------------------------*/ + +struct tvec_timeoutenv { + struct tvec_env _env; + unsigned timer; + double t; + const struct tvec_env *env; +}; + +struct tvec_timeoutctx { + const struct tvec_timeoutenv *te; + unsigned timer; + double t; + unsigned f; /* flags */ +#define TVTF_SETTMO 1u /* set `@timeout' */ +#define TVTF_SETMASK (TVTF_SETTMO) /* mask of @TVTF_SET...@ */ + void *subctx; +}; + +extern tvec_envsetupfn tvec_timeoutsetup; +extern tvec_envsetfn tvec_timeoutset; +extern tvec_envbeforefn tvec_timeoutbefore; +extern tvec_envrunfn tvec_timeoutrun; +extern tvec_envafterfn tvec_timeoutafter; +extern tvec_envteardownfn tvec_timeoutteardown; +#define TVEC_TIMEOUTENV \ + { sizeof(struct tvec_timeoutctx), \ + tvec_timeoutsetup, \ + tvec_timeoutset, \ + tvec_timeoutbefore, \ + tvec_timeoutrun, \ + tvec_timeoutafter, \ + tvec_timeoutteardown } +#define TVEC_TIMEOUTINIT(timer, t) TVEC_TIMEOUTENV, timer, t + /*----- Output functions --------------------------------------------------*/ +/* --- @tvec_strlevel@ --- * + * + * Arguments: @unsigned level@ = level code + * + * Returns: A human-readable description. + * + * Use: Converts a level code into something that you can print in a + * message. + */ + +extern const char *tvec_strlevel(unsigned /*level*/); + /* --- @tvec_report@, @tvec_report_v@ --- * * * Arguments: @struct tvec_state *tv@ = test-vector state @@ -1267,9 +1345,9 @@ extern tvec_connectfn tvec_fork, tvec_exec; * @TVLEV_ERR@ or higher force a nonzero exit code. */ -extern void PRINTF_LIKE(3, 4) - tvec_report(struct tvec_state */*tv*/, unsigned /*level*/, - const char */*msg*/, ...); +extern PRINTF_LIKE(3, 4) + void tvec_report(struct tvec_state */*tv*/, unsigned /*level*/, + const char */*msg*/, ...); extern void tvec_report_v(struct tvec_state */*tv*/, unsigned /*level*/, const char */*msg*/, va_list */*ap*/); @@ -1278,7 +1356,7 @@ extern void tvec_report_v(struct tvec_state */*tv*/, unsigned /*level*/, * Arguments: @struct tvec_state *tv@ = test-vector state * @const char *msg@, @va_list ap@ = error message * - * Returns: The @tvec_error@ function returns @-1@ as a trivial + * Returns: The @tvec_error@ function returns %$-1$% as a trivial * convenience; @tvec_notice@ does not return a value. * * Use: Report an error or a notice. Errors are distinct from test @@ -1288,10 +1366,10 @@ extern void tvec_report_v(struct tvec_state */*tv*/, unsigned /*level*/, * category. */ -extern int PRINTF_LIKE(2, 3) - tvec_error(struct tvec_state */*tv*/, const char */*msg*/, ...); -extern void PRINTF_LIKE(2, 3) - tvec_notice(struct tvec_state */*tv*/, const char */*msg*/, ...); +extern PRINTF_LIKE(2, 3) + int tvec_error(struct tvec_state */*tv*/, const char */*msg*/, ...); +extern PRINTF_LIKE(2, 3) + void tvec_notice(struct tvec_state */*tv*/, const char */*msg*/, ...); /* --- @tvec_humanoutput@ --- * * @@ -1377,7 +1455,7 @@ extern struct tvec_output *tvec_dfltout(FILE */*fp*/); * @unsigned nr@ = number of entries in the @rv@ vector * @size_t regsz@ = true size of each element of @rv@ * - * Returns: Zero on success, @-1@ on failure. + * Returns: Zero on success, %$-1$% on failure. * * Use: Serialize a collection of register values. * @@ -1400,7 +1478,7 @@ extern int tvec_serialize(const struct tvec_reg */*rv*/, buf */*b*/, * @unsigned nr@ = number of entries in the @rv@ vector * @size_t regsz@ = true size of each element of @rv@ * - * Returns: Zero on success, @-1@ on failure. + * Returns: Zero on success, %$-1$% on failure. * * Use: Deserialize a collection of register values. * @@ -1435,26 +1513,13 @@ extern int tvec_deserialize(struct tvec_reg */*rv*/, buf */*b*/, * current line number. */ -/* --- @tvec_skipspc@ --- * - * - * Arguments: @struct tvec_state *tv@ = test-vector state - * - * Returns: --- - * - * Use: Advance over any whitespace characters other than newlines. - * This will stop at `;', end-of-file, or any other kind of - * non-whitespace; and it won't consume a newline. - */ - -extern void tvec_skipspc(struct tvec_state */*tv*/); - /* --- @tvec_syntax@, @tvec_syntax_v@ --- * * * Arguments: @struct tvec_state *tv@ = test-vector state * @int ch@ = the character found (in @fgetc@ format) * @const char *expect@, @va_list ap@ = what was expected * - * Returns: @-1@ + * Returns: %$-1$%. * * Use: Report a syntax error quoting @ch@ and @expect@. If @ch@ is * a newline, then back up so that it can be read again (e.g., @@ -1462,18 +1527,44 @@ extern void tvec_skipspc(struct tvec_state */*tv*/); * advance the line number). */ -extern int PRINTF_LIKE(3, 4) - tvec_syntax(struct tvec_state */*tv*/, int /*ch*/, - const char */*expect*/, ...); +extern PRINTF_LIKE(3, 4) + int tvec_syntax(struct tvec_state */*tv*/, int /*ch*/, + const char */*expect*/, ...); extern int tvec_syntax_v(struct tvec_state */*tv*/, int /*ch*/, const char */*expect*/, va_list */*ap*/); +/* --- @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 + * + * Returns: --- + * + * Use: Advance over any whitespace characters other than newlines. + * This will stop at `;', end-of-file, or any other kind of + * non-whitespace; and it won't consume a newline. + */ + +extern void tvec_skipspc(struct tvec_state */*tv*/); + /* --- @tvec_flushtoeol@ --- * * * Arguments: @struct tvec_state *tv@ = test-vector state * @unsigned f@ = flags (@TVFF_...@) * - * Returns: Zero on success, @-1@ on error. + * Returns: Zero on success, %$-1$% on error. * * Use: Advance to the start of the next line, consuming the * preceding newline. @@ -1493,7 +1584,7 @@ extern int tvec_flushtoeol(struct tvec_state */*tv*/, unsigned /*f*/); * * Arguments: @struct tvec_state *tv@ = test-vector state * - * Returns: Zero if there is a next token which can be read; @-1@ if no + * Returns: Zero if there is a next token which can be read; %$-1$% if no * token is available. * * Use: Advance to the next whitespace-separated token, which may be @@ -1507,21 +1598,21 @@ extern int tvec_flushtoeol(struct tvec_state */*tv*/, unsigned /*f*/); * * If this function returns zero, then the next character in the * file begins a suitable token which can be read and - * processed. If it returns @-1@ then there is no such token, + * processed. If it returns %$-1$% then there is no such token, * and the file position is left correctly. The line number * count is updated appropriately. */ extern int tvec_nexttoken(struct tvec_state */*tv*/); -/* --- @tvec_readword@ --- * +/* --- @tvec_readword@, @tvec_readword_v@ --- * * * Arguments: @struct tvec_state *tv@ = test-vector state * @dstr *d@ = string to append the word to * @const char *delims@ = additional delimiters to stop at * @const char *expect@, @va_list ap@ = what was expected * - * Returns: Zero on success, @-1@ on failure. + * Returns: Zero on success, %$-1$% on failure. * * Use: A `word' consists of characters other than whitespace, null * characters, and other than those listed in @delims@; @@ -1530,8 +1621,8 @@ extern int tvec_nexttoken(struct tvec_state */*tv*/); * include `;' in @delims@. This is a common behaviour.) * * If there is no word beginning at the current file position, - * then return @-1@; furthermore, if @expect@ is not null, then - * report an appropriate error via @tvec_syntax@. + * then return %$-1$%; furthermore, if @expect@ is not null, + * then report an appropriate error via @tvec_syntax@. * * Otherwise, the word is accumulated in @d@ and zero is * returned; if @d@ was not empty at the start of the call, the @@ -1542,9 +1633,9 @@ extern int tvec_nexttoken(struct tvec_state */*tv*/); * terminated. */ -extern int PRINTF_LIKE(4, 5) - tvec_readword(struct tvec_state */*tv*/, dstr */*d*/, - const char */*delims*/, const char */*expect*/, ...); +extern PRINTF_LIKE(4, 5) + int tvec_readword(struct tvec_state */*tv*/, dstr */*d*/, + const char */*delims*/, const char */*expect*/, ...); extern int tvec_readword_v(struct tvec_state */*tv*/, dstr */*d*/, const char */*delims*/, const char */*expect*/, va_list */*ap*/); @@ -1755,6 +1846,8 @@ 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; + /*----- Enumerated types --------------------------------------------------*/ /* An enumeration describes a set of values of some underlying type, each of