/*----- Session lifecycle -------------------------------------------------*/
-struct tvec_info {
- const struct tvec_test *tests;
- unsigned nrout, nreg;
- size_t regsz;
-};
-
-extern void tvec_begin(struct tvec_state */*tv_out*/,
- const struct tvec_info */*info*/,
- struct tvec_output */*o*/);
-extern int tvec_end(struct tvec_state */*tv*/);
-
-extern int tvec_read(struct tvec_state */*tv*/,
- const char */*infile*/, FILE */*fp*/);
-
-/*----- Benchmarking ------------------------------------------------------*/
-
-struct tvec_bench {
- struct tvec_env _env; /* benchmarking is an environment */
- struct bench_state **bst; /* benchmark state anchor or null */
- unsigned long niter; /* iterations done per unit */
- int riter, rbuf; /* iterations and buffer registers */
- const struct tvec_env *env; /* environment (per test, not grp) */
-};
-#define TVEC_BENCHENV \
- { sizeof(struct tvec_benchctx), \
- tvec_benchsetup, \
- tvec_benchset, \
- tvec_benchbefore, \
- tvec_benchrun, \
- tvec_benchafter, \
- tvec_benchteardown }
-#define TVEC_BENCHINIT TVEC_BENCHENV, &tvec_benchstate
+struct tvec_config {
+ /* An overall test configuration. */
-struct tvec_benchctx {
- const struct tvec_bench *b;
- struct bench_state *bst;
- double dflt_target;
- void *subctx;
+ 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 bench_timing;
-extern struct bench_state *tvec_benchstate;
-
-extern int tvec_benchsetup(struct tvec_state */*tv*/,
- const struct tvec_env */*env*/,
- void */*pctx*/, void */*ctx*/);
-extern int tvec_benchset(struct tvec_state */*tv*/, const char */*var*/,
- const struct tvec_env */*env*/, void */*ctx*/);
-extern int tvec_benchbefore(struct tvec_state */*tv*/, void */*ctx*/);
-extern void tvec_benchrun(struct tvec_state */*tv*/,
- tvec_testfn */*fn*/, void */*ctx*/);
-extern void tvec_benchafter(struct tvec_state */*tv*/, void */*ctx*/);
-extern void tvec_benchteardown(struct tvec_state */*tv*/, void */*ctx*/);
-
-extern void tvec_benchreport
- (const struct gprintf_ops */*gops*/, void */*go*/,
- unsigned /*unit*/, const struct bench_timing */*tm*/);
+/* --- @tvec_begin@ --- *
+ *
+ * Arguments: @struct tvec_state *tv_out@ = state structure to fill in
+ * @const struct tvec_config *config@ = test configuration
+ * @struct tvec_output *o@ = output driver
+ *
+ * Returns: ---
+ *
+ * Use: Initialize a state structure ready to do some testing.
+ */
-/*----- Ad-hoc testing ----------------------------------------------------*/
+extern void tvec_begin(struct tvec_state */*tv_out*/,
+ const struct tvec_config */*config*/,
+ struct tvec_output */*o*/);
-extern void tvec_adhoc(struct tvec_state */*tv*/, struct tvec_test */*t*/);
+/* --- @tvec_end@ --- *
+ *
+ * Arguments: @struct tvec_state *tv@ = test-vector state
+ *
+ * Returns: A proposed exit code.
+ *
+ * Use: Conclude testing and suggests an exit code to be returned to
+ * the calling program. (The exit code comes from the output
+ * driver's @esession@ method.)
+ */
-extern void tvec_begingroup(struct tvec_state */*tv*/, const char */*name*/,
- const char */*file*/, unsigned /*lno*/);
-extern void tvec_reportgroup(struct tvec_state */*tv*/);
-extern void tvec_endgroup(struct tvec_state */*tv*/);
+extern int tvec_end(struct tvec_state */*tv*/);
-#define TVEC_BEGINGROUP(tv, name) \
- do tvec_begingroup(tv, name, __FILE__, __LINE__); while (0)
+/* --- @tvec_read@ --- *
+ *
+ * Arguments: @struct tvec_state *tv@ = test-vector state
+ * @const char *infile@ = the name of the input file
+ * @FILE *fp@ = stream to read from
+ *
+ * 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
+ * concerned with whether there were problems with the input
+ * file or with actually running the tests.
+ */
-#define TVEC_TESTGROUP(tag, tv, name) \
- MC_WRAP(tag##__around, \
- { TVEC_BEGINGROUP(tv, name); }, \
- { tvec_endgroup(tv); }, \
- { if (!((tv)->f&TVSF_SKIP)) tvec_skipgroup(tv, 0); \
- tvec_endgroup(tv); })
+extern int tvec_read(struct tvec_state */*tv*/,
+ const char */*infile*/, FILE */*fp*/);
-extern void tvec_begintest(struct tvec_state */*tv*/,
- const char */*file*/, unsigned /*lno*/);
-extern void tvec_endtest(struct tvec_state */*tv*/);
+/*----- Input utilities ---------------------------------------------------*/
-#define TVEC_BEGINTEST(tv) \
- do tvec_begintest(tv, __FILE__, __LINE__); while (0)
+/* These are provided by the core for the benefit of type @parse@ methods,
+ * and test-environment @set@ functions, which get to read from the test
+ * input file. The latter are usually best implemented by calling on the
+ * former.
+ *
+ * The two main rules are as follows.
+ *
+ * * Leave the file position at the beginning of the line following
+ * whatever it was that you read.
+ *
+ * * When you read and consume a newline (which you do at least once, by
+ * the previous rule), then increment @tv->lno@ to keep track of the
+ * current line number.
+ */
-#define TVEC_TEST(tag, tv) \
- MC_WRAP(tag##__around, \
- { TVEC_BEGINTEST(tv); }, \
- { tvec_endtest(tv); }, \
- { if ((tv)->f&TVSF_ACTIVE) tvec_skipgroup((tv), 0); \
- tvec_endtest(tv); })
+/* --- @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 int PRINTF_LIKE(5, 6)
- tvec_claim(struct tvec_state */*tv*/, int /*ok*/,
- const char */*file*/, unsigned /*lno*/,
- const char */*expr*/, ...);
+extern void tvec_skipspc(struct tvec_state */*tv*/);
-#define TVEC_CLAIM(tv, cond) \
- (tvec_claim(tv, !!(cond), __FILE__, __LINE__, #cond " untrue"))
+/* --- @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@
+ *
+ * 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.,
+ * by @tvec_flushtoeol@ or @tvec_nexttoken@, which will also
+ * advance the line number).
+ */
-extern int tvec_claimeq(struct tvec_state */*tv*/,
- const struct tvec_regty */*ty*/,
- const union tvec_misc */*arg*/,
- const char */*file*/, unsigned /*lno*/,
- const char */*expr*/);
+extern int PRINTF_LIKE(3, 4)
+ 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*/);
-/*----- Command-line interface --------------------------------------------*/
+/* --- @tvec_flushtoeol@ --- *
+ *
+ * Arguments: @struct tvec_state *tv@ = test-vector state
+ * @unsigned f@ = flags (@TVFF_...@)
+ *
+ * Returns: Zero on success, @-1@ on error.
+ *
+ * Use: Advance to the start of the next line, consuming the
+ * preceding newline.
+ *
+ * A syntax error is reported if no newline character is found,
+ * i.e., the file ends in mid-line. A syntax error is also
+ * reported if material other than whitespace or a comment is
+ * found before the end of the line end, and @TVFF_ALLOWANY@ is
+ * not set in @f@. The line number count is updated
+ * appropriately.
+ */
-extern const struct tvec_info tvec_adhocinfo;
+#define TVFF_ALLOWANY 1u
+extern int tvec_flushtoeol(struct tvec_state */*tv*/, unsigned /*f*/);
-extern void tvec_parseargs(int /*argc*/, char */*argv*/[],
- struct tvec_state */*tv_out*/,
- int */*argpos_out*/,
- const struct tvec_info */*info*/);
+/* --- @tvec_nexttoken@ --- *
+ *
+ * Arguments: @struct tvec_state *tv@ = test-vector state
+ *
+ * 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
+ * on the next line.
+ *
+ * Tokens are separated by non-newline whitespace, comments, and
+ * newlines followed by whitespace; a newline /not/ followed by
+ * whitespace instead begins the next assignment, and two
+ * newlines separated only by whitespace terminate the data for
+ * a test.
+ *
+ * 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,
+ * and the file position is left correctly. The line number
+ * count is updated appropriately.
+ */
-extern int tvec_readstdin(struct tvec_state */*tv*/);
-extern int tvec_readfile(struct tvec_state */*tv*/, const char */*file*/);
-extern int tvec_readdflt(struct tvec_state */*tv*/, const char */*file*/);
-extern int tvec_readarg(struct tvec_state */*tv*/, const char */*arg*/);
+extern int tvec_nexttoken(struct tvec_state */*tv*/);
-extern int tvec_readargs(int /*argc*/, char */*argv*/[],
- struct tvec_state */*tv*/,
- int */*argpos_inout*/, const char */*dflt*/);
+/* --- @tvec_readword@ --- *
+ *
+ * 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.
+ *
+ * Use: A `word' consists of characters other than whitespace, null
+ * characters, and other than those listed in @delims@;
+ * furthermore, a word does not begin with a `;'. (If you want
+ * reading to stop at comments not preceded by whitespace, then
+ * 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@.
+ *
+ * Otherwise, the word is accumulated in @d@ and zero is
+ * returned; if @d@ was not empty at the start of the call, the
+ * newly read word is separated from the existing material by a
+ * single space character. Since null bytes are never valid
+ * word constituents, a null terminator is written to @d@, and
+ * it is safe to treat the string in @d@ as being null-
+ * terminated.
+ */
-extern int tvec_main(int /*argc*/, char */*argv*/[],
- const struct tvec_info */*info*/,
- const char */*dflt*/);
+extern int PRINTF_LIKE(4, 5)
+ 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*/);
/*----- Output formatting -------------------------------------------------*/
enum { TVBU_OP, TVBU_BYTE };
+struct bench_timing;
+
struct tvec_outops {
void (*error)(struct tvec_output */*o*/,
const char */*msg*/, va_list */*ap*/);
extern void tvec_notice_v(struct tvec_state */*tv*/,
const char */*msg*/, va_list */*ap*/);
-extern int PRINTF_LIKE(3, 4)
- 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*/);
-
extern struct tvec_output *tvec_humanoutput(FILE */*fp*/);
extern struct tvec_output *tvec_tapoutput(FILE */*fp*/);
extern struct tvec_output *tvec_dfltout(FILE */*fp*/);
-/*----- Input utilities ---------------------------------------------------*/
-
-extern void tvec_skipspc(struct tvec_state */*tv*/);
-
-#define TVFF_ALLOWANY 1u
-extern int tvec_flushtoeol(struct tvec_state */*tv*/, unsigned /*f*/);
-
-extern int PRINTF_LIKE(4, 5)
- 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*/);
-
-extern int tvec_nexttoken(struct tvec_state */*tv*/);
-
/*----- Register types ----------------------------------------------------*/
struct tvec_regty {
extern void tvec_allocstring(union tvec_regval */*rv*/, size_t /*sz*/);
extern void tvec_allocbytes(union tvec_regval */*rv*/, size_t /*sz*/);
+/*----- Ad-hoc testing ----------------------------------------------------*/
+
+extern void tvec_adhoc(struct tvec_state */*tv*/, struct tvec_test */*t*/);
+
+extern void tvec_begingroup(struct tvec_state */*tv*/, const char */*name*/,
+ const char */*file*/, unsigned /*lno*/);
+extern void tvec_reportgroup(struct tvec_state */*tv*/);
+extern void tvec_endgroup(struct tvec_state */*tv*/);
+
+#define TVEC_BEGINGROUP(tv, name) \
+ do tvec_begingroup(tv, name, __FILE__, __LINE__); while (0)
+
+#define TVEC_TESTGROUP(tag, tv, name) \
+ MC_WRAP(tag##__around, \
+ { TVEC_BEGINGROUP(tv, name); }, \
+ { tvec_endgroup(tv); }, \
+ { if (!((tv)->f&TVSF_SKIP)) tvec_skipgroup(tv, 0); \
+ tvec_endgroup(tv); })
+
+extern void tvec_begintest(struct tvec_state */*tv*/,
+ const char */*file*/, unsigned /*lno*/);
+extern void tvec_endtest(struct tvec_state */*tv*/);
+
+#define TVEC_BEGINTEST(tv) \
+ do tvec_begintest(tv, __FILE__, __LINE__); while (0)
+
+#define TVEC_TEST(tag, tv) \
+ MC_WRAP(tag##__around, \
+ { TVEC_BEGINTEST(tv); }, \
+ { tvec_endtest(tv); }, \
+ { if ((tv)->f&TVSF_ACTIVE) tvec_skipgroup((tv), 0); \
+ tvec_endtest(tv); })
+
+extern int PRINTF_LIKE(5, 6)
+ tvec_claim(struct tvec_state */*tv*/, int /*ok*/,
+ const char */*file*/, unsigned /*lno*/,
+ const char */*expr*/, ...);
+
+#define TVEC_CLAIM(tv, cond) \
+ (tvec_claim(tv, !!(cond), __FILE__, __LINE__, #cond " untrue"))
+
+extern int tvec_claimeq(struct tvec_state */*tv*/,
+ const struct tvec_regty */*ty*/,
+ const union tvec_misc */*arg*/,
+ const char */*file*/, unsigned /*lno*/,
+ const char */*expr*/);
+
+/*----- Benchmarking ------------------------------------------------------*/
+
+struct tvec_bench {
+ struct tvec_env _env; /* benchmarking is an environment */
+ struct bench_state **bst; /* benchmark state anchor or null */
+ unsigned long niter; /* iterations done per unit */
+ int riter, rbuf; /* iterations and buffer registers */
+ const struct tvec_env *env; /* environment (per test, not grp) */
+};
+#define TVEC_BENCHENV \
+ { sizeof(struct tvec_benchctx), \
+ tvec_benchsetup, \
+ tvec_benchset, \
+ tvec_benchbefore, \
+ tvec_benchrun, \
+ tvec_benchafter, \
+ tvec_benchteardown }
+#define TVEC_BENCHINIT TVEC_BENCHENV, &tvec_benchstate
+
+struct tvec_benchctx {
+ const struct tvec_bench *b;
+ struct bench_state *bst;
+ double dflt_target;
+ void *subctx;
+};
+
+extern struct bench_state *tvec_benchstate;
+
+extern int tvec_benchsetup(struct tvec_state */*tv*/,
+ const struct tvec_env */*env*/,
+ void */*pctx*/, void */*ctx*/);
+extern int tvec_benchset(struct tvec_state */*tv*/, const char */*var*/,
+ const struct tvec_env */*env*/, void */*ctx*/);
+extern int tvec_benchbefore(struct tvec_state */*tv*/, void */*ctx*/);
+extern void tvec_benchrun(struct tvec_state */*tv*/,
+ tvec_testfn */*fn*/, void */*ctx*/);
+extern void tvec_benchafter(struct tvec_state */*tv*/, void */*ctx*/);
+extern void tvec_benchteardown(struct tvec_state */*tv*/, void */*ctx*/);
+
+extern void tvec_benchreport
+ (const struct gprintf_ops */*gops*/, void */*go*/,
+ unsigned /*unit*/, const struct bench_timing */*tm*/);
+
+/*----- Command-line interface --------------------------------------------*/
+
+extern const struct tvec_config tvec_adhocconfig;
+
+extern void tvec_parseargs(int /*argc*/, char */*argv*/[],
+ struct tvec_state */*tv_out*/,
+ int */*argpos_out*/,
+ const struct tvec_config */*config*/);
+
+extern int tvec_readstdin(struct tvec_state */*tv*/);
+extern int tvec_readfile(struct tvec_state */*tv*/, const char */*file*/);
+extern int tvec_readdflt(struct tvec_state */*tv*/, const char */*file*/);
+extern int tvec_readarg(struct tvec_state */*tv*/, const char */*arg*/);
+
+extern int tvec_readargs(int /*argc*/, char */*argv*/[],
+ struct tvec_state */*tv*/,
+ int */*argpos_inout*/, const char */*dflt*/);
+
+extern int tvec_main(int /*argc*/, char */*argv*/[],
+ const struct tvec_config */*config*/,
+ const char */*dflt*/);
+
/*----- That's all, folks -------------------------------------------------*/
#ifdef __cplusplus