3938397b07d6315d37dbce488d3620b4a35411bf
3 * Main test vector driver
5 * (c) 2023 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of the mLib utilities library.
12 * mLib is free software: you can redistribute it and/or modify it under
13 * the terms of the GNU Library General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or (at
15 * your option) any later version.
17 * mLib is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
20 * License for more details.
22 * You should have received a copy of the GNU Library General Public
23 * License along with mLib. If not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
28 /*----- Header files ------------------------------------------------------*/
39 /*----- Output ------------------------------------------------------------*/
41 int tvec_error(struct tvec_state
*tv
, const char *msg
, ...)
45 va_start(ap
, msg
); tvec_error_v(tv
, msg
, &ap
); va_end(ap
);
46 tv
->f
|= TVSF_ERROR
; return (-1);
48 int tvec_error_v(struct tvec_state
*tv
, const char *msg
, va_list *ap
)
49 { tv
->output
->ops
->error(tv
->output
, msg
, ap
); return (-1); }
51 void tvec_notice(struct tvec_state
*tv
, const char *msg
, ...)
54 va_start(ap
, msg
); tvec_notice_v(tv
, msg
, &ap
); va_end(ap
);
56 void tvec_notice_v(struct tvec_state
*tv
, const char *msg
, va_list *ap
)
57 { tv
->output
->ops
->notice(tv
->output
, msg
, ap
); }
59 int tvec_syntax(struct tvec_state
*tv
, int ch
, const char *expect
, ...)
63 va_start(ap
, expect
); tvec_syntax_v(tv
, ch
, expect
, &ap
); va_end(ap
);
66 int tvec_syntax_v(struct tvec_state
*tv
, int ch
,
67 const char *expect
, va_list *ap
)
73 case EOF
: strcpy(found
, "<eof>"); break;
74 case '\n': strcpy(found
, "<eol>"); ungetc(ch
, tv
->fp
); break;
76 if (isprint(ch
)) sprintf(found
, "`%c'", ch
);
77 else sprintf(found
, "<#x%02x>", ch
);
80 dstr_vputf(&d
, expect
, ap
);
81 tvec_error(tv
, "syntax error: expected %s but found %s", expect
, found
);
85 void tvec_skipgroup(struct tvec_state
*tv
, const char *excuse
, ...)
88 va_start(ap
, excuse
); tvec_skipgroup_v(tv
, excuse
, &ap
); va_end(ap
);
90 void tvec_skipgroup_v(struct tvec_state
*tv
, const char *excuse
, va_list *ap
)
92 tv
->f
|= TVSF_SKIP
; tv
->grps
[TVOUT_SKIP
]++;
93 tv
->output
->ops
->skipgroup(tv
->output
, excuse
, ap
);
96 static void set_outcome(struct tvec_state
*tv
, unsigned out
)
98 tv
->f
&= ~(TVSF_ACTIVE
| TVSF_OUTMASK
);
99 tv
->f
|= out
<< TVSF_OUTSHIFT
;
102 void tvec_skip(struct tvec_state
*tv
, const char *excuse
, ...)
105 va_start(ap
, excuse
); tvec_skip_v(tv
, excuse
, &ap
); va_end(ap
);
107 void tvec_skip_v(struct tvec_state
*tv
, const char *excuse
, va_list *ap
)
109 assert(tv
->f
&TVSF_ACTIVE
);
110 set_outcome(tv
, TVOUT_SKIP
);
111 tv
->output
->ops
->skip(tv
->output
, excuse
, ap
);
114 void tvec_fail(struct tvec_state
*tv
, const char *detail
, ...)
117 va_start(ap
, detail
); tvec_fail_v(tv
, detail
, &ap
); va_end(ap
);
119 void tvec_fail_v(struct tvec_state
*tv
, const char *detail
, va_list *ap
)
121 assert((tv
->f
&TVSF_ACTIVE
) ||
122 (tv
->f
&TVSF_OUTMASK
) == (TVOUT_LOSE
<< TVSF_OUTSHIFT
));
123 set_outcome(tv
, TVOUT_LOSE
); tv
->output
->ops
->fail(tv
->output
, detail
, ap
);
126 void tvec_mismatch(struct tvec_state
*tv
)
127 { tv
->output
->ops
->mismatch(tv
->output
); }
129 void tvec_write(struct tvec_state
*tv
, const char *p
, ...)
132 va_start(ap
, p
); tvec_write_v(tv
, p
, &ap
); va_end(ap
);
134 void tvec_write_v(struct tvec_state
*tv
, const char *p
, va_list *ap
)
138 dstr_vputf(&d
, p
, ap
); tv
->output
->ops
->write(tv
->output
, d
.buf
, d
.len
);
142 /*----- Serialization and deserialization ---------------------------------*/
144 int tvec_serialize(const struct tvec_reg
*rv
,
145 const struct tvec_regdef
*regs
,
146 unsigned nr
, size_t regsz
,
147 void **p_out
, size_t *sz_out
)
150 unsigned char *bitmap
;
151 size_t i
, nbits
, bitsz
, sz
;
152 const struct tvec_regdef
*rd
;
153 const struct tvec_reg
*r
;
156 for (rd
= regs
, nbits
= 0, sz
= 0; rd
->name
; rd
++, nbits
++) {
157 if (rd
->i
>= nr
) continue;
158 r
= TVEC_GREG(rv
, rd
->i
, regsz
); if (!(r
->f
&TVRF_LIVE
)) continue;
159 sz
+= rd
->ty
->measure(&r
->v
, rd
);
161 bitsz
= (nbits
+ 7)/8; sz
+= bitsz
;
163 p
= xmalloc(sz
); buf_init(&b
, p
, sz
);
164 bitmap
= buf_get(&b
, bitsz
); assert(bitmap
); memset(bitmap
, 0, bitsz
);
165 for (rd
= regs
, i
= 0; rd
->name
; rd
++, i
++) {
166 if (rd
->i
>= nr
) continue;
167 r
= TVEC_GREG(rv
, rd
->i
, regsz
); if (!(r
->f
&TVRF_LIVE
)) continue;
168 bitmap
[rd
->i
/8] |= 1 << rd
->i
%8;
169 if (rd
->ty
->tobuf(&b
, &r
->v
, rd
)) { rc
= -1; goto end
; }
172 if (BBAD(&b
)) { rc
= -1; goto end
; }
173 *p_out
= p
; *sz_out
= BLEN(&b
); p
= 0; rc
= 0;
179 int tvec_deserialize(struct tvec_reg
*rv
,
180 const struct tvec_regdef
*regs
,
181 unsigned nr
, size_t regsz
,
182 const void *p
, size_t sz
)
185 const unsigned char *bitmap
;
186 size_t i
, nbits
, bitsz
;
187 const struct tvec_regdef
*rd
;
191 for (rd
= regs
, nbits
= 0; rd
->name
; rd
++, nbits
++);
192 bitsz
= (nbits
+ 7)/8; sz
+= bitsz
;
194 buf_init(&b
, (/*unconst*/ void *)p
, sz
);
195 bitmap
= buf_get(&b
, bitsz
); if (!bitmap
) { rc
= -1; goto end
; }
196 for (rd
= regs
, i
= 0; rd
->name
; rd
++, i
++) {
197 if (rd
->i
>= nr
) continue;
198 if (!(bitmap
[rd
->i
/8]&(1 << rd
->i
%8))) continue;
199 r
= TVEC_GREG(rv
, rd
->i
, regsz
);
200 if (rd
->ty
->frombuf(&b
, &r
->v
, rd
)) { rc
= -1; goto end
; }
204 if (BBAD(&b
)) { rc
= -1; goto end
; }
210 /*----- Benchmarking ------------------------------------------------------*/
212 struct bench_state
*tvec_benchstate
;
217 const struct tvec_reg
*in
; struct tvec_reg
*out
;
221 static void benchloop_outer(unsigned long n
, void *p
)
222 { struct benchrun
*r
= p
; while (n
--) r
->fn(r
->in
, r
->out
, r
->ctx
); }
224 static void benchloop_inner(unsigned long n
, void *p
)
225 { struct benchrun
*r
= p
; *r
->n
= n
; r
->fn(r
->in
, r
->out
, r
->ctx
); }
227 int tvec_ensurebench(struct tvec_state
*tv
, struct bench_state
**b_out
)
229 const struct tvec_bench
*tvb
= tv
->test
->arg
.p
;
230 struct bench_state
**bb
;
231 struct bench_timer
*bt
;
233 if (tvb
->b
) bb
= tvb
->b
;
234 else bb
= &tvec_benchstate
;
237 bt
= bench_createtimer();
238 if (!bt
) { tvec_skip(tv
, "failed to create timer"); return (-1); }
239 *bb
= xmalloc(sizeof(**bb
)); bench_init(*bb
, bt
);
240 } else if (!(*bb
)->tm
)
241 { tvec_skip(tv
, "failed to create timer"); return (-1); }
247 int tvec_bench(struct tvec_state
*tv
)
249 const struct tvec_bench
*tvb
= tv
->test
->arg
.p
;
250 struct bench_state
*b
;
251 struct bench_timing tm
;
255 if (tvec_ensurebench(tv
, &b
)) goto end_0
;
257 r
.in
= tv
->in
; r
.out
= tv
->out
; r
.fn
= tv
->test
->fn
;
258 if (tvb
->ctxsz
) r
.ctx
= xmalloc(tvb
->ctxsz
);
260 if (tvb
->setup
&& tvb
->setup(tv
->in
, tv
->out
, &tvb
->arg
, r
.ctx
))
261 { tvec_skip(tv
, "benchmark setup failed"); goto end_1
; }
264 { r
.n
= 0; loopfn
= benchloop_outer
; }
266 { r
.n
= &TVEC_REG(tv
, in
, tvb
->riter
)->v
.u
; loopfn
= benchloop_inner
; }
268 tv
->output
->ops
->bbench(tv
->output
);
269 if (bench_measure(&tm
, b
, loopfn
, &r
))
270 { tv
->output
->ops
->ebench(tv
->output
, 0); goto end_2
; }
271 tv
->output
->ops
->ebench(tv
->output
, &tm
);
274 if (tvb
->teardown
) tvb
->teardown(r
.ctx
);
276 if (r
.ctx
) xfree(r
.ctx
);
281 /*----- Main machinery ----------------------------------------------------*/
283 void tvec_skipspc(struct tvec_state
*tv
)
289 if (ch
== EOF
) break;
290 else if (ch
== '\n' || !isspace(ch
)) { ungetc(ch
, tv
->fp
); break; }
294 int tvec_flushtoeol(struct tvec_state
*tv
, unsigned f
)
301 case '\n': tv
->lno
++; return (rc
);
302 case EOF
: return (rc
);
303 case ';': f
|= TVFF_ALLOWANY
; break;
305 if (!(f
&TVFF_ALLOWANY
) && !isspace(ch
)) {
306 tvec_syntax(tv
, ch
, "end-of-line");
307 rc
= -1; f
|= TVFF_ALLOWANY
;
314 int tvec_nexttoken(struct tvec_state
*tv
)
316 enum { TAIL
, NEWLINE
, INDENT
, COMMENT
};
331 if (s
== NEWLINE
|| s
== INDENT
) { ungetc(ch
, tv
->fp
); return (-1); }
332 else { tv
->lno
++; s
= NEWLINE
; }
337 { if (s
== NEWLINE
) s
= INDENT
; }
338 else if (s
!= COMMENT
) {
340 if (s
== NEWLINE
) return (-1);
348 int tvec_readword(struct tvec_state
*tv
, dstr
*d
, const char *delims
,
349 const char *expect
, ...)
354 va_start(ap
, expect
);
355 rc
= tvec_readword_v(tv
, d
, delims
, expect
, &ap
);
359 int tvec_readword_v(struct tvec_state
*tv
, dstr
*d
, const char *delims
,
360 const char *expect
, va_list *ap
)
365 if (ch
== '\n' || ch
== EOF
|| ch
== ';' ||
366 (delims
&& strchr(delims
, ch
))) {
367 if (expect
) return (tvec_syntax(tv
, ch
, expect
, ap
));
368 else { ungetc(ch
, tv
->fp
); return (-1); }
370 if (d
->len
) DPUTC(d
, ' ');
374 } while (ch
!= EOF
&& !isspace(ch
) && (!delims
|| !strchr(delims
, ch
)));
375 DPUTZ(d
); if (ch
!= EOF
) ungetc(ch
, tv
->fp
);
379 static void init_registers(struct tvec_state
*tv
)
381 const struct tvec_regdef
*rd
;
384 for (rd
= tv
->test
->regs
; rd
->name
; rd
++) {
385 assert(rd
->i
< tv
->nreg
); r
= TVEC_REG(tv
, in
, rd
->i
);
386 rd
->ty
->init(&r
->v
, rd
); r
->f
= 0;
387 if (rd
->i
< tv
->nrout
)
388 { r
= TVEC_REG(tv
, out
, rd
->i
); rd
->ty
->init(&r
->v
, rd
); r
->f
= 0; }
393 static void release_registers(struct tvec_state
*tv
)
395 const struct tvec_regdef
*rd
;
398 for (rd
= tv
->test
->regs
; rd
->name
; rd
++) {
399 assert(rd
->i
< tv
->nreg
); r
= TVEC_REG(tv
, in
, rd
->i
);
400 rd
->ty
->release(&r
->v
, rd
); r
->f
= 0;
401 if (rd
->i
< tv
->nrout
)
402 { r
= TVEC_REG(tv
, out
, rd
->i
); rd
->ty
->release(&r
->v
, rd
); r
->f
= 0; }
406 void tvec_check(struct tvec_state
*tv
, const char *detail
, ...)
409 va_start(ap
, detail
); tvec_check_v(tv
, detail
, &ap
); va_end(ap
);
411 void tvec_check_v(struct tvec_state
*tv
, const char *detail
, va_list *ap
)
413 const struct tvec_regdef
*rd
;
414 const struct tvec_reg
*rin
, *rout
;
416 #define f_mismatch 1u
418 if (tv
->expst
!= tv
->st
) f
|= f_mismatch
;
419 for (rd
= tv
->test
->regs
; rd
->name
; rd
++) {
420 if (rd
->i
>= tv
->nrout
) continue;
421 rin
= TVEC_REG(tv
, in
, rd
->i
); rout
= TVEC_REG(tv
, out
, rd
->i
);
422 if (!rin
->f
&TVRF_LIVE
) continue;
423 if (!rd
->ty
->eq(&rin
->v
, &rout
->v
, rd
)) f
|= f_mismatch
;
425 if (!(f
&f_mismatch
)) return;
427 tvec_fail_v(tv
, detail
, ap
);
433 int tvec_runtest(struct tvec_state
*tv
)
435 tv
->test
->fn(tv
->in
, tv
->out
, (/*unconst*/ void *)tv
->test
->arg
.p
);
436 tvec_check(tv
, 0); return (0);
439 static void begin_test(struct tvec_state
*tv
)
441 tv
->f
|= TVSF_ACTIVE
; tv
->f
&= ~TVSF_OUTMASK
; tv
->st
= '.';
442 tv
->output
->ops
->btest(tv
->output
);
445 void tvec_endtest(struct tvec_state
*tv
)
449 if (tv
->f
&TVSF_ACTIVE
) out
= TVOUT_WIN
;
450 else out
= (tv
->f
&TVSF_OUTMASK
) >> TVSF_OUTSHIFT
;
451 assert(out
< TVOUT_LIMIT
); tv
->curr
[out
]++;
452 tv
->output
->ops
->etest(tv
->output
, out
);
456 static void check(struct tvec_state
*tv
)
458 const struct tvec_regdef
*rd
;
460 if (!(tv
->f
&TVSF_OPEN
)) return;
462 for (rd
= tv
->test
->regs
; rd
->name
; rd
++) {
463 if (TVEC_REG(tv
, in
, rd
->i
)->f
&TVRF_LIVE
)
464 { if (rd
->i
< tv
->nrout
) TVEC_REG(tv
, out
, rd
->i
)->f
|= TVRF_LIVE
; }
465 else if (!(rd
->f
&TVRF_OPT
)) {
466 tvec_error(tv
, "required register `%s' not set in test `%s'",
467 rd
->name
, tv
->test
->name
);
472 if (!(tv
->f
&TVSF_SKIP
))
473 { begin_test(tv
); tv
->test
->run(tv
); tvec_endtest(tv
); }
476 tv
->f
&= ~TVSF_OPEN
; release_registers(tv
); init_registers(tv
);
479 static void begin_test_group(struct tvec_state
*tv
)
483 tv
->output
->ops
->bgroup(tv
->output
);
486 for (i
= 0; i
< TVOUT_LIMIT
; i
++) tv
->curr
[i
] = 0;
487 if (tv
->test
->preflight
) tv
->test
->preflight(tv
);
490 void tvec_reportgroup(struct tvec_state
*tv
)
492 unsigned i
, out
, nrun
;
494 for (i
= 0, nrun
= 0; i
< TVOUT_LIMIT
; i
++)
495 { nrun
+= tv
->curr
[i
]; tv
->all
[i
] += tv
->curr
[i
]; }
497 if (tv
->curr
[TVOUT_SKIP
] == nrun
)
498 { out
= TVOUT_SKIP
; tvec_skipgroup(tv
, nrun ?
0 : "no tests to run"); }
500 if (tv
->curr
[TVOUT_LOSE
]) out
= TVOUT_LOSE
;
501 else out
= TVOUT_WIN
;
502 tv
->grps
[out
]++; tv
->output
->ops
->egroup(tv
->output
, out
);
506 static void end_test_group(struct tvec_state
*tv
)
508 if (!tv
->test
) return;
509 if (tv
->f
&TVSF_OPEN
) check(tv
);
510 if (!(tv
->f
&TVSF_SKIP
)) tvec_reportgroup(tv
);
511 release_registers(tv
); tv
->test
= 0;
514 int tvec_read(struct tvec_state
*tv
, const char *infile
, FILE *fp
)
517 const struct tvec_test
*test
;
518 const struct tvec_regdef
*rd
;
523 tv
->infile
= infile
; tv
->lno
= 1; tv
->fp
= fp
;
535 DRESET(&d
); tvec_readword(tv
, &d
, "];", "group name");
537 ch
= getc(tv
->fp
); if (ch
!= ']') tvec_syntax(tv
, ch
, "`]'");
538 for (test
= tv
->tests
; test
->name
; test
++)
539 if (STRCMP(d
.buf
, ==, test
->name
)) goto found_test
;
540 tvec_error(tv
, "unknown test group `%s'", d
.buf
); goto flush_line
;
542 tvec_flushtoeol(tv
, 0); tv
->test
= test
; begin_test_group(tv
);
547 if (tv
->f
&TVSF_OPEN
) check(tv
);
554 if (ch
== EOF
) goto end
;
555 else if (ch
== ';') tvec_flushtoeol(tv
, TVFF_ALLOWANY
);
556 else if (tvec_flushtoeol(tv
, 0)) rc
= -1;
558 } else if (ch
== ';')
559 tvec_flushtoeol(tv
, TVFF_ALLOWANY
);
563 if (tvec_readword(tv
, &d
, "=:;", "register name")) goto flush_line
;
564 tvec_skipspc(tv
); ch
= getc(tv
->fp
);
565 if (ch
!= '=' && ch
!= ':')
566 { tvec_syntax(tv
, ch
, "`=' or `:'"); goto flush_line
; }
568 if (d
.buf
[0] == '@') {
569 if (STRCMP(d
.buf
, ==, "@status")) {
570 if (!(tv
->f
&TVSF_OPEN
))
571 { tv
->test_lno
= tv
->lno
; tv
->f
|= TVSF_OPEN
; }
573 if (ch
== EOF
|| ch
== '\n' || ch
== ';')
574 { tvec_syntax(tv
, ch
, "status character"); goto flush_line
; }
575 else if (ch
== '\\') {
577 if (ch
== EOF
|| ch
== '\n') {
578 tvec_syntax(tv
, ch
, "escaped status character");
583 tvec_flushtoeol(tv
, 0);
585 tvec_error(tv
, "unknown special register `%s'", d
.buf
);
590 { tvec_error(tv
, "no current test"); goto flush_line
; }
591 for (rd
= tv
->test
->regs
; rd
->name
; rd
++)
592 if (STRCMP(rd
->name
, ==, d
.buf
)) goto found_reg
;
593 tvec_error(tv
, "unknown register `%s' for test `%s'",
594 d
.buf
, tv
->test
->name
);
597 if (!(tv
->f
&TVSF_OPEN
))
598 { tv
->test_lno
= tv
->lno
; tv
->f
|= TVSF_OPEN
; }
600 r
= TVEC_REG(tv
, in
, rd
->i
);
601 if (r
->f
&TVRF_LIVE
) {
602 tvec_error(tv
, "register `%s' already set", rd
->name
);
605 if (rd
->ty
->parse(&r
->v
, rd
, tv
)) goto flush_line
;
614 tvec_flushtoeol(tv
, TVFF_ALLOWANY
); rc
= -1;
617 { tvec_error(tv
, "error reading input: %s", strerror(errno
)); rc
= -1; }
620 tv
->infile
= 0; tv
->fp
= 0;
625 /*----- Ad-hoc testing ----------------------------------------------------*/
627 static const struct tvec_regdef no_regs
= { 0, 0, 0, 0, { 0 } };
629 static int fakerun(struct tvec_state
*tv
)
630 { assert(!"fake run function"); }
631 static void fakefn(const struct tvec_reg
*in
, struct tvec_reg
*out
, void *p
)
632 { assert(!"fake test function"); }
634 void tvec_adhoc(struct tvec_state
*tv
, struct tvec_test
*t
)
636 t
->name
= "<unset>"; t
->regs
= &no_regs
;
637 t
->preflight
= 0; t
->run
= fakerun
; t
->fn
= fakefn
; t
->arg
.p
= 0;
641 void tvec_begingroup(struct tvec_state
*tv
, const char *name
,
642 const char *file
, unsigned lno
)
644 struct tvec_test
*t
= (/*unconst*/ struct tvec_test
*)tv
->tests
;
646 t
->name
= name
; tv
->test
= t
;
647 tv
->infile
= file
; tv
->lno
= tv
->test_lno
= lno
;
648 begin_test_group(tv
);
651 void tvec_endgroup(struct tvec_state
*tv
)
653 if (!(tv
->f
&TVSF_SKIP
)) tvec_reportgroup(tv
);
657 void tvec_begintest(struct tvec_state
*tv
, const char *file
, unsigned lno
)
659 tv
->infile
= file
; tv
->lno
= tv
->test_lno
= lno
;
660 begin_test(tv
); tv
->f
|= TVSF_OPEN
;
666 const char *saved_file
; unsigned saved_lno
;
669 static void adhoc_claim_setup(struct tvec_state
*tv
,
670 struct adhoc_claim
*ck
,
671 const struct tvec_regdef
*regs
,
672 const char *file
, unsigned lno
)
674 struct tvec_test
*t
= (/*unconst*/ struct tvec_test
*)tv
->test
;
678 if (!(tv
->f
&TVSF_OPEN
))
679 { ck
->f
|= ACF_FRESH
; tvec_begintest(tv
, file
, lno
); }
681 ck
->saved_file
= tv
->infile
; if (file
) tv
->infile
= file
;
682 ck
->saved_lno
= tv
->test_lno
; if (file
) tv
->test_lno
= lno
;
683 t
->regs
= regs ? regs
: &no_regs
;
688 static void adhoc_claim_teardown(struct tvec_state
*tv
,
689 struct adhoc_claim
*ck
)
691 struct tvec_test
*t
= (/*unconst*/ struct tvec_test
*)tv
->test
;
694 tv
->infile
= ck
->saved_file
; tv
->test_lno
= ck
->saved_lno
;
696 if (ck
->f
&ACF_FRESH
) tvec_endtest(tv
);
699 int tvec_claim(struct tvec_state
*tv
, int ok
,
700 const char *file
, unsigned lno
, const char *expr
, ...)
702 struct adhoc_claim ck
;
705 adhoc_claim_setup(tv
, &ck
, 0, file
, lno
);
707 { va_start(ap
, expr
); tvec_fail_v(tv
, expr
, &ap
); va_end(ap
); }
708 adhoc_claim_teardown(tv
, &ck
);
712 int tvec_claimeq(struct tvec_state
*tv
,
713 const struct tvec_regty
*ty
, const union tvec_misc
*arg
,
714 const char *file
, unsigned lno
, const char *expr
)
716 struct tvec_regdef regs
[2];
717 struct adhoc_claim ck
;
720 tv
->in
[0].f
= tv
->out
[0].f
= TVRF_LIVE
;
722 regs
[0].name
= "value"; regs
[0].i
= 0;
723 regs
[0].ty
= ty
; regs
[0].f
= 0;
724 if (arg
) regs
[0].arg
= *arg
;
725 else regs
[0].arg
.p
= 0;
729 adhoc_claim_setup(tv
, &ck
, regs
, file
, lno
);
730 ok
= ty
->eq(&tv
->in
[0].v
, &tv
->out
[0].v
, ®s
[0]);
731 if (!ok
) { tvec_fail(tv
, "%s", expr
); tvec_mismatch(tv
); }
732 adhoc_claim_teardown(tv
, &ck
);
736 /*----- Session lifecycle -------------------------------------------------*/
738 void tvec_begin(struct tvec_state
*tv_out
,
739 const struct tvec_info
*info
,
740 struct tvec_output
*o
)
746 assert(info
->nrout
<= info
->nreg
);
747 tv_out
->nrout
= info
->nrout
; tv_out
->nreg
= info
->nreg
;
748 tv_out
->regsz
= info
->regsz
;
749 tv_out
->in
= xmalloc(tv_out
->nreg
*tv_out
->regsz
);
750 tv_out
->out
= xmalloc(tv_out
->nrout
*tv_out
->regsz
);
751 for (i
= 0; i
< tv_out
->nreg
; i
++) {
752 TVEC_REG(tv_out
, in
, i
)->f
= 0;
753 if (i
< tv_out
->nrout
) TVEC_REG(tv_out
, out
, i
)->f
= 0;
756 for (i
= 0; i
< TVOUT_LIMIT
; i
++)
757 tv_out
->curr
[i
] = tv_out
->all
[i
] = tv_out
->grps
[i
] = 0;
759 tv_out
->tests
= info
->tests
; tv_out
->test
= 0;
760 tv_out
->infile
= 0; tv_out
->lno
= 0; tv_out
->fp
= 0;
761 o
->tv
= tv_out
; tv_out
->output
= o
;
763 tv_out
->output
->ops
->bsession(tv_out
->output
);
766 int tvec_end(struct tvec_state
*tv
)
768 int rc
= tv
->output
->ops
->esession(tv
->output
);
770 tv
->output
->ops
->destroy(tv
->output
);
771 xfree(tv
->in
); xfree(tv
->out
);
775 /*----- That's all, folks -------------------------------------------------*/