chiark / gitweb /
@@@ tvec and tty mess
authorMark Wooding <mdw@distorted.org.uk>
Fri, 25 Apr 2025 17:08:35 +0000 (18:08 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Fri, 25 Apr 2025 17:18:26 +0000 (18:18 +0100)
20 files changed:
codec/baseconv.c
codec/null-codec.c
m4/mdw-probe-fltfmt.m4
mLib.supp [new file with mode: 0644]
mem/alloc.3.in
mem/sub.3.in
mem/sub.h
sel/sel.c
struct/dspool.h
struct/hash.3.in
test/tvec-bench.c
test/tvec-core.c
test/tvec-main.c
test/tvec-remote.c
test/tvec-timeout.c
test/tvec-types.c
test/tvec.h
ui/tty.c
utils/t/exc-test.c
utils/tests.at

index 53949bb8ddb0f2c492828d245a30cb7f1c9e749b..f3e2b3a3ce0caad8375304219ba8a3253b22b269 100644 (file)
@@ -427,7 +427,9 @@ static codec *ctxn##_docreate(unsigned flags,                               \
                              const char *encodemap,                    \
                              const signed char *decodemap)             \
 {                                                                      \
-  ctxn##_codec *bc = CREATE(ctxn##_codec);                             \
+  ctxn##_codec *bc;                                                    \
+                                                                       \
+  NEW(bc);                                                             \
   bc->c.ops = ops;                                                     \
   bc->ctx.acc = 0;                                                     \
   bc->ctx.qsz = (flags & ctxn##_FLAGMASK) ^ ctxn##_FLAGXOR;            \
index 1f5493edbdd26f838df2aa3a95269496fe83780c..eef1627af426b376ff0de80563e8e06def913412 100644 (file)
@@ -50,14 +50,18 @@ static const codec_ops ops = { &null_codec_class, encdec, destroy };
 
 static codec *encoder(unsigned flags, const char *indent, unsigned maxlen)
 {
-  null_codec *nc = CREATE(null_codec);
+  null_codec *nc;
+
+  NEW(nc);
   nc->c.ops = &ops;
   return (&nc->c);
 }
 
 static codec *decoder(unsigned flags)
 {
-  null_codec *nc = CREATE(null_codec);
+  null_codec *nc;
+
+  NEW(nc);
   nc->c.ops = &ops;
   return (&nc->c);
 }
index 736e8713075bbd344a11afa2dc4c9515f89cdb17..8d3d465c30fb331c5eab76f234012685d2a603e2 100644 (file)
@@ -291,7 +291,7 @@ int main(void)
        float) var=FLT ;;
        double) var=DBL ;;
        long-double) var=LDBL ;;
-       *) AC_MSG_ERROR([unexpected floating-point type \`$ty']) ;;
+       *) AC_MSG_ERROR([unexpected floating-point type `$ty']) ;;
      esac
      case $fmt in
        nil) value=UNKNOWN ;;
@@ -304,7 +304,7 @@ int main(void)
        ieee-f128-be) value=IEEE_F128_BE ;;
        intel-f80-le) value=INTEL_F80_LE ;;
        intel-f80-be) value=INTEL_F80_BE ;;
-       *) AC_MSG_ERROR([unexpected floating-point format \`$fmt']) ;;
+       *) AC_MSG_ERROR([unexpected floating-point format `$fmt']) ;;
      esac
      AC_DEFINE_UNQUOTED([${var}_FORMAT], [FLTFMT_$value])
    done])
diff --git a/mLib.supp b/mLib.supp
new file mode 100644 (file)
index 0000000..0e82a6a
--- /dev/null
+++ b/mLib.supp
@@ -0,0 +1,8 @@
+{
+       mLib-sub-chunks
+       Memcheck:Leak
+       match-leak-kinds: reachable
+       fun:malloc
+       fun:_alloc
+       fun:subarena_alloc
+}
index a9195bd9e32c37e30f3781fe4a554a79aa5eaa12..adf0d6fec40604dd6f8b52ff429a843588cf3fcc 100644 (file)
@@ -127,7 +127,7 @@ macro sets a pointer
 .I p
 to point to freshly allocated memory large enough for the type that
 .I p
-points to;
+points to.
 The
 .B X_NEWV
 macro sets
index 0382fe0fc263eab711e764f18f9327f866ab02c1..14a22db4815d09bc3a47a6e9cddb5c4ec8cb9871 100644 (file)
 .
 .\" @A_CREATE
 .\" @A_DESTROY
+.\" @A_SUBNEW
 .\" @CREATE
 .\" @DESTROY
+.\" @NEW
 .
 .\"--------------------------------------------------------------------------
 .SH NAME
@@ -57,15 +59,16 @@ sub \- efficient allocation and freeing of small blocks
 .BI "void subarena_create(subarena *" s ", arena *" a );
 .BI "void subarena_destroy(subarena *" s );
 .BI "void subarena_alloc(subarena *" s ", size_t " sz );
