@@@ all the mess ever
[mLib] / test / tvec.h
1 /* -*-c-*-
2 *
3 * Test vector processing framework
4 *
5 * (c) 2023 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_H
29 #define MLIB_TVEC_H
30
31 #ifdef __cplusplus
32 extern "C" {
33 #endif
34
35 /*----- Header files ------------------------------------------------------*/
36
37 #include <stdarg.h>
38 #include <stddef.h>
39 #include <stdio.h>
40 #include <string.h>
41
42 #ifndef MLIB_BUF_H
43 # include "buf.h"
44 #endif
45
46 #ifndef MLIB_CONTROL_H
47 # include "control.h"
48 #endif
49
50 #ifndef MLIB_BUF_H
51 # include "dstr.h"
52 #endif
53
54 #ifndef MLIB_MACROS_H
55 # include "macros.h"
56 #endif
57
58 /*----- Miscellaneous values ----------------------------------------------*/
59
60 /* These are attached to structures which represent extension points, as a
61 * way to pass an opaque parameter to whatever things are hooked onto them.
62 */
63
64 #define TVEC_MISCSLOTS(_) \
65 _(PTR, const void *, p) /* arbitrary pointer */ \
66 _(INT, long, i) /* signed integer */ \
67 _(UINT, unsigned long, u) /* signed integer */
68
69 union tvec_misc {
70 #define TVEC_DEFSLOT(tag, ty, slot) ty slot;
71 TVEC_MISCSLOTS(TVEC_DEFSLOT)
72 #undef TVEC_DEFSLOT
73 };
74 enum {
75 #define TVEC_DEFCONST(tag, ty, slot) TVMISC_##tag,
76 TVEC_MISCSLOTS(TVEC_DEFCONST)
77 TVMISC_LIMIT
78 };
79
80 /*----- Register values ---------------------------------------------------*/
81
82 /* The framework doesn't have a preconceived idea about what's in a register
83 * value: it just allocates them and accesses them through the register type
84 * functions. It doesn't even have a baked-in idea of how big a register
85 * value is: instead, it gets that via the `regsz' slot in `struct
86 * tvec_testinfo'. So, as far as the framework is concerned, it's safe to
87 * add new slots to this union, even if they make the overall union larger.
88 * This can be done by defining the preprocessor macro `TVEC_REGSLOTS' to be
89 * a `union' fragment defining any additional union members.
90 *
91 * This creates a distinction between code which does and doesn't know the
92 * size of a register value. Code which does, which typically means the test
93 * functions, benchmarking setup and teardown functions, and tightly-bound
94 * runner functions, is free to index the register vectors directly. Code
95 * which doesn't, which means the framework core itself and output formatting
96 * machinery, must use the `TVEC_REG' macro (or its more general `TVEC_GREG'
97 * companion) for indexing register vectors. (In principle, register type
98 * handlers also fit into this category, but they have no business peering
99 * into register values other than the one's they're given.)
100 */
101
102 union tvec_regval {
103 /* The actual register value. This is what the type handler sees.
104 * Additional members can be added by setting `TVEC_REGSLOTS' before
105 * including this file.
106 *
107 * A register value can be /initialized/, which simply means that its
108 * contents represent a valid value according to its type -- the
109 * register can be compared, dumped, serialized, parsed into, etc.
110 * You can't do anything safely to an uninitialized register value
111 * other than initialize it.
112 */
113
114 long i; /* signed integer */
115 unsigned long u; /* unsigned integer */
116 void *p; /* pointer */
117 struct { unsigned char *p; size_t sz; } bytes; /* binary string of bytes */
118 struct { char *p; size_t sz; } str; /* text string */
119 #ifdef TVEC_REGSLOTS
120 TVEC_REGSLOTS
121 #endif
122 };
123
124 struct tvec_reg {
125 /* A register.
126 *
127 * Note that all of the registers listed as being used by a
128 * particular test group are initialized at all times[1] while that
129 * test group is being processed. (The other register slots don't
130 * even have types associated with them, so there's nothing useful we
131 * could do with them.)
132 *
133 * The `TVRF_LIVE' flag indicates that the register was assigned a
134 * value by the test vector file: it's the right thing to use to
135 * check whether an optional register is actually present. Even
136 * `dead' registers are still initialized, though.
137 *
138 * [1] This isn't quite true. Between individual tests, the
139 * registers are released and reinitialized in order to reset
140 * them to known values ready for the next test. But you won't
141 * see them at this point.
142 */
143
144 unsigned f; /* flags */
145 #define TVRF_LIVE 1u /* used in current test */
146 union tvec_regval v; /* register value */
147 };
148
149 struct tvec_regdef {
150 /* A register definition. Register definitions list the registers
151 * which are used by a particular test group (see `struct tvec_test'
152 * below).
153 *
154 * A vector of register definitions is terminated by a definition
155 * whose `name' slot is null.
156 */
157
158 const char *name; /* register name (for input files) */
159 unsigned i; /* register index */
160 const struct tvec_regty *ty; /* register type descriptor */
161 unsigned f; /* flags */
162 #define TVRF_OPT 1u /* optional register */
163 #define TVRF_ID 2u /* part of test identity */
164 union tvec_misc arg; /* extra detail for the type */
165 };
166
167 extern int tvec_serialize(const struct tvec_reg */*rv*/,
168 const struct tvec_regdef */*regs*/,
169 unsigned /*nr*/, size_t /*regsz*/,
170 void **/*p_out*/, size_t */*sz_out*/);
171
172 extern int tvec_deserialize(struct tvec_reg */*rv*/,
173 const struct tvec_regdef */*regs*/,
174 unsigned /*nr*/, size_t /*regsz*/,
175 const void */*p*/, size_t /*sz*/);
176
177 /*----- Test state --------------------------------------------------------*/
178
179 enum { TVOUT_LOSE, TVOUT_SKIP, TVOUT_WIN, TVOUT_LIMIT };
180
181 struct tvec_state {
182 unsigned f; /* flags */
183 #define TVSF_SKIP 1u /* skip this test group */
184 #define TVSF_OPEN 2u /* test is open */
185 #define TVSF_ACTIVE 4u /* test is active */
186 #define TVSF_OUTMASK 0xf0 /* test outcome */
187 #define TVSF_OUTSHIFT 4
188 unsigned nrout, nreg; /* number of output/total registers */
189 size_t regsz; /* size of register entry */
190 struct tvec_reg *in, *out; /* register vectors */
191 char expst, st; /* progress status codes */
192 const struct tvec_test *tests, *test; /* all tests and current test */
193 unsigned curr[TVOUT_LIMIT], all[TVOUT_LIMIT], grps[TVOUT_LIMIT];
194 struct tvec_output *output; /* output formatter */
195 const char *infile; unsigned lno, test_lno; /* input file name, line */
196 FILE *fp; /* input file stream */
197 };
198
199 #define TVEC_GREG(vec, i, regsz) \
200 ((struct tvec_reg *)((unsigned char *)(vec) + (i)*(regsz)))
201 #define TVEC_REG(tv, vec, i) TVEC_GREG((tv)->vec, (i), (tv)->regsz)
202
203 /*----- Test descriptions -------------------------------------------------*/
204
205 typedef void tvec_hookfn(struct tvec_state */*tv*/);
206 typedef void tvec_testfn(const struct tvec_reg */*in*/,
207 struct tvec_reg */*out*/,
208 void */*ctx*/);
209
210 struct tvec_test {
211 const char *name; /* name of the test */
212 const struct tvec_regdef *regs; /* descriptions of the registers */
213 tvec_hookfn *preflight; /* check before starting */
214 tvec_hookfn *run; /* test runner */
215 tvec_testfn *fn; /* test function */
216 union tvec_misc arg; /* additional parameter to `run' */
217 };
218
219 extern void PRINTF_LIKE(2, 3)
220 tvec_check(struct tvec_state */*tv*/, const char */*detail*/, ...);
221 extern void tvec_check_v(struct tvec_state */*tv*/,
222 const char */*detail*/, va_list */*ap*/);
223
224 extern void tvec_runtest(struct tvec_state */*tv*/);
225
226 /*----- Input utilities ---------------------------------------------------*/
227
228 extern void tvec_skipspc(struct tvec_state */*tv*/);
229
230 #define TVFF_ALLOWANY 1u
231 extern void tvec_flushtoeol(struct tvec_state */*tv*/, unsigned /*f*/);
232
233 extern int PRINTF_LIKE(4, 5)
234 tvec_readword(struct tvec_state */*tv*/, dstr */*d*/,
235 const char */*delims*/, const char */*expect*/, ...);
236 extern int tvec_readword_v(struct tvec_state */*tv*/, dstr */*d*/,
237 const char */*delims*/, const char */*expect*/,
238 va_list */*ap*/);
239
240 extern int tvec_nexttoken(struct tvec_state */*tv*/);
241
242 /*----- Session lifecycle -------------------------------------------------*/
243
244 struct tvec_info {
245 const struct tvec_test *tests;
246 unsigned nrout, nreg;
247 size_t regsz;
248 };
249
250 extern void tvec_begin(struct tvec_state */*tv_out*/,
251 const struct tvec_info */*info*/,
252 struct tvec_output */*o*/);
253 extern int tvec_end(struct tvec_state */*tv*/);
254
255 extern void tvec_read(struct tvec_state */*tv*/,
256 const char */*infile*/, FILE */*fp*/);
257
258
259 /*----- Benchmarking ------------------------------------------------------*/
260
261 struct tvec_bench {
262 unsigned long niter; /* iterations done per unit */
263 int riter, rbuf; /* iterations and buffer registers */
264 size_t ctxsz; /* size of context */
265 int (*setup)(const struct tvec_reg */*in*/, struct tvec_reg */*out*/,
266 const union tvec_misc */*arg*/, void */*ctx*/); /* setup fn */
267 void (*teardown)(void */*ctx*/); /* teardown function, or null */
268 struct bench_state **b; /* benchmark state anchor or null */
269 union tvec_misc arg; /* argument to setup */
270 };
271
272 extern struct bench_state *tvec_benchstate;
273
274 extern int tvec_ensurebench(struct tvec_state */*tv*/,
275 struct bench_state **/*b_out*/);
276 extern void tvec_bench(struct tvec_state */*tv*/);
277
278 /*----- Ad-hoc testing ----------------------------------------------------*/
279
280 extern void tvec_adhoc(struct tvec_state */*tv*/, struct tvec_test */*t*/);
281
282 extern void tvec_begingroup(struct tvec_state */*tv*/, const char */*name*/,
283 const char */*file*/, unsigned /*lno*/);
284 extern void tvec_reportgroup(struct tvec_state */*tv*/);
285 extern void tvec_endgroup(struct tvec_state */*tv*/);
286
287 #define TVEC_BEGINGROUP(tv, name) \
288 do tvec_begingroup(tv, name, __FILE__, __LINE__); while (0)
289
290 #define TVEC_TESTGROUP(tag, tv, name) \
291 MC_WRAP(tag##__around, \
292 { TVEC_BEGINGROUP(tv, name); }, \
293 { tvec_endgroup(tv); }, \
294 { if (!((tv)->f&TVSF_SKIP)) tvec_skipgroup(tv, 0); \
295 tvec_endgroup(tv); })
296
297 extern void tvec_begintest(struct tvec_state */*tv*/,
298 const char */*file*/, unsigned /*lno*/);
299 extern void tvec_endtest(struct tvec_state */*tv*/);
300
301 #define TVEC_BEGINTEST(tv) \
302 do tvec_begintest(tv, __FILE__, __LINE__); while (0)
303
304 #define TVEC_TEST(tag, tv) \
305 MC_WRAP(tag##__around, \
306 { TVEC_BEGINTEST(tv); }, \
307 { tvec_endtest(tv); }, \
308 { if ((tv)->f&TVSF_ACTIVE) tvec_skipgroup((tv), 0); \
309 tvec_endtest(tv); })
310
311 extern int PRINTF_LIKE(5, 6)
312 tvec_claim(struct tvec_state */*tv*/, int /*ok*/,
313 const char */*file*/, unsigned /*lno*/,
314 const char */*expr*/, ...);
315
316 #define TVEC_CLAIM(tv, cond) \
317 (tvec_claim(tv, !!(cond), __FILE__, __LINE__, #cond " untrue"))
318
319 extern int tvec_claimeq(struct tvec_state */*tv*/,
320 const struct tvec_regty */*ty*/,
321 const union tvec_misc */*arg*/,
322 const char */*file*/, unsigned /*lno*/,
323 const char */*expr*/);
324
325 /*----- Command-line interface --------------------------------------------*/
326
327 extern const struct tvec_info tvec_adhocinfo;
328
329 extern void tvec_parseargs(int /*argc*/, char */*argv*/[],
330 struct tvec_state */*tv_out*/,
331 int */*argpos_out*/,
332 const struct tvec_info */*info*/);
333
334 extern void tvec_readstdin(struct tvec_state */*tv*/);
335 extern void tvec_readfile(struct tvec_state */*tv*/, const char */*file*/);
336 extern void tvec_readdflt(struct tvec_state */*tv*/, const char */*file*/);
337 extern void tvec_readarg(struct tvec_state */*tv*/, const char */*arg*/);
338
339 extern void tvec_readargs(int /*argc*/, char */*argv*/[],
340 struct tvec_state */*tv*/,
341 int */*argpos_inout*/, const char */*dflt*/);
342
343 extern int tvec_main(int /*argc*/, char */*argv*/[],
344 const struct tvec_info */*info*/,
345 const char */*dflt*/);
346
347 /*----- Output formatting -------------------------------------------------*/
348
349 struct tvec_output {
350 const struct tvec_outops *ops;
351 struct tvec_state *tv;
352 };
353
354 struct bench_timing;
355
356 struct tvec_outops {
357 void (*error)(struct tvec_output */*o*/,
358 const char */*msg*/, va_list */*ap*/);
359 void (*notice)(struct tvec_output */*o*/,
360 const char */*msg*/, va_list */*ap*/);
361 void (*write)(struct tvec_output */*o*/, const char */*p*/, size_t /*sz*/);
362
363 void (*bsession)(struct tvec_output */*o*/);
364 int (*esession)(struct tvec_output */*o*/);
365
366 void (*bgroup)(struct tvec_output */*o*/);
367 void (*egroup)(struct tvec_output */*o*/, unsigned /*outcome*/);
368 void (*skipgroup)(struct tvec_output */*o*/,
369 const char */*excuse*/, va_list */*ap*/);
370
371 void (*btest)(struct tvec_output */*o*/);
372 void (*skip)(struct tvec_output */*o*/,
373 const char */*excuse*/, va_list */*ap*/);
374 void (*fail)(struct tvec_output */*o*/,
375 const char */*detail*/, va_list */*ap*/);
376 void (*mismatch)(struct tvec_output */*o*/);
377 void (*etest)(struct tvec_output */*o*/, unsigned /*outcome*/);
378
379 void (*bbench)(struct tvec_output */*o*/);
380 void (*ebench)(struct tvec_output */*o*/,
381 const struct bench_timing */*tm*/);
382
383 void (*destroy)(struct tvec_output */*o*/);
384 };
385
386 extern void PRINTF_LIKE(2, 3) NORETURN
387 tvec_error(struct tvec_state */*tv*/, const char */*msg*/, ...);
388 extern void NORETURN tvec_error_v(struct tvec_state */*tv*/,
389 const char */*msg*/, va_list */*ap*/);
390
391 extern void PRINTF_LIKE(2, 3)
392 tvec_notice(struct tvec_state */*tv*/, const char */*msg*/, ...);
393 extern void tvec_notice_v(struct tvec_state */*tv*/,
394 const char */*msg*/, va_list */*ap*/);
395
396 extern void PRINTF_LIKE(3, 4) NORETURN
397 tvec_syntax(struct tvec_state */*tv*/, int /*ch*/,
398 const char */*expect*/, ...);
399 extern void NORETURN tvec_syntax_v(struct tvec_state */*tv*/, int /*ch*/,
400 const char */*expect*/, va_list */*ap*/);
401
402 extern void PRINTF_LIKE(2, 3)
403 tvec_skipgroup(struct tvec_state */*tv*/, const char */*note*/, ...);
404 extern void tvec_skipgroup_v(struct tvec_state */*tv*/,
405 const char */*note*/, va_list */*ap*/);
406
407 extern void PRINTF_LIKE(2, 3)
408 tvec_skip(struct tvec_state */*tv*/, const char */*excuse*/, ...);
409 extern void tvec_skip_v(struct tvec_state */*tv*/,
410 const char */*excuse*/, va_list */*ap*/);
411
412 extern void PRINTF_LIKE(2, 3)
413 tvec_fail(struct tvec_state */*tv*/, const char */*detail*/, ...);
414 extern void tvec_fail_v(struct tvec_state */*tv*/,
415 const char */*detail*/, va_list */*ap*/);
416
417 extern void tvec_mismatch(struct tvec_state */*tv*/);
418
419 extern void PRINTF_LIKE(2, 3)
420 tvec_write(struct tvec_state */*tv*/, const char */*p*/, ...);
421 extern void tvec_write_v(struct tvec_state */*tv*/,
422 const char */*p*/, va_list */*ap*/);
423
424 extern struct tvec_output *tvec_humanoutput(FILE */*fp*/);
425 extern struct tvec_output *tvec_tapoutput(FILE */*fp*/);
426 extern struct tvec_output *tvec_dfltout(FILE */*fp*/);
427
428 /*----- Register types ----------------------------------------------------*/
429
430 struct tvec_regty {
431 void (*init)(union tvec_regval */*rv*/, const struct tvec_regdef */*rd*/);
432 void (*release)(union tvec_regval */*rv*/,
433 const struct tvec_regdef */*rd*/);
434 int (*eq)(const union tvec_regval */*rv0*/,
435 const union tvec_regval */*rv1*/,
436 const struct tvec_regdef */*rd*/);
437 size_t (*measure)(const union tvec_regval */*rv*/,
438 const struct tvec_regdef */*rd*/);
439 int (*tobuf)(buf */*b*/, const union tvec_regval */*rv*/,
440 const struct tvec_regdef */*rd*/);
441 int (*frombuf)(buf */*b*/, union tvec_regval */*rv*/,
442 const struct tvec_regdef */*rd*/);
443 void (*parse)(union tvec_regval */*rv*/, const struct tvec_regdef */*rd*/,
444 struct tvec_state */*tv*/);
445 void (*dump)(const union tvec_regval */*rv*/,
446 const struct tvec_regdef */*rd*/,
447 struct tvec_state */*tv*/, unsigned /*style*/);
448 #define TVSF_COMPACT 1u
449 };
450
451 extern const struct tvec_regty tvty_int, tvty_uint;
452 struct tvec_irange { long min, max; };
453 struct tvec_urange { unsigned long min, max; };
454
455 extern const struct tvec_irange
456 tvrange_schar, tvrange_short, tvrange_int, tvrange_long,
457 tvrange_sbyte, tvrange_i16, tvrange_i32;
458 extern const struct tvec_urange
459 tvrange_uchar, tvrange_ushort, tvrange_uint, tvrange_ulong, tvrange_size,
460 tvrange_byte, tvrange_u16, tvrange_u32;
461
462 extern int tvec_claimeq_int(struct tvec_state */*tv*/,
463 long /*i0*/, long /*i1*/,
464 const char */*file*/, unsigned /*lno*/,
465 const char */*expr*/);
466 extern int tvec_claimeq_uint(struct tvec_state */*tv*/,
467 unsigned long /*u0*/, unsigned long /*u1*/,
468 const char */*file*/, unsigned /*lno*/,
469 const char */*expr*/);
470 #define TVEC_CLAIMEQ_INT(tv, i0, i1) \
471 (tvec_claimeq_int(tv, i0, i1, __FILE__, __LINE__, #i0 " /= " #i1))
472 #define TVEC_CLAIMEQ_UINT(tv, u0, u1) \
473 (tvec_claimeq_uint(tv, u0, u1, __FILE__, __LINE__, #u0 " /= " #u1))
474
475 extern const struct tvec_regty tvty_enum;
476
477 #define DEFASSOC(tag_, ty, slot) \
478 struct tvec_##slot##assoc { const char *tag; ty slot; };
479 TVEC_MISCSLOTS(DEFASSOC)
480 #undef DEFASSOC
481
482 struct tvec_enuminfo {
483 const char *name; unsigned mv;
484 union {
485 #define DEFENUMINFO(tag, ty, slot) struct { \
486 const struct tvec_##slot##assoc *av; \
487 RANGESLOT_##tag \
488 } slot;
489 #define RANGESLOT_INT const struct tvec_irange *ir;
490 #define RANGESLOT_UINT const struct tvec_urange *ur;
491 #define RANGESLOT_PTR
492 TVEC_MISCSLOTS(DEFENUMINFO)
493 #undef DEFENUMINFO
494 #undef RANGESLOT_INT
495 #undef RANGESLOT_UINT
496 #undef RANGESLOT_PTR
497 } u;
498 };
499
500 #define DECLCLAIM(tag, ty, slot) \
501 extern int tvec_claimeq_##slot##enum \
502 (struct tvec_state */*tv*/, \
503 const struct tvec_enuminfo */*ei*/, ty /*e0*/, ty /*e1*/, \
504 const char */*file*/, unsigned /*lno*/, const char */*expr*/);
505 TVEC_MISCSLOTS(DECLCLAIM)
506 #undef DECLCLAIM
507 #define TVEC_CLAIMEQ_IENUM(tv, ei, e0, e1) \
508 (tvec_claimeq_ienum(tv, ei, e0, e1, \
509 __FILE__, __LINE__, #e0 " /= " #e1))
510 #define TVEC_CLAIMEQ_UENUM(tv, ei, e0, e1) \
511 (tvec_claimeq_uenum(tv, ei, e0, e1, \
512 __FILE__, __LINE__, #e0 " /= " #e1))
513 #define TVEC_CLAIMEQ_PENUM(tv, ei, e0, e1) \
514 (tvec_claimeq_penum(tv, ei, e0, e1, \
515 __FILE__, __LINE__, #e0 " /= " #e1))
516
517 extern const struct tvec_regty tvty_flags;
518 struct tvec_flag { const char *tag; unsigned long m, v; };
519 struct tvec_flaginfo {
520 const char *name;
521 const struct tvec_flag *fv;
522 const struct tvec_urange *range;
523 };
524
525 extern int tvec_claimeq_flags(struct tvec_state */*tv*/,
526 const struct tvec_flaginfo */*fi*/,
527 unsigned long /*f0*/, unsigned long /*f1*/,
528 const char */*file*/, unsigned /*lno*/,
529 const char */*expr*/);
530 #define TVEC_CLAIMEQ_FLAGS(tv, fi, f0, f1) \
531 (tvec_claimeq_flags(tv, fi, f0, f1, \
532 __FILE__, __LINE__, #f0 " /= " #f1))
533
534 extern const struct tvec_regty tvty_string, tvty_bytes;
535
536 extern int tvec_claimeq_string(struct tvec_state */*tv*/,
537 const char */*p0*/, size_t /*sz0*/,
538 const char */*p1*/, size_t /*sz1*/,
539 const char */*file*/, unsigned /*lno*/,
540 const char */*expr*/);
541 extern int tvec_claimeq_strz(struct tvec_state */*tv*/,
542 const char */*p0*/, const char */*p1*/,
543 const char */*file*/, unsigned /*lno*/,
544 const char */*expr*/);
545 extern int tvec_claimeq_bytes(struct tvec_state */*tv*/,
546 const void */*p0*/, size_t /*sz0*/,
547 const void */*p1*/, size_t /*sz1*/,
548 const char */*file*/, unsigned /*lno*/,
549 const char */*expr*/);
550
551 #define TVEC_CLAIMEQ_STRING(tv, p0, sz0, p1, sz1) \
552 (tvec_claimeq_string(tv, p0, sz0, p1, sz1, __FILE__, __LINE__, \
553 #p0 "[" #sz0 "] /= " #p1 "[" #sz1 "]"))
554 #define TVEC_CLAIMEQ_STRZ(tv, p0, p1) \
555 (tvec_claimeq_strz(tv, p0, p1, __FILE__, __LINE__, #p0 " /= " #p1))
556 #define TVEC_CLAIMEQ_BYTES(tv, p0, sz0, p1, sz1) \
557 (tvec_claimeq(tv, p0, sz0, p1, sz1, __FILE__, __LINE__, \
558 #p0 "[" #sz0 "] /= " #p1 "[" #sz1 "]"))
559
560 extern const struct tvec_regty tvty_buffer;
561
562 extern void tvec_allocstring(union tvec_regval */*rv*/, size_t /*sz*/);
563 extern void tvec_allocbytes(union tvec_regval */*rv*/, size_t /*sz*/);
564
565 /*----- That's all, folks -------------------------------------------------*/
566
567 #ifdef __cplusplus
568 }
569 #endif
570
571 #endif