chiark / gitweb /
@@@ tty commentary
[mLib] / test / tvec-types.h
1 /* -*-c-*-
2  *
3  * Test-vector framework basic register types
4  *
5  * (c) 2024 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of the mLib utilities library.
11  *
12  * mLib is free software: you can redistribute it and/or modify it under
13  * the terms of the GNU Library General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or (at
15  * your option) any later version.
16  *
17  * mLib is distributed in the hope that it will be useful, but WITHOUT
18  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
20  * License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public
23  * License along with mLib.  If not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
25  * USA.
26  */
27
28 #ifndef MLIB_TVEC_TYPES_H
29 #define MLIB_TVEC_TYPES_H
30
31 #ifdef __cplusplus
32   extern "C" {
33 #endif
34
35 /*----- Header files ------------------------------------------------------*/
36
37 #ifndef MLIB_TVEC_H
38 #  include "tvec.h"
39 #endif
40
41 /*----- Integer types: signed and unsigned --------------------------------*/
42
43 /* Integers may be input in decimal, hex, binary, or octal, following
44  * approximately usual conventions.
45  *
46  *   * Signed integers may be preceded with a `+' or `-' sign.
47  *
48  *   * Decimal integers are just a sequence of decimal digits `0' ... `9'.
49  *
50  *   * Octal integers are a sequence of digits `0' ... `7', preceded by `0o'
51  *     or `0O'.
52  *
53  *   * Hexadecimal integers are a sequence of digits `0' ... `9', `a'
54  *     ... `f', or `A' ... `F', preceded by `0x' or `0X'.
55  *
56  *   * Radix-B integers are a sequence of digits `0' ... `9', `a' ... `f', or
57  *     `A' ... `F', each with value less than B, preceded by `Br' or `BR',
58  *     where 0 < B < 36 is expressed in decimal without any leading `0' or
59  *     internal underscores `_'.
60  *
61  *   * A digit sequence may contain internal underscore `_' separators, but
62  *     not before or after all of the digits; and two consecutive `_'
63  *     characters are not permitted.
64  */
65
66 extern const struct tvec_regty tvty_int, tvty_uint;
67
68 /* The @arg.p@ slot may be null or a pointer to @struct tvec_irange@ or
69  * @struct tvec_urange@ as appropriate.  The bounds are inclusive; use, e.g.,
70  * @LONG_MAX@ explicitly if one or the other bound is logically inapplicable.
71  * If %$m$% is nonzero, then the value must additionally be congruent to
72  * %$a$% modulo %$m$%.
73  */
74 struct tvec_irange { long min, max, a, m; };
75 struct tvec_urange { unsigned long min, max, a, m; };
76
77 /* Bounds corresponding to common integer types. */
78 extern const struct tvec_irange
79   tvrange_schar, tvrange_short, tvrange_int, tvrange_long,
80   tvrange_sbyte, tvrange_i16, tvrange_i32;
81 extern const struct tvec_urange
82   tvrange_uchar, tvrange_ushort, tvrange_uint, tvrange_ulong, tvrange_size,
83   tvrange_byte, tvrange_u16, tvrange_u32;
84
85 /* --- @tvec_claimeq_int@, @TVEC_CLAIMEQ_INT@ --- *
86  *
87  * Arguments:   @struct tvec_state *tv@ = test-vector state
88  *              @long i0, i1@ = two signed integers
89  *              @const char *file@, @unsigned @lno@ = calling file and line
90  *              @const char *expr@ = the expression to quote on failure
91  *
92  * Returns:     Nonzero if @i0@ and @i1@ are equal, otherwise zero.
93  *
94  * Use:         Check that values of @i0@ and @i1@ are equal.  As for
95  *              @tvec_claim@ above, a test case is automatically begun and
96  *              ended if none is already underway.  If the values are
97  *              unequal, then @tvec_fail@ is called, quoting @expr@, and the
98  *              mismatched values are dumped: @i0@ is printed as the output
99  *              value and @i1@ is printed as the input reference.
100  *
101  *              The @TVEC_CLAIM_INT@ macro is similar, only it (a) identifies
102  *              the file and line number of the call site automatically, and
103  *              (b) implicitly quotes the source text of the @i0@ and @i1@
104  *              arguments in the failure message.
105  */
106
107 extern int tvec_claimeq_int(struct tvec_state */*tv*/,
108                             long /*i0*/, long /*i1*/,
109                             const char */*file*/, unsigned /*lno*/,
110                             const char */*expr*/);
111 #define TVEC_CLAIMEQ_INT(tv, i0, i1)                                    \
112         (tvec_claimeq_int(tv, i0, i1, __FILE__, __LINE__, #i0 " /= " #i1))
113
114 /* --- @tvec_claimeq_uint@, @TVEC_CLAIMEQ_UINT@ --- *
115  *
116  * Arguments:   @struct tvec_state *tv@ = test-vector state
117  *              @unsigned long u0, u1@ = two unsigned integers
118  *              @const char *file@, @unsigned @lno@ = calling file and line
119  *              @const char *expr@ = the expression to quote on failure
120  *
121  * Returns:     Nonzero if @u0@ and @u1@ are equal, otherwise zero.
122  *
123  * Use:         Check that values of @u0@ and @u1@ are equal.  As for
124  *              @tvec_claim@ above, a test case is automatically begun and
125  *              ended if none is already underway.  If the values are
126  *              unequal, then @tvec_fail@ is called, quoting @expr@, and the
127  *              mismatched values are dumped: @u0@ is printed as the output
128  *              value and @u1@ is printed as the input reference.
129  *
130  *              The @TVEC_CLAIM_UINT@ macro is similar, only it (a)
131  *              identifies the file and line number of the call site
132  *              automatically, and (b) implicitly quotes the source text of
133  *              the @u0@ and @u1@ arguments in the failure message.
134  */
135
136 extern int tvec_claimeq_uint(struct tvec_state */*tv*/,
137                             unsigned long /*u0*/, unsigned long /*u1*/,
138                             const char */*file*/, unsigned /*lno*/,
139                             const char */*expr*/);
140 #define TVEC_CLAIMEQ_UINT(tv, u0, u1)                                   \
141         (tvec_claimeq_uint(tv, u0, u1, __FILE__, __LINE__, #u0 " /= " #u1))
142
143 /*----- Size type ---------------------------------------------------------*/
144
145 /* A size is an unsigned integer followed by an optional unit specifier
146  * consisting of an SI unit prefix and (optionally) the letter `B'.
147  */
148
149 extern const struct tvec_regty tvty_size;
150
151 /* --- @tvec_claimeq_size@ --- *
152  *
153  * Arguments:   @struct tvec_state *tv@ = test-vector state
154  *              @unsigned long sz0, sz1@ = two sizes
155  *              @const char *file@, @unsigned @lno@ = calling file and line
156  *              @const char *expr@ = the expression to quote on failure
157  *
158  * Returns:     Nonzero if @sz0@ and @sz1@ are equal, otherwise zero.
159  *
160  * Use:         Check that values of @u0@ and @u1@ are equal.  As for
161  *              @tvec_claim@ above, a test case is automatically begun and
162  *              ended if none is already underway.  If the values are
163  *              unequal, then @tvec_fail@ is called, quoting @expr@, and the
164  *              mismatched values are dumped: @u0@ is printed as the output
165  *              value and @u1@ is printed as the input reference.
166  *
167  *              The @TVEC_CLAIM_SIZE@ macro is similar, only it (a)
168  *              identifies the file and line number of the call site
169  *              automatically, and (b) implicitly quotes the source text of
170  *              the @u0@ and @u1@ arguments in the failure message.
171  */
172
173 int tvec_claimeq_size(struct tvec_state *tv,
174                       unsigned long sz0, unsigned long sz1,
175                       const char *file, unsigned lno, const char *expr);
176 #define TVEC_CLAIMEQ_UINT(tv, u0, u1)                                   \
177         (tvec_claimeq_uint(tv, u0, u1, __FILE__, __LINE__, #u0 " /= " #u1))
178
179 /*----- Floating-point type -----------------------------------------------*/
180
181 /* Floating-point values are either NaN (%|#nan|%, if supported by the
182  * platform); positive or negative infinity (%|#inf|%, %|+#inf|%, or
183  * %|#+inf|% (preferring the last), and %|-#inf|% or %|#-inf|% (preferring
184  * the latter), if supported by the platform); or a number in strtod(3)
185  * syntax.
186  *
187  * The comparison rules for floating-point numbers are complex: see
188  * @tvec_claimeqish_float@ for details.
189  */
190
191 extern const struct tvec_regty tvty_float;
192
193 struct tvec_floatinfo {
194   /* Details about acceptable floating-point values. */
195
196   unsigned f;                           /* flags (@TVFF_...@ bits) */
197 #define TVFF_NOMIN 0x0001               /*   ignore @min@ (allow -∞) */
198 #define TVFF_NOMAX 0x0002               /*   ignore @max@ (allow +∞) */
199 #define TVFF_NANOK 0x0004               /*   permit NaN */
200 #define TVFF_NEGINFOK 0x0008            /*   permit -∞, check finite */
201 #define TVFF_POSINFOK 0x0010            /*   permit +∞, check finite */
202 #define TVFF_INFOK (TVFF_NEGINFOK | TVFF_POSINFOK) /* permit ±∞ */
203 #define TVFF_EQMASK 0x0f00              /*   how to compare */
204 #define TVFF_EXACT 0x0000               /*     must equal exactly */
205 #define TVFF_ABSDELTA 0x0100            /*     must be within @delta@ */
206 #define TVFF_RELDELTA 0x0200            /*     diff < @delta@ fraction */
207   double min, max;                      /* smallest/largest value allowed */
208   double delta;                         /* maximum tolerable difference */
209 };
210
211 extern const struct tvec_floatinfo
212   tvflt_float, tvflt_double, tvflt_finite, tvflt_nonneg;
213
214 /* --- @tvec_claimeqish_float@, @TVEC_CLAIMEQISH_FLOAT@ --- *
215  *
216  * Arguments:   @struct tvec_state *tv@ = test-vector state
217  *              @double f0, f1@ = two floating-point numbers
218  *              @unsigned f@ = flags (@TVFF_...@)
219  *              @double delta@ = maximum tolerable difference
220  *              @const char *file@, @unsigned @lno@ = calling file and line
221  *              @const char *expr@ = the expression to quote on failure
222  *
223  * Returns:     Nonzero if @f0@ and @f1@ are sufficiently close, otherwise
224  *              zero.
225  *
226  * Use:         Check that values of @f0@ and @f1@ are sufficiently close.
227  *              As for @tvec_claim@ above, a test case is automatically begun
228  *              and ended if none is already underway.  If the values are
229  *              too far apart, then @tvec_fail@ is called, quoting @expr@,
230  *              and the mismatched values are dumped: @f0@ is printed as the
231  *              output value and @f1@ is printed as the input reference.
232  *
233  *              The details for the comparison are as follows.
234  *
235  *                * A NaN value matches any other NaN, and nothing else.
236  *
237  *                * An infinity matches another infinity of the same sign,
238  *                  and nothing else.
239  *
240  *                * If @f&TVFF_EQMASK@ is @TVFF_EXACT@, then any
241  *                  representable number matches only itself: in particular,
242  *                  positive and negative zero are considered distinct.
243  *                  (This allows tests to check that they land on the correct
244  *                  side of branch cuts, for example.)
245  *
246  *                * If @f&TVFF_EQMASK@ is @TVFF_ABSDELTA@, then %$x$% matches
247  *                  %$y$% when %$|x - y| < \delta$%.
248  *
249  *                * If @f&TVFF_EQMASK@ is @TVFF_RELDELTA@, then %$x$% matches
250  *                  %$y$% when %$|1 - x/y| < \delta$%.  (Note that this
251  *                  criterion is asymmetric.  Write %$x \approx_\delta y$%
252  *                  if and only if %$|1 - x/y < \delta$%.  Then, for example,
253  *                  if %$y/(1 + \delta) < x < y (1 - \delta)$%, then
254  *                  %$x \approx_\delta y$%, but %$y \not\approx_\delta x$%.)
255  *
256  *              The @TVEC_CLAIM_FLOAT@ macro is similar, only it (a)
257  *              identifies the file and line number of the call site
258  *              automatically, and (b) implicitly quotes the source text of
259  *              the @f0@ and @f1@ arguments (and @delta@) in the failure
260  *              message.
261  */
262
263 extern int tvec_claimeqish_float(struct tvec_state */*tv*/,
264                                  double /*f0*/, double /*f1*/,
265                                  unsigned /*f*/, double /*delta*/,
266                                  const char */*file*/, unsigned /*lno*/,
267                                  const char */*expr*/);
268 #define TVEC_CLAIMEQISH_FLOAT(tv, f0, f1, f, delta)                     \
269         (tvec_claimeqish_float(tv, f0, f1, f, delta, __FILE__, __LINE__, \
270                                #f0 " /= " #f1 " (+/- " #delta ")"))
271
272 /* --- @tvec_claimeq_float@, @TVEC_CLAIMEQ_FLOAT@ --- *
273  *
274  * Arguments:   @struct tvec_state *tv@ = test-vector state
275  *              @double f0, f1@ = two floating-point numbers
276  *              @const char *file@, @unsigned @lno@ = calling file and line
277  *              @const char *expr@ = the expression to quote on failure
278  *
279  * Returns:     Nonzero if @f0@ and @u1@ are identical, otherwise zero.
280  *
281  * Use:         Check that values of @f0@ and @f1@ are identical.  The
282  *              function is exactly equivalent to @tvec_claimeqish_float@
283  *              with @f == TVFF_EXACT@; the macro is similarly like
284  *              @TVEC_CLAIMEQISH_FLOAT@ with @f == TVFF_EXACT@, except that
285  *              it doesn't bother to quote a delta.
286  */
287
288 extern int tvec_claimeq_float(struct tvec_state */*tv*/,
289                               double /*f0*/, double /*f1*/,
290                               const char */*file*/, unsigned /*lno*/,
291                               const char */*expr*/);
292 #define TVEC_CLAIMEQ_FLOAT(tv, f0, f1)                                  \
293         (tvec_claimeq_float(tv, f0, f1, __FILE__, __LINE__, #f0 " /= " #f1))
294
295 /*----- Durations ---------------------------------------------------------*/
296
297 /* A duration measures a time interval in seconds.  The input format consists
298  * of a nonnegative decimal floating-point number in @strtod@ format followed
299  * by an optional unit specification.
300  */
301
302 extern const struct tvec_regty tvty_duration;
303
304 /* --- @tvec_parsedurunit@ --- *
305  *
306  * Arguments:   @double *scale_out@ = where to leave the scale
307  *              @const char **p_inout@ = input unit string, updated
308  *
309  * Returns:     Zero on success, %$-1$% on error.
310  *
311  * Use:         If @*p_inout@ begins with a unit string followed by the end
312  *              of the string or some non-alphanumeric character, then store
313  *              the corresponding scale factor in @*scale_out@, advance
314  *              @*p_inout@ past the unit string, and return zero.  Otherwise,
315  *              return %$-1$%.
316  */
317
318 extern int tvec_parsedurunit(double */*scale_out*/,
319                              const char **/*p_inout*/);
320
321 /* --- @tvec_claimeqish_duration@, @TVEC_CLAIMEQISH_DURATION@ --- *
322  *
323  * Arguments:   @struct tvec_state *tv@ = test-vector state
324  *              @double t0, t1@ = two durations
325  *              @unsigned f@ = flags (@TVFF_...@)
326  *              @double delta@ = maximum tolerable difference
327  *              @const char *file@, @unsigned @lno@ = calling file and line
328  *              @const char *expr@ = the expression to quote on failure
329  *
330  * Returns:     Nonzero if @t0@ and @t1@ are sufficiently close, otherwise
331  *              zero.
332  *
333  * Use:         Check that values of @t0@ and @t1@ are sufficiently close.
334  *              This is essentially the same as @tvec_claimeqish_float@, only
335  *              it dumps the values as durations on a mismatch.
336  *
337  *              The @TVEC_CLAIM_FLOAT@ macro is similar, only it (a)
338  *              identifies the file and line number of the call site
339  *              automatically, and (b) implicitly quotes the source text of
340  *              the @t0@ and @t1@ arguments (and @delta@) in the failure
341  *              message.
342  */
343
344 extern int tvec_claimeqish_duration(struct tvec_state */*tv*/,
345                                     double /*t0*/, double /*t1*/,
346                                     unsigned /*f*/, double /*delta*/,
347                                     const char */*file*/, unsigned /*lno*/,
348                                     const char */*expr*/);
349 #define TVEC_CLAIMEQISH_DURATION(tv, t0, t1, f, delta)                  \
350         (tvec_claimeqish_duration(tv, t0, t1, f, delta, __FILE__, __LINE__, \
351                                #t0 " /= " #t1 " (+/- " #delta ")"))
352
353 /* --- @tvec_claimeq_duration@, @TVEC_CLAIMEQ_DURATION@ --- *
354  *
355  * Arguments:   @struct tvec_state *tv@ = test-vector state
356  *              @double t0, t1@ = two durations
357  *              @const char *file@, @unsigned @lno@ = calling file and line
358  *              @const char *expr@ = the expression to quote on failure
359  *
360  * Returns:     Nonzero if @t0@ and @t1@ are identical, otherwise zero.
361  *
362  * Use:         Check that values of @t0@ and @t1@ are identical.  The
363  *              function is exactly equivalent to @tvec_claimeqish_duration@
364  *              with @f == TVFF_EXACT@; the macro is similarly like
365  *              @TVEC_CLAIMEQISH_DURATION@ with @f == TVFF_EXACT@, except
366  *              that it doesn't bother to quote a delta.
367  */
368
369 int tvec_claimeq_duration(struct tvec_state */*tv*/,
370                           double /*t0*/, double /*t1*/,
371                           const char */*file*/, unsigned /*lno*/,
372                           const char */*expr*/);
373 #define TVEC_CLAIMEQ_DURATION(tv, t0, t1)                                       \
374         (tvec_claimeq_float(tv, t0, t1, __FILE__, __LINE__, #t0 " /= " #t1))
375
376 /*----- Enumerated types --------------------------------------------------*/
377
378 /* An enumeration describes a set of values of some underlying type, each of
379  * which has a symbolic name.  Values outside of the defined set can occur --
380  * on output, because of bugs in the tested code, or on input to test
381  * handling of unexpected values.
382  *
383  * There is a distinct enumerated type for each of the branches of
384  * @tvec_misc@.  In the following, we write @t@ for the type code, which is
385  * @i@ for signed integer, @u@ for unsigned integer, @f@ for floating-point,
386  * and @p@ for pointer.
387  *
388  * On input, an enumerated value may be given by name or as a literal value.
389  * For enumerations based on numeric types, the literal values can be written
390  * in the same syntax as the underlying values.  For enumerations based on
391  * pointers, the only permitted literal is %|#nil|%, which denotes a null
392  * pointer.  On output, names are preferred (with the underlying value given
393  * in a comment).
394  */
395
396 #define DEFENUMTY(tag, ty, slot)                                        \
397         extern const struct tvec_regty tvty_##slot##enum;
398 TVEC_MISCSLOTS(DEFENUMTY)
399 #undef DEFENUMTY
400
401 /* A @struct tvec_tassoc@ associates a string tag with a value. */
402 #define DEFASSOC(tag_, ty, slot)                                        \
403         struct tvec_##slot##assoc { const char *tag; ty slot; };
404 TVEC_MISCSLOTS(DEFASSOC)
405 #undef DEFASSOC
406
407 #define TVEC_ENDENUM { 0, 0 }
408
409 /* Information about an enumerated type. */
410 #define DEFINFO(tag, ty, slot)                                          \
411         struct tvec_##slot##enuminfo {                                  \
412           const char *name;             /* type name for diagnostics */ \
413           const struct tvec_##slot##assoc *av; /* name/value mappings */ \
414           EXTRA_##tag##_INFOSLOTS       /* type-specific extra info */  \
415         };
416
417 #define EXTRA_INT_INFOSLOTS                                             \
418         const struct tvec_irange *ir;   /* allowed range of raw values */
419
420 #define EXTRA_UINT_INFOSLOTS                                            \
421         const struct tvec_urange *ur;   /* allowed range of raw values */
422
423 #define EXTRA_FLT_INFOSLOTS                                             \
424         const struct tvec_floatinfo *fi; /* range and matching policy */
425
426 #define EXTRA_PTR_INFOSLOTS             /* (nothing) */
427
428 TVEC_MISCSLOTS(DEFINFO)
429
430 #undef EXTRA_INT_INFOSLOTS
431 #undef EXTRA_UINT_INFOSLOTS
432 #undef EXTRA_FLT_INFOSLOTS
433 #undef EXTRA_PTR_INFOSLOTS
434
435 #undef DEFINFO
436
437 /* Standard enumerations. */
438 extern const struct tvec_ienuminfo tvenum_bool;
439 extern const struct tvec_ienuminfo tvenum_cmp;
440
441 /* --- @tvec_claimeq_tenum@, @TVEC_CLAIMEQ_TENUM@, @TVEC_CLAIMEQ_PTR@ --- *
442  *
443  * Arguments:   @struct tvec_state *tv@ = test-vector state
444  *              @const struct tvec_typeenuminfo *ei@ = enumeration type info
445  *              @ty t0, t1@ = two values
446  *              @const char *file@, @unsigned @lno@ = calling file and line
447  *              @const char *expr@ = the expression to quote on failure
448  *
449  * Returns:     Nonzero if @t0@ and @t1@ are equal, otherwise zero.
450  *
451  * Use:         Check that values of @t0@ and @t1@ are equal.  As for
452  *              @tvec_claim@ above, a test case is automatically begun and
453  *              ended if none is already underway.  If the values are
454  *              unequal, then @tvec_fail@ is called, quoting @expr@, and the
455  *              mismatched values are dumped: @t0@ is printed as the output
456  *              value and @t1@ is printed as the input reference.
457  *
458  *              The @ei@ argument to @tvec_claimeq_penum@ (but not the other
459  *              functions) may be null, as a hack for comparing two plain
460  *              pointers.
461  *
462  *              The @TVEC_CLAIM_TENUM@ macro is similar, only it (a)
463  *              identifies the file and line number of the call site
464  *              automatically, and (b) implicitly quotes the source text of
465  *              the @t0@ and @t1@ arguments in the failure message.  The
466  *              @TVEC_CLAIMEQ_PTR@ macro simply compares two pointers in the
467  *              same way.
468  */
469
470 #define DECLCLAIM(tag, ty, slot)                                        \
471         extern int tvec_claimeq_##slot##enum                            \
472           (struct tvec_state */*tv*/,                                   \
473            const struct tvec_##slot##enuminfo */*ei*/,                  \
474            ty /*t0*/, ty /*t1*/,                                        \
475            const char */*file*/, unsigned /*lno*/, const char */*expr*/);
476 TVEC_MISCSLOTS(DECLCLAIM)
477 #undef DECLCLAIM
478 #define TVEC_CLAIMEQ_IENUM(tv, ei, i0, i1)                              \
479         (tvec_claimeq_ienum(tv, ei, i0, i1,                             \
480                             __FILE__, __LINE__, #i0 " /= " #i1))
481 #define TVEC_CLAIMEQ_UENUM(tv, ei, u0, u1)                              \
482         (tvec_claimeq_uenum(tv, ei, u0, u1,                             \
483                             __FILE__, __LINE__, #u0 " /= " #u1))
484 #define TVEC_CLAIMEQ_FENUM(tv, ei, f0, f1)                              \
485         (tvec_claimeq_fenum(tv, ei, f0, f1,                             \
486                             __FILE__, __LINE__, #f0 " /= " #f1))
487 #define TVEC_CLAIMEQ_PENUM(tv, ei, p0, p1)                              \
488         (tvec_claimeq_penum(tv, ei, p0, p1,                             \
489                             __FILE__, __LINE__, #p0 " /= " #p1))
490 #define TVEC_CLAIMEQ_PTR(tv, p0, p1)                                    \
491         (tvec_claimeq_penum(tv, 0, p0, p1,                              \
492                             __FILE__, __LINE__, #p0 " /= " #p1))
493
494 /*----- Flags type --------------------------------------------------------*/
495
496 /* A flags value packs a number of fields into a single nonnegative integer.
497  * Symbolic names are associated with the possible values of the various
498  * fields; more precisely, each name is associated with a value and a
499  * covering bitmask.
500  *
501  * The input syntax is a sequence of items separated by `%|||%' signs.  Each
502  * item may be the symbolic name of a field value, or a literal unsigned
503  * integer.  The masks associated with the given symbolic names must be
504  * disjoint.  The resulting numerical value is simply the bitwise OR of the
505  * given values.
506  *
507  * On output, the table of symbolic names and their associated values and
508  * masks is repeatedly scanned, in order, to find disjoint matches -- i.e.,
509  * entries whose value matches the target value in the bit positions
510  * indicated by the mask, and whose mask doesn't overlap with any previously
511  * found matches; the names are then output, separated by `%|||%'.  Any
512  * remaining nonzero bits not covered by any of the matching masks are output
513  * as a single literal integer, in hex.
514  */
515
516 extern const struct tvec_regty tvty_flags;
517
518 struct tvec_flag {
519   /* Definition of a single flag or bitfield value.
520    *
521    * Each named setting comes with a value @v@ and a mask @m@; the mask
522    * should cover all of the value bits, i.e., @(v&~m) == 0@.
523    */
524
525   const char *tag;                      /* name */
526   unsigned long m, v;                   /* mask and value */
527 };
528
529 #define TVEC_ENDFLAGS { 0, 0, 0 }
530
531 struct tvec_flaginfo {
532   /* Information about a flags type. */
533
534   const char *name;                     /* type name for diagnostics  */
535   const struct tvec_flag *fv;           /* name/mask/value mappings */
536   const struct tvec_urange *range;      /* permitted range for literals */
537 };
538
539 /* --- @tvec_claimeq_flags@, @TVEC_CLAIMEQ_FLAGS@ --- *
540  *
541  * Arguments:   @struct tvec_state *tv@ = test-vector state
542  *              @const struct tvec_flaginfo *fi@ = flags type info
543  *              @unsigned long f0, f1@ = two values
544  *              @const char *file@, @unsigned @lno@ = calling file and line
545  *              @const char *expr@ = the expression to quote on failure
546  *
547  * Returns:     Nonzero if @f0@ and @f1@ are equal, otherwise zero.
548  *
549  * Use:         Check that values of @f0@ and @f1@ are equal.  As for
550  *              @tvec_claim@ above, a test case is automatically begun and
551  *              ended if none is already underway.  If the values are
552  *              unequal, then @tvec_fail@ is called, quoting @expr@, and the
553  *              mismatched values are dumped: @f0@ is printed as the output
554  *              value and @f1@ is printed as the input reference.
555  *
556  *              The @TVEC_CLAIM_FLAGS@ macro is similar, only it (a)
557  *              identifies the file and line number of the call site
558  *              automatically, and (b) implicitly quotes the source text of
559  *              the @f0@ and @f1@ arguments in the failure message.
560  */
561
562 extern int tvec_claimeq_flags(struct tvec_state */*tv*/,
563                               const struct tvec_flaginfo */*fi*/,
564                               unsigned long /*f0*/, unsigned long /*f1*/,
565                               const char */*file*/, unsigned /*lno*/,
566                               const char */*expr*/);
567 #define TVEC_CLAIMEQ_FLAGS(tv, fi, f0, f1)                              \
568         (tvec_claimeq_flags(tv, fi, f0, f1,                             \
569                             __FILE__, __LINE__, #f0 " /= " #f1))
570
571 /*----- Character type ----------------------------------------------------*/
572
573 /* A character value holds a character, as read by @fgetc@.  The special
574  * @EOF@ value can also be represented.
575  *
576  * On input, a character value can be given by symbolic name, with a leading
577  * `%|#|%'; or a character or `%|\|%'-escape sequence, optionally in single
578  * quotes.
579  *
580  * The following escape sequences and character names are recognized.
581  *
582  *   * `%|#eof|%' is the special end-of-file marker.
583  *
584  *   * `%|#nul|%' is the NUL character, sometimes used to terminate strings.
585  *
586  *   * `%|bell|%', `%|bel|%', `%|ding|%', or `%|\a|%' is the BEL character
587  *     used to ring the terminal bell (or do some other thing to attract the
588  *     user's attention).
589  *
590  *   * %|#backspace|%, %|#bs|%, or %|\b|% is the backspace character, used to
591  *     move the cursor backwords by one cell.
592  *
593  *   * %|#escape|% %|#esc|%, or%|\e|% is the escape character, used to
594  *     introduce special terminal commands.
595  *
596  *   * %|#formfeed|%, %|#ff|%, or %|\f|% is the formfeed character, used to
597  *     separate pages of text.
598  *
599  *   * %|#newline|%, %|#linefeed|%, %|#lf|%, %|#nl|%, or %|\n|% is the
600  *     newline character, used to terminate lines of text or advance the
601  *     cursor to the next line (perhaps without returning it to the start of
602  *     the line).
603  *
604  *   * %|#return|%, %|#carriage-return|%, %|#cr|%, or %|\r|% is the
605  *     carriage-return character, used to return the cursor to the start of
606  *     the line.
607  *
608  *   * %|#tab|%, %|#horizontal-tab|%, %|#ht|%, or %|\t|% is the tab
609  *     character, used to advance the cursor to the next tab stop on the
610  *     current line.
611  *
612  *   * %|#vertical-tab|%, %|#vt|%, %|\v|% is the vertical tab character.
613  *
614  *   * %|#space|%, %|#spc|% is the space character.
615  *
616  *   * %|#delete|%, %|#del|% is the delete character, used to erase the most
617  *     recent character.
618  *
619  *   * %|\'|% is the single-quote character.
620  *
621  *   * %|\\|% is the backslash character.
622  *
623  *   * %|\"|% is the double-quote character.
624  *
625  *   * %|\NNN|% or %|\{NNN}|% is the character with code NNN in octal.  The
626  *     NNN may be up to three digits long.
627  *
628  *   * %|\xNN|% or %|\x{NN}|% is the character with code NNN in hexadecimal.
629  */
630
631 extern const struct tvec_regty tvty_char;
632
633 /* --- @tvec_claimeq_char@, @TVEC_CLAIMEQ_CHAR@ --- *
634  *
635  * Arguments:   @struct tvec_state *tv@ = test-vector state
636  *              @int ch0, ch1@ = two character codes
637  *              @const char *file@, @unsigned @lno@ = calling file and line
638  *              @const char *expr@ = the expression to quote on failure
639  *
640  * Returns:     Nonzero if @ch0@ and @ch1@ are equal, otherwise zero.
641  *
642  * Use:         Check that values of @ch0@ and @ch1@ are equal.  As for
643  *              @tvec_claim@ above, a test case is automatically begun and
644  *              ended if none is already underway.  If the values are
645  *              unequal, then @tvec_fail@ is called, quoting @expr@, and the
646  *              mismatched values are dumped: @ch0@ is printed as the output
647  *              value and @ch1@ is printed as the input reference.
648  *
649  *              The @TVEC_CLAIM_CHAR@ macro is similar, only it (a)
650  *              identifies the file and line number of the call site
651  *              automatically, and (b) implicitly quotes the source text of
652  *              the @ch0@ and @ch1@ arguments in the failure message.
653  */
654
655 extern int tvec_claimeq_char(struct tvec_state */*tv*/,
656                              int /*ch0*/, int /*ch1*/,
657                              const char */*file*/, unsigned /*lno*/,
658                              const char */*expr*/);
659 #define TVEC_CLAIMEQ_CHAR(tv, c0, c1)                                   \
660         (tvec_claimeq_char(tv, c0, c1, __FILE__, __LINE__, #c0 " /= " #c1))
661
662 /*----- Text and binary string types --------------------------------------*/
663
664 /* A string is a sequence of octets.  Text and binary strings differ
665  * primarily in presentation: text strings are shown as raw characters where
666  * possible; binary strings are shown as hex dumps with an auxiliary text
667  * display.  Storage for strings always uses the standard C library
668  * allocator, though applications will probably need to call @malloc@ or
669  * @free@ only rarely.
670  *
671  * The input format for both kinds of strings is basically the same: a
672  * `compound string', consisting of
673  *
674  *   * single-quoted strings, which are interpreted entirely literally, but
675  *     can't contain single quotes or newlines;
676  *
677  *   * double-quoted strings, in which `%|\|%'-escapes are interpreted as for
678  *     characters;
679  *
680  *   * character names, marked by an initial `%|#|%' sign;
681  *
682  *   * special tokens marked by an initial `%|!|%' sign; or
683  *
684  *   * barewords interpreted according to the current coding scheme.
685  *
686  * The special tokens are
687  *
688  *   * `%|!bare|%', which causes subsequent sequences of barewords to be
689  *     treated as plain text;
690  *
691  *   * `%|!hex|%', `%|!base32|%', `%|!base64|%', which cause subsequent
692  *     barewords to be decoded in the requested manner.
693  *
694  *   * `%|!repeat|% %$n$% %|{|% %%\textit{string}%% %|}|%', which includes
695  *     %$n$% copies of the (compound) string.
696  *
697  * The only difference between text and binary strings is that the initial
698  * coding scheme is %|bare|% for text strings and %|hex|% for binary strings.
699  *
700  * Either kind of string can contain internal nul characters.  A trailing nul
701  * is appended -- beyond the stated input length -- to input strings as a
702  * convenience to test functions.  Test functions may include such a nul
703  * character on output but this is not checked by the equality test.
704  *
705  * A @struct tvec_urange@ may be supplied as an argument: the length of the
706  * string (in bytes) will be checked against the permitted range.
707  */
708
709 extern const struct tvec_regty tvty_text, tvty_bytes;
710
711 /* --- @tvec_alloctext@, @tvec_allocbytes@ --- *
712  *
713  * Arguments:   @union tvec_regval *rv@ = register value
714  *              @size_t sz@ = required size
715  *
716  * Returns:     ---
717  *
718  * Use:         Allocated space in a text or binary string register.  If the
719  *              current register size is sufficient, its buffer is left
720  *              alone; otherwise, the old buffer, if any, is freed and a
721  *              fresh buffer allocated.  These functions are not intended to
722  *              be used to adjust a buffer repeatedly, e.g., while building
723  *              output incrementally: (a) they will perform badly, and (b)
724  *              the old buffer contents are simply discarded if reallocation
725  *              is necessary.  Instead, use a @dbuf@ or @dstr@.
726  *
727  *              The @tvec_alloctext@ function sneakily allocates an extra
728  *              byte for a terminating zero.  The @tvec_allocbytes@ function
729  *              doesn't do this.
730  */
731
732 extern void tvec_alloctext(union tvec_regval */*rv*/, size_t /*sz*/);
733 extern void tvec_allocbytes(union tvec_regval */*rv*/, size_t /*sz*/);
734
735 /* --- @tvec_claimeq_text@, @TVEC_CLAIMEQ_TEXT@ --- *
736  *
737  * Arguments:   @struct tvec_state *tv@ = test-vector state
738  *              @const char *p0@, @size_t sz0@ = first string with length
739  *              @const char *p1@, @size_t sz1@ = second string with length
740  *              @const char *file@, @unsigned @lno@ = calling file and line
741  *              @const char *expr@ = the expression to quote on failure
742  *
743  * Returns:     Nonzero if the strings at @p0@ and @p1@ are equal, otherwise
744  *              zero.
745  *
746  * Use:         Check that strings at @p0@ and @p1@ are equal.  As for
747  *              @tvec_claim@ above, a test case is automatically begun and
748  *              ended if none is already underway.  If the values are
749  *              unequal, then @tvec_fail@ is called, quoting @expr@, and the
750  *              mismatched values are dumped: @p0@ is printed as the output
751  *              value and @p1@ is printed as the input reference.
752  *
753  *              The @TVEC_CLAIM_TEXT@ macro is similar, only it (a)
754  *              identifies the file and line number of the call site
755  *              automatically, and (b) implicitly quotes the source text of
756  *              the @ch0@ and @ch1@ arguments in the failure message.
757  */
758
759 extern int tvec_claimeq_text(struct tvec_state */*tv*/,
760                              const char */*p0*/, size_t /*sz0*/,
761                              const char */*p1*/, size_t /*sz1*/,
762                              const char */*file*/, unsigned /*lno*/,
763                              const char */*expr*/);
764 #define TVEC_CLAIMEQ_TEXT(tv, p0, sz0, p1, sz1)                         \
765         (tvec_claimeq_text(tv, p0, sz0, p1, sz1, __FILE__, __LINE__,    \
766                            #p0 "[" #sz0 "] /= " #p1 "[" #sz1 "]"))
767
768 /* --- @tvec_claimeq_textz@, @TVEC_CLAIMEQ_TEXTZ@ --- *
769  *
770  * Arguments:   @struct tvec_state *tv@ = test-vector state
771  *              @const char *p0, *p1@ = two strings to compare
772  *              @const char *file@, @unsigned @lno@ = calling file and line
773  *              @const char *expr@ = the expression to quote on failure
774  *
775  * Returns:     Nonzero if the strings at @p0@ and @p1@ are equal, otherwise
776  *              zero.
777  *
778  * Use:         Check that strings at @p0@ and @p1@ are equal, as for
779  *              @tvec_claimeq_string@, except that the strings are assumed
780  *              null-terminated, so their lengths don't need to be supplied
781  *              explicitly.  The macro is similarly like @TVEC_CLAIMEQ_TEXT@.
782  */
783
784 extern int tvec_claimeq_textz(struct tvec_state */*tv*/,
785                               const char */*p0*/, const char */*p1*/,
786                               const char */*file*/, unsigned /*lno*/,
787                               const char */*expr*/);
788 #define TVEC_CLAIMEQ_TEXTZ(tv, p0, p1)                                  \
789         (tvec_claimeq_textz(tv, p0, p1, __FILE__, __LINE__, #p0 " /= " #p1))
790
791 /* --- @tvec_claimeq_bytes@, @TVEC_CLAIMEQ_BYTES@ --- *
792  *
793  * Arguments:   @struct tvec_state *tv@ = test-vector state
794  *              @const void *p0@, @size_t sz0@ = first string with length
795  *              @const void *p1@, @size_t sz1@ = second string with length
796  *              @const char *file@, @unsigned @lno@ = calling file and line
797  *              @const char *expr@ = the expression to quote on failure
798  *
799  * Returns:     Nonzero if the strings at @p0@ and @p1@ are equal, otherwise
800  *              zero.
801  *
802  * Use:         Check that binary strings at @p0@ and @p1@ are equal.  As for
803  *              @tvec_claim@ above, a test case is automatically begun and
804  *              ended if none is already underway.  If the values are
805  *              unequal, then @tvec_fail@ is called, quoting @expr@, and the
806  *              mismatched values are dumped: @p0@ is printed as the output
807  *              value and @p1@ is printed as the input reference.
808  *
809  *              The @TVEC_CLAIM_STRING@ macro is similar, only it (a)
810  *              identifies the file and line number of the call site
811  *              automatically, and (b) implicitly quotes the source text of
812  *              the @ch0@ and @ch1@ arguments in the failure message.
813  */
814
815 extern int tvec_claimeq_bytes(struct tvec_state */*tv*/,
816                                const void */*p0*/, size_t /*sz0*/,
817                                const void */*p1*/, size_t /*sz1*/,
818                                const char */*file*/, unsigned /*lno*/,
819                                const char */*expr*/);
820 #define TVEC_CLAIMEQ_BYTES(tv, p0, sz0, p1, sz1)                        \
821         (tvec_claimeq(tv, p0, sz0, p1, sz1, __FILE__, __LINE__,         \
822                       #p0 "[" #sz0 "] /= " #p1 "[" #sz1 "]"))
823
824 /*----- Buffer type -------------------------------------------------------*/
825
826 /* Buffer registers are primarily used for benchmarking.  Only a buffer's
827  * allocation parameters are significant: its contents are ignored on
828  * comparison and output, and unspecified on input.
829  *
830  * The input format gives the buffer's size, and an optional alignment
831  * specification, in the form %|SZ [`@' M [`+' A]]|%.  Each of %|SZ|%, %|M|%
832  * and %|A|% are sizes, as an integer, optionally suffixed with a unit `kB',
833  * `MB', `GB', `TB', `PB', `EB', `ZB', `YB' (with or without the `B')
834  * denoting a power of 1024.  The %|SZ|% gives the (effective) buffer size.
835  * %|M|% is the `alignment quantum' and %|A|% is the `alignment offset'; both
836  * default to zero, but if %|M|% is nonzero then the start of the buffer is
837  * aligned such that it is %|A|% more than a multiple of %|M|% bytes.  Note
838  * that %|M|% need not be a power of two, though this is common.
839  *
840  * Units other than `B' are used on output only when the size would be
841  * expressed exactly.
842  *
843  * Buffers are %%\emph{not}%% allocated by default.  In benchmarks, this is
844  * best done in a @before@ function.
845  *
846  * No @claimeq@ functions or macros are provided for buffers because they
847  * don't seem very useful.
848  */
849
850 extern const struct tvec_regty tvty_buffer;
851
852 /* --- @tvec_initbuffer@ --- *
853  *
854  * Arguments:   @union tvec_regval *rv@ = register value
855  *              @const union tvec_regval *ref@ = reference buffer
856  *              @size_t sz@ = size to allocate
857  *
858  * Returns:     ---
859  *
860  * Use:         Initialize the alignment parameters in @rv@ to match @ref@,
861  *              and the size to @sz@.
862  */
863
864 extern void tvec_initbuffer(union tvec_regval */*rv*/,
865                             const union tvec_regval */*ref*/, size_t /*sz*/);
866
867 /* --- @tvec_allocbuffer@ --- *
868  *
869  * Arguments:   @union tvec_regval *rv@ = register value
870  *
871  * Returns:     ---
872  *
873  * Use:         Allocate @sz@ bytes to the buffer and fill the space with a
874  *              distinctive pattern.
875  */
876
877 extern void tvec_allocbuffer(union tvec_regval */*rv*/);
878
879 /*----- That's all, folks -------------------------------------------------*/
880
881 #ifdef __cplusplus
882   }
883 #endif
884
885 #endif