@@@ tvec error return
authorMark Wooding <mdw@distorted.org.uk>
Thu, 11 May 2023 01:46:22 +0000 (02:46 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Thu, 11 May 2023 01:46:22 +0000 (02:46 +0100)
hash/t/hash-test.c
test/t/tvec-test.c
test/tvec-core.c
test/tvec-main.c
test/tvec-output.c
test/tvec-types.c
test/tvec.h
utils/t/versioncmp-test.c

index 12d8222..6298b82 100644 (file)
@@ -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[] = {
index 6bcf025..8b27f7f 100644 (file)
@@ -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
index dc2f8ab..3938397 100644 (file)
@@ -29,6 +29,7 @@
 
 #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, ...)
 {
@@ -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, "<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);
@@ -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"); }
index ea597ad..aa36180 100644 (file)
@@ -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>", 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[],
index af120d9..015013b 100644 (file)
@@ -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) { ; }
index a5d57db..249371b 100644 (file)
@@ -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
 }
index f6cbcc8..2309edf 100644 (file)
@@ -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*/);
index 789565d..1368e00 100644 (file)
@@ -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 };