+.BI "void *A_CREATE(subarena *" s ", " type );
+.BI "A_SUBNEW(" type "* " p ", subarena *" s );
 .BI "void subarena_free(subarena *" s ", void *" p ", size_t " sz );
+.BI "void A_DESTROY(subarena *" s ", " type " *" p );
 .PP
 .B "void sub_init(void);"
 .BI "void *sub_alloc(size_t " sz );
-.BI "void sub_free(void *" p ", size_t " sz );
-.PP
-.BI "void *A_CREATE(subarena *" s ", " type );
-.BI "void A_DESTROY(subarena *" s ", " type " *" p );
 .BI "void *CREATE(" type );
+.BI "NEW(" type "* " p );
+.BI "void sub_free(void *" p ", size_t " sz );
 .BI "void DESTROY(" type " *" p );
 .fi
 .
@@ -118,8 +121,9 @@ function using
 .BR subarena_free .
 If you do, you'll get what you deserve.
 .PP
-The pair of macros
-.B A_CREATE
+The macros
+.BR A_CREATE ,
+.BR A_SUBNEW ,
 and
 .B A_DESTROY
 are intended to provide a slightly more natural interface to
@@ -129,7 +133,12 @@ mystruct *p = subarena_alloc(s, sizeof(mystruct));
 .VE
 can be replaced by
 .VS
-mystruct p = A_CREATE(s, mystruct);
+mystruct *p = A_CREATE(s, mystruct);
+.VE
+or
+.VS
+mystruct *p;
+A_SUBNEW(p, s);
 .VE
 Similarly, the block can be freed by saying
 .VS
@@ -149,7 +158,8 @@ used).  The functions
 and
 .B sub_free
 and the macros
-.B CREATE
+.BI CREATE ,
+.BI NEW
 and
 .B DESTROY
 use this subarena.
index 1dddd194b1f10217e0d9856b96d889f320697421..661341e52f78d571644f01a77aa83ddfcb288870 100644 (file)
--- a/mem/sub.h
+++ b/mem/sub.h
@@ -168,6 +168,21 @@ extern void subarena_free(subarena */*s*/, void */*p*/, size_t /*sz*/);
 
 #define A_CREATE(a, type) subarena_alloc((a), sizeof(type))
 
+/* --- @A_SUBNEW@ --- *
+ *
+ * Arguments:  @type *p@ = a pointer to allocate
+ *             @subarena *s@ = pointer to arena
+ *
+ * Returns:    ---
+ *
+ * Use:                Set @p@ to point to a freshly allocated block large enough to
+ *             hold an object of the type pointed to by @p@.  If there is
+ *             not enough memory, the exception @EXC_NOMEM@ is thrown.
+ */
+
+#define A_SUBNEW(p, a)                                                 \
+       do { (p) = subarena_alloc((a), sizeof(*(p))); } while (0)
+
 /* --- @A_DESTROY@ --- *
  *
  * Arguments:  @subarena *s@ = pointer to arena
@@ -220,6 +235,19 @@ extern void sub_free(void */*p*/, size_t /*sz*/);
 
 #define CREATE(type) sub_alloc(sizeof(type))
 
