diff --git a/include/slibtool/slibtool.h b/include/slibtool/slibtool.h index 3c436a4..a742037 100644 --- a/include/slibtool/slibtool.h +++ b/include/slibtool/slibtool.h @@ -71,6 +71,8 @@ extern "C" { #define SLBT_DRIVER_STATIC_LIBTOOL_LIBS SLBT_DRIVER_XFLAG(0x0100) #define SLBT_DRIVER_OUTPUT_MACHINE SLBT_DRIVER_XFLAG(0x1000) +#define SLBT_DRIVER_MODE_AR SLBT_DRIVER_XFLAG(0x010000) + /* error flags */ #define SLBT_ERROR_TOP_LEVEL 0x0001 #define SLBT_ERROR_NESTED 0x0002 @@ -93,6 +95,7 @@ enum slbt_custom_error { SLBT_ERR_LCONF_OPEN, SLBT_ERR_LCONF_MAP, SLBT_ERR_LCONF_PARSE, + SLBT_ERR_AR_FAIL, }; /* execution modes */ @@ -106,6 +109,7 @@ enum slbt_mode { SLBT_MODE_INSTALL, SLBT_MODE_LINK, SLBT_MODE_UNINSTALL, + SLBT_MODE_AR, }; enum slbt_tag { @@ -304,6 +308,7 @@ slbt_api int slbt_exec_execute (const struct slbt_driver_ctx *, struct slbt_api int slbt_exec_install (const struct slbt_driver_ctx *, struct slbt_exec_ctx *); slbt_api int slbt_exec_link (const struct slbt_driver_ctx *, struct slbt_exec_ctx *); slbt_api int slbt_exec_uninstall (const struct slbt_driver_ctx *, struct slbt_exec_ctx *); +slbt_api int slbt_exec_ar (const struct slbt_driver_ctx *, struct slbt_exec_ctx *); slbt_api int slbt_set_alternate_host (const struct slbt_driver_ctx *, const char * host, const char * flavor); slbt_api void slbt_reset_alternate_host (const struct slbt_driver_ctx *); diff --git a/project/common.mk b/project/common.mk index 2769569..8fffae8 100644 --- a/project/common.mk +++ b/project/common.mk @@ -6,6 +6,7 @@ API_SRCS = \ src/helper/slbt_dump_machine.c \ src/helper/slbt_map_input.c \ src/helper/slbt_realpath.c \ + src/logic/slbt_exec_ar.c \ src/logic/slbt_exec_compile.c \ src/logic/slbt_exec_ctx.c \ src/logic/slbt_exec_execute.c \ @@ -18,6 +19,7 @@ API_SRCS = \ src/output/slbt_output_fdcwd.c \ src/output/slbt_output_features.c \ src/output/slbt_output_machine.c \ + src/skin/slbt_skin_ar.c \ src/skin/slbt_skin_default.c \ src/skin/slbt_skin_install.c \ src/skin/slbt_skin_uninstall.c \ diff --git a/project/headers.mk b/project/headers.mk index 03bd019..0d22e4c 100644 --- a/project/headers.mk +++ b/project/headers.mk @@ -4,6 +4,7 @@ API_HEADERS = \ INTERNAL_HEADERS = \ $(PROJECT_DIR)/src/internal/argv/argv.h \ + $(PROJECT_DIR)/src/internal/$(PACKAGE)_ar_impl.h \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_dprintf_impl.h \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_driver_impl.h \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_errinfo_impl.h \ diff --git a/src/driver/slbt_amain.c b/src/driver/slbt_amain.c index eff2b45..1cc1c07 100644 --- a/src/driver/slbt_amain.c +++ b/src/driver/slbt_amain.c @@ -79,6 +79,9 @@ static void slbt_perform_driver_actions(struct slbt_driver_ctx * dctx) if (dctx->cctx->mode == SLBT_MODE_UNINSTALL) slbt_exec_uninstall(dctx,0); + + if (dctx->cctx->mode == SLBT_MODE_AR) + slbt_exec_ar(dctx,0); } static int slbt_exit(struct slbt_driver_ctx * dctx, int ret) @@ -122,6 +125,10 @@ int slbt_main(char ** argv, char ** envp, const struct slbt_fd_ctx * fdctx) else if (!(strcmp(dash,"static"))) flags = SLBT_DRIVER_FLAGS | SLBT_DRIVER_DISABLE_SHARED; + /* internal ar mode */ + else if (!(strcmp(dash,"ar"))) + flags |= SLBT_DRIVER_MODE_AR; + /* debug */ if (!(strcmp(program,"dlibtool"))) flags |= SLBT_DRIVER_DEBUG; diff --git a/src/driver/slbt_driver_ctx.c b/src/driver/slbt_driver_ctx.c index cd89a00..458f9c8 100644 --- a/src/driver/slbt_driver_ctx.c +++ b/src/driver/slbt_driver_ctx.c @@ -21,6 +21,7 @@ #include "slibtool_objlist_impl.h" #include "slibtool_errinfo_impl.h" #include "slibtool_lconf_impl.h" +#include "slibtool_ar_impl.h" #include "argv/argv.h" extern char ** environ; @@ -309,6 +310,7 @@ static int slbt_split_argv( char * dst; bool flast; bool fcopy; + bool altmode; size_t size; const char * base; struct argv_meta * meta; @@ -321,6 +323,7 @@ static int slbt_split_argv( struct argv_entry * features; struct argv_entry * ccwrap; struct argv_entry * dumpmachine; + struct argv_entry * aropt; const struct argv_option ** popt; const struct argv_option ** optout; const struct argv_option * optv[SLBT_OPTV_ELEMENTS]; @@ -331,9 +334,14 @@ static int slbt_split_argv( program = argv_program_name(argv[0]); /* missing arguments? */ - argv_optv_init(slbt_default_options,optv); + if ((altmode = (flags & SLBT_DRIVER_MODE_AR))) { + argv_optv_init(slbt_ar_options,optv); + } else { + argv_optv_init(slbt_default_options,optv); + } + - if (!argv[1] && (flags & SLBT_DRIVER_VERBOSITY_USAGE)) + if (!argv[1] && !altmode && (flags & SLBT_DRIVER_VERBOSITY_USAGE)) return slbt_driver_usage( fderr,program, 0,optv,0,sargv,0, @@ -343,7 +351,7 @@ static int slbt_split_argv( argv_scan(argv,optv,&ctx,0); /* invalid slibtool arguments? */ - if (ctx.erridx && !ctx.unitidx) { + if (ctx.erridx && !ctx.unitidx && altmode) { if (flags & SLBT_DRIVER_VERBOSITY_ERRORS) argv_get( argv,optv, @@ -352,6 +360,10 @@ static int slbt_split_argv( return -1; } + /* error possibly due to an altmode argument? */ + if (ctx.erridx && !ctx.unitidx) + ctx.unitidx = ctx.erridx; + /* obtain slibtool's own arguments */ if (ctx.unitidx) { compiler = argv[ctx.unitidx]; @@ -364,7 +376,7 @@ static int slbt_split_argv( } /* missing all of --mode, --help, --version, --config, --dumpmachine, --features, and --finish? */ - mode = help = version = config = finish = features = ccwrap = dumpmachine = 0; + mode = help = version = config = finish = features = ccwrap = dumpmachine = aropt = 0; for (entry=meta->entries; entry->fopt; entry++) if (entry->tag == TAG_MODE) @@ -384,9 +396,24 @@ static int slbt_split_argv( else if (entry->tag == TAG_DUMPMACHINE) dumpmachine = entry; + /* alternate execusion mode? */ + if (!altmode && mode && !strcmp(mode->arg,"ar")) + aropt = mode; + + /* release temporary argv meta context */ argv_free(meta); - if (!mode && !help && !version && !config && !finish && !features && !dumpmachine) { + /* error not due to an altmode argument? */ + if (!aropt && ctx.erridx && (ctx.erridx == ctx.unitidx)) { + if (flags & SLBT_DRIVER_VERBOSITY_ERRORS) + argv_get( + argv,optv, + slbt_argv_flags(flags), + fderr); + return -1; + } + + if (!mode && !help && !version && !config && !finish && !features && !dumpmachine && !altmode) { slbt_dprintf(fderr, "%s: error: --mode must be specified.\n", program); @@ -394,7 +421,7 @@ static int slbt_split_argv( } /* missing compiler? */ - if (!ctx.unitidx && !help && !version && !finish && !features && !dumpmachine) { + if (!ctx.unitidx && !help && !version && !finish && !features && !dumpmachine && !altmode && !aropt) { if (flags & SLBT_DRIVER_VERBOSITY_ERRORS) slbt_dprintf(fderr, "%s: error: is missing.\n", @@ -423,7 +450,7 @@ static int slbt_split_argv( csysroot = 0; for (i=0,flast=false,dargv=sargv->dargv,dst=sargv->dargs; itargv[i] = argv[i]; - sargv->cargv = slbt_default_cargv; + sargv->cargv = altmode ? sargv->targv : slbt_default_cargv; return 0; } + /* --mode=ar and no ar-specific arguments? */ + if (aropt && !ctx.unitidx) + ctx.unitidx = argc; + /* split vectors: slibtool's own options */ for (i=0; itargv[i] = argv[i]; @@ -562,7 +593,7 @@ static int slbt_split_argv( cargv = sargv->cargv; /* known wrappers */ - if (ctx.unitidx && !ccwrap) { + if (ctx.unitidx && !ccwrap && !aropt) { if ((base = strrchr(argv[i],'/'))) base++; else if ((base = strrchr(argv[i],'\\'))) @@ -580,11 +611,17 @@ static int slbt_split_argv( } /* split vectors: legacy mixture */ - for (optout=optv; optout[0]->tag != TAG_OUTPUT; optout++) + for (optout=optv; optout[0] && (optout[0]->tag != TAG_OUTPUT); optout++) (void)0; - /* compiler */ - *cargv++ = argv[i++]; + /* compiler, archiver, etc. */ + if (altmode) { + i = 0; + } else if (aropt) { + *cargv++ = argv[0]; + } else { + *cargv++ = argv[i++]; + } /* sysroot */ if (csysroot) @@ -592,7 +629,10 @@ static int slbt_split_argv( /* remaining vector */ for (objlistp=objlistv; i= ctx.unitidx)) { + *cargv++ = argv[i]; + + } else if (argv[i][0] != '-') { if (argv[i+1] && (argv[i+1][0] == '+') && (argv[i+1][1] == '=') && (argv[i+1][2] == 0) @@ -1433,7 +1473,10 @@ int slbt_get_driver_ctx( const char * lconf; uint64_t lflags; - argv_optv_init(slbt_default_options,optv); + if (flags & SLBT_DRIVER_MODE_AR) + argv_optv_init(slbt_ar_options,optv); + else + argv_optv_init(slbt_default_options,optv); if (!fdctx) fdctx = &slbt_default_fdctx; @@ -1466,6 +1509,9 @@ int slbt_get_driver_ctx( memset(&cctx,0,sizeof(cctx)); + if (flags & SLBT_DRIVER_MODE_AR) + cctx.mode = SLBT_MODE_AR; + /* shared and static objects: enable by default, disable by ~switch */ cctx.drvflags = flags | SLBT_DRIVER_SHARED | SLBT_DRIVER_STATIC; @@ -1488,6 +1534,7 @@ int slbt_get_driver_ctx( switch (cctx.mode) { case SLBT_MODE_INSTALL: case SLBT_MODE_UNINSTALL: + case SLBT_MODE_AR: break; default: @@ -1532,6 +1579,9 @@ int slbt_get_driver_ctx( else if (!strcmp("uninstall",entry->arg)) cctx.mode = SLBT_MODE_UNINSTALL; + + else if (!strcmp("ar",entry->arg)) + cctx.mode = SLBT_MODE_AR; break; case TAG_FINISH: diff --git a/src/internal/slibtool_ar_impl.h b/src/internal/slibtool_ar_impl.h new file mode 100644 index 0000000..3dfabe7 --- /dev/null +++ b/src/internal/slibtool_ar_impl.h @@ -0,0 +1,12 @@ +#ifndef SLIBTOOL_AR_IMPL_H +#define SLIBTOOL_AR_IMPL_H + +#include "argv/argv.h" + +extern const struct argv_option slbt_ar_options[]; + +enum ar_tags { + TAG_AR_HELP, +}; + +#endif diff --git a/src/logic/slbt_exec_ar.c b/src/logic/slbt_exec_ar.c new file mode 100644 index 0000000..7c15d8b --- /dev/null +++ b/src/logic/slbt_exec_ar.c @@ -0,0 +1,173 @@ +/*******************************************************************/ +/* slibtool: a skinny libtool implementation, written in C */ +/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */ +/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ +/*******************************************************************/ + +#define ARGV_DRIVER + +#include +#include "slibtool_driver_impl.h" +#include "slibtool_ar_impl.h" +#include "slibtool_errinfo_impl.h" +#include "argv/argv.h" + +struct slbt_archive_ctx; + +static int slbt_ar_usage( + int fdout, + const char * program, + const char * arg, + const struct argv_option ** optv, + struct argv_meta * meta, + struct slbt_exec_ctx * ectx, + int noclr) +{ + char header[512]; + bool armode; + const char * dash; + + armode = (dash = strrchr(program,'-')) + && !strcmp(++dash,"ar"); + + snprintf(header,sizeof(header), + "Usage: %s%s [options] [ARCHIVE-FILE] [ARCHIVE_FILE] ...\n" + "Options:\n", + program, + armode ? "" : " --mode=ar"); + + switch (noclr) { + case 0: + argv_usage(fdout,header,optv,arg); + break; + + default: + argv_usage_plain(fdout,header,optv,arg); + break; + } + + if (ectx) + slbt_free_exec_ctx(ectx); + + argv_free(meta); + + return SLBT_USAGE; +} + +static int slbt_exec_ar_fail( + struct slbt_exec_ctx * actx, + struct argv_meta * meta, + int ret) +{ + argv_free(meta); + slbt_free_exec_ctx(actx); + return ret; +} + +int slbt_exec_ar( + const struct slbt_driver_ctx * dctx, + struct slbt_exec_ctx * ectx) +{ + int ret; + int fdout; + char ** argv; + char ** iargv; + struct slbt_archive_ctx ** arctxv; + const char ** unitv; + const char ** unitp; + size_t nunits; + struct slbt_exec_ctx * actx; + struct argv_meta * meta; + struct argv_entry * entry; + const struct argv_option * optv[SLBT_OPTV_ELEMENTS]; + + /* context */ + if (ectx) + actx = 0; + else if ((ret = slbt_get_exec_ctx(dctx,&ectx))) + return ret; + else + actx = ectx; + + /* initial state, ar mode skin */ + slbt_reset_arguments(ectx); + slbt_disable_placeholders(ectx); + iargv = ectx->cargv; + fdout = slbt_driver_fdout(dctx); + + /* missing arguments? */ + argv_optv_init(slbt_ar_options,optv); + + if (!iargv[1] && (dctx->cctx->drvflags & SLBT_DRIVER_VERBOSITY_USAGE)) + return slbt_ar_usage( + fdout, + dctx->program, + 0,optv,0,actx, + dctx->cctx->drvflags & SLBT_DRIVER_ANNOTATE_NEVER); + + /* argv meta */ + if (!(meta = argv_get( + iargv,optv, + dctx->cctx->drvflags & SLBT_DRIVER_VERBOSITY_ERRORS + ? ARGV_VERBOSITY_ERRORS + : ARGV_VERBOSITY_NONE, + fdout))) + return slbt_exec_ar_fail( + actx,meta, + SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_AR_FAIL)); + + /* dest, alternate argument vector options */ + argv = ectx->altv; + *argv++ = iargv[0]; + nunits = 0; + + for (entry=meta->entries; entry->fopt || entry->arg; entry++) { + if (entry->fopt) { + switch (entry->tag) { + case TAG_AR_HELP: + slbt_ar_usage( + fdout, + dctx->program, + 0,optv,0,ectx, + dctx->cctx->drvflags + & SLBT_DRIVER_ANNOTATE_NEVER); + return 0; + } + + if (entry->fval) { + *argv++ = (char *)entry->arg; + } + } else { + nunits++; + }; + } + + /* archive vector allocation */ + if (!(arctxv = calloc(nunits+1,sizeof(struct slbt_archive_ctx *)))) + return slbt_exec_ar_fail( + actx,meta, + SLBT_SYSTEM_ERROR(dctx,0)); + + /* unit vector allocation */ + if (!(unitv = calloc(nunits+1,sizeof(const char *)))) { + free (arctxv); + + return slbt_exec_ar_fail( + actx,meta, + SLBT_SYSTEM_ERROR(dctx,0)); + } + + /* unit vector initialization */ + for (entry=meta->entries,unitp=unitv; entry->fopt || entry->arg; entry++) + if (!entry->fopt) + *unitp++ = entry->arg; + + /* all done */ + free(unitv); + free(arctxv); + + argv_free(meta); + slbt_free_exec_ctx(actx); + + return 0; +} diff --git a/src/skin/slbt_skin_ar.c b/src/skin/slbt_skin_ar.c new file mode 100644 index 0000000..4376421 --- /dev/null +++ b/src/skin/slbt_skin_ar.c @@ -0,0 +1,9 @@ +#include "slibtool_ar_impl.h" +#include "argv/argv.h" + +const struct argv_option slbt_ar_options[] = { + {"help", 'h',TAG_AR_HELP,ARGV_OPTARG_NONE,0,0,0, + "display ar mode help"}, + + {0,0,0,0,0,0,0,0} +}; diff --git a/src/skin/slbt_skin_default.c b/src/skin/slbt_skin_default.c index 5c4d67d..9dd372e 100644 --- a/src/skin/slbt_skin_default.c +++ b/src/skin/slbt_skin_default.c @@ -19,7 +19,7 @@ const struct argv_option slbt_default_options[] = { {"mode", 0,TAG_MODE,ARGV_OPTARG_REQUIRED,0, "clean|compile|execute|finish" - "|install|link|uninstall",0, + "|install|link|uninstall|ar",0, "set the execution mode, where " "is one of {%s}. of the above modes, " "'finish' is not needed and is therefore "