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