From 882a39c1c269818ed00b1b600180c1d22e8ee0d2 Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Thu, 11 May 2023 02:46:22 +0100 Subject: [PATCH] @@@ tvec error return --- hash/t/hash-test.c | 3 +- test/t/tvec-test.c | 3 +- test/tvec-core.c | 115 ++++++++++++++-------- test/tvec-main.c | 56 +++++++---- test/tvec-output.c | 43 ++++---- test/tvec-types.c | 245 +++++++++++++++++++++++++++++----------------- test/tvec.h | 44 ++++----- utils/t/versioncmp-test.c | 3 +- 8 files changed, 312 insertions(+), 200 deletions(-) diff --git a/hash/t/hash-test.c b/hash/t/hash-test.c index 12d8222..6298b82 100644 --- a/hash/t/hash-test.c +++ b/hash/t/hash-test.c @@ -86,7 +86,7 @@ static int setup_unihash(const struct tvec_reg *in, struct tvec_reg *out, 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; @@ -100,6 +100,7 @@ static void run_step(struct tvec_state *tv) 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[] = { diff --git a/test/t/tvec-test.c b/test/t/tvec-test.c index 6bcf025..8b27f7f 100644 --- a/test/t/tvec-test.c +++ b/test/t/tvec-test.c @@ -135,7 +135,7 @@ struct test_context { 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; @@ -145,6 +145,7 @@ static void capture_state_and_run(struct tvec_state *tv) tv->in[RRC].f |= TVRF_LIVE; tv->out[RRC].f |= TVRF_LIVE; } tvec_check(tv, 0); + return (0); } static void test_serialization diff --git a/test/tvec-core.c b/test/tvec-core.c index dc2f8ab..3938397 100644 --- a/test/tvec-core.c +++ b/test/tvec-core.c @@ -29,6 +29,7 @@ #include #include +#include #include #include "alloc.h" @@ -37,10 +38,15 @@ /*----- 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, ...) { @@ -50,12 +56,14 @@ 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; @@ -63,7 +71,7 @@ void tvec_syntax_v(struct tvec_state *tv, int ch, switch (ch) { case EOF: strcpy(found, ""); break; - case '\n': 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); @@ -71,6 +79,7 @@ void tvec_syntax_v(struct tvec_state *tv, int 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, ...) @@ -235,7 +244,7 @@ int tvec_ensurebench(struct tvec_state *tv, struct bench_state **b_out) 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; @@ -266,7 +275,7 @@ end_2: end_1: if (r.ctx) xfree(r.ctx); end_0: - return; + return (0); } /*----- Main machinery ----------------------------------------------------*/ @@ -282,19 +291,21 @@ void tvec_skipspc(struct tvec_state *tv) } } -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; } } @@ -353,7 +364,7 @@ int tvec_readword_v(struct tvec_state *tv, dstr *d, const char *delims, 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, ' '); @@ -419,10 +430,10 @@ void tvec_check_v(struct tvec_state *tv, const char *detail, va_list *ap) #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) @@ -451,14 +462,17 @@ static void check(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); } @@ -497,13 +511,14 @@ static void end_test_group(struct tvec_state *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; @@ -515,18 +530,16 @@ void tvec_read(struct tvec_state *tv, const char *infile, FILE *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': @@ -538,19 +551,19 @@ void tvec_read(struct tvec_state *tv, const char *infile, FILE *fp) 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")) { @@ -558,46 +571,62 @@ void tvec_read(struct tvec_state *tv, const char *infile, FILE *fp) { 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"); } diff --git a/test/tvec-main.c b/test/tvec-main.c index ea597ad..aa36180 100644 --- a/test/tvec-main.c +++ b/test/tvec-main.c @@ -172,52 +172,68 @@ void tvec_parseargs(int argc, char *argv[], struct tvec_state *tv_out, tvec_begin(tv_out, info, o); *argpos_out = optind; } -void tvec_readstdin(struct tvec_state *tv) - { tvec_read(tv, "", stdin); } +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_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[], diff --git a/test/tvec-output.c b/test/tvec-output.c index af120d9..015013b 100644 --- a/test/tvec-output.c +++ b/test/tvec-output.c @@ -287,6 +287,7 @@ static const struct tvec_outops ..._ops = { #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; @@ -363,9 +364,10 @@ static void write_scoreboard_char(struct human_output *h, int ch) 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); @@ -397,11 +399,12 @@ static void report_location(struct human_output *h, FILE *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); @@ -412,20 +415,7 @@ static void human_report(struct human_output *h, 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) @@ -475,7 +465,12 @@ static int human_esession(struct tvec_output *o) } 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) @@ -651,7 +646,7 @@ static void human_destroy(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, @@ -751,9 +746,17 @@ static unsigned tap_grpix(struct tap_output *t) 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) { ; } diff --git a/test/tvec-types.c b/test/tvec-types.c index a5d57db..249371b 100644 --- a/test/tvec-types.c +++ b/test/tvec-types.c @@ -92,27 +92,33 @@ static int hex_width(unsigned long u) 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; @@ -120,29 +126,31 @@ static void parse_signed(long *i_out, const char *p, 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) @@ -153,7 +161,7 @@ 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; @@ -167,7 +175,7 @@ static void read_quoted_string(dstr *d, int quote, struct tvec_state *tv) reinsert: switch (ch) { case EOF: case '\n': - tvec_syntax(tv, ch, expect); + return (tvec_syntax(tv, ch, expect)); case '\\': if (quote == '\'') goto ordinary; @@ -191,16 +199,18 @@ static void read_quoted_string(dstr *d, int quote, struct tvec_state *tv) 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: @@ -212,12 +222,12 @@ static void read_quoted_string(dstr *d, int quote, struct tvec_state *tv) 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; @@ -231,6 +241,7 @@ static void read_quoted_string(dstr *d, int quote, struct tvec_state *tv) end: DPUTZ(d); + return (0); #undef f_brace } @@ -247,15 +258,16 @@ static int collect_bare(dstr *d, struct tvec_state *tv) 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; @@ -273,10 +285,9 @@ static int collect_bare(dstr *d, struct tvec_state *tv) 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, @@ -300,21 +311,21 @@ 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"); @@ -322,18 +333,24 @@ static void read_compound_string(void **p_inout, size_t *sz_inout, 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: @@ -349,7 +366,10 @@ done: 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 ----------------------------------------------------------*/ @@ -410,32 +430,40 @@ static int tobuf_uint(buf *b, const union tvec_regval *rv, 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, @@ -578,8 +606,8 @@ static int frombuf_enum(buf *b, 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) \ @@ -587,14 +615,16 @@ static void parse_enum(union tvec_regval *rv, const struct tvec_regdef *rd, 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)) @@ -607,11 +637,16 @@ static void parse_enum(union tvec_regval *rv, const struct tvec_regdef *rd, 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 @@ -619,11 +654,15 @@ static void parse_enum(union tvec_regval *rv, const struct tvec_regdef *rd, #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, @@ -720,31 +759,42 @@ TVEC_MISCSLOTS(DEFCLAIM) /*----- 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, @@ -869,30 +919,36 @@ static int frombuf_bytes(buf *b, 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, @@ -1064,19 +1120,20 @@ static int frombuf_buffer(buf *b, 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; @@ -1097,17 +1154,21 @@ static void parse_buffer(union tvec_regval *rv, } } 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 } diff --git a/test/tvec.h b/test/tvec.h index f6cbcc8..2309edf 100644 --- a/test/tvec.h +++ b/test/tvec.h @@ -183,6 +183,7 @@ struct tvec_state { #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 */ @@ -202,7 +203,7 @@ struct tvec_state { /*----- 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*/); @@ -221,14 +222,14 @@ extern void PRINTF_LIKE(2, 3) 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*/, @@ -252,9 +253,8 @@ extern void tvec_begin(struct tvec_state */*tv_out*/, 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 ------------------------------------------------------*/ @@ -273,7 +273,7 @@ extern struct bench_state *tvec_benchstate; 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 ----------------------------------------------------*/ @@ -331,14 +331,14 @@ extern void tvec_parseargs(int /*argc*/, char */*argv*/[], 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*/, @@ -383,21 +383,21 @@ struct tvec_outops { 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*/, ...); @@ -440,8 +440,8 @@ struct tvec_regty { 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*/); diff --git a/utils/t/versioncmp-test.c b/utils/t/versioncmp-test.c index 789565d..1368e00 100644 --- a/utils/t/versioncmp-test.c +++ b/utils/t/versioncmp-test.c @@ -37,7 +37,7 @@ static void test_versioncmp(const struct tvec_reg *in, struct tvec_reg *out, 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; @@ -46,6 +46,7 @@ static void swap_test(struct tvec_state *tv) 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 }; -- 2.11.0