const union tvec_misc *arg, void *ctx)
{ unihash_setkey(ctx, 0); return (0); }
-static void run_step(struct tvec_state *tv)
+static int run_step(struct tvec_state *tv)
{
static const size_t steps[] = { 1, 5, 6, 7, 8, 23 };
struct step step;
tv->test->fn(tv->in, tv->out, &step);
tvec_check(tv, "step = %lu", (unsigned long)steps[i]);
}
+ return (0);
}
static const struct tvec_regdef unihash_regs[] = {
struct tvec_state *tv;
};
-static void capture_state_and_run(struct tvec_state *tv)
+static int capture_state_and_run(struct tvec_state *tv)
{
struct test_context tctx;
tv->in[RRC].f |= TVRF_LIVE; tv->out[RRC].f |= TVRF_LIVE;
}
tvec_check(tv, 0);
+ return (0);
}
static void test_serialization
#include <assert.h>
#include <ctype.h>
+#include <errno.h>
#include <string.h>
#include "alloc.h"
/*----- Output ------------------------------------------------------------*/
-void tvec_error(struct tvec_state *tv, const char *msg, ...)
- { va_list ap; va_start(ap, msg); tvec_error_v(tv, msg, &ap); }
-void tvec_error_v(struct tvec_state *tv, const char *msg, va_list *ap)
- { tv->output->ops->error(tv->output, msg, ap); exit(2); }
+int tvec_error(struct tvec_state *tv, const char *msg, ...)
+{
+ va_list ap;
+
+ va_start(ap, msg); tvec_error_v(tv, msg, &ap); va_end(ap);
+ tv->f |= TVSF_ERROR; return (-1);
+}
+int tvec_error_v(struct tvec_state *tv, const char *msg, va_list *ap)
+ { tv->output->ops->error(tv->output, msg, ap); return (-1); }
void tvec_notice(struct tvec_state *tv, const char *msg, ...)
{
void tvec_notice_v(struct tvec_state *tv, const char *msg, va_list *ap)
{ tv->output->ops->notice(tv->output, msg, ap); }
-void tvec_syntax(struct tvec_state *tv, int ch, const char *expect, ...)
+int tvec_syntax(struct tvec_state *tv, int ch, const char *expect, ...)
{
va_list ap;
+
va_start(ap, expect); tvec_syntax_v(tv, ch, expect, &ap); va_end(ap);
+ return (-1);
}
-void tvec_syntax_v(struct tvec_state *tv, int ch,
+int tvec_syntax_v(struct tvec_state *tv, int ch,
const char *expect, va_list *ap)
{
dstr d = DSTR_INIT;
switch (ch) {
case EOF: strcpy(found, "<eof>"); break;
- case '\n': strcpy(found, "<eol>"); 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);
}
dstr_vputf(&d, expect, ap);
tvec_error(tv, "syntax error: expected %s but found %s", expect, found);
+ return (-1);
}
void tvec_skipgroup(struct tvec_state *tv, const char *excuse, ...)
return (0);
}
-void tvec_bench(struct tvec_state *tv)
+int tvec_bench(struct tvec_state *tv)
{
const struct tvec_bench *tvb = tv->test->arg.p;
struct bench_state *b;
end_1:
if (r.ctx) xfree(r.ctx);
end_0:
- return;
+ return (0);
}
/*----- Main machinery ----------------------------------------------------*/
}
}
-void tvec_flushtoeol(struct tvec_state *tv, unsigned f)
+int tvec_flushtoeol(struct tvec_state *tv, unsigned f)
{
- int ch;
+ int ch, rc = 0;
for (;;) {
ch = getc(tv->fp);
switch (ch) {
- case '\n': tv->lno++; return;
- case EOF: return;
+ case '\n': tv->lno++; return (rc);
+ case EOF: return (rc);
case ';': f |= TVFF_ALLOWANY; break;
default:
- if (!(f&TVFF_ALLOWANY) && !isspace(ch))
+ if (!(f&TVFF_ALLOWANY) && !isspace(ch)) {
tvec_syntax(tv, ch, "end-of-line");
+ rc = -1; f |= TVFF_ALLOWANY;
+ }
break;
}
}
ch = getc(tv->fp);
if (ch == '\n' || ch == EOF || ch == ';' ||
(delims && strchr(delims, ch))) {
- if (expect) tvec_syntax(tv, ch, expect, ap);
+ if (expect) return (tvec_syntax(tv, ch, expect, ap));
else { ungetc(ch, tv->fp); return (-1); }
}
if (d->len) DPUTC(d, ' ');
#undef f_mismatch
}
-void tvec_runtest(struct tvec_state *tv)
+int tvec_runtest(struct tvec_state *tv)
{
tv->test->fn(tv->in, tv->out, (/*unconst*/ void *)tv->test->arg.p);
- tvec_check(tv, 0);
+ tvec_check(tv, 0); return (0);
}
static void begin_test(struct tvec_state *tv)
for (rd = tv->test->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))
+ else if (!(rd->f&TVRF_OPT)) {
tvec_error(tv, "required register `%s' not set in test `%s'",
rd->name, tv->test->name);
+ goto end;
+ }
}
if (!(tv->f&TVSF_SKIP))
{ begin_test(tv); tv->test->run(tv); tvec_endtest(tv); }
+end:
tv->f &= ~TVSF_OPEN; release_registers(tv); init_registers(tv);
}
release_registers(tv); tv->test = 0;
}
-void tvec_read(struct tvec_state *tv, const char *infile, FILE *fp)
+int tvec_read(struct tvec_state *tv, const char *infile, FILE *fp)
{
dstr d = DSTR_INIT;
const struct tvec_test *test;
const struct tvec_regdef *rd;
struct tvec_reg *r;
int ch;
+ int rc = 0;
tv->infile = infile; tv->lno = 1; tv->fp = fp;
goto end;
case '[':
+ end_test_group(tv);
tvec_skipspc(tv);
DRESET(&d); tvec_readword(tv, &d, "];", "group name");
+ tvec_skipspc(tv);
+ ch = getc(tv->fp); if (ch != ']') tvec_syntax(tv, ch, "`]'");
for (test = tv->tests; test->name; test++)
if (STRCMP(d.buf, ==, test->name)) goto found_test;
- tvec_error(tv, "unknown test group `%s'", d.buf);
+ tvec_error(tv, "unknown test group `%s'", d.buf); goto flush_line;
found_test:
- tvec_skipspc(tv);
- ch = getc(tv->fp); if (ch != ']') tvec_syntax(tv, ch, "`]'");
- tvec_flushtoeol(tv, 0);
- end_test_group(tv);
- tv->test = test;
- begin_test_group(tv);
+ tvec_flushtoeol(tv, 0); tv->test = test; begin_test_group(tv);
break;
case '\n':
if (isspace(ch)) {
tvec_skipspc(tv);
ch = getc(tv->fp);
- if (ch == EOF)
- goto end;
- else if (ch == ';')
- { tvec_flushtoeol(tv, TVFF_ALLOWANY); continue; }
- else
- { tvec_flushtoeol(tv, 0); check(tv); }
+ 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 if (ch == ';')
- { tvec_flushtoeol(tv, TVFF_ALLOWANY); continue; }
+ tvec_flushtoeol(tv, TVFF_ALLOWANY);
else {
ungetc(ch, tv->fp);
- DRESET(&d); tvec_readword(tv, &d, "=:;", "register name");
+ DRESET(&d);
+ if (tvec_readword(tv, &d, "=:;", "register name")) goto flush_line;
tvec_skipspc(tv); ch = getc(tv->fp);
- if (ch != '=' && ch != ':') tvec_syntax(tv, ch, "`=' or `:'");
+ if (ch != '=' && ch != ':')
+ { tvec_syntax(tv, ch, "`=' or `:'"); goto flush_line; }
tvec_skipspc(tv);
if (d.buf[0] == '@') {
if (STRCMP(d.buf, ==, "@status")) {
{ 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");
- if (ch == '\\') {
+ { tvec_syntax(tv, ch, "status character"); goto flush_line; }
+ else if (ch == '\\') {
ch = getc(tv->fp);
- if (ch == EOF || ch == '\n')
+ if (ch == EOF || ch == '\n') {
tvec_syntax(tv, ch, "escaped status character");
+ goto flush_line;
+ }
}
tv->expst = ch;
tvec_flushtoeol(tv, 0);
- } else
+ } else {
tvec_error(tv, "unknown special register `%s'", d.buf);
+ goto flush_line;
+ }
} else {
- if (!tv->test) tvec_error(tv, "no current test");
+ 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'",
d.buf, tv->test->name);
+ goto flush_line;
found_reg:
if (!(tv->f&TVSF_OPEN))
{ tv->test_lno = tv->lno; tv->f |= TVSF_OPEN; }
tvec_skipspc(tv);
r = TVEC_REG(tv, in, rd->i);
- if (r->f&TVRF_LIVE)
+ if (r->f&TVRF_LIVE) {
tvec_error(tv, "register `%s' already set", rd->name);
- rd->ty->parse(&r->v, rd, tv); r->f |= TVRF_LIVE;
+ goto flush_line;
+ }
+ if (rd->ty->parse(&r->v, rd, tv)) goto flush_line;
+ r->f |= TVRF_LIVE;
}
}
break;
}
+ continue;
+
+ flush_line:
+ tvec_flushtoeol(tv, TVFF_ALLOWANY); rc = -1;
}
+ if (ferror(tv->fp))
+ { tvec_error(tv, "error reading input: %s", strerror(errno)); rc = -1; }
end:
end_test_group(tv);
tv->infile = 0; tv->fp = 0;
dstr_destroy(&d);
+ return (rc);
}
/*----- Ad-hoc testing ----------------------------------------------------*/
static const struct tvec_regdef no_regs = { 0, 0, 0, 0, { 0 } };
-static void fakerun(struct tvec_state *tv)
+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"); }
tvec_begin(tv_out, info, o); *argpos_out = optind;
}
-void tvec_readstdin(struct tvec_state *tv)
- { tvec_read(tv, "<stdin>", stdin); }
+int tvec_readstdin(struct tvec_state *tv)
+ { return (tvec_read(tv, "<stdin>", 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_readdflt(struct tvec_state *tv, const char *file)
{
dstr d = DSTR_INIT;
const char *p;
+ int rc;
if (file) {
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, file); file = d.buf; }
+ rc = tvec_readfile(tv, file);
} 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)
+int tvec_readarg(struct tvec_state *tv, const char *arg)
{
- if (STRCMP(arg, ==, "-")) tvec_readstdin(tv);
- else tvec_readfile(tv, arg);
+ int rc;
+
+ if (STRCMP(arg, ==, "-")) rc = tvec_readstdin(tv);
+ else rc = tvec_readfile(tv, arg);
+ return (rc);
}
-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;
+ int rc;
-
- if (i == argc) tvec_readdflt(tv, dflt);
- else while (i < argc) tvec_readarg(tv, argv[i++]);
+ 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);
}
int tvec_main(int argc, char *argv[],
#define HA_WIN (HFG(GREEN))
#define HA_LOSE (HFG(RED) | HAF_BOLD)
#define HA_SKIP (HFG(YELLOW))
+#define HA_ERR (HFG(MAGENTA) | HAF_BOLD)
struct human_output {
struct tvec_output _o;
static void show_progress(struct human_output *h)
{
+ struct tvec_state *tv = h->_o.tv;
const char *p, *l;
- if ((h->f&HOF_TTY) && !(h->f&HOF_PROGRESS)) {
+ if (tv->test && (h->f&HOF_TTY) && !(h->f&HOF_PROGRESS)) {
fprintf(h->fp, "%s: ", h->_o.tv->test->name);
if (!(h->f&HOF_COLOUR))
dstr_write(&h->scoreboard, h->fp);
#undef FLUSH
}
-static void human_report(struct human_output *h,
- const char *msg, va_list *ap)
+static void human_report(struct tvec_output *o, const char *msg, va_list *ap)
{
+ struct human_output *h = (struct human_output *)o;
struct tvec_state *tv = h->_o.tv;
+ clear_progress(h); fflush(h->fp);
fprintf(stderr, "%s: ", QUIS);
report_location(h, stderr, tv->infile, tv->lno);
vfprintf(stderr, msg, *ap);
vfprintf(h->fp, msg, *ap);
fputc('\n', h->fp);
}
-}
-
-static void human_error(struct tvec_output *o, const char *msg, va_list *ap)
-{
- struct human_output *h = (struct human_output *)o;
-
- if (h->f&HOF_PROGRESS) fputc('\n', h->fp);
- human_report(h, msg, ap);
-}
-
-static void human_notice(struct tvec_output *o, const char *msg, va_list *ap)
-{
- struct human_output *h = (struct human_output *)o;
- clear_progress(h); human_report(h, msg, ap); show_progress(h);
+ show_progress(h);
}
static void human_write(struct tvec_output *o, const char *p, size_t sz)
}
fputc('\n', h->fp);
- return (tv->all[TVOUT_LOSE] ? 1 : 0);
+ if (tv->f&TVSF_ERROR) {
+ setattr(h, HA_ERR); fputs("ERRORS", h->fp); setattr(h, 0);
+ fputs(" found in input; tests may not have run correctly\n", h->fp);
+ }
+
+ return (tv->f&TVSF_ERROR ? 2 : tv->all[TVOUT_LOSE] ? 1 : 0);
}
static void human_bgroup(struct tvec_output *o)
}
static const struct tvec_outops human_ops = {
- human_error, human_notice, human_write,
+ human_report, human_report, human_write,
human_bsession, human_esession,
human_bgroup, human_egroup, human_skipgroup,
human_btest, human_skip, human_fail, human_mismatch, human_etest,
static int tap_esession(struct tvec_output *o)
{
struct tap_output *t = (struct tap_output *)o;
+ struct tvec_state *tv = t->_o.tv;
+
+ if (tv->f&TVSF_ERROR) {
+ fputs("Bail out! "
+ "Errors found in input; tests may not have run correctly\n",
+ t->fp);
+ return (2);
+ }
fprintf(t->fp, "1..%u\n", tap_grpix(t));
- return (0);
+ return (tv->all[TVOUT_LOSE] ? 1 : 0);
}
static void tap_bgroup(struct tvec_output *o) { ; }
return (wd/4);
}
-static void check_signed_range(long i,
- const struct tvec_irange *ir,
- struct tvec_state *tv)
+static int check_signed_range(long i,
+ const struct tvec_irange *ir,
+ struct tvec_state *tv)
{
- if (ir && (ir->min > i || i > ir->max))
+ if (ir && (ir->min > i || i > ir->max)) {
tvec_error(tv, "integer %ld out of range (must be in [%ld .. %ld])",
i, ir->min, ir->max);
+ return (-1);
+ }
+ return (0);
}
-static void check_unsigned_range(unsigned long u,
- const struct tvec_urange *ur,
- struct tvec_state *tv)
+static int check_unsigned_range(unsigned long u,
+ const struct tvec_urange *ur,
+ struct tvec_state *tv)
{
- if (ur && (ur->min > u || u > ur->max))
+ if (ur && (ur->min > u || u > ur->max)) {
tvec_error(tv, "integer %lu out of range (must be in [%lu .. %lu])",
u, ur->min, ur->max);
+ return (-1);
+ }
+ return (0);
}
-static void parse_signed(long *i_out, const char *p,
- const struct tvec_irange *ir,
- struct tvec_state *tv)
+static int parse_signed(long *i_out, const char *p,
+ const struct tvec_irange *ir,
+ struct tvec_state *tv)
{
char *q; const char *pp;
int olderr;
olderr = errno; errno = 0;
pp = p; if (*pp == '-' || *pp == '+') pp++;
- if (!ISDIGIT(*pp)) tvec_syntax(tv, *pp, "signed integer");
+ if (!ISDIGIT(*pp)) return (tvec_syntax(tv, *pp, "signed integer"));
i = strtol(p, &q, 0);
- if (*q && !ISSPACE(*q)) tvec_syntax(tv, *q, "end-of-line");
- if (errno) tvec_error(tv, "invalid integer `%s'", p);
+ if (*q && !ISSPACE(*q)) return (tvec_syntax(tv, *q, "end-of-line"));
+ if (errno) return (tvec_error(tv, "invalid integer `%s'", p));
check_signed_range(i, ir, tv);
errno = olderr; *i_out = i;
+ return (0);
}
-static void parse_unsigned(unsigned long *u_out, const char *p,
- const struct tvec_urange *ur,
- struct tvec_state *tv)
+static int parse_unsigned(unsigned long *u_out, const char *p,
+ const struct tvec_urange *ur,
+ struct tvec_state *tv)
{
char *q;
int olderr;
unsigned long u;
olderr = errno; errno = 0;
- if (!ISDIGIT(*p)) tvec_syntax(tv, *p, "unsigned integer");
+ if (!ISDIGIT(*p)) return (tvec_syntax(tv, *p, "unsigned integer"));
u = strtoul(p, &q, 0);
- if (*q && !ISSPACE(*q)) tvec_syntax(tv, *q, "end-of-line");
- if (errno) tvec_error(tv, "invalid integer `%s'", p);
+ if (*q && !ISSPACE(*q)) return (tvec_syntax(tv, *q, "end-of-line"));
+ if (errno) return (tvec_error(tv, "invalid integer `%s'", p));
check_unsigned_range(u, ur, tv);
errno = olderr; *u_out = u;
+ return (0);
}
static int convert_hex(char ch, int *v_out)
else return (-1);
}
-static void read_quoted_string(dstr *d, int quote, struct tvec_state *tv)
+static int read_quoted_string(dstr *d, int quote, struct tvec_state *tv)
{
char expect[4];
int ch, i, esc;
reinsert:
switch (ch) {
case EOF: case '\n':
- tvec_syntax(tv, ch, expect);
+ return (tvec_syntax(tv, ch, expect));
case '\\':
if (quote == '\'') goto ordinary;
ch = getc(tv->fp);
if (ch == '{') { f |= f_brace; ch = getc(tv->fp); }
else f &= ~f_brace;
- if (convert_hex(ch, &esc)) tvec_syntax(tv, ch, "hex digit");
+ if (convert_hex(ch, &esc))
+ return (tvec_syntax(tv, ch, "hex digit"));
for (;;) {
ch = getc(tv->fp); if (convert_hex(ch, &i)) break;
esc = 8*esc + i;
if (esc > UCHAR_MAX)
- tvec_error(tv, "character code %d out of range", esc);
+ return (tvec_error(tv,
+ "character code %d out of range", esc));
}
DPUTC(d, esc);
if (!(f&f_brace)) goto reinsert;
- else if (ch != '}') tvec_syntax(tv, ch, "`}'");
+ else if (ch != '}') return (tvec_syntax(tv, ch, "`}'"));
break;
default:
esc = 8*esc + ch - '0'; i++;
}
if (esc > UCHAR_MAX)
- tvec_error(tv, "character code %d out of range", esc);
+ return (tvec_error(tv,
+ "character code %d out of range", esc));
DPUTC(d, esc);
goto reinsert;
}
- tvec_syntax(tv, ch, "string escape");
- break;
+ return (tvec_syntax(tv, ch, "string escape"));
}
break;
end:
DPUTZ(d);
+ return (0);
#undef f_brace
}
ch = getc(tv->fp);
switch (ch) {
case EOF:
- goto bad;
+ tvec_syntax(tv, ch, "bareword");
+ rc = -1; goto end;
case '\n':
if (s == ESCAPE) { tv->lno++; goto addch; }
if (s == WORD) pos = d->len;
- ungetc(ch, tv->fp); if (tvec_nexttoken(tv)) { rc = -1; goto done; }
+ ungetc(ch, tv->fp); if (tvec_nexttoken(tv)) { rc = -1; goto end; }
DPUTC(d, ' '); s = SPACE;
break;
case '"': case '\'': case '!':
- if (s == SPACE) { ungetc(ch, tv->fp); rc = 0; goto done; }
+ if (s == SPACE) { ungetc(ch, tv->fp); goto done; }
goto addch;
case '\\':
s = ESCAPE;
done:
if (s == SPACE) d->len = pos;
- DPUTZ(d); return (rc);
-
-bad:
- tvec_syntax(tv, ch, "bareword");
+ DPUTZ(d); rc = 0;
+end:
+ return (rc);
}
static void set_up_encoding(const codec_class **ccl_out, unsigned *f_out,
}
}
-static void read_compound_string(void **p_inout, size_t *sz_inout,
- unsigned code, struct tvec_state *tv)
+static int read_compound_string(void **p_inout, size_t *sz_inout,
+ unsigned code, struct tvec_state *tv)
{
const codec_class *ccl; unsigned f;
codec *cdc;
dstr d = DSTR_INIT, w = DSTR_INIT;
char *p;
- int ch, err;
+ int ch, err, rc;
set_up_encoding(&ccl, &f, code);
if (tvec_nexttoken(tv)) tvec_syntax(tv, fgetc(tv->fp), "string");
do {
ch = getc(tv->fp);
if (ch == '"' || ch == '\'')
- read_quoted_string(&d, ch, tv);
+ { if (read_quoted_string(&d, ch, tv)) { rc = -1; goto end; } }
else if (ch == '!') {
ungetc(ch, tv->fp);
DRESET(&w); tvec_readword(tv, &w, ";", "`!'-keyword");
else if (STRCMP(w.buf, ==, "!hex")) code = TVCODE_HEX;
else if (STRCMP(w.buf, ==, "!base32")) code = TVCODE_BASE32;
else if (STRCMP(w.buf, ==, "!base64")) code = TVCODE_BASE64;
- else tvec_error(tv, "unknown string keyword `%s'", w.buf);
+ else {
+ tvec_error(tv, "unknown string keyword `%s'", w.buf);
+ rc = -1; goto end;
+ }
set_up_encoding(&ccl, &f, code);
} else if (ccl) {
ungetc(ch, tv->fp);
DRESET(&w);
- tvec_readword(tv, &w, ";", "%s-encoded fragment", ccl->name);
+ if (tvec_readword(tv, &w, ";", "%s-encoded fragment", ccl->name))
+ { rc = -1; goto end; }
cdc = ccl->decoder(f);
err = cdc->ops->code(cdc, w.buf, w.len, &d);
if (!err) err = cdc->ops->code(cdc, 0, 0, &d);
- if (err)
+ if (err) {
tvec_error(tv, "invalid %s fragment `%s': %s",
ccl->name, w.buf, codec_strerror(err));
+ rc = -1; goto end;
+ }
cdc->ops->destroy(cdc);
} else switch (code) {
case TVCODE_BARE:
if (*sz_inout <= d.len)
{ xfree(*p_inout); *p_inout = xmalloc(d.len + 1); }
p = *p_inout; memcpy(p, d.buf, d.len); p[d.len] = 0; *sz_inout = d.len;
+ rc = 0;
+end:
dstr_destroy(&d); dstr_destroy(&w);
+ return (rc);
}
/*----- Skeleton ----------------------------------------------------------*/
static int frombuf_int(buf *b, union tvec_regval *rv,
const struct tvec_regdef *rd)
- { return signed_from_buf(b, &rv->i); }
+ { return (signed_from_buf(b, &rv->i)); }
static int frombuf_uint(buf *b, union tvec_regval *rv,
const struct tvec_regdef *rd)
{ return (unsigned_from_buf(b, &rv->u)); }
-static void parse_int(union tvec_regval *rv, const struct tvec_regdef *rd,
- struct tvec_state *tv)
+static int parse_int(union tvec_regval *rv, const struct tvec_regdef *rd,
+ struct tvec_state *tv)
{
dstr d = DSTR_INIT;
+ int rc;
- tvec_readword(tv, &d, ";", "signed integer");
- parse_signed(&rv->i, d.buf, rd->arg.p, tv);
- tvec_flushtoeol(tv, 0);
+ if (tvec_readword(tv, &d, ";", "signed integer")) { rc = -1; goto end; }
+ if (parse_signed(&rv->i, d.buf, rd->arg.p, tv)) { rc = -1; goto end; }
+ if (tvec_flushtoeol(tv, 0)) { rc = -1; goto end; }
+ rc = 0;
+end:
dstr_destroy(&d);
+ return (rc);
}
-static void parse_uint(union tvec_regval *rv, const struct tvec_regdef *rd,
- struct tvec_state *tv)
+static int parse_uint(union tvec_regval *rv, const struct tvec_regdef *rd,
+ struct tvec_state *tv)
{
dstr d = DSTR_INIT;
+ int rc;
- tvec_readword(tv, &d, ";", "unsigned integer");
- parse_unsigned(&rv->u, d.buf, rd->arg.p, tv);
- tvec_flushtoeol(tv, 0);
+ if (tvec_readword(tv, &d, ";", "unsigned integer")) { rc = -1; goto end; }
+ if (parse_unsigned(&rv->u, d.buf, rd->arg.p, tv)) { rc = -1; goto end; }
+ if (tvec_flushtoeol(tv, 0)) { rc = -1; goto end; }
+ rc = 0;
+end:
dstr_destroy(&d);
+ return (rc);
}
static void dump_int(const union tvec_regval *rv,
}
}
-static void parse_enum(union tvec_regval *rv, const struct tvec_regdef *rd,
- struct tvec_state *tv)
+static int parse_enum(union tvec_regval *rv, const struct tvec_regdef *rd,
+ struct tvec_state *tv)
{
const struct tvec_enuminfo *ei = rd->arg.p;
#define DECLS(tag, ty, slot) \
TVEC_MISCSLOTS(DECLS)
#undef DECLS
dstr d = DSTR_INIT;
+ int rc;
- tvec_readword(tv, &d, ";", "enumeration tag or literal integer");
+ if (tvec_readword(tv, &d, ";", "enumeration tag or literal integer"))
+ { rc = -1; goto end; }
switch (ei->mv) {
#define CASE(tag_, ty, slot) \
case TVMISC_##tag_: \
for (slot##a = ei->u.slot.av; slot##a->tag; slot##a++) \
if (STRCMP(d.buf, ==, slot##a->tag)) \
- { rv->slot = FETCH_##tag_; goto end; }
+ { rv->slot = FETCH_##tag_; goto done; }
#define FETCH_INT (ia->i)
#define FETCH_UINT (ua->u)
#define FETCH_PTR ((/*unconst*/ void *)(pa->p))
switch (ei->mv) {
#define CASE(tag, ty, slot) \
- case TVMISC_##tag: HANDLE_##tag goto end;
-#define HANDLE_INT parse_signed(&rv->i, d.buf, ei->u.i.ir, tv);
-#define HANDLE_UINT parse_unsigned(&rv->u, d.buf, ei->u.u.ur, tv);
-#define HANDLE_PTR if (STRCMP(d.buf, ==, "#nil")) rv->p = 0; \
- else goto tagonly;
+ case TVMISC_##tag: HANDLE_##tag goto done;
+#define HANDLE_INT \
+ if (parse_signed(&rv->i, d.buf, ei->u.i.ir, tv)) \
+ { rc = -1; goto end; }
+#define HANDLE_UINT \
+ if (parse_unsigned(&rv->u, d.buf, ei->u.u.ur, tv)) \
+ { rc = -1; goto end; }
+#define HANDLE_PTR \
+ if (STRCMP(d.buf, ==, "#nil")) rv->p = 0; \
+ else goto tagonly;
TVEC_MISCSLOTS(CASE)
#undef CASE
#undef HANDLE_INT
#undef HANDLE_PTR
default: tagonly:
tvec_error(tv, "unknown `%s' value `%s'", ei->name, d.buf);
+ rc = -1; goto end;
}
+done:
+ if (tvec_flushtoeol(tv, 0)) { rc = -1; goto end; }
+ rc = 0;
end:
- tvec_flushtoeol(tv, 0);
dstr_destroy(&d);
+ return (rc);
}
static void dump_enum(const union tvec_regval *rv,
/*----- Flag types --------------------------------------------------------*/
-static void parse_flags(union tvec_regval *rv, const struct tvec_regdef *rd,
- struct tvec_state *tv)
+static int parse_flags(union tvec_regval *rv, const struct tvec_regdef *rd,
+ struct tvec_state *tv)
{
const struct tvec_flaginfo *fi = rd->arg.p;
const struct tvec_flag *f;
unsigned long m = 0, v = 0, t;
dstr d = DSTR_INIT;
- int ch;
+ int ch, rc;
for (;;) {
- DRESET(&d); tvec_readword(tv, &d, "|;", "flag name or integer");
+ DRESET(&d);
+ if (tvec_readword(tv, &d, "|;", "flag name or integer"))
+ { rc = -1; goto end; }
for (f = fi->fv; f->tag; f++)
if (STRCMP(f->tag, ==, d.buf)) {
- if (m&f->m) tvec_error(tv, "colliding flag setting");
- else { m |= f->m; v |= f->v; goto next; }
+ if (m&f->m)
+ { tvec_error(tv, "colliding flag setting"); rc = -1; goto end; }
+ else
+ { m |= f->m; v |= f->v; goto next; }
}
- parse_unsigned(&t, d.buf, fi->range, tv); v |= t;
+ if (parse_unsigned(&t, d.buf, fi->range, tv)) { rc = -1; goto end; }
+ v |= t;
next:
if (tvec_nexttoken(tv)) break;
- ch = getc(tv->fp); if (ch != '|') tvec_syntax(tv, ch, "`|'");
- if (tvec_nexttoken(tv)) tvec_syntax(tv, '\n', "flag name or integer");
+ ch = getc(tv->fp);
+ if (ch != '|') { tvec_syntax(tv, ch, "`|'"); rc = -1; goto end; }
+ if (tvec_nexttoken(tv))
+ { tvec_syntax(tv, '\n', "flag name or integer"); rc = -1; goto end; }
}
rv->u = v;
+ rc = 0;
+end:
+ dstr_destroy(&d);
+ return (rc);
}
static void dump_flags(const union tvec_regval *rv,
return (0);
}
-static void check_string_length(size_t sz, const struct tvec_urange *ur,
- struct tvec_state *tv)
+static int check_string_length(size_t sz, const struct tvec_urange *ur,
+ struct tvec_state *tv)
{
if (ur && (ur->min > sz || sz > ur->max))
- tvec_error(tv, "invalid string length %lu; must be in [%lu..%lu]",
- (unsigned long)sz, ur->min, ur->max);
+ return (tvec_error(tv,
+ "invalid string length %lu; must be in [%lu..%lu]",
+ (unsigned long)sz, ur->min, ur->max));
+ return (0);
}
-static void parse_string(union tvec_regval *rv, const struct tvec_regdef *rd,
- struct tvec_state *tv)
+static int parse_string(union tvec_regval *rv, const struct tvec_regdef *rd,
+ struct tvec_state *tv)
{
void *p = rv->str.p;
- read_compound_string(&p, &rv->str.sz, TVCODE_BARE, tv); rv->str.p = p;
- check_string_length(rv->str.sz, rd->arg.p, tv);
+ if (read_compound_string(&p, &rv->str.sz, TVCODE_BARE, tv)) return (-1);
+ rv->str.p = p;
+ if (check_string_length(rv->str.sz, rd->arg.p, tv)) return (-1);
+ return (0);
}
-static void parse_bytes(union tvec_regval *rv, const struct tvec_regdef *rd,
- struct tvec_state *tv)
+static int parse_bytes(union tvec_regval *rv, const struct tvec_regdef *rd,
+ struct tvec_state *tv)
{
void *p = rv->bytes.p;
- read_compound_string(&p, &rv->bytes.sz, TVCODE_HEX, tv); rv->bytes.p = p;
- check_string_length(rv->bytes.sz, rd->arg.p, tv);
+ if (read_compound_string(&p, &rv->bytes.sz, TVCODE_HEX, tv)) return (-1);
+ rv->bytes.p = p;
+ if (check_string_length(rv->bytes.sz, rd->arg.p, tv)) return (-1);
+ return (0);
}
static void dump_string(const union tvec_regval *rv,
static const char units[] = "kMGTPEZY";
-static void parse_buffer(union tvec_regval *rv,
- const struct tvec_regdef *rd,
- struct tvec_state *tv)
+static int parse_buffer(union tvec_regval *rv,
+ const struct tvec_regdef *rd,
+ struct tvec_state *tv)
{
dstr d = DSTR_INIT;
char *q; const char *unit;
int olderr;
size_t pos;
unsigned long u, t;
+ int rc;
unsigned f = 0;
#define f_range 1u
- tvec_readword(tv, &d, ";", "buffer length");
+ if (tvec_readword(tv, &d, ";", "buffer length")) { rc = -1; goto end; }
olderr = errno; errno = 0;
u = strtoul(d.buf, &q, 0);
if (errno) goto bad;
}
}
if (*q && *q != ';') goto bad;
- check_string_length(u, rd->arg.p, tv);
+ if (check_string_length(u, rd->arg.p, tv)) { rc = -1; goto end; }
- tvec_flushtoeol(tv, 0);
- tvec_allocbytes(rv, u); memset(rv->bytes.p, 0, u);
- DDESTROY(&d); return;
+ if (tvec_flushtoeol(tv, 0)) { rc = -1; goto end; }
+ tvec_allocbytes(rv, u); memset(rv->bytes.p, '?', u);
+ rc = 0;
+end:
+ DDESTROY(&d); return (rc);
bad:
tvec_error(tv, "invalid buffer length `%s'", d.buf);
+ rc = -1; goto end;
rangerr:
tvec_error(tv, "buffer length `%s' out of range", d.buf);
+ rc = -1; goto end;
#undef f_range
}
#define TVSF_SKIP 1u /* skip this test group */
#define TVSF_OPEN 2u /* test is open */
#define TVSF_ACTIVE 4u /* test is active */
+#define TVSF_ERROR 8u /* an error occurred */
#define TVSF_OUTMASK 0xf0 /* test outcome */
#define TVSF_OUTSHIFT 4
unsigned nrout, nreg; /* number of output/total registers */
/*----- Test descriptions -------------------------------------------------*/
-typedef void tvec_hookfn(struct tvec_state */*tv*/);
+typedef int tvec_hookfn(struct tvec_state */*tv*/);
typedef void tvec_testfn(const struct tvec_reg */*in*/,
struct tvec_reg */*out*/,
void */*ctx*/);
extern void tvec_check_v(struct tvec_state */*tv*/,
const char */*detail*/, va_list */*ap*/);
-extern void tvec_runtest(struct tvec_state */*tv*/);
+extern int tvec_runtest(struct tvec_state */*tv*/);
/*----- Input utilities ---------------------------------------------------*/
extern void tvec_skipspc(struct tvec_state */*tv*/);
#define TVFF_ALLOWANY 1u
-extern void tvec_flushtoeol(struct tvec_state */*tv*/, unsigned /*f*/);
+extern int tvec_flushtoeol(struct tvec_state */*tv*/, unsigned /*f*/);
extern int PRINTF_LIKE(4, 5)
tvec_readword(struct tvec_state */*tv*/, dstr */*d*/,
struct tvec_output */*o*/);
extern int tvec_end(struct tvec_state */*tv*/);
-extern void tvec_read(struct tvec_state */*tv*/,
- const char */*infile*/, FILE */*fp*/);
-
+extern int tvec_read(struct tvec_state */*tv*/,
+ const char */*infile*/, FILE */*fp*/);
/*----- Benchmarking ------------------------------------------------------*/
extern int tvec_ensurebench(struct tvec_state */*tv*/,
struct bench_state **/*b_out*/);
-extern void tvec_bench(struct tvec_state */*tv*/);
+extern int tvec_bench(struct tvec_state */*tv*/);
/*----- Ad-hoc testing ----------------------------------------------------*/
int */*argpos_out*/,
const struct tvec_info */*info*/);
-extern void tvec_readstdin(struct tvec_state */*tv*/);
-extern void tvec_readfile(struct tvec_state */*tv*/, const char */*file*/);
-extern void tvec_readdflt(struct tvec_state */*tv*/, const char */*file*/);
-extern void tvec_readarg(struct tvec_state */*tv*/, const char */*arg*/);
+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 void tvec_readargs(int /*argc*/, char */*argv*/[],
- struct tvec_state */*tv*/,
- int */*argpos_inout*/, const char */*dflt*/);
+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_info */*info*/,
void (*destroy)(struct tvec_output */*o*/);
};
-extern void PRINTF_LIKE(2, 3) NORETURN
+extern int PRINTF_LIKE(2, 3)
tvec_error(struct tvec_state */*tv*/, const char */*msg*/, ...);
-extern void NORETURN tvec_error_v(struct tvec_state */*tv*/,
- const char */*msg*/, va_list */*ap*/);
+extern int tvec_error_v(struct tvec_state */*tv*/,
+ const char */*msg*/, va_list */*ap*/);
extern void PRINTF_LIKE(2, 3)
tvec_notice(struct tvec_state */*tv*/, const char */*msg*/, ...);
extern void tvec_notice_v(struct tvec_state */*tv*/,
const char */*msg*/, va_list */*ap*/);
-extern void PRINTF_LIKE(3, 4) NORETURN
+extern int PRINTF_LIKE(3, 4)
tvec_syntax(struct tvec_state */*tv*/, int /*ch*/,
const char */*expect*/, ...);
-extern void NORETURN tvec_syntax_v(struct tvec_state */*tv*/, int /*ch*/,
- const char */*expect*/, va_list */*ap*/);
+extern int tvec_syntax_v(struct tvec_state */*tv*/, int /*ch*/,
+ const char */*expect*/, va_list */*ap*/);
extern void PRINTF_LIKE(2, 3)
tvec_skipgroup(struct tvec_state */*tv*/, const char */*note*/, ...);
const struct tvec_regdef */*rd*/);
int (*frombuf)(buf */*b*/, union tvec_regval */*rv*/,
const struct tvec_regdef */*rd*/);
- void (*parse)(union tvec_regval */*rv*/, const struct tvec_regdef */*rd*/,
- struct tvec_state */*tv*/);
+ int (*parse)(union tvec_regval */*rv*/, const struct tvec_regdef */*rd*/,
+ struct tvec_state */*tv*/);
void (*dump)(const union tvec_regval */*rv*/,
const struct tvec_regdef */*rd*/,
struct tvec_state */*tv*/, unsigned /*style*/);
void *ctx)
{ out[RRC].v.i = versioncmp(in[RV0].v.str.p, in[RV1].v.str.p); }
-static void swap_test(struct tvec_state *tv)
+static int swap_test(struct tvec_state *tv)
{
struct tvec_reg rt;
rt = tv->in[RV0]; tv->in[RV0] = tv->in[RV1]; tv->in[RV1] = rt;
tv->in[RRC].v.i = -tv->in[RRC].v.i;
tv->test->fn(tv->in, tv->out, 0); tvec_check(tv, "swapped");
+ return (0);
}
static const struct tvec_irange cmp_range = { -1, +1 };