diff options
Diffstat (limited to 'src/logic')
-rw-r--r-- | src/logic/slbt_exec_ctx.c | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/src/logic/slbt_exec_ctx.c b/src/logic/slbt_exec_ctx.c new file mode 100644 index 0000000..87d8412 --- /dev/null +++ b/src/logic/slbt_exec_ctx.c @@ -0,0 +1,164 @@ +/*******************************************************************/ +/* slibtool: a skinny libtool implementation, written in C */ +/* Copyright (C) 2016 Z. Gilboa */ +/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ +/*******************************************************************/ + +#include <stdint.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> + +#include <slibtool/slibtool.h> + +#define SLBT_ARGV_SPARE_PTRS 16 + +struct slbt_exec_ctx_impl { + int argc; + char * args; + struct slbt_exec_ctx ctx; + char * buffer[]; +}; + + +static size_t slbt_parse_comma_separated_flags( + const char * str, + int * argc) +{ + const char * ch; + + for (ch=str; *ch; ch++) + if (*ch == ',') + (*argc)++; + + return ch - str; +} + + +static struct slbt_exec_ctx_impl * slbt_exec_ctx_alloc( + const struct slbt_driver_ctx * dctx) +{ + struct slbt_exec_ctx_impl * ictx; + size_t size; + int argc; + char * args; + char ** parg; + + size = argc = 0; + + /* buffer size (cargv, -Wc) */ + for (parg=dctx->cctx->cargv; *parg; parg++, argc++) + if (!(strncmp("-Wc,",*parg,4))) + size += sizeof('\0') + slbt_parse_comma_separated_flags( + parg[4],&argc); + else + size += sizeof('\0') + strlen(*parg); + + /* alloc */ + if (!(args = malloc(size + strlen(".libs/") + + strlen(".lo") + + strlen(dctx->cctx->output)))) + return 0; + + size = sizeof(*ictx) + (argc+SLBT_ARGV_SPARE_PTRS)*sizeof(char *); + + if (!(ictx = calloc(1,size))) { + free(args); + return 0; + } + + ictx->args = args; + ictx->argc = argc; + + return ictx; +} + + +int slbt_get_exec_ctx( + const struct slbt_driver_ctx * dctx, + struct slbt_exec_ctx ** ectx) +{ + struct slbt_exec_ctx_impl * ictx; + char ** parg; + char * ch; + char * slash; + int i; + + /* alloc */ + if (!(ictx = slbt_exec_ctx_alloc(dctx))) + return -1; + + /* init with guard for later .lo check */ + ch = ictx->args + strlen(".lo"); + ictx->ctx.argv = ictx->buffer; + + /* <compiler> */ + ictx->ctx.program = dctx->cctx->cargv[0]; + + /* cargv, -Wc */ + for (i=0, parg=dctx->cctx->cargv; *parg; parg++, ch++) { + if (!(strncmp("-Wc,",*parg,4))) { + strcpy(ch,parg[4]); + ictx->ctx.argv[i++] = ch; + + for (; *ch; ch++) + if (*ch == ',') { + *ch = '\0'; + ictx->ctx.argv[i++] = ch+1; + } + } else { + ictx->ctx.argv[i++] = ch; + ch += sprintf(ch,"%s",*parg); + } + } + + if (dctx->cctx->mode == SLBT_MODE_COMPILE) { + if (dctx->cctx->drvflags & SLBT_DRIVER_SHARED) { + ictx->ctx.argv[i++] = "-DPIC"; + ictx->ctx.argv[i++] = "-fPIC"; + } + + ictx->ctx.argv[i++] = "-c"; + ictx->ctx.argv[i++] = "-o"; + ictx->ctx.argv[i++] = ch; + + if ((slash = strrchr(dctx->cctx->output,'/'))) { + sprintf(ch,"%s",dctx->cctx->output); + ch += slash - dctx->cctx->output; + ch += sprintf(ch,"/.libs%s",slash); + } else + ch += sprintf(ch,".libs/%s",dctx->cctx->output); + + if ((ch[-3] == '.') && (ch[-2] == 'l') && (ch[-1] == 'o')) { + ch[-2] = 'o'; + ch[-1] = '\0'; + ch--; + } + } + + *ectx = &ictx->ctx; + return 0; +} + + +static int slbt_free_exec_ctx_impl( + struct slbt_exec_ctx_impl * ictx, + int status) +{ + free(ictx->args); + free (ictx); + return status; +} + + +void slbt_free_exec_ctx(struct slbt_exec_ctx * ctx) +{ + struct slbt_exec_ctx_impl * ictx; + uintptr_t addr; + + if (ctx) { + addr = (uintptr_t)ctx - offsetof(struct slbt_exec_ctx_impl,ctx); + ictx = (struct slbt_exec_ctx_impl *)addr; + slbt_free_exec_ctx_impl(ictx,0); + } +} |