From: Mark Wooding Date: Fri, 25 Apr 2025 17:08:35 +0000 (+0100) Subject: @@@ tvec and tty mess X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/mLib/commitdiff_plain/a077a9a931a4b81abf0f549d7f463ae75075149a?hp=43f490c377cb05d1ac6e7d2c27a06ae940e2c047 @@@ tvec and tty mess --- diff --git a/codec/baseconv.c b/codec/baseconv.c index 53949bb..f3e2b3a 100644 --- a/codec/baseconv.c +++ b/codec/baseconv.c @@ -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; \ diff --git a/codec/null-codec.c b/codec/null-codec.c index 1f5493e..eef1627 100644 --- a/codec/null-codec.c +++ b/codec/null-codec.c @@ -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); } diff --git a/m4/mdw-probe-fltfmt.m4 b/m4/mdw-probe-fltfmt.m4 index 736e871..8d3d465 100644 --- a/m4/mdw-probe-fltfmt.m4 +++ b/m4/mdw-probe-fltfmt.m4 @@ -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 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 +} diff --git a/mem/alloc.3.in b/mem/alloc.3.in index a9195bd..adf0d6f 100644 --- a/mem/alloc.3.in +++ b/mem/alloc.3.in @@ -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 diff --git a/mem/sub.3.in b/mem/sub.3.in index 0382fe0..14a22db 100644 --- a/mem/sub.3.in +++ b/mem/sub.3.in @@ -39,8 +39,10 @@ . .\" @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. diff --git a/mem/sub.h b/mem/sub.h index 1dddd19..661341e 100644 --- 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 diff --git a/sel/sel.c b/sel/sel.c index a0d9ed3..8ccf862 100644 --- 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; diff --git a/struct/dspool.h b/struct/dspool.h index 47ca6e2..0e1c093 100644 --- a/struct/dspool.h +++ b/struct/dspool.h @@ -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); \ diff --git a/struct/hash.3.in b/struct/hash.3.in index 41258fa..98d853b 100644 --- a/struct/hash.3.in +++ b/struct/hash.3.in @@ -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 diff --git a/test/tvec-bench.c b/test/tvec-bench.c index c4e123d..6201219 100644 --- a/test/tvec-bench.c +++ b/test/tvec-bench.c @@ -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) { diff --git a/test/tvec-core.c b/test/tvec-core.c index 7a65c51..7aced97 100644 --- a/test/tvec-core.c +++ b/test/tvec-core.c @@ -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@ --- * diff --git a/test/tvec-main.c b/test/tvec-main.c index f2ba9ca..0566292 100644 --- a/test/tvec-main.c +++ b/test/tvec-main.c @@ -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 diff --git a/test/tvec-remote.c b/test/tvec-remote.c index 637f851..7fbd1b6 100644 --- a/test/tvec-remote.c +++ b/test/tvec-remote.c @@ -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)) diff --git a/test/tvec-timeout.c b/test/tvec-timeout.c index 778673e..e7b23b5 100644 --- a/test/tvec-timeout.c +++ b/test/tvec-timeout.c @@ -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 -------------------------------------------------*/ diff --git a/test/tvec-types.c b/test/tvec-types.c index 70ce87a..3c60057 100644 --- a/test/tvec-types.c +++ b/test/tvec-types.c @@ -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 diff --git a/test/tvec.h b/test/tvec.h index 8a18539..3d483b9 100644 --- a/test/tvec.h +++ b/test/tvec.h @@ -127,6 +127,10 @@ # 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)@ diff --git a/ui/tty.c b/ui/tty.c index ff24256..b65f6b7 100644 --- 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 } }; diff --git a/utils/t/exc-test.c b/utils/t/exc-test.c index 89701bf..69fa8cd 100644 --- a/utils/t/exc-test.c +++ b/utils/t/exc-test.c @@ -1,44 +1,65 @@ #include + #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)); } diff --git a/utils/tests.at b/utils/tests.at index a19d4c0..ce8bcc4 100644 --- a/utils/tests.at +++ b/utils/tests.at @@ -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