+/* --- @NEW@ --- *
+ *
+ * Arguments:  @type *p@ = a pointer to allocate
+ *
+ * Returns:    ---
+ *
+ * Use:                Set @p@ to point to a freshly allocated block large enough to
+ *             hold an object of the type pointed to by @p@.  If there is
+ *             not enough memory, the exception @EXC_NOMEM@ is thrown.
+ */
+
+#define NEW(p) do { (p) = sub_alloc(sizeof(*(p))); } while (0)
+
 /* --- @DESTROY@ --- *
  *
  * Arguments:  @void *p@ = pointer to an object
index a0d9ed3549aa5101dd3f9a66189d62cb2966e9f1..8ccf862b554cd7a6bbd49ed930368bd3ec004575 100644 (file)
--- a/sel/sel.c
+++ b/sel/sel.c
@@ -379,7 +379,7 @@ int sel_select(sel_state *s)
     sel_timer *t;
 
     for (t = s->timers; t && TV_CMP(&t->tv, <=, &a.now); t = t->next) {
-      pt = CREATE(ptimer);
+      NEW(pt);
       pt->t = t;
       t->pend = pt;
       *ptt = pt;
@@ -422,7 +422,7 @@ int sel_select(sel_state *s)
       for (f = s->files[i]; f; f = f->next) {
        if (!FD_ISSET(f->fd, &a.fd[i]))
          continue;
-       pf = CREATE(pfile);
+       NEW(pf);
        pf->f = f;
        f->pend = pf;
        *pff = pf;
index 47ca6e291bb2ed38ead873c605cb2d34a740c6b7..0e1c09343e7c378dce5ca8734ee83c05e58b6706 100644 (file)
@@ -101,7 +101,7 @@ extern dstr *dspool_get(dspool */*p*/);
     _s = _p->free;                                                     \
     _p->free = _s->next;                                               \
   } else {                                                             \
-    _s = CREATE(dspoolstr);                                            \
+    NEW(_s);                                                           \
     DCREATE(&_s->ds);                                                  \
     if (_p->isz)                                                       \
       DENSURE(&_s->ds, _p->isz);                                       \
index 41258fa701f181c4667359d40082246c36a1a20f..98d853bacec5b3fa267ee7e24a498e6eaebb6979 100644 (file)
@@ -270,7 +270,7 @@ item *add(item_table *t, const char *k, /* ... */)
 .VP
        /* --- Make a new hashtable item --- */
 .VP
-       i = CREATE(item);
+       NEW(i);
        i->k = xstrdup(k);
        /* ... */
 .VP
index c4e123d50c0c7ebab93afdd9787703e4797eac6b..62012193c9151b7262d2dadf576429327202d67a 100644 (file)
@@ -261,8 +261,10 @@ void tvec_benchsetup(struct tvec_state *tv, const struct tvec_env *env,
   bc->be = be; bc->bst = 0; bc->subctx = 0;
   if (!tvec_benchprep(tv, be->bst, BTF_INDIRECT))
     { bc->bst = *be->bst; bc->dflt_target = bc->bst->target_s; }
-  if (subenv && subenv->ctxsz) bc->subctx = x_alloc(tv->a, subenv->ctxsz);
-  if (subenv && subenv->setup) subenv->setup(tv, subenv, bc, bc->subctx);
+  if (subenv && subenv->ctxsz)
+    bc->subctx = pool_alloc(tv->p_group, subenv->ctxsz);
+  if (subenv && subenv->setup)
+    subenv->setup(tv, subenv, bc, bc->subctx);
 }
 
 /* --- @tvec_benchfindvar@, @setvar@ --- *
@@ -438,7 +440,6 @@ void tvec_benchteardown(struct tvec_state *tv, void *ctx)
 
   /* Tear down any subsidiary environment. */
   if (subenv && subenv->teardown) subenv->teardown(tv, bc->subctx);
-  if (bc->subctx) x_free(tv->a, bc->subctx);
 
   /* If the benchmark state was temporary, then dispose of it. */
   if (bc->bst) {
index 7a65c519f1cb4a44a12a1a567c402182d605aea4..7aced9757be9e1a487f7565cdb94906930b2fa1a 100644 (file)
@@ -901,6 +901,7 @@ void tvec_endtest(struct tvec_state *tv)
   assert(out < TVOUT_LIMIT); tv->curr[out]++;
   tv->output->ops->etest(tv->output, out);
   tv->f &= ~TVSF_OPEN;
+  pool_recycle(tv->p_test);
 }
 
 /* --- @tvec_xfail@ --- *
@@ -1013,7 +1014,7 @@ static void begin_test_group(struct tvec_state *tv, struct groupstate *g)
   tv->f &= ~(TVSF_SKIP | TVSF_MUFFLE);
   tvec_initregs(tv);
   for (i = 0; i < TVOUT_LIMIT; i++) tv->curr[i] = 0;
-  if (env && env->ctxsz) g->ctx = x_alloc(tv->a, env->ctxsz);
+  if (env && env->ctxsz) g->ctx = pool_alloc(tv->p_group, env->ctxsz);
   if (env && env->setup) env->setup(tv, env, 0, g->ctx);
 }
 
@@ -1073,7 +1074,7 @@ static void end_test_group(struct tvec_state *tv, struct groupstate *g)
   if (tv->f&TVSF_OPEN) check(tv, g);
   if (!(tv->f&TVSF_SKIP)) report_group(tv);
   env = t->env; if (env && env->teardown) env->teardown(tv, g->ctx);
-  tvec_releaseregs(tv); tv->test = 0; x_free(tv->a, g->ctx); g->ctx = 0;
+  tvec_releaseregs(tv); tv->test = 0; g->ctx = 0; pool_recycle(tv->p_group);
 }
 
 /* --- @core_findvar@, @core_setvar@ --- *
@@ -1427,6 +1428,9 @@ void tvec_begin(struct tvec_state *tv_out,
   /* General setup. */
   tv_out->f = 0;
   tv_out->a = arena_global;
+  tv_out->p_session = pool_create(tv_out->a);
+  tv_out->p_group = pool_sub(tv_out->p_session);
+  tv_out->p_test = pool_sub(tv_out->p_session);
 
   /* Run sanity checks on the test configuration. */
   bad = 0;
@@ -1475,8 +1479,10 @@ void tvec_begin(struct tvec_state *tv_out,
     /* Standard initialization for file-directed testing. */
 
     tv_out->cfg = *config;
-    tv_out->in = x_allocv(tv_out->a, tv_out->cfg.nreg, tv_out->cfg.regsz);
-    tv_out->out = x_allocv(tv_out->a, tv_out->cfg.nrout, tv_out->cfg.regsz);
+    tv_out->in = pool_allocv(tv_out->p_session,
+                            tv_out->cfg.nreg, tv_out->cfg.regsz);
+    tv_out->out = pool_allocv(tv_out->p_session,
+                             tv_out->cfg.nrout, tv_out->cfg.regsz);
     for (i = 0; i < tv_out->cfg.nreg; i++) {
       TVEC_REG(tv_out, in, i)->f = 0;
       if (i < tv_out->cfg.nrout) TVEC_REG(tv_out, out, i)->f = 0;
@@ -1522,7 +1528,7 @@ int tvec_end(struct tvec_state *tv)
 
   if (tv->test) tvec_releaseregs(tv);
   tv->output->ops->destroy(tv->output);
-  x_free(tv->a, tv->in); x_free(tv->a, tv->out);
+  pool_destroy(tv->p_session);
   return (rc);
 }
 
@@ -1674,7 +1680,7 @@ void tvec_begingroup(struct tvec_state *tv, const char *name,
 void tvec_endgroup(struct tvec_state *tv)
 {
   if (!(tv->f&TVSF_SKIP)) report_group(tv);
-  tv->test = 0;
+  tv->test = 0; pool_recycle(tv->p_group);
 }
 
 /* --- @tvec_begintest@ --- *
index f2ba9cad36b0a9c1d83ff60f89c7aaa7f48ecf1f..05662927832a183a23125971950039279d148e41 100644 (file)
@@ -141,6 +141,18 @@ Automake driver options:\n\
 ", fp);
 }
 
+struct bench_resource {
+  pool_resource r;
+  struct bench_state **bst;
+};
+
+static void release_bench(pool_resource *r)
+{
+  struct bench_resource *br = (struct bench_resource *)r;
+
+  if (*br->bst) { bench_destroy(*br->bst); *br->bst = 0; }
+}
+
 /* --- @tvec_parseargs@ --- *
  *
  * Arguments:  @int argc@ = number of command-line arguments
@@ -170,6 +182,7 @@ void tvec_parseargs(int argc, char *argv[], struct tvec_state *tv_out,
   struct tvec_amargs am;
   double benchtime = 1.0, scale;
   struct bench_timer *tm;
+  struct bench_resource *br;
   const char *p; char *q;
   int opt;
   unsigned f = 0;
@@ -306,6 +319,9 @@ void tvec_parseargs(int argc, char *argv[], struct tvec_state *tv_out,
   }
 
   tvec_begin(tv_out, config, o); *argpos_out = optind;
+  POOL_NEW(br, tv_out->p_session);
+  br->bst = &tvec_benchstate;
+  POOL_ADD(tv_out->p_session, &br->r, release_bench);
 
 #undef f_bogus
 #undef f_bench
index 637f851efde34a2f00cc3c4a73286874671b246b..7fbd1b6e1fc21e80a8811ea02cb5dad02e3c98fc 100644 (file)
@@ -667,7 +667,7 @@ int tvec_remoteserver(int infd, int outfd, const struct tvec_config *config)
        if (env && env->setup == tvec_remotesetup)
          env = ((struct tvec_remoteenv *)env)->r.env;
        if (!env || !env->ctxsz) ctx = 0;
-       else ctx = x_alloc(srvtv.a, env->ctxsz);
+       else ctx = pool_alloc(srvtv.p_group, env->ctxsz);
        if (env && env->setup) env->setup(&srvtv, env, 0, ctx);
 
        /* Initialize the registers. */
@@ -803,7 +803,7 @@ int tvec_remoteserver(int infd, int outfd, const struct tvec_config *config)
        /* Tear down the environment and release other resources. */
        if (env && env->teardown) env->teardown(&srvtv, ctx);
        tvec_releaseregs(&srvtv);
-       x_free(srvtv.a, ctx); srvtv.test = 0; env = 0; ctx = 0;
+       srvtv.test = 0; env = 0; ctx = 0; pool_recycle(srvtv.p_group);
 
        /* Report completion. */
        QUEUEPK(&srvtv, &srvrc, QF_FORCE, TVPK_EGROUP | TVPF_ACK);
@@ -821,7 +821,7 @@ end:
   /* Clean up and return. */
   if (env && env->teardown) env->teardown(&srvtv, ctx);
   if (vd) vd->def.ty->release(&r->v, &vd->def);
-  x_free(srvtv.a, ctx); x_free(srvtv.a, r_alloc);
+  x_free(srvtv.a, r_alloc); dstr_destroy(&d);
   if (srvtv.test) tvec_releaseregs(&srvtv);
   release_comms(&srvtv, &srvrc); tvec_end(&srvtv);
   return (rc ? 2 : 0);
@@ -1932,16 +1932,17 @@ void tvec_remotesetup(struct tvec_state *tv, const struct tvec_env *env,
   const struct tvec_remoteenv *re = (const struct tvec_remoteenv *)env;
   const struct tvec_env *subenv = re->r.env;
 
-  r->tv = tv;
+  r->tv = tv; r->subctx = 0;
   init_comms(&r->rc);
   r->re = re; r->kid = -1;
   DCREATE(&r->prgwant); DCREATE(&r->progress);
   if (connect_remote(tv, r))
     tvec_skipgroup(tv, "failed to connect to test backend");
   reset_vars(r);
-  if (subenv && subenv->ctxsz) r->subctx = x_alloc(tv->a, subenv->ctxsz);
-  else r->subctx = 0;
-  if (subenv && subenv->setup) subenv->setup(tv, subenv, r, r->subctx);
+  if (subenv && subenv->ctxsz)
+    r->subctx = pool_alloc(tv->p_group, subenv->ctxsz);
+  if (subenv && subenv->setup)
+    subenv->setup(tv, subenv, r, r->subctx);
 }
 
 /* --- @tvec_remotefindvar@, @setvar_local@, @setvar_remote@ --- *
@@ -2212,7 +2213,6 @@ void tvec_remoteteardown(struct tvec_state *tv, void *ctx)
   buf b;
 
   if (subenv && subenv->teardown) subenv->teardown(tv, r->subctx);
-  x_free(tv->a, r->subctx);
   if (r->rc.outfd >= 0) {
     QUEUEPK(tv, &r->rc, QF_FORCE, TVPK_EGROUP);
     if (!handle_packets(tv, r, RCVF_ALLOWEOF, TVPK_EGROUP | TVPF_ACK, &b))
index 778673eadb9d6322ff0e12906f6989044e742430..e7b23b51fad1bbb31906e718d17525edd25d190b 100644 (file)
@@ -74,8 +74,10 @@ void tvec_timeoutsetup(struct tvec_state *tv, const struct tvec_env *env,
 
   reset(tc);
 
-  if (subenv && subenv->ctxsz) tc->subctx = x_alloc(tv->a, subenv->ctxsz);
-  else tc->subctx = 0;
+  if (subenv && subenv->ctxsz)
+    tc->subctx = pool_alloc(tv->p_group, subenv->ctxsz);
+  else
+    tc->subctx = 0;
   if (subenv && subenv->setup) subenv->setup(tv, subenv, tc, tc->subctx);
 }
 
@@ -247,7 +249,6 @@ void tvec_timeoutteardown(struct tvec_state *tv, void *ctx)
 
   /* Just call the subsidiary environment. */
   if (subenv && subenv->teardown) subenv->teardown(tv, tc->subctx);
-  x_free(tv->a, tc->subctx);
 }
 
 /*----- That's all, folks -------------------------------------------------*/
index 70ce87aad71d29441d5c7482758c3935d9ae9c09..3c6005768f3175bc198e2b6d3af102154426b84c 100644 (file)
@@ -452,6 +452,7 @@ static int parse_szint(struct tvec_state *tv, unsigned long *u_out,
   unsigned f = 0;
 #define f_range 1u
 
+  d.a = &tv->p_test->a;
   if (tvec_readword(tv, &d, 0, delims, what)) { rc = -1; goto end; }
   p = d.buf;
   if (parse_unsigned_integer(&u, &p, p)) goto bad;
@@ -470,7 +471,6 @@ static int parse_szint(struct tvec_state *tv, unsigned long *u_out,
 
   *u_out = u; rc = 0;
 end:
-  dstr_destroy(&d);
   return (rc);
 
 bad:
@@ -680,6 +680,8 @@ static int parse_floating(double *x_out, const char **q_out, const char *p,
   double x;
   int olderr, rc;
 
+  d.a = &tv->p_test->a;
+
   /* Check for special tokens. */
   if (STRCMP(p, ==, "#nan")) {
 #ifdef NAN
@@ -770,7 +772,6 @@ static int parse_floating(double *x_out, const char **q_out, const char *p,
   /* All done. */
   *x_out = x; rc = 0;
 end:
-  dstr_destroy(&d);
   return (rc);
 }
 
@@ -1276,6 +1277,7 @@ static int read_compound_string(void **p_inout, size_t *sz_inout,
   int ch, err, rc;
 
   set_up_encoding(&ccl, &cdf, code); cdc = 0;
+  d.a = w.a = &tv->p_test->a;
 
   if (tvec_nexttoken(tv)) return (tvec_syntax(tv, fgetc(tv->fp), "string"));
   do {
@@ -1361,7 +1363,7 @@ static int read_compound_string(void **p_inout, size_t *sz_inout,
            dstr_ensure(&d, n);
            fill_pattern(d.buf + d.len, n, pp, sz); d.len += n;
          }
-         xfree(pp); pp = 0;
+         free(pp); pp = 0;
        }
 
        /* Anything else is an error. */
@@ -1410,7 +1412,7 @@ done:
 end:
   /* Clean up any debris. */
   if (cdc) cdc->ops->destroy(cdc);
-  if (pp) xfree(pp);
+  if (pp) free(pp);
   dstr_destroy(&d); dstr_destroy(&w);
   return (rc);
 }
@@ -1559,12 +1561,12 @@ static int parse_int(union tvec_regval *rv, const struct tvec_regdef *rd,
   dstr d = DSTR_INIT;
   int rc;
 
+  d.a = &tv->p_test->a;
   if (tvec_readword(tv, &d, 0, ";", "signed integer"))
     { rc = -1; goto end; }
   if (parse_signed(&rv->i, d.buf, rd->arg.p, tv)) { rc = -1; goto end; }
   rc = 0;
 end:
-  dstr_destroy(&d);
   return (rc);
 }
 
@@ -1574,12 +1576,12 @@ static int parse_uint(union tvec_regval *rv, const struct tvec_regdef *rd,
   dstr d = DSTR_INIT;
   int rc;
 
+  d.a = &tv->p_test->a;
   if (tvec_readword(tv, &d, 0, ";", "unsigned integer"))
     { rc = -1; goto end; }
   if (parse_unsigned(&rv->u, d.buf, rd->arg.p, tv)) { rc = -1; goto end; }
   rc = 0;
 end:
-  dstr_destroy(&d);
   return (rc);
 }
 
@@ -1922,13 +1924,13 @@ static int parse_float(union tvec_regval *rv, const struct tvec_regdef *rd,
   dstr d = DSTR_INIT;
   int rc;
 
+  d.a = &tv->p_test->a;
   if (tvec_readword(tv, &d, 0, ";", "floating-point number"))
     { rc = -1; goto end; }
   if (parse_floating(&rv->f, 0, d.buf, rd->arg.p, tv))
     { rc = -1; goto end; }
   rc = 0;
 end:
-  dstr_destroy(&d);
   return (rc);
 }
 
@@ -2173,6 +2175,7 @@ static int parse_duration(union tvec_regval *rv,
   double t;
   int rc;
 
+  d.a = &tv->p_test->a;
   if (tvec_readword(tv, &d, 0, ";", "duration")) { rc = -1; goto end; }
   if (parse_floating(&t, &q, d.buf,
                     rd->arg.p ? rd->arg.p : &tvflt_nonneg, tv))
@@ -2188,7 +2191,6 @@ static int parse_duration(union tvec_regval *rv,
 
   rv->f = t; rc = 0;
 end:
-  dstr_destroy(&d);
   return (rc);
 }
 
@@ -2470,6 +2472,7 @@ static int frombuf_penum(buf *b, union tvec_regval *rv,
     dstr d = DSTR_INIT;                                                        \
     int rc;                                                            \
                                                                        \
+    d.a = &tv->p_test->a;                                              \
     if (tvec_readword(tv, &d, 0,                                       \
                      ";", "%s tag or " LITSTR_##tag_, ei->name))       \
       { rc = -1; goto end; }                                           \
@@ -2479,7 +2482,6 @@ static int frombuf_penum(buf *b, union tvec_regval *rv,
     done:                                                              \
     rc = 0;                                                            \
   end:                                                                 \
-    dstr_destroy(&d);                                                  \
     return (rc);                                                       \
   }
 
@@ -2653,6 +2655,9 @@ static const struct tvec_iassoc cmp_assoc[] = {
 const struct tvec_ienuminfo tvenum_cmp =
   { "cmp", cmp_assoc, &tvrange_int };
 
+static const struct tvec_passoc dummy_assoc[] = { TVEC_ENDENUM };
+static const struct tvec_penuminfo dummy_peinfo = { "pointer", dummy_assoc };
+
 /* --- @tvec_claimeq_tenum@ --- *
  *
  * Arguments:  @struct tvec_state *tv@ = test-vector state
@@ -2680,21 +2685,31 @@ const struct tvec_ienuminfo tvenum_cmp =
          union tvec_misc arg;                                          \
          struct tvec_reg rval, rref;                                   \
                                                                        \
+         PREFLIGHT_##tag;                                              \
          arg.p = ei;                                                   \
          rval.f = rref.f = TVRF_LIVE;                                  \
          rval.v.slot = GET_##tag(e0); rref.v.slot = GET_##tag(e1);     \
          return (tvec_claimeq(tv, &tvty_##slot##enum, &arg,            \
                               &rval, &rref, file, lno, expr));         \
        }
+#define PREFLIGHT_INT do ; while (0)
 #define GET_INT(e) (e)
+#define PREFLIGHT_UINT do ; while (0)
 #define GET_UINT(e) (e)
+#define PREFLIGHT_FLT do ; while (0)
 #define GET_FLT(e) (e)
+#define PREFLIGHT_PTR                                                  \
+       if (!ei) ei = &dummy_peinfo
 #define GET_PTR(e) (UNCONST(void, (e)))
 TVEC_MISCSLOTS(DEFCLAIM)
 #undef DEFCLAIM
+#undef PREFLIGHT_INT
 #undef GET_INT
+#undef PREFLIGHT_UINT
 #undef GET_UINT
+#undef PREFLIGHT_FLT
 #undef GET_FLT
+#undef PREFLIGHT_PTR
 #undef GET_PTR
 
 /*----- Flag types --------------------------------------------------------*/
@@ -2729,6 +2744,8 @@ static int parse_flags(union tvec_regval *rv, const struct tvec_regdef *rd,
   dstr d = DSTR_INIT;
   int ch, rc;
 
+  d.a = &tv->p_test->a;
+
   for (;;) {
 
     /* Read the next item. */
@@ -2746,9 +2763,9 @@ static int parse_flags(union tvec_regval *rv, const struct tvec_regdef *rd,
       }
 
     /* Otherwise, try to parse it as a raw integer. */
-    if (parse_unsigned(&t, d.buf, fi->range, tv))
-      { rc = -1; goto end; }
-    v |= t;
+    if (parse_unsigned(&t, d.buf, fi->range, tv)) { rc = -1; goto end; }
+    if (m&t) { tvec_error(tv, "colliding flag setting"); rc = -1; goto end; }
+    v |= t; m |= t;
 
   next:
     /* Advance to the next token.  If it's a separator then consume it, and
@@ -2766,7 +2783,6 @@ static int parse_flags(union tvec_regval *rv, const struct tvec_regdef *rd,
   /* Done. */
   rv->u = v; rc = 0;
 end:
-  dstr_destroy(&d);
   return (rc);
 }
 
@@ -2853,6 +2869,7 @@ int tvec_claimeq_flags(struct tvec_state *tv,
   union tvec_misc arg;
   struct tvec_reg rval, rref;
 
+  arg.p = fi;
   rval.f = rref.f = TVRF_LIVE; rval.v.u = f0; rref.v.u = f1;
   return (tvec_claimeq(tv, &tvty_flags, &arg,
                       &rval, &rref, file, lno, expr));
@@ -2990,6 +3007,8 @@ static int parse_char(union tvec_regval *rv, const struct tvec_regdef *rd,
   unsigned f = 0;
 #define f_quote 1u
 
+  d.a = &tv->p_test->a;
+
   /* Advance until we find something. */
   if (tvec_nexttoken(tv))
     return (tvec_syntax(tv, fgetc(tv->fp), "character"));
@@ -3062,7 +3081,6 @@ static int parse_char(union tvec_regval *rv, const struct tvec_regdef *rd,
   /* Done. */
   rc = 0;
 end:
-  dstr_destroy(&d);
   return (rc);
 
 #undef f_quote
index 8a185393e8b84c3ec03cfb79b87fa0583509147f..3d483b91b4db1c7c36742a3d18661ebf633562b0 100644 (file)
 #  include "macros.h"
 #endif
 
+#ifndef MLIB_POOL_H
+#  include "pool.h"
+#endif
+
 /*----- Miscellaneous values ----------------------------------------------*/
 
 /* These are attached to structures which represent extension points, as a
@@ -483,6 +487,7 @@ struct tvec_state {
 
   /* Memory allocation.  Read-only for all callers. */
   arena *a;
+  pool *p_session, *p_group, *p_test;  /* allocation pools */
 
   /* Test configuration.  Read-only for all callers. */
   struct tvec_config cfg;              /* test configuration */
@@ -508,7 +513,7 @@ struct tvec_state {
 
   /* Adhoc testing state.  Private. */
   struct tvec_test adhoc_test;
-  const struct tvec_test *adhoc_tests[];
+  const struct tvec_test *adhoc_tests[2];
 };
 
 /* @TVEC_REG(tv, vec, i)@
index ff24256cb4b240a4054ee9e8cb6e54a92a1f6e7c..b65f6b744b00595319ef697719cdfe5d92185b4c 100644 (file)
--- a/ui/tty.c
+++ b/ui/tty.c
@@ -2565,13 +2565,13 @@ static struct tty *ansi_init(FILE *fp)
 
   static const struct kw { const char *name; uint32 val; }
     kw_colours[] = {
-      { "no",                  COLS_NO },
-      { "8",                   COLS_8 },
-      { "16",                  COLS_16 },
-      { "88",                  COLS_88 },
-      { "256",                 COLS_256 },
-      { "16m",                 COLS_16M },
-      { 0,                     0 }
+      { "no",          COLS_NO },
+      { "8",           COLS_8 },
+      { "16",          COLS_16 },
+      { "88",          COLS_88 },
+      { "256",         COLS_256 },
+      { "16m",         COLS_16M },
+      { 0,             0 }
     };
 
   static const struct enummap {
@@ -2579,8 +2579,9 @@ static struct tty *ansi_init(FILE *fp)
     uint32 mask;
     const struct kw *kw;
   } enummap[] = {
-    { "colours",               TTACF_CSPCMASK,         kw_colours },
-    { 0,                       0,                      0 }
+    { "colours",       TTACF_CSPCMASK | TTACF_FG | TTACF_BG,
+                                                       kw_colours },
+    { 0,               0,                              0 }
   };
 
 
@@ -2807,9 +2808,15 @@ struct tty *tty_open(FILE *fp, unsigned f, const unsigned *backends)
     const char *name; unsigned code;
     struct tty *(*init)(FILE */*fp*/);
   } betab[] = {
+#ifdef HAVE_UNIBILIUM
     { "unibilium",     TTBK_UNIBI,     termunibi_init },
+#endif
+#ifdef HAVE_TERMINFO
     { "terminfo",      TTBK_TERMINFO,  terminfo_init },
+#endif
+#ifdef HAVE_TERMCAP
     { "termcap",       TTBK_TERMCAP,   termcap_init },
+#endif
     { "ansi",          TTBK_ANSI,      ansi_init },
     { 0,               0,              0 }
   };
index 89701bfd223b66580e69901bf450fa38aa61acd7..69fa8cdb26d60bb7901f2e94f54d65938501fb63 100644 (file)
@@ -1,44 +1,65 @@
 #include <stdio.h>
+
 #include "exc.h"
+#include "macros.h"
+#include "report.h"
+#include "tvec.h"
+#include "tvec-adhoc.h"
+#include "tvec-types.h"
+
+static struct tvec_state tvstate;
+static int step;
 
-void func(void)
+#define TESTGROUP(name)                                                        \
+       TVEC_TESTGROUP_TAG(grp, &tvstate, name)                         \
+       MC_BEFORE(init, { step = 0; })
+#define TEST TVEC_TEST_TAG(test, &tvstate)
+#define STEP(s) do {                                                   \
+         tvec_claim(&tvstate, s == step, __FILE__, __LINE__,           \
+                    "found %d /= expected %d", s, step);               \
+         step++;                                                       \
+       } while (0)
+#define MISSTEP do {                                                   \
+         tvec_claim(&tvstate, 0, __FILE__, __LINE__,                   \
+                    "shouldn't have reached here");                    \
+         step++;                                                       \
+       } while (0)
+
+static void func(void)
 {
-  printf("cabbage\n");
-  TRY {
-    printf("dibble\n");
-    THROW(EXC_FAIL, "excession");
-    printf("can't see me\n");
-  } CATCH switch (exc_type) {
-    case 1:
-      printf("exc type 1 (not possible)\n");
-      break;
-    case EXC_FAIL:
-      printf("exc type 2 (%s)\n", exc_s);
-      break;
-    default:
-      RETHROW;
+  TRY { STEP(2); THROW(EXC_FAIL, "excession"); MISSTEP; }
+  CATCH switch (exc_type) {
+    case EXC_FAIL: TVEC_CLAIMEQ_TEXTZ(&tvstate, exc_s, "excession"); break;
+    default: MISSTEP; break;
   } END_TRY;
 
-  printf("fennel\n");
-  THROW(EXC_ERRNO, 53);
+  TRY { STEP(3); THROW(EXC_ERRNO, 53); }
+  CATCH switch (exc_type) {
+    case EXC_ERRNO: RETHROW;
+    default: MISSTEP; break;
+  } END_TRY;
+  MISSTEP;
 }
 
-int main(void)
+int main(int argc, char *argv[])
 {
-  printf("apple\n");
-  TRY {
-    printf("banana\n");
-    func();
-    printf("can't see me\n");
-  } CATCH switch (exc_type) {
-    default:
-      printf("%lu exception (val = %i)\n", exc_type, exc_i);
-      break;
-  } END_TRY;
-  printf("hello! __exc_list = ");
-  if (__exc_list) printf("%p", (void *)__exc_list);
-  else printf("(nil)");
-  putchar('\n');
+  int argpos;
+
+  tvec_parseargs(argc, argv, &tvstate, &argpos, &tvec_adhocconfig);
+  if (argpos < argc) die(2, "no input files expected");
+
+  TESTGROUP("flow") {
+    STEP(0);
+    TRY { STEP(1); func(); MISSTEP; }
+    CATCH switch (exc_type) {
+      case EXC_ERRNO: STEP(4); TVEC_CLAIMEQ_INT(&tvstate, exc_i, 53); break;
+      default: MISSTEP;
+    } END_TRY;
+    STEP(5);
+  }
+
+  TESTGROUP("final")
+    TVEC_CLAIMEQ_PTR(&tvstate, __exc_list, 0);
 
-  return (0);
+  return (tvec_end(&tvstate));
 }
index a19d4c02e66096f0e72670d5714e59a3b72816bf..ce8bcc4d9f651748867cf6bb0987c657f6063fa1 100644 (file)
@@ -43,17 +43,7 @@ AT_CLEANUP
 ## exc
 AT_SETUP([utilities: exc])
 AT_KEYWORDS([utils exc])
-AT_DATA([expout],
-[apple
-banana
-cabbage
-dibble
-exc type 2 (excession)
-fennel
-65 exception (val = 53)
-hello! __exc_list = (nil)
-])
-AT_CHECK([BUILDDIR/t/exc.t], [0], [expout])
+AT_CHECK([BUILDDIR/t/exc.t -fh], [0], [ignore])
 AT_CLEANUP
 
 ## fltfmt