--- /dev/null
+/* -*-c-*-
+ *
+ * Test-vector framework output machinery
+ *
+ * (c) 2024 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the mLib utilities library.
+ *
+ * mLib is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * mLib is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with mLib. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#ifndef MLIB_TVEC_OUTPUT_H
+#define MLIB_TVEC_OUTPUT_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#ifndef MLIB_TVEC_H
+# include "tvec.h"
+#endif
+
+/*----- Data structures ---------------------------------------------------*/
+
+struct tvec_state;
+
+struct tvec_output {
+ /* An output formatter. */
+
+ const struct tvec_outops *ops; /* pointer to operations */
+};
+
+enum {
+ /* Register output dispositions. */
+
+ TVRD_INPUT, /* input-only register */
+ TVRD_OUTPUT, /* output-only (input is dead) */
+ TVRD_MATCH, /* matching (equal) registers */
+ TVRD_FOUND, /* mismatching output register */
+ TVRD_EXPECT, /* mismatching input register */
+ TVRD_LIMIT /* (number of dispositions) */
+};
+
+struct tvec_fallbackoutput {
+ /* Dummy fallback output driver. This may be useful for fallback output
+ * driver implementations.
+ */
+
+ struct tvec_output _o;
+ struct tvec_state *tv;
+};
+
+struct tvec_outops {
+ /* Output operations. */
+
+ void (*bsession)(struct tvec_output */*o*/, struct tvec_state */*tv*/);
+ /* Begin a test session. The output driver will probably want to
+ * save @tv@, because this isn't provided to any other methods.
+ */
+
+ int (*esession)(struct tvec_output */*o*/);
+ /* End a session, and return the suggested exit code. */
+
+ void (*bgroup)(struct tvec_output */*o*/);
+ /* Begin a test group. The test group description is @tv->test@. */
+
+ void (*skipgroup)(struct tvec_output */*o*/,
+ const char */*excuse*/, va_list */*ap*/);
+ /* The group is being skipped; @excuse@ may be null or a format
+ * string explaining why. The @egroup@ method will not be called
+ * separately.
+ */
+
+ void (*egroup)(struct tvec_output */*o*/);
+ /* End a test group. At least one test was attempted or @skipgroup@
+ * would have been called instead. If @tv->curr[TVOUT_LOSE]@ is nonzero
+ * then the test group as a whole failed; otherwise it passed.
+ */
+
+ void (*btest)(struct tvec_output */*o*/);
+ /* Begin a test case. */
+
+ void (*skip)(struct tvec_output */*o*/,
+ const char */*excuse*/, va_list */*ap*/);
+ /* The test case is being skipped; @excuse@ may be null or a format
+ * string explaining why. The @etest@ function will still be called (so
+ * this works differently from @skipgroup@ and @egroup@). A test case
+ * can be skipped at most once, and, if skipped, it cannot fail.
+ */
+
+ void (*fail)(struct tvec_output */*o*/,
+ const char */*detail*/, va_list */*ap*/);
+ /* The test case failed.
+ *
+ * The output driver should preferably report the filename (@infile@) and
+ * line number (@test_lno@, not @lno@) for the failing test.
+ *
+ * The @detail@ may be null or a format string describing detail about
+ * how the failing test was run which can't be determined from the
+ * registers; a @detail@ is usually provided when (and only when) the
+ * test environment potentially invokes the test function more than once.
+ *
+ * A single test case can fail multiple times!
+ */
+
+ void (*dumpreg)(struct tvec_output */*o*/,
+ unsigned /*disp*/, const union tvec_regval */*rv*/,
+ const struct tvec_regdef */*rd*/);
+ /* Dump a register. The `disposition' @disp@ explains what condition the
+ * register is in; see @tvec_dumpreg@ and the @TVRD_...@ codes. The
+ * register value is at @rv@, and its definition, including its type, at
+ * @rd@. Note that this function may be called on virtual registers
+ * which aren't in either of the register vectors or mentioned by the
+ * test description. It may also be called with @rv@ null, indicating
+ * that the register is not live.
+ */
+
+ void (*etest)(struct tvec_output */*o*/, unsigned /*outcome*/);
+ /* The test case concluded with the given @outcome@ (one of the
+ * @TVOUT_...@ codes.
+ */
+
+ void (*report)(struct tvec_output */*o*/, unsigned /*level*/,
+ const char */*msg*/, va_list */*ap*/);
+ /* Report a message. The driver should ideally report the filename
+ * (@infile@) and line number (@lno@) prompting the error.
+ */
+
+ const void *(*extend)(struct tvec_output */*o*/, const char */*name*/);
+ /* Return a pointer to the output driver's implementation of the
+ * extension @name@, or null. Typically, the implementation will be a
+ * structure of function pointers, though the details are necessarily
+ * extension-specific.
+ */
+
+ void (*destroy)(struct tvec_output */*o*/);
+ /* Release any resources acquired by the driver. */
+};
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @tvec_outputext@ --- *
+ *
+ * Arguments: @struct tvec_state *tv@ = test-vector state
+ * @struct tvec_output **o_out@ = output object
+ * @struct tvec_fallbackoutput *fo@ = fallback output
+ * (uninitialized)
+ * @const char *ext@ = extension name
+ * @const void *fops@ = fallback operations
+ *
+ * Returns: An output extension operations table.
+ *
+ * Use: Calls the output driver's @extend@ function, passing @ext@ as
+ * the extension name. If the output driver recognizes the
+ * extension, then @*o_out@ is set to the output driver object
+ * and the driver's extension-operations table is returned.
+ * Otherwise, a fallback output object is constructed in @*fo@,
+ * @*o_out@ is set to @&fo->_o@, and @fops@ is returned. In
+ * this way, a call to an extension function, passing @*o_out@
+ * as the output object, will either call the output driver's
+ * extension implementation or the fallback implementation as
+ * required.
+ */
+
+extern const void *tvec_outputext(struct tvec_state */*tv*/,
+ struct tvec_output **/*o_out*/,
+ struct tvec_fallbackoutput */*fo*/,
+ const char */*ext*/, const void */*fops*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif