X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/mLib/blobdiff_plain/c7da785d89746cbcdc25bdea0fd66156d4c61cb9..e63124bc579bfd97cfe2f620ddd84df9f20477d8:/test/tvec-core.c diff --git a/test/tvec-core.c b/test/tvec-core.c index a25d653..9ec5d10 100644 --- a/test/tvec-core.c +++ b/test/tvec-core.c @@ -33,7 +33,6 @@ #include #include "alloc.h" -#include "bench.h" #include "tvec.h" /*----- Output ------------------------------------------------------------*/ @@ -70,11 +69,11 @@ int tvec_syntax_v(struct tvec_state *tv, int ch, char found[8]; switch (ch) { - case EOF: strcpy(found, ""); break; - case '\n': strcpy(found, ""); ungetc(ch, tv->fp); break; + case EOF: strcpy(found, "#"); break; + case '\n': strcpy(found, "#"); ungetc(ch, tv->fp); break; default: if (isprint(ch)) sprintf(found, "`%c'", ch); - else sprintf(found, "<#x%02x>", ch); + else sprintf(found, "#<\\x%02x>", ch); break; } dstr_vputf(&d, expect, ap); @@ -123,92 +122,43 @@ void tvec_fail_v(struct tvec_state *tv, const char *detail, va_list *ap) set_outcome(tv, TVOUT_LOSE); tv->output->ops->fail(tv->output, detail, ap); } -void tvec_mismatch(struct tvec_state *tv) - { tv->output->ops->mismatch(tv->output); } +void tvec_dumpreg(struct tvec_state *tv, + unsigned disp, const union tvec_regval *r, + const struct tvec_regdef *rd) + { tv->output->ops->dumpreg(tv->output, disp, r, rd); } -void tvec_write(struct tvec_state *tv, const char *p, ...) +void tvec_mismatch(struct tvec_state *tv, unsigned f) { - va_list ap; - va_start(ap, p); tvec_write_v(tv, p, &ap); va_end(ap); -} -void tvec_write_v(struct tvec_state *tv, const char *p, va_list *ap) -{ - dstr d = DSTR_INIT; - - dstr_vputf(&d, p, ap); tv->output->ops->write(tv->output, d.buf, d.len); - DDESTROY(&d); -} - -/*----- Serialization and deserialization ---------------------------------*/ - -int tvec_serialize(const struct tvec_reg *rv, - const struct tvec_regdef *regs, - unsigned nr, size_t regsz, - void **p_out, size_t *sz_out) -{ - void *p = 0; buf b; - unsigned char *bitmap; - size_t i, nbits, bitsz, sz; - const struct tvec_regdef *rd; - const struct tvec_reg *r; - int rc; - - for (rd = regs, nbits = 0, sz = 0; rd->name; rd++, nbits++) { - if (rd->i >= nr) continue; - r = TVEC_GREG(rv, rd->i, regsz); if (!(r->f&TVRF_LIVE)) continue; - sz += rd->ty->measure(&r->v, rd); - } - bitsz = (nbits + 7)/8; sz += bitsz; - - p = xmalloc(sz); buf_init(&b, p, sz); - bitmap = buf_get(&b, bitsz); assert(bitmap); memset(bitmap, 0, bitsz); - for (rd = regs, i = 0; rd->name; rd++, i++) { - if (rd->i >= nr) continue; - r = TVEC_GREG(rv, rd->i, regsz); if (!(r->f&TVRF_LIVE)) continue; - bitmap[rd->i/8] |= 1 << rd->i%8; - if (rd->ty->tobuf(&b, &r->v, rd)) { rc = -1; goto end; } - } - - if (BBAD(&b)) { rc = -1; goto end; } - *p_out = p; *sz_out = BLEN(&b); p = 0; rc = 0; -end: - xfree(p); - return (rc); -} - -int tvec_deserialize(struct tvec_reg *rv, - const struct tvec_regdef *regs, - unsigned nr, size_t regsz, - const void *p, size_t sz) -{ - buf b; - const unsigned char *bitmap; - size_t i, nbits, bitsz; const struct tvec_regdef *rd; - struct tvec_reg *r; - int rc; - - for (rd = regs, nbits = 0; rd->name; rd++, nbits++); - bitsz = (nbits + 7)/8; sz += bitsz; + const struct tvec_reg *rin, *rout; - buf_init(&b, (/*unconst*/ void *)p, sz); - bitmap = buf_get(&b, bitsz); if (!bitmap) { rc = -1; goto end; } - for (rd = regs, i = 0; rd->name; rd++, i++) { - if (rd->i >= nr) continue; - if (!(bitmap[rd->i/8]&(1 << rd->i%8))) continue; - r = TVEC_GREG(rv, rd->i, regsz); - if (rd->ty->frombuf(&b, &r->v, rd)) { rc = -1; goto end; } - r->f |= TVRF_LIVE; + for (rd = tv->test->regs; rd->name; rd++) { + if (rd->i >= tv->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); + } else { + if (!(f&TVMF_OUT)) continue; + rin = TVEC_REG(tv, in, rd->i); rout = TVEC_REG(tv, out, rd->i); + if (!(rin->f&TVRF_LIVE)) + tvec_dumpreg(tv, TVRD_OUTPUT, rout->f&TVRF_LIVE ? &rout->v : 0, rd); + else if ((rout->f&TVRF_LIVE) && rd->ty->eq(&rin->v, &rout->v, rd)) + tvec_dumpreg(tv, TVRD_MATCH, &rin->v, rd); + else { + tvec_dumpreg(tv, TVRD_FOUND, rout->f&TVRF_LIVE ? &rout->v : 0, rd); + tvec_dumpreg(tv, TVRD_EXPECT, &rin->v, rd); + } + } } - - if (BBAD(&b)) { rc = -1; goto end; } - rc = 0; -end: - return (rc); } /*----- Main machinery ----------------------------------------------------*/ +struct groupstate { + void *ctx; +}; +#define GROUPSTATE_INIT { 0 } + void tvec_skipspc(struct tvec_state *tv) { int ch; @@ -291,7 +241,7 @@ int tvec_readword_v(struct tvec_state *tv, dstr *d, const char *delims, int ch; ch = getc(tv->fp); - if (ch == '\n' || ch == EOF || ch == ';' || + if (!ch || ch == '\n' || ch == EOF || ch == ';' || (delims && strchr(delims, ch))) { if (expect) return (tvec_syntax(tv, ch, expect, ap)); else { ungetc(ch, tv->fp); return (-1); } @@ -300,11 +250,27 @@ int tvec_readword_v(struct tvec_state *tv, dstr *d, const char *delims, do { DPUTC(d, ch); ch = getc(tv->fp); - } while (ch != EOF && !isspace(ch) && (!delims || !strchr(delims, ch))); + } while (ch && ch != EOF && !isspace(ch) && + (!delims || !strchr(delims, ch))); DPUTZ(d); if (ch != EOF) ungetc(ch, tv->fp); return (0); } +void tvec_resetoutputs(struct tvec_state *tv) +{ + const struct tvec_regdef *rd; + struct tvec_reg *r; + + for (rd = tv->test->regs; rd->name; rd++) { + assert(rd->i < tv->nreg); + if (rd->i >= tv->nrout) continue; + r = TVEC_REG(tv, out, rd->i); + rd->ty->release(&r->v, rd); + rd->ty->init(&r->v, rd); + r->f = TVEC_REG(tv, in, rd->i)->f&TVRF_LIVE; + } +} + static void init_registers(struct tvec_state *tv) { const struct tvec_regdef *rd; @@ -316,7 +282,6 @@ static void init_registers(struct tvec_state *tv) if (rd->i < tv->nrout) { r = TVEC_REG(tv, out, rd->i); rd->ty->init(&r->v, rd); r->f = 0; } } - tv->expst = '.'; } static void release_registers(struct tvec_state *tv) @@ -332,42 +297,35 @@ static void release_registers(struct tvec_state *tv) } } -void tvec_check(struct tvec_state *tv, const char *detail, ...) -{ - va_list ap; - va_start(ap, detail); tvec_check_v(tv, detail, &ap); va_end(ap); -} -void tvec_check_v(struct tvec_state *tv, const char *detail, va_list *ap) +int tvec_checkregs(struct tvec_state *tv) { const struct tvec_regdef *rd; const struct tvec_reg *rin, *rout; - unsigned f = 0; -#define f_mismatch 1u - if (tv->expst != tv->st) f |= f_mismatch; for (rd = tv->test->regs; rd->name; rd++) { if (rd->i >= tv->nrout) continue; rin = TVEC_REG(tv, in, rd->i); rout = TVEC_REG(tv, out, rd->i); if (!rin->f&TVRF_LIVE) continue; - if (!rd->ty->eq(&rin->v, &rout->v, rd)) f |= f_mismatch; + if (!(rout->f&TVRF_LIVE) || !rd->ty->eq(&rin->v, &rout->v, rd)) + return (-1); } - if (!(f&f_mismatch)) return; - - tvec_fail_v(tv, detail, ap); - tvec_mismatch(tv); - -#undef f_mismatch + return (0); } -int tvec_runtest(struct tvec_state *tv) +void tvec_check(struct tvec_state *tv, const char *detail, ...) +{ + va_list ap; + va_start(ap, detail); tvec_check_v(tv, detail, &ap); va_end(ap); +} +void tvec_check_v(struct tvec_state *tv, const char *detail, va_list *ap) { - tv->test->fn(tv->in, tv->out, (/*unconst*/ void *)tv->test->arg.p); - tvec_check(tv, 0); return (0); + if (tvec_checkregs(tv)) + { tvec_fail_v(tv, detail, ap); tvec_mismatch(tv, TVMF_IN | TVMF_OUT); } } static void begin_test(struct tvec_state *tv) { - tv->f |= TVSF_ACTIVE; tv->f &= ~TVSF_OUTMASK; tv->st = '.'; + tv->f |= TVSF_ACTIVE; tv->f &= ~TVSF_OUTMASK; tv->output->ops->btest(tv->output); } @@ -382,38 +340,56 @@ void tvec_endtest(struct tvec_state *tv) tv->f &= ~TVSF_OPEN; } -static void check(struct tvec_state *tv) +static void check(struct tvec_state *tv, struct groupstate *g) { + const struct tvec_test *t = tv->test; + const struct tvec_env *env; const struct tvec_regdef *rd; if (!(tv->f&TVSF_OPEN)) return; - for (rd = tv->test->regs; rd->name; rd++) { + 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)) { tvec_error(tv, "required register `%s' not set in test `%s'", - rd->name, tv->test->name); + rd->name, t->name); goto end; } } - if (!(tv->f&TVSF_SKIP)) - { begin_test(tv); tv->test->run(tv); tvec_endtest(tv); } + if (!(tv->f&TVSF_SKIP)) { + begin_test(tv); + env = t->env; + if (env && env->before && env->before(tv, g->ctx)) + tvec_skip(tv, "test setup failed"); + else { + if (env && env->run) env->run(tv, t->fn, g->ctx); + else { t->fn(tv->in, tv->out, g->ctx); tvec_check(tv, 0); } + } + if (env && env->after) env->after(tv, g->ctx); + tvec_endtest(tv); + } end: tv->f &= ~TVSF_OPEN; release_registers(tv); init_registers(tv); } -static void begin_test_group(struct tvec_state *tv) +static void begin_test_group(struct tvec_state *tv, struct groupstate *g) { + const struct tvec_test *t = tv->test; + const struct tvec_env *env = t->env; unsigned i; tv->output->ops->bgroup(tv->output); tv->f &= ~TVSF_SKIP; init_registers(tv); for (i = 0; i < TVOUT_LIMIT; i++) tv->curr[i] = 0; - if (tv->test->preflight) tv->test->preflight(tv); + if (env && env->ctxsz) g->ctx = xmalloc(env->ctxsz); + if (env && env->setup && env->setup(tv, env, 0, g->ctx)) { + tvec_skipgroup(tv, "setup failed"); + xfree(g->ctx); g->ctx = 0; + } } void tvec_reportgroup(struct tvec_state *tv) @@ -432,22 +408,27 @@ void tvec_reportgroup(struct tvec_state *tv) } } -static void end_test_group(struct tvec_state *tv) +static void end_test_group(struct tvec_state *tv, struct groupstate *g) { - if (!tv->test) return; - if (tv->f&TVSF_OPEN) check(tv); + const struct tvec_test *t = tv->test; + const struct tvec_env *env; + + if (!t) return; + if (tv->f&TVSF_OPEN) check(tv, g); if (!(tv->f&TVSF_SKIP)) tvec_reportgroup(tv); - release_registers(tv); tv->test = 0; + env = t->env; if (env && env->teardown) env->teardown(tv, g->ctx); + release_registers(tv); tv->test = 0; xfree(g->ctx); g->ctx = 0; } int tvec_read(struct tvec_state *tv, const char *infile, FILE *fp) { dstr d = DSTR_INIT; const struct tvec_test *test; + const struct tvec_env *env; const struct tvec_regdef *rd; struct tvec_reg *r; - int ch; - int rc = 0; + struct groupstate g = GROUPSTATE_INIT; + int ch, ret, rc = 0; tv->infile = infile; tv->lno = 1; tv->fp = fp; @@ -459,7 +440,7 @@ int tvec_read(struct tvec_state *tv, const char *infile, FILE *fp) goto end; case '[': - end_test_group(tv); + end_test_group(tv, &g); tvec_skipspc(tv); DRESET(&d); tvec_readword(tv, &d, "];", "group name"); tvec_skipspc(tv); @@ -468,12 +449,12 @@ int tvec_read(struct tvec_state *tv, const char *infile, FILE *fp) if (STRCMP(d.buf, ==, test->name)) goto found_test; tvec_error(tv, "unknown test group `%s'", d.buf); goto flush_line; found_test: - tvec_flushtoeol(tv, 0); tv->test = test; begin_test_group(tv); + tvec_flushtoeol(tv, 0); tv->test = test; begin_test_group(tv, &g); break; case '\n': tv->lno++; - if (tv->f&TVSF_OPEN) check(tv); + if (tv->f&TVSF_OPEN) check(tv, &g); break; default: @@ -483,7 +464,7 @@ int tvec_read(struct tvec_state *tv, const char *infile, FILE *fp) if (ch == EOF) goto end; else if (ch == ';') tvec_flushtoeol(tv, TVFF_ALLOWANY); else if (tvec_flushtoeol(tv, 0)) rc = -1; - else check(tv); + else check(tv, &g); } else if (ch == ';') tvec_flushtoeol(tv, TVFF_ALLOWANY); else { @@ -494,29 +475,20 @@ int tvec_read(struct tvec_state *tv, const char *infile, FILE *fp) if (ch != '=' && ch != ':') { tvec_syntax(tv, ch, "`=' or `:'"); goto flush_line; } tvec_skipspc(tv); + if (!tv->test) + { tvec_error(tv, "no current test"); goto flush_line; } if (d.buf[0] == '@') { - if (STRCMP(d.buf, ==, "@status")) { - if (!(tv->f&TVSF_OPEN)) - { tv->test_lno = tv->lno; tv->f |= TVSF_OPEN; } - ch = getc(tv->fp); - if (ch == EOF || ch == '\n' || ch == ';') - { tvec_syntax(tv, ch, "status character"); goto flush_line; } - else if (ch == '\\') { - ch = getc(tv->fp); - if (ch == EOF || ch == '\n') { - tvec_syntax(tv, ch, "escaped status character"); - goto flush_line; - } - } - tv->expst = ch; - tvec_flushtoeol(tv, 0); - } else { - tvec_error(tv, "unknown special register `%s'", d.buf); + env = tv->test->env; + if (!env || !env->set) ret = 0; + else ret = env->set(tv, d.buf, env, g.ctx); + if (ret <= 0) { + if (!ret) + tvec_error(tv, "unknown special register `%s'", d.buf); goto flush_line; } + if (!(tv->f&TVSF_OPEN)) + { tv->test_lno = tv->lno; tv->f |= TVSF_OPEN; } } else { - if (!tv->test) - { tvec_error(tv, "no current test"); goto flush_line; } for (rd = tv->test->regs; rd->name; rd++) if (STRCMP(rd->name, ==, d.buf)) goto found_reg; tvec_error(tv, "unknown register `%s' for test `%s'", @@ -545,80 +517,97 @@ int tvec_read(struct tvec_state *tv, const char *infile, FILE *fp) if (ferror(tv->fp)) { tvec_error(tv, "error reading input: %s", strerror(errno)); rc = -1; } end: - end_test_group(tv); + end_test_group(tv, &g); tv->infile = 0; tv->fp = 0; dstr_destroy(&d); return (rc); } -/*----- Benchmarking ------------------------------------------------------*/ +/*----- Session lifecycle -------------------------------------------------*/ -struct bench_state *tvec_benchstate; +void tvec_begin(struct tvec_state *tv_out, + const struct tvec_info *info, + struct tvec_output *o) +{ + unsigned i; -struct benchrun { - unsigned long *n; - tvec_testfn *fn; - const struct tvec_reg *in; struct tvec_reg *out; - void *ctx; -}; + tv_out->f = 0; -static void benchloop_outer(unsigned long n, void *p) - { struct benchrun *r = p; while (n--) r->fn(r->in, r->out, r->ctx); } + assert(info->nrout <= info->nreg); + tv_out->nrout = info->nrout; tv_out->nreg = info->nreg; + tv_out->regsz = info->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++) { + TVEC_REG(tv_out, in, i)->f = 0; + if (i < tv_out->nrout) TVEC_REG(tv_out, out, i)->f = 0; + } -static void benchloop_inner(unsigned long n, void *p) - { struct benchrun *r = p; *r->n = n; r->fn(r->in, r->out, r->ctx); } + for (i = 0; i < TVOUT_LIMIT; i++) + tv_out->curr[i] = tv_out->all[i] = tv_out->grps[i] = 0; -int tvec_ensurebench(struct tvec_state *tv, struct bench_state **b_out) -{ - const struct tvec_bench *tvb = tv->test->arg.p; - struct bench_state **bb; - struct bench_timer *bt; + tv_out->tests = info->tests; tv_out->test = 0; + tv_out->infile = 0; tv_out->lno = 0; tv_out->fp = 0; + o->tv = tv_out; tv_out->output = o; - if (tvb->b) bb = tvb->b; - else bb = &tvec_benchstate; + tv_out->output->ops->bsession(tv_out->output); +} - if (!*bb) { - bt = bench_createtimer(); - if (!bt) { tvec_skip(tv, "failed to create timer"); return (-1); } - *bb = xmalloc(sizeof(**bb)); bench_init(*bb, bt); - } else if (!(*bb)->tm) - { tvec_skip(tv, "failed to create timer"); return (-1); } +int tvec_end(struct tvec_state *tv) +{ + int rc = tv->output->ops->esession(tv->output); - *b_out = *bb; - return (0); + tv->output->ops->destroy(tv->output); + xfree(tv->in); xfree(tv->out); + return (rc); } -int tvec_bench(struct tvec_state *tv) +/*----- Serialization and deserialization ---------------------------------*/ + +int tvec_serialize(const struct tvec_reg *rv, buf *b, + const struct tvec_regdef *regs, + unsigned nr, size_t regsz) { - const struct tvec_bench *tvb = tv->test->arg.p; - struct bench_state *b; - struct bench_timing tm; - struct benchrun r; - bench_fn *loopfn; + unsigned char *bitmap; + size_t i, bitoff, nbits, bitsz; + const struct tvec_regdef *rd; + const struct tvec_reg *r; - if (tvec_ensurebench(tv, &b)) goto end_0; + bitoff = BLEN(b); + for (rd = regs, nbits = 0; rd->name; rd++, nbits++); + bitsz = (nbits + 7)/8; - r.in = tv->in; r.out = tv->out; r.fn = tv->test->fn; - if (tvb->ctxsz) r.ctx = xmalloc(tvb->ctxsz); - else r.ctx = 0; - if (tvb->setup && tvb->setup(tv->in, tv->out, &tvb->arg, r.ctx)) - { tvec_skip(tv, "benchmark setup failed"); goto end_1; } + bitmap = buf_get(b, bitsz); if (!bitmap) return (-1); + memset(bitmap, 0, bitsz); + for (rd = regs, i = 0; rd->name; rd++, i++) { + if (rd->i >= nr) continue; + r = TVEC_GREG(rv, rd->i, regsz); if (!(r->f&TVRF_LIVE)) continue; + bitmap = BBASE(b) + bitoff; bitmap[rd->i/8] |= 1 << rd->i%8; + if (rd->ty->tobuf(b, &r->v, rd)) return (-1); + } + return (0); +} - if (tvb->riter < 0) - { r.n = 0; loopfn = benchloop_outer; } - else - { r.n = &TVEC_REG(tv, in, tvb->riter)->v.u; loopfn = benchloop_inner; } +int tvec_deserialize(struct tvec_reg *rv, buf *b, + const struct tvec_regdef *regs, + unsigned nr, size_t regsz) +{ + const unsigned char *bitmap; + size_t i, nbits, bitsz; + const struct tvec_regdef *rd; + struct tvec_reg *r; - tv->output->ops->bbench(tv->output); - if (bench_measure(&tm, b, loopfn, &r)) - { tv->output->ops->ebench(tv->output, 0); goto end_2; } - tv->output->ops->ebench(tv->output, &tm); + for (rd = regs, nbits = 0; rd->name; rd++, nbits++); + bitsz = (nbits + 7)/8; -end_2: - if (tvb->teardown) tvb->teardown(r.ctx); -end_1: - if (r.ctx) xfree(r.ctx); -end_0: + bitmap = buf_get(b, bitsz); if (!bitmap) return (-1); + for (rd = regs, i = 0; rd->name; rd++, i++) { + if (rd->i >= nr) continue; + if (!(bitmap[rd->i/8]&(1 << rd->i%8))) continue; + r = TVEC_GREG(rv, rd->i, regsz); + if (rd->ty->frombuf(b, &r->v, rd)) return (-1); + r->f |= TVRF_LIVE; + } return (0); } @@ -626,15 +615,12 @@ end_0: static const struct tvec_regdef no_regs = { 0, 0, 0, 0, { 0 } }; -static int fakerun(struct tvec_state *tv) - { assert(!"fake run function"); } static void fakefn(const struct tvec_reg *in, struct tvec_reg *out, void *p) { assert(!"fake test function"); } void tvec_adhoc(struct tvec_state *tv, struct tvec_test *t) { - t->name = ""; t->regs = &no_regs; - t->preflight = 0; t->run = fakerun; t->fn = fakefn; t->arg.p = 0; + t->name = ""; t->regs = &no_regs; t->env = 0; t->fn = fakefn; tv->tests = t; } @@ -645,7 +631,7 @@ void tvec_begingroup(struct tvec_state *tv, const char *name, t->name = name; tv->test = t; tv->infile = file; tv->lno = tv->test_lno = lno; - begin_test_group(tv); + begin_test_group(tv, 0); } void tvec_endgroup(struct tvec_state *tv) @@ -681,8 +667,6 @@ static void adhoc_claim_setup(struct tvec_state *tv, ck->saved_file = tv->infile; if (file) tv->infile = file; ck->saved_lno = tv->test_lno; if (file) tv->test_lno = lno; t->regs = regs ? regs : &no_regs; - - tv->st = '.'; } static void adhoc_claim_teardown(struct tvec_state *tv, @@ -728,48 +712,10 @@ int tvec_claimeq(struct tvec_state *tv, adhoc_claim_setup(tv, &ck, regs, file, lno); ok = ty->eq(&tv->in[0].v, &tv->out[0].v, ®s[0]); - if (!ok) { tvec_fail(tv, "%s", expr ); tvec_mismatch(tv); } + if (!ok) + { tvec_fail(tv, "%s", expr ); tvec_mismatch(tv, TVMF_IN | TVMF_OUT); } adhoc_claim_teardown(tv, &ck); return (ok); } -/*----- Session lifecycle -------------------------------------------------*/ - -void tvec_begin(struct tvec_state *tv_out, - const struct tvec_info *info, - struct tvec_output *o) -{ - unsigned i; - - tv_out->f = 0; - - assert(info->nrout <= info->nreg); - tv_out->nrout = info->nrout; tv_out->nreg = info->nreg; - tv_out->regsz = info->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++) { - TVEC_REG(tv_out, in, i)->f = 0; - if (i < tv_out->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 = info->tests; tv_out->test = 0; - tv_out->infile = 0; tv_out->lno = 0; tv_out->fp = 0; - o->tv = tv_out; tv_out->output = o; - - tv_out->output->ops->bsession(tv_out->output); -} - -int tvec_end(struct tvec_state *tv) -{ - int rc = tv->output->ops->esession(tv->output); - - tv->output->ops->destroy(tv->output); - xfree(tv->in); xfree(tv->out); - return (rc); -} - /*----- That's all, folks -------------------------------------------------*/