From 4c3fb76f0341f4ac98f23a434fc741e1252d9627 Mon Sep 17 00:00:00 2001
From: midipix <writeonce@midipix.org>
Date: Sun, 17 Mar 2024 16:02:00 +0000
Subject: slibtoolize mode: program skeleton, driver integration, and symlink
 extra.

---
 include/slibtool/slibtool.h          |   6 ++
 project/common.mk                    |   2 +
 project/extras.mk                    |   7 ++
 project/headers.mk                   |   1 +
 src/driver/slbt_amain.c              |  17 +++-
 src/driver/slbt_driver_ctx.c         |  10 ++
 src/driver/slbt_split_argv.c         |  41 ++++++--
 src/internal/slibtool_driver_impl.h  |   3 +
 src/internal/slibtool_stoolie_impl.h |  15 +++
 src/logic/slbt_exec_stoolie.c        | 178 +++++++++++++++++++++++++++++++++++
 src/skin/slbt_skin_default.c         |   3 +-
 src/skin/slbt_skin_stoolie.c         |  13 +++
 12 files changed, 282 insertions(+), 14 deletions(-)
 create mode 100644 src/internal/slibtool_stoolie_impl.h
 create mode 100644 src/logic/slbt_exec_stoolie.c
 create mode 100644 src/skin/slbt_skin_stoolie.c

