diff options
Diffstat (limited to 'src/driver/tbnf_unit_ctx.c')
-rw-r--r-- | src/driver/tbnf_unit_ctx.c | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/src/driver/tbnf_unit_ctx.c b/src/driver/tbnf_unit_ctx.c new file mode 100644 index 0000000..fedcbaa --- /dev/null +++ b/src/driver/tbnf_unit_ctx.c @@ -0,0 +1,139 @@ +/**************************************************************/ +/* treebnf: a tree oriented bnf library */ +/* Copyright (C) 2024 SysDeer Technologies, LLC */ +/* Released under GPLv2 and GPLv3; see COPYING.TREEBNF. */ +/**************************************************************/ + +#include <stdint.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> + +#include <treebnf/treebnf.h> +#include "treebnf_driver_impl.h" +#include "treebnf_errinfo_impl.h" +#include "treebnf_tmpfile_impl.h" + +static int tbnf_free_unit_ctx_impl(struct tbnf_unit_ctx_impl * ctx, int ret) +{ + if (ctx) { + tbnf_lib_unmap_raw_input(&ctx->map); + free(ctx); + } + + return ret; +} + +static int tbnf_stdin_to_tmp(const struct tbnf_driver_ctx * dctx) +{ + struct tbnf_driver_ctx_impl * ictx; + int fdtmp; + + ssize_t ret; + ssize_t cnt; + char * ch; + char buf[4096]; + + ictx = tbnf_get_driver_ictx(dctx); + + if (ictx->fdtmpin >= 0) + return dup(ictx->fdtmpin); + + if ((fdtmp = tbnf_tmpfile()) < 0) + return -1; + + if ((ictx->fdtmpin = dup(fdtmp)) < 0) { + close(fdtmp); + return -1; + } + + for (;;) { + ret = read(0,buf,sizeof(buf)-1); + + while ((ret < 0) && (errno == EINTR)) + ret = read(0,buf,sizeof(buf)-1); + + if (ret < 0) { + close(fdtmp); + return -1; + + } else if (ret == 0) { + return fdtmp; + + } else { + ch = buf; + cnt = ret; + + for (; cnt; ) { + ret = write(fdtmp,ch,cnt); + + while ((ret < 0) && (errno == EINTR)) + ret = write(fdtmp,ch,cnt); + + if (ret < 0) { + close(fdtmp); + return -1; + } + + ch += ret; + cnt -= ret; + } + } + } +} + +int tbnf_lib_get_unit_ctx( + const struct tbnf_driver_ctx * dctx, + const char * path, + struct tbnf_unit_ctx ** pctx) +{ + struct tbnf_unit_ctx_impl * ctx; + int prot; + int fd; + + if (!dctx) + return TBNF_CUSTOM_ERROR( + dctx,TBNF_ERR_NULL_CONTEXT); + + else if (!(ctx = calloc(1,sizeof(*ctx)))) + return TBNF_BUFFER_ERROR(dctx); + + tbnf_driver_set_ectx( + dctx,0,path); + + prot = PROT_READ; + + if (strcmp(path,"-")) + fd = -1; + + else if ((fd = tbnf_stdin_to_tmp(dctx)) < 0) + return tbnf_free_unit_ctx_impl( + ctx,TBNF_FILE_ERROR(dctx)); + + if (tbnf_lib_map_raw_input(dctx,fd,path,prot,&ctx->map)) + return tbnf_free_unit_ctx_impl( + ctx,TBNF_NESTED_ERROR(dctx)); + + if (fd >= 0) + close(fd); + + ctx->path = path; + ctx->uctx.path = &ctx->path; + ctx->uctx.map = &ctx->map; + + *pctx = &ctx->uctx; + return 0; +} + +void tbnf_lib_free_unit_ctx(struct tbnf_unit_ctx * ctx) +{ + struct tbnf_unit_ctx_impl * ictx; + uintptr_t addr; + + if (ctx) { + addr = (uintptr_t)ctx - offsetof(struct tbnf_unit_ctx_impl,uctx); + ictx = (struct tbnf_unit_ctx_impl *)addr; + tbnf_free_unit_ctx_impl(ictx,0); + } +} |