From 29086b1d12a2c28cffdbfbf0b3990a7bd75506b9 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Thu, 20 Apr 2017 16:49:35 +0300 Subject: work in progress --- src/fspec/bcode.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 src/fspec/bcode.c (limited to 'src/fspec/bcode.c') diff --git a/src/fspec/bcode.c b/src/fspec/bcode.c new file mode 100644 index 0000000..0a89260 --- /dev/null +++ b/src/fspec/bcode.c @@ -0,0 +1,189 @@ +#include +#include "bcode-internal.h" + +#include +#include +#include +#include + +static_assert(sizeof(fspec_off) <= sizeof(((struct fspec_mem*)0)->len), "fspec_off should not be larger than what fspec_mem can represent"); +static_assert(sizeof(enum fspec_op) == sizeof(uint8_t), "enum fspec_op is expected to have size of uint8_t"); +static_assert(sizeof(enum fspec_arg) == sizeof(uint8_t), "enum fspec_arg is expected to have size of uint8_t"); + +static fspec_off +arg_data_len(const enum fspec_arg *arg) +{ + assert(arg); + + switch (*arg) { + case FSPEC_ARG_NUM: + return sizeof(fspec_num); + + case FSPEC_ARG_VAR: + return sizeof(fspec_var); + + case FSPEC_ARG_STR: + case FSPEC_ARG_OFF: + return sizeof(fspec_off); + + case FSPEC_ARG_DAT: + { + struct fspec_mem mem; + fspec_arg_get_mem(arg, NULL, &mem); + return sizeof(fspec_off) + mem.len; + } + + case FSPEC_ARG_EOF: + break; + + case FSPEC_ARG_LAST: + errx(EXIT_FAILURE, "%s: unexpected argument type %u", __func__, *arg); + break; + } + + return 0; +} + +static fspec_off +arg_len(const enum fspec_arg *arg) +{ + return sizeof(*arg) + arg_data_len(arg); +} + +void +fspec_arg_get_mem(const enum fspec_arg *arg, const void *data, struct fspec_mem *out_mem) +{ + assert(arg && out_mem); + + switch (*arg) { + case FSPEC_ARG_STR: + { + assert(data); + fspec_off off; + fspec_strsz len; + memcpy(&off, (char*)arg + sizeof(*arg), sizeof(off)); + memcpy(&len, (char*)data + off, sizeof(len)); + out_mem->data = (char*)data + off + sizeof(len); + out_mem->len = len; + } + break; + + case FSPEC_ARG_DAT: + { + fspec_off len; + memcpy(&len, (char*)arg + sizeof(*arg), sizeof(len)); + out_mem->data = (char*)arg + sizeof(*arg) + sizeof(len); + out_mem->len = len; + } + break; + + case FSPEC_ARG_VAR: + case FSPEC_ARG_NUM: + case FSPEC_ARG_OFF: + out_mem->data = (char*)arg + sizeof(*arg); + out_mem->len = arg_data_len(arg); + break; + + case FSPEC_ARG_EOF: + *out_mem = (struct fspec_mem){0}; + break; + + case FSPEC_ARG_LAST: + errx(EXIT_FAILURE, "%s: unexpected argument type %u", __func__, *arg); + break; + } +} + +fspec_num +fspec_arg_get_num(const enum fspec_arg *arg) +{ + assert(arg); + fspec_num v; + switch (*arg) { + case FSPEC_ARG_NUM: + memcpy(&v, arg + sizeof(*arg), sizeof(v)); + break; + + case FSPEC_ARG_VAR: + { + fspec_var var; + memcpy(&var, arg + sizeof(*arg), sizeof(var)); + v = var; + } + break; + + case FSPEC_ARG_DAT: + case FSPEC_ARG_OFF: + { + fspec_off off; + memcpy(&off, arg + sizeof(*arg), sizeof(off)); + v = off; + } + break; + + case FSPEC_ARG_STR: + case FSPEC_ARG_EOF: + case FSPEC_ARG_LAST: + errx(EXIT_FAILURE, "%s: unexpected argument type %u", __func__, *arg); + break; + } + return v; +} + +const char* +fspec_arg_get_cstr(const enum fspec_arg *arg, const void *data) +{ + assert(arg && *arg == FSPEC_ARG_STR); + struct fspec_mem mem; + fspec_arg_get_mem(arg, data, &mem); + return (const char*)mem.data; +} + +const enum fspec_arg* +fspec_op_get_arg(const enum fspec_op *start, const void *end, const uint8_t nth, const uint32_t expect) +{ + uint8_t i = 0; + const enum fspec_arg *arg = NULL; + for (const enum fspec_op *op = fspec_op_next(start, end, false); op && i < nth; op = fspec_op_next(op, end, false)) { + if (*op != FSPEC_OP_ARG) + return NULL; + + arg = (void*)(op + 1); + assert(*arg >= 0 && *arg < FSPEC_ARG_LAST); + ++i; + } + + if (arg && !(expect & (1<<*arg))) + errx(EXIT_FAILURE, "got unexpected argument of type %u", *arg); + + return arg; +} + +const enum fspec_arg* +fspec_arg_next(const enum fspec_arg *arg, const void *end, const uint8_t nth, const uint32_t expect) +{ + return fspec_op_get_arg((void*)(arg - 1), end, nth, expect); +} + +const enum fspec_op* +fspec_op_next(const enum fspec_op *start, const void *end, const bool skip_args) +{ + assert(start && end); + fspec_off off = sizeof(*start); + if ((void*)start < end && *start == FSPEC_OP_ARG) + off += arg_len((void*)(start + 1)); + + for (const enum fspec_op *op = start + off; (void*)start < end && (void*)op < end; ++op) { + if (*op >= FSPEC_OP_LAST) + errx(EXIT_FAILURE, "got unexected opcode %u", *op); + + if (skip_args && *op == FSPEC_OP_ARG) { + op += arg_len((void*)(op + 1)); + continue; + } + + return op; + } + + return NULL; +} -- cgit v1.2.3