#include <string.h>
#include "alloc.h"
-#include "bench.h"
#include "tvec.h"
/*----- Output ------------------------------------------------------------*/
char found[8];
switch (ch) {
- case EOF: strcpy(found, "<eof>"); break;
- case '\n': strcpy(found, "<eol>"); ungetc(ch, tv->fp); break;
+ case EOF: strcpy(found, "#<eof>"); break;
+ case '\n': strcpy(found, "#<eol>"); 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);
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;
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); }
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;
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)
}
}
-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);
}
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)
}
}
-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;
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);
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:
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 {
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'",
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);
}
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 = "<unset>"; t->regs = &no_regs;
- t->preflight = 0; t->run = fakerun; t->fn = fakefn; t->arg.p = 0;
+ t->name = "<unset>"; t->regs = &no_regs; t->env = 0; t->fn = fakefn;
tv->tests = t;
}
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)
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,
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 -------------------------------------------------*/