diff options
Diffstat (limited to 'src/driver')
-rw-r--r-- | src/driver/slbt_txtfile_ctx.c | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/src/driver/slbt_txtfile_ctx.c b/src/driver/slbt_txtfile_ctx.c new file mode 100644 index 0000000..12b9cff --- /dev/null +++ b/src/driver/slbt_txtfile_ctx.c @@ -0,0 +1,153 @@ +/*******************************************************************/ +/* slibtool: a skinny libtool implementation, written in C */ +/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */ +/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ +/*******************************************************************/ + +#include <ctype.h> +#include <stdint.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> + +#include <slibtool/slibtool.h> +#include "slibtool_driver_impl.h" +#include "slibtool_errinfo_impl.h" + +/********************************************************/ +/* Read a text file, and create an in-memory vecotr of */ +/* normalized text lines, stripped of both leading and */ +/* trailing white space. */ +/********************************************************/ + +static int slbt_lib_free_txtfile_ctx_impl( + struct slbt_txtfile_ctx_impl * ctx, + struct slbt_input * mapinfo, + int ret) +{ + if (mapinfo) + slbt_fs_unmap_input(mapinfo); + + if (ctx) { + if (ctx->pathbuf) + free(ctx->pathbuf); + + if (ctx->txtlines) + free(ctx->txtlines); + + if (ctx->txtlinev) + free(ctx->txtlinev); + + free(ctx); + } + + return ret; +} + +int slbt_lib_get_txtfile_ctx( + const struct slbt_driver_ctx * dctx, + const char * path, + struct slbt_txtfile_ctx ** pctx) +{ + struct slbt_txtfile_ctx_impl * ctx; + struct slbt_input mapinfo; + size_t nlines; + char * ch; + char * cap; + char * src; + char * mark; + const char ** pline; + char dummy; + int cint; + + /* map txtfile file temporarily */ + if (slbt_fs_map_input(dctx,-1,path,PROT_READ,&mapinfo) < 0) + return SLBT_NESTED_ERROR(dctx); + + /* alloc context */ + if (!(ctx = calloc(1,sizeof(*ctx)))) + return slbt_lib_free_txtfile_ctx_impl( + ctx,&mapinfo, + SLBT_BUFFER_ERROR(dctx)); + + /* count lines */ + src = mapinfo.size ? mapinfo.addr : &dummy; + cap = &src[mapinfo.size]; + + for (; (src<cap) && isspace((cint=*src)); ) + src++; + + for (ch=src,nlines=0; ch<cap; ch++) + nlines += (*ch == '\n'); + + nlines += (ch[-1] != '\n'); + + /* clone path, alloc string buffer and line vector */ + if (!(ctx->pathbuf = strdup(path))) + return slbt_lib_free_txtfile_ctx_impl( + ctx,&mapinfo, + SLBT_SYSTEM_ERROR(dctx,0)); + + if (!(ctx->txtlines = calloc(mapinfo.size+1,1))) + return slbt_lib_free_txtfile_ctx_impl( + ctx,&mapinfo, + SLBT_SYSTEM_ERROR(dctx,0)); + + if (!(ctx->txtlinev = calloc(nlines+1,sizeof(char *)))) + return slbt_lib_free_txtfile_ctx_impl( + ctx,&mapinfo, + SLBT_SYSTEM_ERROR(dctx,0)); + + /* copy the source to the allocated string buffer */ + memcpy(ctx->txtlines,mapinfo.addr,mapinfo.size); + slbt_fs_unmap_input(&mapinfo); + + /* populate the line vector, handle whitespace */ + src = ctx->txtlines; + cap = &src[mapinfo.size]; + + for (; (src<cap) && isspace((cint=*src)); ) + *src++ = '\0'; + + for (ch=src,pline=ctx->txtlinev; ch<cap; pline++) { + for (; (ch<cap) && isspace((cint = *ch)); ) + ch++; + + if (ch < cap) + *pline = ch; + + for (; (ch<cap) && (*ch != '\n'); ) + ch++; + + mark = ch; + + for (--ch; (ch > *pline) && isspace((cint = *ch)); ch--) + *ch = '\0'; + + if ((ch = mark) < cap) + *ch++ = '\0'; + } + + /* all done */ + ctx->dctx = dctx; + ctx->path = ctx->pathbuf; + ctx->tctx.path = &ctx->path; + ctx->tctx.txtlinev = ctx->txtlinev; + + *pctx = &ctx->tctx; + + return 0; +} + +void slbt_lib_free_txtfile_ctx(struct slbt_txtfile_ctx * ctx) +{ + struct slbt_txtfile_ctx_impl * ictx; + uintptr_t addr; + + if (ctx) { + addr = (uintptr_t)ctx - offsetof(struct slbt_txtfile_ctx_impl,tctx); + ictx = (struct slbt_txtfile_ctx_impl *)addr; + slbt_lib_free_txtfile_ctx_impl(ictx,0,0); + } +} |