xref: /openbsd-src/regress/lib/libcrypto/mlkem/parse_test_file.c (revision a22ce74601c5d6878965e0c1b7b4f0a3c9646976)
1*a22ce746Stb /*	$OpenBSD: parse_test_file.c,v 1.3 2024/12/27 11:17:48 tb Exp $ */
20c814320Stb 
30c814320Stb /*
40c814320Stb  * Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
50c814320Stb  *
60c814320Stb  * Permission to use, copy, modify, and distribute this software for any
70c814320Stb  * purpose with or without fee is hereby granted, provided that the above
80c814320Stb  * copyright notice and this permission notice appear in all copies.
90c814320Stb  *
100c814320Stb  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
110c814320Stb  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
120c814320Stb  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
130c814320Stb  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
140c814320Stb  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
150c814320Stb  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
160c814320Stb  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
170c814320Stb  */
180c814320Stb 
190c814320Stb #include <sys/types.h>
200c814320Stb 
210c814320Stb #include <assert.h>
220c814320Stb #include <err.h>
230c814320Stb #include <stdarg.h>
240c814320Stb #include <stdint.h>
250c814320Stb #include <stdio.h>
260c814320Stb #include <stdlib.h>
270c814320Stb #include <string.h>
280c814320Stb 
290c814320Stb #include "bytestring.h"
300c814320Stb 
310c814320Stb #include "parse_test_file.h"
320c814320Stb 
330c814320Stb struct line_data {
340c814320Stb 	uint8_t	*data;
350c814320Stb 	size_t	 data_len;
360c814320Stb 	CBS	 cbs;
370c814320Stb 	int	 val;
380c814320Stb };
390c814320Stb 
400c814320Stb static struct line_data *
410c814320Stb line_data_new(void)
420c814320Stb {
430c814320Stb 	return calloc(1, sizeof(struct line_data));
440c814320Stb }
450c814320Stb 
460c814320Stb static void
470c814320Stb line_data_clear(struct line_data *ld)
480c814320Stb {
490c814320Stb 	freezero(ld->data, ld->data_len);
500c814320Stb 	explicit_bzero(ld, sizeof(*ld));
510c814320Stb }
520c814320Stb 
530c814320Stb static void
540c814320Stb line_data_free(struct line_data *ld)
550c814320Stb {
560c814320Stb 	if (ld == NULL)
570c814320Stb 		return;
580c814320Stb 	line_data_clear(ld);
590c814320Stb 	free(ld);
600c814320Stb }
610c814320Stb 
620c814320Stb static void
630c814320Stb line_data_get_int(struct line_data *ld, int *out)
640c814320Stb {
650c814320Stb 	*out = ld->val;
660c814320Stb }
670c814320Stb 
680c814320Stb static void
690c814320Stb line_data_get_cbs(struct line_data *ld, CBS *out)
700c814320Stb {
710c814320Stb 	CBS_dup(&ld->cbs, out);
720c814320Stb }
730c814320Stb 
740c814320Stb static void
750c814320Stb line_data_set_int(struct line_data *ld, int val)
760c814320Stb {
770c814320Stb 	ld->val = val;
780c814320Stb }
790c814320Stb 
800c814320Stb static int
810c814320Stb line_data_set_from_cbb(struct line_data *ld, CBB *cbb)
820c814320Stb {
830c814320Stb 	if (!CBB_finish(cbb, &ld->data, &ld->data_len))
840c814320Stb 		return 0;
850c814320Stb 
860c814320Stb 	CBS_init(&ld->cbs, ld->data, ld->data_len);
870c814320Stb 
880c814320Stb 	return 1;
890c814320Stb }
900c814320Stb 
910c814320Stb struct parse_state {
920c814320Stb 	size_t line;
930c814320Stb 	size_t test;
940c814320Stb 
950c814320Stb 	size_t max;
960c814320Stb 	size_t cur;
970c814320Stb 	struct line_data **data;
980c814320Stb 
990c814320Stb 	size_t instruction_max;
1000c814320Stb 	size_t instruction_cur;
1010c814320Stb 	struct line_data **instruction_data;
1020c814320Stb 
1030c814320Stb 	int running_test_case;
1040c814320Stb };
1050c814320Stb 
1060c814320Stb static void
1070c814320Stb parse_state_init(struct parse_state *ps, size_t max, size_t instruction_max)
1080c814320Stb {
1090c814320Stb 	size_t i;
1100c814320Stb 
1110c814320Stb 	assert(max > 0);
1120c814320Stb 
1130c814320Stb 	memset(ps, 0, sizeof(*ps));
1140c814320Stb 	ps->test = 1;
1150c814320Stb 
1160c814320Stb 	ps->max = max;
1170c814320Stb 	if ((ps->data = calloc(max, sizeof(*ps->data))) == NULL)
1180c814320Stb 		err(1, NULL);
1190c814320Stb 	for (i = 0; i < max; i++) {
1200c814320Stb 		if ((ps->data[i] = line_data_new()) == NULL)
1210c814320Stb 			err(1, NULL);
1220c814320Stb 	}
1230c814320Stb 
1240c814320Stb 	if ((ps->instruction_max = instruction_max) > 0) {
1250c814320Stb 		if ((ps->instruction_data = calloc(instruction_max,
1260c814320Stb 		    sizeof(*ps->instruction_data))) == NULL)
1270c814320Stb 			err(1, NULL);
1280c814320Stb 		for (i = 0; i < instruction_max; i++)
1290c814320Stb 			if ((ps->instruction_data[i] = line_data_new()) == NULL)
1300c814320Stb 				err(1, NULL);
1310c814320Stb 	}
1320c814320Stb }
1330c814320Stb 
1340c814320Stb static void
1350c814320Stb parse_state_finish(struct parse_state *ps)
1360c814320Stb {
1370c814320Stb 	size_t i;
1380c814320Stb 
1390c814320Stb 	for (i = 0; i < ps->max; i++)
1400c814320Stb 		line_data_free(ps->data[i]);
1410c814320Stb 	free(ps->data);
1420c814320Stb 
1430c814320Stb 	for (i = 0; i < ps->instruction_max; i++)
1440c814320Stb 		line_data_free(ps->instruction_data[i]);
1450c814320Stb 	free(ps->instruction_data);
1460c814320Stb }
1470c814320Stb 
1480c814320Stb static void
1490c814320Stb parse_state_new_line(struct parse_state *ps)
1500c814320Stb {
1510c814320Stb 	ps->line++;
1520c814320Stb }
1530c814320Stb 
1540c814320Stb static void
1550c814320Stb parse_instruction_advance(struct parse_state *ps)
1560c814320Stb {
1570c814320Stb 	assert(ps->instruction_cur < ps->instruction_max);
1580c814320Stb 	ps->instruction_cur++;
1590c814320Stb }
1600c814320Stb 
1610c814320Stb static void
1620c814320Stb parse_state_advance(struct parse_state *ps)
1630c814320Stb {
1640c814320Stb 	assert(ps->cur < ps->max);
1650c814320Stb 
1660c814320Stb 	ps->cur++;
1670c814320Stb 	if ((ps->cur %= ps->max) == 0)
1680c814320Stb 		ps->test++;
1690c814320Stb }
1700c814320Stb 
1710c814320Stb struct parse {
1720c814320Stb 	struct parse_state state;
1732a1ab3c3Stb 
1740c814320Stb 	char	*buf;
1750c814320Stb 	size_t	 buf_max;
1762a1ab3c3Stb 	CBS	 cbs;
1772a1ab3c3Stb 
1780c814320Stb 	const struct test_parse *tctx;
1790c814320Stb 	void *ctx;
1800c814320Stb 
1810c814320Stb 	const char *fn;
1820c814320Stb 	FILE *fp;
1830c814320Stb };
1840c814320Stb 
1850c814320Stb static int
1860c814320Stb parse_instructions_parsed(struct parse *p)
1870c814320Stb {
1880c814320Stb 	return p->state.instruction_max == p->state.instruction_cur;
1890c814320Stb }
1900c814320Stb 
1910c814320Stb static void
1920c814320Stb parse_advance(struct parse *p)
1930c814320Stb {
1940c814320Stb 	if (!parse_instructions_parsed(p)) {
1950c814320Stb 		parse_instruction_advance(&p->state);
1960c814320Stb 		return;
1970c814320Stb 	}
1980c814320Stb 	parse_state_advance(&p->state);
1990c814320Stb }
2000c814320Stb 
2010c814320Stb static size_t
2020c814320Stb parse_max(struct parse *p)
2030c814320Stb {
2040c814320Stb 	return p->state.max;
2050c814320Stb }
2060c814320Stb 
2070c814320Stb static size_t
2080c814320Stb parse_instruction_max(struct parse *p)
2090c814320Stb {
2100c814320Stb 	return p->state.instruction_max;
2110c814320Stb }
2120c814320Stb 
2130c814320Stb static size_t
2140c814320Stb parse_cur(struct parse *p)
2150c814320Stb {
2160c814320Stb 	if (!parse_instructions_parsed(p)) {
2170c814320Stb 		assert(p->state.instruction_cur < p->state.instruction_max);
2180c814320Stb 		return p->state.instruction_cur;
2190c814320Stb 	}
2200c814320Stb 
2210c814320Stb 	assert(p->state.cur < parse_max(p));
2220c814320Stb 	return p->state.cur;
2230c814320Stb }
2240c814320Stb 
2250c814320Stb static size_t
2260c814320Stb parse_must_run_test_case(struct parse *p)
2270c814320Stb {
2280c814320Stb 	return parse_instructions_parsed(p) && parse_max(p) - parse_cur(p) == 1;
2290c814320Stb }
2300c814320Stb 
2310c814320Stb static const struct line_spec *
2320c814320Stb parse_states(struct parse *p)
2330c814320Stb {
2340c814320Stb 	if (!parse_instructions_parsed(p))
2350c814320Stb 		return p->tctx->instructions;
2360c814320Stb 	return p->tctx->states;
2370c814320Stb }
2380c814320Stb 
2390c814320Stb static const struct line_spec *
2400c814320Stb parse_instruction_states(struct parse *p)
2410c814320Stb {
2420c814320Stb 	return p->tctx->instructions;
2430c814320Stb }
2440c814320Stb 
2450c814320Stb static const struct line_spec *
2460c814320Stb parse_state(struct parse *p)
2470c814320Stb {
2480c814320Stb 	return &parse_states(p)[parse_cur(p)];
2490c814320Stb }
2500c814320Stb 
2510c814320Stb static size_t
2520c814320Stb line(struct parse *p)
2530c814320Stb {
2540c814320Stb 	return p->state.line;
2550c814320Stb }
2560c814320Stb 
2570c814320Stb static size_t
2580c814320Stb test(struct parse *p)
2590c814320Stb {
2600c814320Stb 	return p->state.test;
2610c814320Stb }
2620c814320Stb 
2630c814320Stb static const char *
2640c814320Stb name(struct parse *p)
2650c814320Stb {
2660c814320Stb 	if (p->state.running_test_case)
2670c814320Stb 		return "running test case";
2680c814320Stb 	return parse_state(p)->name;
2690c814320Stb }
2700c814320Stb 
2710c814320Stb static const char *
2720c814320Stb label(struct parse *p)
2730c814320Stb {
2740c814320Stb 	return parse_state(p)->label;
2750c814320Stb }
2760c814320Stb 
2770c814320Stb static const char *
2780c814320Stb match(struct parse *p)
2790c814320Stb {
2800c814320Stb 	return parse_state(p)->match;
2810c814320Stb }
2820c814320Stb 
2830c814320Stb static enum line
2840c814320Stb parse_line_type(struct parse *p)
2850c814320Stb {
2860c814320Stb 	return parse_state(p)->type;
2870c814320Stb }
2880c814320Stb 
2890c814320Stb static void
2900c814320Stb parse_vinfo(struct parse *p, const char *fmt, va_list ap)
2910c814320Stb {
2920c814320Stb 	fprintf(stderr, "%s:%zu test #%zu (%s): ",
2930c814320Stb 	    p->fn, line(p), test(p), name(p));
2940c814320Stb 	vfprintf(stderr, fmt, ap);
2950c814320Stb 	fprintf(stderr, "\n");
2960c814320Stb }
2970c814320Stb 
2980c814320Stb void
2990c814320Stb parse_info(struct parse *p, const char *fmt, ...)
3000c814320Stb {
3010c814320Stb 	va_list ap;
3020c814320Stb 
3030c814320Stb 	va_start(ap, fmt);
3040c814320Stb 	parse_vinfo(p, fmt, ap);
3050c814320Stb 	va_end(ap);
3060c814320Stb }
3070c814320Stb 
3080c814320Stb void
3090c814320Stb parse_errx(struct parse *p, const char *fmt, ...)
3100c814320Stb {
3110c814320Stb 	va_list ap;
3120c814320Stb 
3130c814320Stb 	va_start(ap, fmt);
3140c814320Stb 	parse_vinfo(p, fmt, ap);
3150c814320Stb 	va_end(ap);
3160c814320Stb 
3170c814320Stb 	exit(1);
3180c814320Stb }
3190c814320Stb 
3200c814320Stb int
3210c814320Stb parse_length_equal(struct parse *p, const char *descr, size_t want, size_t got)
3220c814320Stb {
3230c814320Stb 	if (want == got)
3240c814320Stb 		return 1;
3250c814320Stb 
3260c814320Stb 	parse_info(p, "%s length: want %zu, got %zu", descr, want, got);
3270c814320Stb 	return 0;
3280c814320Stb }
3290c814320Stb 
3300c814320Stb static void
3310c814320Stb hexdump(const uint8_t *buf, size_t len, const uint8_t *compare)
3320c814320Stb {
3330c814320Stb 	const char *mark = "", *newline;
3340c814320Stb 	size_t i;
3350c814320Stb 
3360c814320Stb 	for (i = 1; i <= len; i++) {
3370c814320Stb 		if (compare != NULL)
3380c814320Stb 			mark = (buf[i - 1] != compare[i - 1]) ? "*" : " ";
3390c814320Stb 		newline = i % 8 ? "" : "\n";
3400c814320Stb 		fprintf(stderr, " %s0x%02x,%s", mark, buf[i - 1], newline);
3410c814320Stb 	}
3420c814320Stb 	if ((len % 8) != 0)
3430c814320Stb 		fprintf(stderr, "\n");
3440c814320Stb }
3450c814320Stb 
3460c814320Stb int
3470c814320Stb parse_data_equal(struct parse *p, const char *descr, CBS *want,
3480c814320Stb     const uint8_t *got, size_t got_len)
3490c814320Stb {
3500c814320Stb 	if (!parse_length_equal(p, descr, CBS_len(want), got_len))
3510c814320Stb 		return 0;
3520c814320Stb 	if (CBS_mem_equal(want, got, got_len))
3530c814320Stb 		return 1;
3540c814320Stb 
3550c814320Stb 	parse_info(p, "%s differs", descr);
3560c814320Stb 	fprintf(stderr, "want:\n");
3570c814320Stb 	hexdump(CBS_data(want), CBS_len(want), got);
3580c814320Stb 	fprintf(stderr, "got:\n");
3590c814320Stb 	hexdump(got, got_len, CBS_data(want));
3600c814320Stb 	fprintf(stderr, "\n");
3610c814320Stb 
3620c814320Stb 	return 0;
3630c814320Stb }
3640c814320Stb 
3650c814320Stb static void
3660c814320Stb parse_line_data_clear(struct parse *p)
3670c814320Stb {
3680c814320Stb 	size_t i;
3690c814320Stb 
3700c814320Stb 	for (i = 0; i < parse_max(p); i++)
3710c814320Stb 		line_data_clear(p->state.data[i]);
3720c814320Stb }
3730c814320Stb 
3740c814320Stb static struct line_data **
3750c814320Stb parse_state_data(struct parse *p)
3760c814320Stb {
3770c814320Stb 	if (!parse_instructions_parsed(p))
3780c814320Stb 		return p->state.instruction_data;
3790c814320Stb 	return p->state.data;
3800c814320Stb }
3810c814320Stb 
3820c814320Stb static void
3830c814320Stb parse_state_set_int(struct parse *p, int val)
3840c814320Stb {
3850c814320Stb 	if (parse_line_type(p) != LINE_STRING_MATCH)
3860c814320Stb 		parse_errx(p, "%s: want %d, got %d", __func__,
3870c814320Stb 		    LINE_STRING_MATCH, parse_line_type(p));
3880c814320Stb 	line_data_set_int(parse_state_data(p)[parse_cur(p)], val);
3890c814320Stb }
3900c814320Stb 
3910c814320Stb static void
3920c814320Stb parse_state_set_from_cbb(struct parse *p, CBB *cbb)
3930c814320Stb {
3940c814320Stb 	if (parse_line_type(p) != LINE_HEX)
3950c814320Stb 		parse_errx(p, "%s: want %d, got %d", __func__,
3962a1ab3c3Stb 		    LINE_HEX, parse_line_type(p));
3970c814320Stb 	if (!line_data_set_from_cbb(parse_state_data(p)[parse_cur(p)], cbb))
3980c814320Stb 		parse_errx(p, "line_data_set_from_cbb");
3990c814320Stb }
4000c814320Stb 
4010c814320Stb int
4020c814320Stb parse_get_int(struct parse *p, size_t idx, int *out)
4030c814320Stb {
4040c814320Stb 	assert(parse_must_run_test_case(p));
4050c814320Stb 	assert(idx < parse_max(p));
4060c814320Stb 	assert(parse_states(p)[idx].type == LINE_STRING_MATCH);
4070c814320Stb 
4080c814320Stb 	line_data_get_int(p->state.data[idx], out);
4090c814320Stb 
4100c814320Stb 	return 1;
4110c814320Stb }
4120c814320Stb 
4130c814320Stb int
4140c814320Stb parse_get_cbs(struct parse *p, size_t idx, CBS *out)
4150c814320Stb {
4160c814320Stb 	assert(parse_must_run_test_case(p));
4170c814320Stb 	assert(idx < parse_max(p));
4180c814320Stb 	assert(parse_states(p)[idx].type == LINE_HEX);
4190c814320Stb 
4200c814320Stb 	line_data_get_cbs(p->state.data[idx], out);
4210c814320Stb 
4220c814320Stb 	return 1;
4230c814320Stb }
4240c814320Stb 
4250c814320Stb int
4260c814320Stb parse_instruction_get_int(struct parse *p, size_t idx, int *out)
4270c814320Stb {
4280c814320Stb 	assert(parse_must_run_test_case(p));
4290c814320Stb 	assert(idx < parse_instruction_max(p));
4300c814320Stb 	assert(parse_instruction_states(p)[idx].type == LINE_STRING_MATCH);
4310c814320Stb 
4320c814320Stb 	line_data_get_int(p->state.instruction_data[idx], out);
4330c814320Stb 
4340c814320Stb 	return 1;
4350c814320Stb }
4360c814320Stb 
4370c814320Stb int
4380c814320Stb parse_instruction_get_cbs(struct parse *p, size_t idx, CBS *out)
4390c814320Stb {
4400c814320Stb 	assert(parse_must_run_test_case(p));
4410c814320Stb 	assert(idx < parse_instruction_max(p));
4420c814320Stb 	assert(parse_instruction_states(p)[idx].type == LINE_HEX);
4430c814320Stb 
4440c814320Stb 	line_data_get_cbs(p->state.instruction_data[idx], out);
4450c814320Stb 
4460c814320Stb 	return 1;
4470c814320Stb }
4480c814320Stb 
449*a22ce746Stb static void
450*a22ce746Stb parse_line_skip_to_end(struct parse *p)
451*a22ce746Stb {
452*a22ce746Stb 	if (!CBS_skip(&p->cbs, CBS_len(&p->cbs)))
453*a22ce746Stb 		parse_errx(p, "CBS_skip");
454*a22ce746Stb }
455*a22ce746Stb 
4560c814320Stb static int
4570c814320Stb CBS_peek_bytes(CBS *cbs, CBS *out, size_t len)
4580c814320Stb {
4590c814320Stb 	CBS dup;
4600c814320Stb 
4610c814320Stb 	CBS_dup(cbs, &dup);
4620c814320Stb 	return CBS_get_bytes(&dup, out, len);
4630c814320Stb }
4640c814320Stb 
4650c814320Stb static int
4660c814320Stb parse_peek_string_cbs(struct parse *p, const char *str)
4670c814320Stb {
4680c814320Stb 	CBS cbs;
4690c814320Stb 	size_t len = strlen(str);
4700c814320Stb 
4710c814320Stb 	if (!CBS_peek_bytes(&p->cbs, &cbs, len))
472*a22ce746Stb 		parse_errx(p, "CBS_peek_bytes");
4730c814320Stb 
4740c814320Stb 	return CBS_mem_equal(&cbs, (const uint8_t *)str, len);
4750c814320Stb }
4760c814320Stb 
4770c814320Stb static int
4780c814320Stb parse_get_string_cbs(struct parse *p, const char *str)
4790c814320Stb {
4800c814320Stb 	CBS cbs;
4810c814320Stb 	size_t len = strlen(str);
4820c814320Stb 
4830c814320Stb 	if (!CBS_get_bytes(&p->cbs, &cbs, len))
4840c814320Stb 		parse_errx(p, "CBS_get_bytes");
4850c814320Stb 
4860c814320Stb 	return CBS_mem_equal(&cbs, (const uint8_t *)str, len);
4870c814320Stb }
4880c814320Stb 
4890c814320Stb static int
4900c814320Stb parse_get_string_end_cbs(struct parse *p, const char *str)
4910c814320Stb {
4920c814320Stb 	CBS cbs;
4930c814320Stb 	int equal = 1;
4940c814320Stb 
4950c814320Stb 	CBS_init(&cbs, (const uint8_t *)str, strlen(str));
4960c814320Stb 
4970c814320Stb 	if (CBS_len(&p->cbs) < CBS_len(&cbs))
4980c814320Stb 		parse_errx(p, "line too short to match %s", str);
4990c814320Stb 
5000c814320Stb 	while (CBS_len(&cbs) > 0) {
5010c814320Stb 		uint8_t want, got;
5020c814320Stb 
5030c814320Stb 		if (!CBS_get_last_u8(&cbs, &want))
5040c814320Stb 			parse_errx(p, "CBS_get_last_u8");
5050c814320Stb 		if (!CBS_get_last_u8(&p->cbs, &got))
5060c814320Stb 			parse_errx(p, "CBS_get_last_u8");
5070c814320Stb 		if (want != got)
5080c814320Stb 			equal = 0;
5090c814320Stb 	}
5100c814320Stb 
5110c814320Stb 	return equal;
5120c814320Stb }
5130c814320Stb 
5140c814320Stb static void
5150c814320Stb parse_check_label_matches(struct parse *p)
5160c814320Stb {
5170c814320Stb 	const char *sep = ": ";
5180c814320Stb 
5190c814320Stb 	if (!parse_get_string_cbs(p, label(p)))
5200c814320Stb 		parse_errx(p, "label mismatch %s", label(p));
5210c814320Stb 
5220c814320Stb 	/* Now we expect either ": " or " = ". */
5230c814320Stb 	if (!parse_peek_string_cbs(p, sep))
5240c814320Stb 		sep = " = ";
5250c814320Stb 	if (!parse_get_string_cbs(p, sep))
5260c814320Stb 		parse_errx(p, "error getting \"%s\"", sep);
5270c814320Stb }
5280c814320Stb 
5290c814320Stb static int
5300c814320Stb parse_empty_or_comment_line(struct parse *p)
5310c814320Stb {
5320c814320Stb 	if (CBS_len(&p->cbs) == 0) {
5330c814320Stb 		return 1;
5340c814320Stb 	}
5350c814320Stb 	if (parse_peek_string_cbs(p, "#")) {
536*a22ce746Stb 		parse_line_skip_to_end(p);
5370c814320Stb 		return 1;
5380c814320Stb 	}
5390c814320Stb 	return 0;
5400c814320Stb }
5410c814320Stb 
5420c814320Stb static void
5430c814320Stb parse_string_match_line(struct parse *p)
5440c814320Stb {
5450c814320Stb 	int string_matches;
5460c814320Stb 
5470c814320Stb 	parse_check_label_matches(p);
5480c814320Stb 
5490c814320Stb 	string_matches = parse_get_string_cbs(p, match(p));
5500c814320Stb 	parse_state_set_int(p, string_matches);
5510c814320Stb 
552*a22ce746Stb 	if (!string_matches)
553*a22ce746Stb 		parse_line_skip_to_end(p);
5540c814320Stb }
5550c814320Stb 
5560c814320Stb static int
5570c814320Stb parse_get_hex_nibble_cbs(CBS *cbs, uint8_t *out_nibble)
5580c814320Stb {
5590c814320Stb 	uint8_t c;
5600c814320Stb 
5610c814320Stb 	if (!CBS_get_u8(cbs, &c))
5620c814320Stb 		return 0;
5630c814320Stb 
5640c814320Stb 	if (c >= '0' && c <= '9') {
5650c814320Stb 		*out_nibble = c - '0';
5660c814320Stb 		return 1;
5670c814320Stb 	}
5680c814320Stb 	if (c >= 'a' && c <= 'f') {
5690c814320Stb 		*out_nibble = c - 'a' + 10;
5700c814320Stb 		return 1;
5710c814320Stb 	}
5720c814320Stb 	if (c >= 'A' && c <= 'F') {
5730c814320Stb 		*out_nibble = c - 'A' + 10;
5740c814320Stb 		return 1;
5750c814320Stb 	}
5760c814320Stb 
5770c814320Stb 	return 0;
5780c814320Stb }
5790c814320Stb 
5800c814320Stb static void
5810c814320Stb parse_hex_line(struct parse *p)
5820c814320Stb {
5830c814320Stb 	CBB cbb;
5840c814320Stb 
5850c814320Stb 	parse_check_label_matches(p);
5860c814320Stb 
5870c814320Stb 	if (!CBB_init(&cbb, 0))
5880c814320Stb 		parse_errx(p, "CBB_init");
5890c814320Stb 
5900c814320Stb 	while (CBS_len(&p->cbs) > 0) {
5910c814320Stb 		uint8_t hi, lo;
5920c814320Stb 
5930c814320Stb 		if (!parse_get_hex_nibble_cbs(&p->cbs, &hi))
5940c814320Stb 			parse_errx(p, "parse_get_hex_nibble_cbs");
5950c814320Stb 		if (!parse_get_hex_nibble_cbs(&p->cbs, &lo))
5960c814320Stb 			parse_errx(p, "parse_get_hex_nibble_cbs");
5970c814320Stb 
5980c814320Stb 		if (!CBB_add_u8(&cbb, hi << 4 | lo))
5990c814320Stb 			parse_errx(p, "CBB_add_u8");
6000c814320Stb 	}
6010c814320Stb 
6020c814320Stb 	parse_state_set_from_cbb(p, &cbb);
6030c814320Stb }
6040c814320Stb 
6050c814320Stb static void
6060c814320Stb parse_maybe_prepare_instruction_line(struct parse *p)
6070c814320Stb {
6080c814320Stb 	if (parse_instructions_parsed(p))
6090c814320Stb 		return;
6100c814320Stb 
6110c814320Stb 	/* Should not happen due to parse_empty_or_comment_line(). */
6120c814320Stb 	if (CBS_len(&p->cbs) == 0)
6130c814320Stb 		parse_errx(p, "empty instruction line");
6140c814320Stb 
6150c814320Stb 	if (!parse_peek_string_cbs(p, "["))
6160c814320Stb 		parse_errx(p, "expected instruction line");
6170c814320Stb 	if (!parse_get_string_cbs(p, "["))
6180c814320Stb 		parse_errx(p, "expected start of instruction line");
6190c814320Stb 	if (!parse_get_string_end_cbs(p, "]"))
6200c814320Stb 		parse_errx(p, "expected end of instruction line");
6210c814320Stb }
6220c814320Stb 
6230c814320Stb static void
6240c814320Stb parse_check_line_consumed(struct parse *p)
6250c814320Stb {
6260c814320Stb 	if (CBS_len(&p->cbs) > 0)
6270c814320Stb 		parse_errx(p, "%zu unprocessed bytes", CBS_len(&p->cbs));
6280c814320Stb }
6290c814320Stb 
6300c814320Stb static int
6310c814320Stb parse_run_test_case(struct parse *p)
6320c814320Stb {
6330c814320Stb 	const struct test_parse *tctx = p->tctx;
6340c814320Stb 
6350c814320Stb 	p->state.running_test_case = 1;
6360c814320Stb 	return tctx->run_test_case(p->ctx);
6370c814320Stb }
6380c814320Stb 
6390c814320Stb static void
6400c814320Stb parse_reinit(struct parse *p)
6410c814320Stb {
6420c814320Stb 	const struct test_parse *tctx = p->tctx;
6430c814320Stb 
6440c814320Stb 	p->state.running_test_case = 0;
6450c814320Stb 	parse_line_data_clear(p);
6460c814320Stb 	tctx->finish(p->ctx);
6470c814320Stb 	tctx->init(p->ctx, p);
6480c814320Stb }
6490c814320Stb 
6500c814320Stb static int
6510c814320Stb parse_maybe_run_test_case(struct parse *p)
6520c814320Stb {
6530c814320Stb 	int failed = 0;
6540c814320Stb 
6550c814320Stb 	if (parse_must_run_test_case(p)) {
6560c814320Stb 		failed |= parse_run_test_case(p);
6570c814320Stb 		parse_reinit(p);
6580c814320Stb 	}
6590c814320Stb 
6600c814320Stb 	parse_advance(p);
6610c814320Stb 
6620c814320Stb 	return failed;
6630c814320Stb }
6640c814320Stb 
6650c814320Stb static int
6660c814320Stb parse_process_line(struct parse *p)
6670c814320Stb {
6680c814320Stb 	if (parse_empty_or_comment_line(p))
6690c814320Stb 		return 0;
6700c814320Stb 
6710c814320Stb 	parse_maybe_prepare_instruction_line(p);
6720c814320Stb 
6730c814320Stb 	switch (parse_line_type(p)) {
6740c814320Stb 	case LINE_STRING_MATCH:
6750c814320Stb 		parse_string_match_line(p);
6760c814320Stb 		break;
6770c814320Stb 	case LINE_HEX:
6780c814320Stb 		parse_hex_line(p);
6790c814320Stb 		break;
6800c814320Stb 	default:
6810c814320Stb 		parse_errx(p, "unknown line type %d", parse_line_type(p));
6820c814320Stb 	}
6830c814320Stb 	parse_check_line_consumed(p);
6840c814320Stb 
6850c814320Stb 	return parse_maybe_run_test_case(p);
6860c814320Stb }
6870c814320Stb 
6880c814320Stb static void
6890c814320Stb parse_init(struct parse *p, const char *fn, const struct test_parse *tctx,
6900c814320Stb     void *ctx)
6910c814320Stb {
6920c814320Stb 	FILE *fp;
6930c814320Stb 
6940c814320Stb 	memset(p, 0, sizeof(*p));
6950c814320Stb 
6960c814320Stb 	if ((fp = fopen(fn, "r")) == NULL)
6970c814320Stb 		err(1, "error opening %s", fn);
6980c814320Stb 
6990c814320Stb 	/* Poor man's basename since POSIX basename is stupid. */
7000c814320Stb 	if ((p->fn = strrchr(fn, '/')) != NULL)
7010c814320Stb 		p->fn++;
7020c814320Stb 	else
7030c814320Stb 		p->fn = fn;
7040c814320Stb 
7050c814320Stb 	p->fp = fp;
7060c814320Stb 	parse_state_init(&p->state, tctx->num_states, tctx->num_instructions);
7070c814320Stb 	p->tctx = tctx;
7080c814320Stb 	p->ctx = ctx;
7090c814320Stb 	tctx->init(ctx, p);
7100c814320Stb }
7110c814320Stb 
7120c814320Stb static int
7130c814320Stb parse_next_line(struct parse *p)
7140c814320Stb {
7150c814320Stb 	ssize_t len;
7160c814320Stb 	uint8_t u8;
7170c814320Stb 
7180c814320Stb 	if ((len = getline(&p->buf, &p->buf_max, p->fp)) == -1)
7190c814320Stb 		return 0;
7200c814320Stb 
7210c814320Stb 	CBS_init(&p->cbs, (const uint8_t *)p->buf, len);
7220c814320Stb 	parse_state_new_line(&p->state);
7230c814320Stb 
7240c814320Stb 	if (!CBS_get_last_u8(&p->cbs, &u8))
7250c814320Stb 		parse_errx(p, "CBS_get_last_u8");
7260c814320Stb 
7270c814320Stb 	assert(u8 == '\n');
7280c814320Stb 
7290c814320Stb 	return 1;
7300c814320Stb }
7310c814320Stb 
7320c814320Stb static void
7330c814320Stb parse_finish(struct parse *p)
7340c814320Stb {
7350c814320Stb 	parse_state_finish(&p->state);
7360c814320Stb 
7370c814320Stb 	free(p->buf);
7380c814320Stb 
7390c814320Stb 	if (ferror(p->fp))
7400c814320Stb 		err(1, "%s", p->fn);
7410c814320Stb 	fclose(p->fp);
7420c814320Stb }
7430c814320Stb 
7440c814320Stb int
7450c814320Stb parse_test_file(const char *fn, const struct test_parse *tctx, void *ctx)
7460c814320Stb {
7470c814320Stb 	struct parse p;
7480c814320Stb 	int failed = 0;
7490c814320Stb 
7500c814320Stb 	parse_init(&p, fn, tctx, ctx);
7510c814320Stb 
7520c814320Stb 	while (parse_next_line(&p))
7530c814320Stb 		failed |= parse_process_line(&p);
7540c814320Stb 
7550c814320Stb 	parse_finish(&p);
7560c814320Stb 
7570c814320Stb 	return failed;
7580c814320Stb }
759