X-Git-Url: https://git.distorted.org.uk/~mdw/mLib/blobdiff_plain/b64eb60f6c1fdb12f3922e04913e137199838807..c81c35dfd10050ffef85d57dc2ad73f52f38a3f2:/test/tvec-main.c diff --git a/test/tvec-main.c b/test/tvec-main.c index ea597ad..fc1a2ae 100644 --- a/test/tvec-main.c +++ b/test/tvec-main.c @@ -47,6 +47,7 @@ /*----- Main code ---------------------------------------------------------*/ +/* Table of output formats. */ static const struct outform { const char *name; struct tvec_output *(*makefn)(FILE *fp); @@ -56,11 +57,20 @@ static const struct outform { { 0, 0 } }; -static struct bench_state benchstate; - -const struct tvec_info tvec_adhocinfo = +/* Configuration for ad-hoc testing. */ +const struct tvec_config tvec_adhocconfig = { 0, 1, 1, sizeof(struct tvec_reg) }; +/* --- @find_outform@ --- + * + * Arguments: @const char *p@ = output name + * + * Returns: Pointer to output format record. + * + * Use: Looks up an output format by name. Reports a fatal error if + * no matching record is found. + */ + static const struct outform *find_outform(const char *p) { const struct outform *best = 0, *of; @@ -80,6 +90,15 @@ static const struct outform *find_outform(const char *p) else die(2, "unknown output format `%s'", optarg); } +/* --- @version@, @usage@, @help@ --- * + * + * Arguments: @FILE *fp@ = stream to write on + * + * Returns: --- + * + * Use: Output information about the program. + */ + static void version(FILE *fp) { pquis(fp, "$, mLib test-vector framework version " VERSION "\n"); } @@ -101,20 +120,32 @@ Options:\n\ \n\ -f, --format=FORMAT produce output in FORMAT.\n\ -o, --output=OUTPUT write output to OUTPUT file.\n\ - -t, --target=SECS aim to run benchmarks for SECS.\n\ ", fp); } +/* --- @tvec_parseargs@ --- * + * + * Arguments: @int argc@ = number of command-line arguments + * @char *argv[]@ = vector of argument strings + * @struct tvec_state *tv_out@ = test vector state to initialize + * @int *argpos_out@ = where to leave unread argument index + * @const struct tvec_config *cofig@ = test vector configuration + * + * Returns: --- + * + * Use: Parse arguments and set up the test vector state @*tv_out@. + * If errors occur, print messages to standard error and exit + * with status 2. + */ + void tvec_parseargs(int argc, char *argv[], struct tvec_state *tv_out, - int *argpos_out, const struct tvec_info *info) + int *argpos_out, const struct tvec_config *config) { FILE *ofp = 0; const struct outform *of = 0; struct tvec_output *o; - struct bench_timer *tm; - const char *p; char *q; + const char *p; int opt; - double t; unsigned f = 0; #define f_bogus 1u @@ -125,15 +156,12 @@ void tvec_parseargs(int argc, char *argv[], struct tvec_state *tv_out, { "format", OPTF_ARGREQ, 0, 'f' }, { "output", OPTF_ARGREQ, 0, 'o' }, - { "target", OPTF_ARGREQ, 0, 't' }, { 0, 0, 0, 0 } }; - tvec_benchstate = &benchstate; - tm = bench_createtimer(); bench_init(&benchstate, tm); ego(argv[0]); for (;;) { - opt = mdwopt(argc, argv, "hvu" "f:o:t:", options, 0, 0, 0); + opt = mdwopt(argc, argv, "hvu" "f:o:", options, 0, 0, 0); if (opt < 0) break; switch (opt) { case 'h': help(stdout); exit(0); @@ -148,12 +176,6 @@ void tvec_parseargs(int argc, char *argv[], struct tvec_state *tv_out, die(2, "failed to open `%s' for writing: %s", optarg, strerror(errno)); break; - case 't': - errno = 0; t = strtod(optarg, &q); - while (ISSPACE(*q)) q++; - if (errno || *q || t < 0) die(2, "invalid time `%s'", optarg); - benchstate.target_s = t; - break; default: f |= f_bogus; @@ -169,64 +191,139 @@ void tvec_parseargs(int argc, char *argv[], struct tvec_state *tv_out, if (of) o = of->makefn(ofp); else o = tvec_dfltout(ofp); - tvec_begin(tv_out, info, o); *argpos_out = optind; + tvec_begin(tv_out, config, o); *argpos_out = optind; } -void tvec_readstdin(struct tvec_state *tv) - { tvec_read(tv, "", stdin); } +/* --- @tvec_readstdin@, @tvec_readfile@, @tvec_readarg@ --- * + * + * Arguments: @struct tvec_state *tv@ = test vector state + * @const char *file@ = pathname of file to read + * @const char *arg@ = argument to interpret + * + * 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 `%|-|%', + * and from the named file otherwise. + */ + +int tvec_readstdin(struct tvec_state *tv) + { return (tvec_read(tv, "", stdin)); } -void tvec_readfile(struct tvec_state *tv, const char *file) +int tvec_readfile(struct tvec_state *tv, const char *file) { - FILE *fp; + FILE *fp = 0; + int rc; fp = fopen(file, "r"); - if (!fp) + if (!fp) { tvec_error(tv, "failed to open `%s' for reading: %s", file, strerror(errno)); - tvec_read(tv, file, fp); - fclose(fp); + rc = -1; goto end; + } + if (tvec_read(tv, file, fp)) { rc = -1; goto end; } + rc = 0; +end: + if (fp) fclose(fp); + return (rc); } -void tvec_readdflt(struct tvec_state *tv, const char *file) +int tvec_readarg(struct tvec_state *tv, const char *arg) +{ + int rc; + + if (STRCMP(arg, ==, "-")) rc = tvec_readstdin(tv); + else rc = tvec_readfile(tv, arg); + return (rc); +} + +/* --- @tvec_readdflt@ --- * + * + * Arguments: @struct tvec_state *tv@ = test vector state + * @const char *dflt@ = defsault filename or null + * + * 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 + * @file@ is not null, then read the named file, looking in the + * directory named by the `%|srcdir|%' environment variable if + * that's set, or otherwise in the current directory. + */ + +int tvec_readdflt(struct tvec_state *tv, const char *dflt) { dstr d = DSTR_INIT; const char *p; + int rc; - if (file) { + if (dflt) { p = getenv("srcdir"); - if (p) - { dstr_putf(&d, "%s/%s", p, file); file = d.buf; } - tvec_readfile(tv, file); + if (p) { dstr_putf(&d, "%s/%s", p, dflt); dflt = d.buf; } + rc = tvec_readfile(tv, dflt); } else if (isatty(0)) - tvec_error(tv, "use `-' to force reading from interactive stdin"); + rc = tvec_error(tv, "use `-' to force reading from interactive stdin"); else - tvec_readstdin(tv); + rc = tvec_readstdin(tv); + dstr_destroy(&d); + return (rc); } -void tvec_readarg(struct tvec_state *tv, const char *arg) -{ - if (STRCMP(arg, ==, "-")) tvec_readstdin(tv); - else tvec_readfile(tv, arg); -} +/* --- @tvec_readargs@ --- * + * + * Arguments: @int argc@ = number of command-line arguments + * @char *argv[]@ = vector of argument strings + * @struct tvec_state *tv@ = test vector state + * @int *argpos_inout@ = current argument position (updated) + * @const char *dflt@ = default filename or null + * + * 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@; + * if no arguments are given then read from @dflt@ as for + * @tvec_readdflt@. + */ -void tvec_readargs(int argc, char *argv[], struct tvec_state *tv, +int tvec_readargs(int argc, char *argv[], struct tvec_state *tv, int *argpos_inout, const char *dflt) { int i = *argpos_inout; - - - if (i == argc) tvec_readdflt(tv, dflt); - else while (i < argc) tvec_readarg(tv, argv[i++]); + int rc; + + if (i == argc) + rc = tvec_readdflt(tv, dflt); + else { + rc = 0; + while (i < argc) + if (tvec_readarg(tv, argv[i++])) rc = -1; + } *argpos_inout = i; + return (rc); } +/* --- @tvec_main@ --- * + * + * Arguments: @int argc@ = number of command-line arguments + * @char *argv[]@ = vector of argument strings + * @const struct tvec_config *cofig@ = test vector configuration + * @const char *dflt@ = default filename or null + * + * Returns: Exit code. + * + * Use: All-in-one test vector front-end. Parse options from the + * command-line as for @tvec_parseargs@, and then process the + * remaining positional arguments as for @tvec_readargs@. The + * function constructs and disposes of a test vector state. + */ + int tvec_main(int argc, char *argv[], - const struct tvec_info *info, const char *dflt) + const struct tvec_config *config, const char *dflt) { struct tvec_state tv; int argpos; - tvec_parseargs(argc, argv, &tv, &argpos, info); + tvec_parseargs(argc, argv, &tv, &argpos, config); tvec_readargs(argc, argv, &tv, &argpos, dflt); return (tvec_end(&tv)); }