diff --git a/include/slibtool/slibtool.h b/include/slibtool/slibtool.h
index bb1fc84..153a202 100644
--- a/include/slibtool/slibtool.h
+++ b/include/slibtool/slibtool.h
@@ -78,6 +78,9 @@ extern "C" {
 #define SLBT_DRIVER_MODE_AR_CHECK	SLBT_DRIVER_XFLAG(0x020000)
 #define SLBT_DRIVER_MODE_AR_MERGE	SLBT_DRIVER_XFLAG(0x040000)
 
+#define SLBT_DRIVER_MODE_STOOLIE	SLBT_DRIVER_XFLAG(0x080000)
+#define SLBT_DRIVER_MODE_SLIBTOOLIZE    SLBT_DRIVER_XFLAG(0x080000)
+
 #define SLBT_DRIVER_PREFER_SHARED       SLBT_DRIVER_XFLAG(0x100000)
 #define SLBT_DRIVER_PREFER_STATIC       SLBT_DRIVER_XFLAG(0x200000)
 
@@ -154,6 +157,7 @@ enum slbt_mode {
 	SLBT_MODE_LINK,
 	SLBT_MODE_UNINSTALL,
 	SLBT_MODE_AR,
+	SLBT_MODE_STOOLIE,
 };
 
 enum slbt_tag {
@@ -422,6 +426,8 @@ slbt_api int  slbt_exec_install         (const struct slbt_driver_ctx *);
 slbt_api int  slbt_exec_link            (const struct slbt_driver_ctx *);
 slbt_api int  slbt_exec_uninstall       (const struct slbt_driver_ctx *);
 slbt_api int  slbt_exec_ar              (const struct slbt_driver_ctx *);
+slbt_api int  slbt_exec_stoolie         (const struct slbt_driver_ctx *);
+slbt_api int  slbt_exec_slibtoolize     (const struct slbt_driver_ctx *);
 
 /* host and flavor interfaces */
 slbt_api int  slbt_host_set_althost     (const struct slbt_driver_ctx *, const char * host, const char * flavor);
diff --git a/project/common.mk b/project/common.mk
index e7d687a..a87d577 100644
--- a/project/common.mk
+++ b/project/common.mk
@@ -39,6 +39,7 @@ API_SRCS = \
 	src/logic/slbt_exec_execute.c \
 	src/logic/slbt_exec_install.c \
 	src/logic/slbt_exec_link.c \
+	src/logic/slbt_exec_stoolie.c \
 	src/logic/slbt_exec_uninstall.c \
 	src/logic/linkcmd/slbt_linkcmd_archive.c \
 	src/logic/linkcmd/slbt_linkcmd_argv.c \
@@ -58,6 +59,7 @@ API_SRCS = \
 	src/skin/slbt_skin_ar.c \
 	src/skin/slbt_skin_default.c \
 	src/skin/slbt_skin_install.c \
+	src/skin/slbt_skin_stoolie.c \
 	src/skin/slbt_skin_uninstall.c \
 
 FALLBACK_SRCS = \
diff --git a/project/extras.mk b/project/extras.mk
index da2faaf..5118914 100644
--- a/project/extras.mk
+++ b/project/extras.mk
@@ -15,6 +15,7 @@ RAPUNZEL = rlibtool
 RAPUNCEL = rclibtool
 RAPUNDEL = rdlibtool
 RAPUNJEL = rdclibtool
+STOOLIE  = slibtoolize
 
 install-app-extras:
 	mkdir -p $(DESTDIR)$(BINDIR)
@@ -38,6 +39,8 @@ install-app-extras:
 	rm -f bin/$(RAPUNDEL)$(OS_APP_SUFFIX).tmp
 	rm -f bin/$(RAPUNJEL)$(OS_APP_SUFFIX).tmp
 
+	rm -f bin/$(STOOLIE)$(OS_APP_SUFFIX).tmp
+
 	ln -s ./$(NICKNAME)$(OS_APP_SUFFIX) bin/$(NICKNAME)-shared$(OS_APP_SUFFIX).tmp
 	ln -s ./$(NICKNAME)$(OS_APP_SUFFIX) bin/$(NICKNAME)-static$(OS_APP_SUFFIX).tmp
 	ln -s ./$(NICKNAME)$(OS_APP_SUFFIX) bin/$(NICKNAME)-ar$(OS_APP_SUFFIX).tmp
@@ -57,6 +60,8 @@ install-app-extras:
 	ln -s ./$(NICKNAME)$(OS_APP_SUFFIX) bin/$(RAPUNDEL)$(OS_APP_SUFFIX).tmp
 	ln -s ./$(NICKNAME)$(OS_APP_SUFFIX) bin/$(RAPUNJEL)$(OS_APP_SUFFIX).tmp
 
+	ln -s ./$(NICKNAME)$(OS_APP_SUFFIX) bin/$(STOOLIE)$(OS_APP_SUFFIX).tmp
+
 	mv bin/$(NICKNAME)-shared$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(NICKNAME)-shared$(OS_APP_SUFFIX)
 	mv bin/$(NICKNAME)-static$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(NICKNAME)-static$(OS_APP_SUFFIX)
 	mv bin/$(NICKNAME)-ar$(OS_APP_SUFFIX).tmp     $(DESTDIR)$(BINDIR)/$(NICKNAME)-ar$(OS_APP_SUFFIX)
@@ -75,3 +80,5 @@ install-app-extras:
 	mv bin/$(RAPUNCEL)$(OS_APP_SUFFIX).tmp        $(DESTDIR)$(BINDIR)/$(RAPUNCEL)$(OS_APP_SUFFIX)
 	mv bin/$(RAPUNDEL)$(OS_APP_SUFFIX).tmp        $(DESTDIR)$(BINDIR)/$(RAPUNDEL)$(OS_APP_SUFFIX)
 	mv bin/$(RAPUNJEL)$(OS_APP_SUFFIX).tmp        $(DESTDIR)$(BINDIR)/$(RAPUNJEL)$(OS_APP_SUFFIX)
+
+	mv bin/$(STOOLIE)$(OS_APP_SUFFIX).tmp         $(DESTDIR)$(BINDIR)/$(STOOLIE)$(OS_APP_SUFFIX)
diff --git a/project/headers.mk b/project/headers.mk
index b986ec2..f57eaae 100644
--- a/project/headers.mk
+++ b/project/headers.mk
@@ -23,6 +23,7 @@ INTERNAL_HEADERS = \
 	$(PROJECT_DIR)/src/internal/$(PACKAGE)_realpath_impl.h \
 	$(PROJECT_DIR)/src/internal/$(PACKAGE)_snprintf_impl.h \
 	$(PROJECT_DIR)/src/internal/$(PACKAGE)_spawn_impl.h \
+	$(PROJECT_DIR)/src/internal/$(PACKAGE)_stoolie_impl.h \
 	$(PROJECT_DIR)/src/internal/$(PACKAGE)_symlink_impl.h \
 	$(PROJECT_DIR)/src/internal/$(PACKAGE)_uninstall_impl.h \
 	$(PROJECT_DIR)/src/internal/$(PACKAGE)_visibility_impl.h \
diff --git a/src/driver/slbt_amain.c b/src/driver/slbt_amain.c
index 3b21500..73d1462 100644
--- a/src/driver/slbt_amain.c
+++ b/src/driver/slbt_amain.c
@@ -85,6 +85,9 @@ static void slbt_perform_driver_actions(struct slbt_driver_ctx * dctx)
 
 	if (dctx->cctx->mode == SLBT_MODE_AR)
 		slbt_exec_ar(dctx);
+
+	if (dctx->cctx->mode == SLBT_MODE_STOOLIE)
+		slbt_exec_stoolie(dctx);
 }
 
 static int slbt_exit(struct slbt_driver_ctx * dctx, int ret)
@@ -132,6 +135,13 @@ int slbt_main(char ** argv, char ** envp, const struct slbt_fd_ctx * fdctx)
 	else if (!(strcmp(dash,"ar")))
 		flags |= SLBT_DRIVER_MODE_AR;
 
+	/* slibtoolize (stoolie) mode */
+	if (!(strcmp(program,"stoolie")))
+		flags |= SLBT_DRIVER_MODE_STOOLIE;
+
+	else if (!(strcmp(program,"slibtoolize")))
+		flags |= SLBT_DRIVER_MODE_STOOLIE;
+
 	/* debug */
 	if (!(strcmp(program,"dlibtool")))
 		flags |= SLBT_DRIVER_DEBUG;
@@ -182,9 +192,10 @@ int slbt_main(char ** argv, char ** envp, const struct slbt_fd_ctx * fdctx)
 	/* --version must be the first (and only) action */
 	if (dctx->cctx->drvflags & SLBT_DRIVER_VERSION)
 		if (dctx->cctx->mode != SLBT_MODE_AR)
-			return (slbt_version(dctx,fdout) < 0)
-				? slbt_exit(dctx,SLBT_ERROR)
-				: slbt_exit(dctx,SLBT_OK);
+			if (dctx->cctx->mode != SLBT_MODE_STOOLIE)
+				return (slbt_version(dctx,fdout) < 0)
+					? slbt_exit(dctx,SLBT_ERROR)
+					: slbt_exit(dctx,SLBT_OK);
 
 	/* perform all other actions */
 	slbt_perform_driver_actions(dctx);
diff --git a/src/driver/slbt_driver_ctx.c b/src/driver/slbt_driver_ctx.c
index a5b3861..3bb0e58 100644
--- a/src/driver/slbt_driver_ctx.c
+++ b/src/driver/slbt_driver_ctx.c
@@ -454,6 +454,9 @@ int slbt_lib_get_driver_ctx(
 	if (flags & SLBT_DRIVER_MODE_AR)
 		cctx.mode = SLBT_MODE_AR;
 
+	else if (flags & SLBT_DRIVER_MODE_STOOLIE)
+		cctx.mode = SLBT_MODE_STOOLIE;
+
 	/* default flags (set at compile time and derived from symlink) */
 	cctx.drvflags = flags;
 
@@ -484,6 +487,7 @@ int slbt_lib_get_driver_ctx(
 						case SLBT_MODE_INSTALL:
 						case SLBT_MODE_UNINSTALL:
 						case SLBT_MODE_AR:
+						case SLBT_MODE_STOOLIE:
 							break;
 
 					default:
@@ -531,6 +535,12 @@ int slbt_lib_get_driver_ctx(
 
 					else if (!strcmp("ar",entry->arg))
 						cctx.mode = SLBT_MODE_AR;
+
+					else if (!strcmp("stoolie",entry->arg))
+						cctx.mode = SLBT_MODE_STOOLIE;
+
+					else if (!strcmp("slibtoolize",entry->arg))
+						cctx.mode = SLBT_MODE_STOOLIE;
 					break;
 
 				case TAG_FINISH:
diff --git a/src/driver/slbt_split_argv.c b/src/driver/slbt_split_argv.c
index 43af9f8..7ad20a3 100644
--- a/src/driver/slbt_split_argv.c
+++ b/src/driver/slbt_split_argv.c
@@ -16,6 +16,7 @@
 #include "slibtool_objlist_impl.h"
 #include "slibtool_errinfo_impl.h"
 #include "slibtool_visibility_impl.h"
+#include "slibtool_stoolie_impl.h"
 #include "slibtool_ar_impl.h"
 #include "argv/argv.h"
 
@@ -59,6 +60,7 @@ slbt_hidden int slbt_split_argv(
 	struct argv_entry *		ccwrap;
 	struct argv_entry *		dumpmachine;
 	struct argv_entry *		aropt;
+	struct argv_entry *		stoolieopt;
 	const struct argv_option **	popt;
 	const struct argv_option **	optout;
 	const struct argv_option *	optv[SLBT_OPTV_ELEMENTS];
@@ -71,6 +73,8 @@ slbt_hidden int slbt_split_argv(
 	/* missing arguments? */
 	if ((altmode = (flags & SLBT_DRIVER_MODE_AR))) {
 		slbt_optv_init(slbt_ar_options,optv);
+	} else if ((altmode = (flags & SLBT_DRIVER_MODE_STOOLIE))) {
+		slbt_optv_init(slbt_stoolie_options,optv);
 	} else {
 		slbt_optv_init(slbt_default_options,optv);
 	}
@@ -120,7 +124,7 @@ slbt_hidden int slbt_split_argv(
 	}
 
 	/* missing all of --mode, --help, --version, --info, --config, --dumpmachine, --features, and --finish? */
-	mode = help = version = info = config = finish = features = ccwrap = dumpmachine = aropt = 0;
+	mode = help = version = info = config = finish = features = ccwrap = dumpmachine = aropt = stoolieopt = 0;
 
 	for (entry=meta->entries; entry->fopt; entry++)
 		if (entry->tag == TAG_MODE)
@@ -146,11 +150,17 @@ slbt_hidden int slbt_split_argv(
 	if (!altmode && mode && !strcmp(mode->arg,"ar"))
 		aropt = mode;
 
+	if (!altmode && mode && !strcmp(mode->arg,"stoolie"))
+		stoolieopt = mode;
+
+	if (!altmode && mode && !strcmp(mode->arg,"slibtoolize"))
+		stoolieopt = mode;
+
 	/* release temporary argv meta context */
 	slbt_argv_free(meta);
 
 	/* error not due to an altmode argument? */
-	if (!aropt && ctx.erridx && (ctx.erridx == ctx.unitidx)) {
+	if (!aropt && !stoolieopt && ctx.erridx && (ctx.erridx == ctx.unitidx)) {
 		if (flags & SLBT_DRIVER_VERBOSITY_ERRORS)
 			slbt_argv_get(
 				argv,optv,
@@ -167,12 +177,14 @@ slbt_hidden int slbt_split_argv(
 	}
 
 	/* missing compiler? */
-	if (!ctx.unitidx && !help && !info && !config && !version && !finish && !features && !dumpmachine && !altmode && !aropt) {
-		if (flags & SLBT_DRIVER_VERBOSITY_ERRORS)
-			slbt_dprintf(fderr,
-				"%s: error: <compiler> is missing.\n",
-				program);
-		return -1;
+	if (!ctx.unitidx && !help && !info && !config && !version && !finish && !features && !dumpmachine) {
+		if (!altmode && !aropt && !stoolieopt) {
+			if (flags & SLBT_DRIVER_VERBOSITY_ERRORS)
+				slbt_dprintf(fderr,
+					"%s: error: <compiler> is missing.\n",
+					program);
+			return -1;
+		}
 	}
 
 	/* clone and normalize the argv vector */
@@ -196,7 +208,7 @@ slbt_hidden int slbt_split_argv(
 	csysroot = 0;
 
 	for (i=0,flast=false,dargv=sargv->dargv,dst=sargv->dargs; i<argc; i++) {
-		if ((fcopy = (flast || altmode || aropt))) {
+		if ((fcopy = (flast || altmode || aropt || stoolieopt))) {
 			(void)0;
 
 		} else if (!strcmp(argv[i],"--")) {
@@ -340,6 +352,10 @@ slbt_hidden int slbt_split_argv(
 	if (aropt && !ctx.unitidx)
 		ctx.unitidx = argc;
 
+	/* --mode=slibtoolize and no slibtoolize-specific arguments? */
+	if (stoolieopt && !ctx.unitidx)
+		ctx.unitidx = argc;
+
 	/* split vectors: slibtool's own options */
 	for (i=0; i<ctx.unitidx; i++)
 		sargv->targv[i] = argv[i];
@@ -349,7 +365,7 @@ slbt_hidden int slbt_split_argv(
 	cargv = sargv->cargv;
 
 	/* known wrappers */
-	if (ctx.unitidx && !ccwrap && !aropt) {
+	if (ctx.unitidx && !ccwrap && !aropt && !stoolieopt) {
 		if ((base = strrchr(argv[i],'/')))
 			base++;
 		else if ((base = strrchr(argv[i],'\\')))
@@ -375,6 +391,8 @@ slbt_hidden int slbt_split_argv(
 		i = 0;
 	} else if (aropt) {
 		*cargv++ = argv[0];
+	} else if (stoolieopt) {
+		*cargv++ = argv[0];
 	} else {
 		*cargv++ = argv[i++];
 	}
@@ -388,6 +406,9 @@ slbt_hidden int slbt_split_argv(
 		if (aropt && (i >= ctx.unitidx)) {
 			*cargv++ = argv[i];
 
+		} else if (stoolieopt && (i >= ctx.unitidx)) {
+			*cargv++ = argv[i];
+
 		} else if (argv[i][0] != '-') {
 			if (argv[i+1] && (argv[i+1][0] == '+')
 					&& (argv[i+1][1] == '=')
diff --git a/src/internal/slibtool_driver_impl.h b/src/internal/slibtool_driver_impl.h
index 047a69b..458f74f 100644
--- a/src/internal/slibtool_driver_impl.h
+++ b/src/internal/slibtool_driver_impl.h
@@ -102,6 +102,9 @@ enum app_tags {
 	TAG_AR_MERGE,
 	TAG_AR_OUTPUT,
 	TAG_AR_VERBOSE,
+	/* slibtoolize (stoolie) mode */
+	TAG_STLE_VERSION,
+	TAG_STLE_HELP,
 };
 
 struct slbt_split_vector {
diff --git a/src/internal/slibtool_stoolie_impl.h b/src/internal/slibtool_stoolie_impl.h
new file mode 100644
index 0000000..43d70a5
--- /dev/null
+++ b/src/internal/slibtool_stoolie_impl.h
@@ -0,0 +1,15 @@
+/*******************************************************************/
+/*  slibtool: a strong libtool implementation, written in C        */
+/*  Copyright (C) 2016--2024  SysDeer Technologies, LLC            */
+/*  Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#ifndef SLIBTOOL_STOOLIE_IMPL_H
+#define SLIBTOOL_STOOLIE_IMPL_H
+
+#include "argv/argv.h"
+#include <slibtool/slibtool.h>
+
+extern const struct argv_option slbt_stoolie_options[];
+
+#endif
diff --git a/src/logic/slbt_exec_stoolie.c b/src/logic/slbt_exec_stoolie.c
new file mode 100644
index 0000000..6b2f883
--- /dev/null
+++ b/src/logic/slbt_exec_stoolie.c
@@ -0,0 +1,178 @@
+/*******************************************************************/
+/*  slibtool: a strong libtool implementation, written in C        */
+/*  Copyright (C) 2016--2024  SysDeer Technologies, LLC            */
+/*  Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <slibtool/slibtool.h>
+#include <slibtool/slibtool_output.h>
+#include "slibtool_driver_impl.h"
+#include "slibtool_stoolie_impl.h"
+#include "slibtool_errinfo_impl.h"
+#include "argv/argv.h"
+
+static int slbt_stoolie_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    stooliemode;
+
+	stooliemode = !strcmp(program,"slibtoolize");
+
+	snprintf(header,sizeof(header),
+		"Usage: %s%s [options] ...\n"
+		"Options:\n",
+		program,
+		stooliemode ? "" : " --mode=slibtoolize");
+
+	switch (noclr) {
+		case 0:
+			slbt_argv_usage(fdout,header,optv,arg);
+			break;
+
+		default:
+			slbt_argv_usage_plain(fdout,header,optv,arg);
+			break;
+	}
+
+	if (ectx)
+		slbt_ectx_free_exec_ctx(ectx);
+
+	slbt_argv_free(meta);
+
+	return SLBT_USAGE;
+}
+
+static int slbt_exec_stoolie_fail(
+	struct slbt_exec_ctx *	ectx,
+	struct argv_meta *	meta,
+	int			ret)
+{
+	slbt_argv_free(meta);
+	slbt_ectx_free_exec_ctx(ectx);
+	return ret;
+}
+
+static int slbt_exec_stoolie_perform_actions(
+	const struct slbt_driver_ctx *  dctx)
+{
+	(void)dctx;
+	return 0;
+}
+
+int slbt_exec_stoolie(const struct slbt_driver_ctx * dctx)
+{
+	int				ret;
+	int				fdout;
+	int				fderr;
+	char **				argv;
+	char **				iargv;
+	struct slbt_exec_ctx *		ectx;
+	struct slbt_driver_ctx_impl *	ictx;
+	const struct slbt_common_ctx *	cctx;
+	struct argv_meta *		meta;
+	struct argv_entry *		entry;
+	size_t				nunits;
+	const struct argv_option *	optv[SLBT_OPTV_ELEMENTS];
+
+	/* context */
+	if (slbt_ectx_get_exec_ctx(dctx,&ectx) < 0)
+		return SLBT_NESTED_ERROR(dctx);
+
+	/* initial state, slibtoolize (stoolie) mode skin */
+	slbt_ectx_reset_arguments(ectx);
+	slbt_disable_placeholders(ectx);
+
+	ictx  = slbt_get_driver_ictx(dctx);
+	cctx  = dctx->cctx;
+	iargv = ectx->cargv;
+
+	fdout = slbt_driver_fdout(dctx);
+	fderr = slbt_driver_fderr(dctx);
+
+	(void)fderr;
+
+	/* missing arguments? */
+	slbt_optv_init(slbt_stoolie_options,optv);
+
+	if (!iargv[1] && (dctx->cctx->drvflags & SLBT_DRIVER_VERBOSITY_USAGE))
+		return slbt_stoolie_usage(
+			fdout,
+			dctx->program,
+			0,optv,0,ectx,
+			dctx->cctx->drvflags & SLBT_DRIVER_ANNOTATE_NEVER);
+
+	/* <stoolie> argv meta */
+	if (!(meta = slbt_argv_get(
+			iargv,optv,
+			dctx->cctx->drvflags & SLBT_DRIVER_VERBOSITY_ERRORS
+				? ARGV_VERBOSITY_ERRORS
+				: ARGV_VERBOSITY_NONE,
+			fdout)))
+		return slbt_exec_stoolie_fail(
+			ectx,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_STLE_HELP:
+					slbt_stoolie_usage(
+						fdout,
+						dctx->program,
+						0,optv,0,ectx,
+						dctx->cctx->drvflags
+							& SLBT_DRIVER_ANNOTATE_NEVER);
+
+					ictx->cctx.drvflags |= SLBT_DRIVER_VERSION;
+					ictx->cctx.drvflags ^= SLBT_DRIVER_VERSION;
+
+					slbt_argv_free(meta);
+
+					return SLBT_OK;
+
+				case TAG_STLE_VERSION:
+					ictx->cctx.drvflags |= SLBT_DRIVER_VERSION;
+					break;
+			}
+
+			if (entry->fval) {
+				*argv++ = (char *)entry->arg;
+			}
+		} else {
+			nunits++;
+		};
+	}
+
+	/* defer --version printing to slbt_main() as needed */
+	if (cctx->drvflags & SLBT_DRIVER_VERSION) {
+		slbt_argv_free(meta);
+		slbt_ectx_free_exec_ctx(ectx);
+		return SLBT_OK;
+	}
+
+	/* slibtoolize operations */
+	ret = slbt_exec_stoolie_perform_actions(dctx);
+
+	/* all done */
+	slbt_argv_free(meta);
+	slbt_ectx_free_exec_ctx(ectx);
+
+	return ret;
+}
+
+int slbt_exec_slibtoolize(const struct slbt_driver_ctx * dctx)
+{
+	return slbt_exec_stoolie(dctx);
+}
diff --git a/src/skin/slbt_skin_default.c b/src/skin/slbt_skin_default.c
index 630afc1..7c54f76 100644
--- a/src/skin/slbt_skin_default.c
+++ b/src/skin/slbt_skin_default.c
@@ -20,7 +20,8 @@ const slbt_hidden struct argv_option slbt_default_options[] = {
 
 	{"mode",		0,TAG_MODE,ARGV_OPTARG_REQUIRED,0,
 				"clean|compile|execute|finish"
-				"|install|link|uninstall|ar",0,
+				"|install|link|uninstall|ar"
+				"|stoolie|slibtoolize",0,
 				"set the execution mode, where <mode> "
 				"is one of {%s}. of the above modes, "
 				"'finish' is not needed and is therefore "
diff --git a/src/skin/slbt_skin_stoolie.c b/src/skin/slbt_skin_stoolie.c
new file mode 100644
index 0000000..c4a10b8
--- /dev/null
+++ b/src/skin/slbt_skin_stoolie.c
@@ -0,0 +1,13 @@
+#include "slibtool_driver_impl.h"
+#include "slibtool_visibility_impl.h"
+#include "argv/argv.h"
+
+const slbt_hidden struct argv_option slbt_stoolie_options[] = {
+	{"version",	0,TAG_STLE_VERSION,ARGV_OPTARG_NONE,0,0,0,
+			"show version information"},
+
+	{"help",	'h',TAG_STLE_HELP,ARGV_OPTARG_NONE,0,0,0,
+			"display slibtoolize (stoolie) mode help"},
+
+	{0,0,0,0,0,0,0,0}
+};
-- 
cgit v1.2.3