+/*----- Session lifecycle -------------------------------------------------*/
+
+/* --- @tvec_begin@ --- *
+ *
+ * Arguments: @struct tvec_state *tv_out@ = state structure to fill in
+ * @const struct tvec_config *config@ = test configuration
+ * @struct tvec_output *o@ = output driver
+ *
+ * Returns: ---
+ *
+ * Use: Initialize a state structure ready to do some testing.
+ */
+
+void tvec_begin(struct tvec_state *tv_out,
+ const struct tvec_config *config,
+ struct tvec_output *o)
+{
+ unsigned i;
+
+ tv_out->f = 0;
+
+ assert(config->nrout <= config->nreg);
+ tv_out->nrout = config->nrout; tv_out->nreg = config->nreg;
+ tv_out->regsz = config->regsz;
+ tv_out->in = xmalloc(tv_out->nreg*tv_out->regsz);
+ tv_out->out = xmalloc(tv_out->nrout*tv_out->regsz);
+ for (i = 0; i < tv_out->nreg; i++) {
+ TVEC_REG(tv_out, in, i)->f = 0;
+ if (i < tv_out->nrout) TVEC_REG(tv_out, out, i)->f = 0;
+ }
+
+ for (i = 0; i < TVOUT_LIMIT; i++)
+ tv_out->curr[i] = tv_out->all[i] = tv_out->grps[i] = 0;
+
+ tv_out->tests = config->tests; tv_out->test = 0;
+ tv_out->infile = 0; tv_out->lno = 0; tv_out->fp = 0;
+ tv_out->output = o; tv_out->output->ops->bsession(tv_out->output, tv_out);
+}
+
+/* --- @tvec_end@ --- *
+ *
+ * Arguments: @struct tvec_state *tv@ = test-vector state
+ *
+ * Returns: A proposed exit code.
+ *
+ * Use: Conclude testing and suggests an exit code to be returned to
+ * the calling program. (The exit code comes from the output
+ * driver's @esession@ method.)
+ */
+
+int tvec_end(struct tvec_state *tv)
+{
+ int rc = tv->output->ops->esession(tv->output);
+
+ if (tv->test) tvec_releaseregs(tv);
+ tv->output->ops->destroy(tv->output);
+ xfree(tv->in); xfree(tv->out);
+ return (rc);
+}
+
+/*----- Serialization and deserialization ---------------------------------*/
+
+/* --- @tvec_serialize@ --- *
+ *
+ * Arguments: @const struct tvec_reg *rv@ = vector of registers
+ * @buf *b@ = buffer to write on
+ * @const struct tvec_regdef *regs@ = vector of register
+ * descriptions, terminated by an entry with a null
+ * @name@ slot
+ * @unsigned nr@ = number of entries in the @rv@ vector
+ * @size_t regsz@ = true size of each element of @rv@
+ *
+ * Returns: Zero on success, @-1@ on failure.
+ *
+ * Use: Serialize a collection of register values.
+ *
+ * The serialized output is written to the buffer @b@. Failure
+ * can be caused by running out of buffer space, or a failing
+ * type handler.
+ */
+
+int tvec_serialize(const struct tvec_reg *rv, buf *b,
+ const struct tvec_regdef *regs,
+ unsigned nr, size_t regsz)
+{
+ unsigned char *bitmap;
+ size_t i, bitoff, nbits, bitsz;
+ const struct tvec_regdef *rd;
+ const struct tvec_reg *r;
+
+ bitoff = BLEN(b);
+ for (rd = regs, nbits = 0; rd->name; rd++, nbits++);
+ bitsz = (nbits + 7)/8;
+
+ bitmap = buf_get(b, bitsz); if (!bitmap) return (-1);
+ memset(bitmap, 0, bitsz);
+ for (rd = regs, i = 0; rd->name; rd++, i++) {
+ if (rd->i >= nr) continue;
+ r = TVEC_GREG(rv, rd->i, regsz); if (!(r->f&TVRF_LIVE)) continue;
+ bitmap = BBASE(b) + bitoff; bitmap[i/8] |= 1 << i%8;
+ if (rd->ty->tobuf(b, &r->v, rd)) return (-1);
+ }
+ return (0);
+}
+
+/* --- @tvec_deserialize@ --- *
+ *
+ * Arguments: @struct tvec_reg *rv@ = vector of registers
+ * @buf *b@ = buffer to write on
+ * @const struct tvec_regdef *regs@ = vector of register
+ * descriptions, terminated by an entry with a null
+ * @name@ slot
+ * @unsigned nr@ = number of entries in the @rv@ vector
+ * @size_t regsz@ = true size of each element of @rv@
+ *
+ * Returns: Zero on success, @-1@ on failure.
+ *
+ * Use: Deserialize a collection of register values.
+ *
+ * The size of the register vector @nr@ and the register
+ * definitions @regs@ must match those used when producing the
+ * serialization. For each serialized register value,
+ * deserialize and store the value into the appropriate register
+ * slot, and set the @TVRF_LIVE@ flag on the register. See
+ * @tvec_serialize@ for a description of the format.
+ *
+ * Failure results only from a failing register type handler.
+ */
+
+int tvec_deserialize(struct tvec_reg *rv, buf *b,
+ const struct tvec_regdef *regs,
+ unsigned nr, size_t regsz)
+{
+ const unsigned char *bitmap;
+ size_t i, nbits, bitsz;
+ const struct tvec_regdef *rd;
+ struct tvec_reg *r;
+
+ for (rd = regs, nbits = 0; rd->name; rd++, nbits++);
+ bitsz = (nbits + 7)/8;
+
+ bitmap = buf_get(b, bitsz); if (!bitmap) return (-1);
+ for (rd = regs, i = 0; rd->name; rd++, i++) {
+ if (rd->i >= nr) continue;
+ if (!(bitmap[i/8]&(1 << i%8))) continue;
+ r = TVEC_GREG(rv, rd->i, regsz);
+ if (rd->ty->frombuf(b, &r->v, rd)) return (-1);
+ r->f |= TVRF_LIVE;
+ }
+ return (0);
+}
+