From 3d55672811ed7f35d226ab714a5bd812729eb48b Mon Sep 17 00:00:00 2001
From: midipix <writeonce@midipix.org>
Date: Sat, 10 Feb 2024 03:49:05 +0000
Subject: link mode: move the argument vector logic to its own translation
 unit.

---
 project/common.mk                     |   1 +
 src/internal/slibtool_linkcmd_impl.h  |  30 ++
 src/logic/linkcmd/slbt_linkcmd_argv.c | 738 ++++++++++++++++++++++++++++++++++
 src/logic/slbt_exec_link.c            | 695 --------------------------------
 4 files changed, 769 insertions(+), 695 deletions(-)
 create mode 100644 src/logic/linkcmd/slbt_linkcmd_argv.c

diff --git a/project/common.mk b/project/common.mk
index 971173d..e3ca463 100644
--- a/project/common.mk
+++ b/project/common.mk
@@ -28,6 +28,7 @@ API_SRCS = \
 	src/logic/slbt_exec_install.c \
 	src/logic/slbt_exec_link.c \
 	src/logic/slbt_exec_uninstall.c \
+	src/logic/linkcmd/slbt_linkcmd_argv.c \
 	src/logic/linkcmd/slbt_linkcmd_deps.c \
 	src/output/slbt_output_config.c \
 	src/output/slbt_output_error.c \
diff --git a/src/internal/slibtool_linkcmd_impl.h b/src/internal/slibtool_linkcmd_impl.h
index c2598f3..df5a731 100644
--- a/src/internal/slibtool_linkcmd_impl.h
+++ b/src/internal/slibtool_linkcmd_impl.h
@@ -21,4 +21,34 @@ int slbt_exec_link_create_dep_file(
 	const char *			libfilename,
 	bool				farchive);
 
+bool slbt_adjust_object_argument(
+	char *		arg,
+	bool		fpic,
+	bool		fany,
+	int		fdcwd);
+
+bool slbt_adjust_wrapper_argument(
+	char *		arg,
+	bool		fpic);
+
+int slbt_adjust_linker_argument(
+	const struct slbt_driver_ctx *	dctx,
+	char *				arg,
+	char **				xarg,
+	bool				fpic,
+	const char *			dsosuffix,
+	const char *			arsuffix,
+	struct slbt_deps_meta * 	depsmeta);
+
+int slbt_exec_link_adjust_argument_vector(
+	const struct slbt_driver_ctx *	dctx,
+	struct slbt_exec_ctx *		ectx,
+	struct slbt_deps_meta *		depsmeta,
+	const char *			cwd,
+	bool				flibrary);
+
+int slbt_exec_link_finalize_argument_vector(
+	const struct slbt_driver_ctx *	dctx,
+	struct slbt_exec_ctx *		ectx);
+
 #endif
diff --git a/src/logic/linkcmd/slbt_linkcmd_argv.c b/src/logic/linkcmd/slbt_linkcmd_argv.c
new file mode 100644
index 0000000..ec3b11e
--- /dev/null
+++ b/src/logic/linkcmd/slbt_linkcmd_argv.c
@@ -0,0 +1,738 @@
+/*******************************************************************/
+/*  slibtool: a skinny libtool implementation, written in C        */
+/*  Copyright (C) 2016--2021  SysDeer Technologies, LLC            */
+/*  Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include <slibtool/slibtool.h>
+#include "slibtool_driver_impl.h"
+#include "slibtool_errinfo_impl.h"
+#include "slibtool_linkcmd_impl.h"
+#include "slibtool_mapfile_impl.h"
+#include "slibtool_metafile_impl.h"
+#include "slibtool_snprintf_impl.h"
+#include "slibtool_symlink_impl.h"
+#include "slibtool_readlink_impl.h"
+
+
+static int slbt_linkcmd_exit(
+	struct slbt_deps_meta *	depsmeta,
+	int			ret)
+{
+	if (depsmeta->altv)
+		free(depsmeta->altv);
+
+	if (depsmeta->args)
+		free(depsmeta->args);
+
+	return ret;
+}
+
+
+static int slbt_emit_fdwrap_amend_dl_path(
+	const struct slbt_driver_ctx *	dctx,
+	struct slbt_exec_ctx *		ectx,
+	struct slbt_deps_meta * 	depsmeta,
+	const char *			fmt,
+					...)
+{
+	va_list		ap;
+	char *		buf;
+	int		cnt;
+	char		dlpathbuf[2048];
+	int		fdwrap;
+	const char *	fdwrap_fmt;
+	int		size;
+
+	va_start(ap,fmt);
+
+	size = sizeof(dlpathbuf);
+
+	buf  = ((cnt = vsnprintf(dlpathbuf,size,fmt,ap)) < size)
+		? dlpathbuf : malloc((size = cnt + 1));
+
+	va_end(ap);
+
+	if (buf == dlpathbuf) {
+		(void)0;
+
+	} else if (buf) {
+		va_start(ap,fmt);
+		vsprintf(buf,fmt,ap);
+		va_end(ap);
+
+	} else {
+		return slbt_linkcmd_exit(
+			depsmeta,
+			SLBT_SYSTEM_ERROR(dctx,0));
+	}
+
+	if ((fdwrap = slbt_exec_get_fdwrapper(ectx)) >= 0) {
+		if (buf[0] == '/') {
+			fdwrap_fmt =
+				"DL_PATH=\"${DL_PATH}${COLON}%s\"\n"
+				"COLON=':'\n\n";
+		} else {
+			fdwrap_fmt =
+				"DL_PATH=\"${DL_PATH}${COLON}${DL_PATH_FIXUP}%s\"\n"
+				"COLON=':'\n\n";
+		}
+
+		if (slbt_dprintf(fdwrap,fdwrap_fmt,buf) < 0) {
+			return slbt_linkcmd_exit(
+				depsmeta,
+				SLBT_SYSTEM_ERROR(dctx,0));
+		}
+	}
+
+	return 0;
+}
+
+
+bool slbt_adjust_object_argument(
+	char *		arg,
+	bool		fpic,
+	bool		fany,
+	int		fdcwd)
+{
+	char *	slash;
+	char *	dot;
+	char	base[PATH_MAX];
+
+	if (*arg == '-')
+		return false;
+
+	/* object argument: foo.lo or foo.o */
+	if (!(dot = strrchr(arg,'.')))
+		return false;
+
+	if ((dot[1]=='l') && (dot[2]=='o') && !dot[3]) {
+		dot[1] = 'o';
+		dot[2] = 0;
+
+	} else if ((dot[1]=='o') && !dot[2]) {
+		(void)0;
+
+	} else {
+		return false;
+	}
+
+	/* foo.o requested and is present? */
+	if (!fpic && !faccessat(fdcwd,arg,0,0))
+		return true;
+
+	/* .libs/foo.o */
+	if ((slash = strrchr(arg,'/')))
+		slash++;
+	else
+		slash = arg;
+
+	if (slbt_snprintf(base,sizeof(base),
+			"%s",slash) < 0)
+		return false;
+
+	sprintf(slash,".libs/%s",base);
+
+	if (!faccessat(fdcwd,arg,0,0))
+		return true;
+
+	/* foo.o requested and neither is present? */
+	if (!fpic) {
+		strcpy(slash,base);
+		return true;
+	}
+
+	/* .libs/foo.o explicitly requested and is not present? */
+	if (!fany)
+		return true;
+
+	/* use foo.o in place of .libs/foo.o */
+	strcpy(slash,base);
+
+	if (faccessat(fdcwd,arg,0,0))
+		sprintf(slash,".libs/%s",base);
+
+	return true;
+}
+
+
+bool slbt_adjust_wrapper_argument(
+	char *		arg,
+	bool		fpic)
+{
+	char *	slash;
+	char *	dot;
+	char	base[PATH_MAX];
+
+	if (*arg == '-')
+		return false;
+
+	if (!(dot = strrchr(arg,'.')))
+		return false;
+
+	if (strcmp(dot,".la"))
+		return false;
+
+	if (fpic) {
+		if ((slash = strrchr(arg,'/')))
+			slash++;
+		else
+			slash = arg;
+
+		if (slbt_snprintf(base,sizeof(base),
+				"%s",slash) < 0)
+			return false;
+
+		sprintf(slash,".libs/%s",base);
+		dot = strrchr(arg,'.');
+	}
+
+	strcpy(dot,".a");
+	return true;
+}
+
+
+int slbt_adjust_linker_argument(
+	const struct slbt_driver_ctx *	dctx,
+	char *				arg,
+	char **				xarg,
+	bool				fpic,
+	const char *			dsosuffix,
+	const char *			arsuffix,
+	struct slbt_deps_meta * 	depsmeta)
+{
+	int	fdcwd;
+	int	fdlib;
+	char *	slash;
+	char *	dot;
+	char	base[PATH_MAX];
+
+	if (*arg == '-')
+		return 0;
+
+	if (!(dot = strrchr(arg,'.')))
+		return 0;
+
+	if (!(strcmp(dot,arsuffix))) {
+		*xarg = arg;
+		return slbt_get_deps_meta(dctx,arg,1,depsmeta);
+	}
+
+	if (!(strcmp(dot,dsosuffix)))
+		return slbt_get_deps_meta(dctx,arg,1,depsmeta);
+
+	if (strcmp(dot,".la"))
+		return 0;
+
+	if (fpic) {
+		if ((slash = strrchr(arg,'/')))
+			slash++;
+		else
+			slash = arg;
+
+		if (slbt_snprintf(base,sizeof(base),
+				"%s",slash) < 0)
+			return 0;
+
+		sprintf(slash,".libs/%s",base);
+		dot = strrchr(arg,'.');
+	}
+
+	/* fdcwd */
+	fdcwd = slbt_driver_fdcwd(dctx);
+
+	/* shared library dependency? */
+	if (fpic) {
+		sprintf(dot,"%s",dsosuffix);
+
+		if (slbt_symlink_is_a_placeholder(fdcwd,arg))
+			sprintf(dot,"%s",arsuffix);
+		else if ((fdlib = openat(fdcwd,arg,O_RDONLY)) >= 0)
+			close(fdlib);
+		else
+			sprintf(dot,"%s",arsuffix);
+
+		return slbt_get_deps_meta(dctx,arg,0,depsmeta);
+	}
+
+	/* input archive */
+	sprintf(dot,"%s",arsuffix);
+	return slbt_get_deps_meta(dctx,arg,0,depsmeta);
+}
+
+
+int slbt_exec_link_adjust_argument_vector(
+	const struct slbt_driver_ctx *	dctx,
+	struct slbt_exec_ctx *		ectx,
+	struct slbt_deps_meta *		depsmeta,
+	const char *			cwd,
+	bool				flibrary)
+{
+	int			fd;
+	int			fdcwd;
+	char ** 		carg;
+	char ** 		aarg;
+	char *			ldir;
+	char *			slash;
+	char *			mark;
+	char *			darg;
+	char *			dot;
+	char *			base;
+	char *			dpath;
+	int			argc;
+	char			arg[PATH_MAX];
+	char			lib[PATH_MAX];
+	char			depdir  [PATH_MAX];
+	char			rpathdir[PATH_MAX];
+	char			rpathlnk[PATH_MAX];
+	struct stat		st;
+	size_t			size;
+	size_t			dlen;
+	struct slbt_map_info *	mapinfo;
+	bool			fwholearchive = false;
+	int			ret;
+
+	for (argc=0,carg=ectx->cargv; *carg; carg++)
+		argc++;
+
+	if (!(depsmeta->args = calloc(1,depsmeta->infolen)))
+		return SLBT_SYSTEM_ERROR(dctx,0);
+
+	argc *= 3;
+	argc += depsmeta->depscnt;
+
+	if (!(depsmeta->altv = calloc(argc,sizeof(char *))))
+		return slbt_linkcmd_exit(
+			depsmeta,
+			SLBT_SYSTEM_ERROR(dctx,0));
+
+	fdcwd = slbt_driver_fdcwd(dctx);
+
+	carg = ectx->cargv;
+	aarg = depsmeta->altv;
+	darg = depsmeta->args;
+	size = depsmeta->infolen;
+
+	for (; *carg; ) {
+		dpath = 0;
+
+		if (!strcmp(*carg,"-Wl,--whole-archive"))
+			fwholearchive = true;
+		else if (!strcmp(*carg,"-Wl,--no-whole-archive"))
+			fwholearchive = false;
+
+
+
+		/* output annotation */
+		if (carg == ectx->lout[0]) {
+			ectx->mout[0] = &aarg[0];
+			ectx->mout[1] = &aarg[1];
+		}
+
+		/* argument translation */
+		mark = *carg;
+
+		if ((mark[0] == '-') && (mark[1] == 'L')) {
+			if (mark[2]) {
+				ldir = &mark[2];
+			} else {
+				*aarg++ = *carg++;
+				ldir    = *carg;
+			}
+
+			mark = ldir + strlen(ldir);
+
+			if (mark[-1] == '/')
+				strcpy(mark,".libs");
+			else
+				strcpy(mark,"/.libs");
+
+			if ((fd = openat(fdcwd,ldir,O_DIRECTORY,0)) < 0)
+				*mark = 0;
+			else {
+				close(fd);
+
+				if ((ret = slbt_emit_fdwrap_amend_dl_path(
+						dctx,ectx,depsmeta,
+						"%s",ldir)) < 0)
+					return ret;
+			}
+
+			*aarg++ = *carg++;
+
+		} else if (**carg == '-') {
+			*aarg++ = *carg++;
+
+		} else if (!(dot = strrchr(*carg,'.'))) {
+			*aarg++ = *carg++;
+
+		} else if (ectx->xargv[carg - ectx->cargv]) {
+			*aarg++ = *carg++;
+
+		} else if (!(strcmp(dot,".a"))) {
+			if (flibrary && !fwholearchive)
+				*aarg++ = "-Wl,--whole-archive";
+
+			dpath = lib;
+			sprintf(lib,"%s.slibtool.deps",*carg);
+			*aarg++ = *carg++;
+
+			if (flibrary && !fwholearchive)
+				*aarg++ = "-Wl,--no-whole-archive";
+
+		} else if (strcmp(dot,dctx->cctx->settings.dsosuffix)) {
+			*aarg++ = *carg++;
+
+		} else if (carg == ectx->lout[1]) {
+			/* ^^^hoppla^^^ */
+			*aarg++ = *carg++;
+		} else {
+			/* -rpath */
+			sprintf(rpathlnk,"%s.slibtool.rpath",*carg);
+
+			if (!fstatat(fdcwd,rpathlnk,&st,AT_SYMLINK_NOFOLLOW)) {
+				if (slbt_readlinkat(
+						fdcwd,
+						rpathlnk,
+						rpathdir,
+						sizeof(rpathdir)))
+					return slbt_linkcmd_exit(
+						depsmeta,
+						SLBT_SYSTEM_ERROR(dctx,rpathlnk));
+
+				sprintf(darg,"-Wl,%s",rpathdir);
+				*aarg++ = "-Wl,-rpath";
+				*aarg++ = darg;
+				darg   += strlen(darg);
+				darg++;
+			}
+
+			dpath = lib;
+			sprintf(lib,"%s.slibtool.deps",*carg);
+
+			/* account for {'-','L','-','l'} */
+			if (slbt_snprintf(arg,
+					sizeof(arg) - 4,
+					"%s",*carg) < 0)
+				return slbt_linkcmd_exit(
+					depsmeta,
+					SLBT_BUFFER_ERROR(dctx));
+
+			if ((slash = strrchr(arg,'/'))) {
+				sprintf(*carg,"-L%s",arg);
+
+				mark   = strrchr(*carg,'/');
+				*mark  = 0;
+				*slash = 0;
+
+				if ((ret = slbt_emit_fdwrap_amend_dl_path(
+						dctx,ectx,depsmeta,
+						"%s%s%s",
+						((arg[0] == '/') ? "" : cwd),
+						((arg[0] == '/') ? "" : "/"),
+						arg)) < 0) {
+					return ret;
+				}
+
+				dlen = strlen(dctx->cctx->settings.dsoprefix);
+
+				/* -module? (todo: non-portable usage, display warning) */
+				if (strncmp(++slash,dctx->cctx->settings.dsoprefix,dlen)) {
+					*--slash = '/';
+					strcpy(*carg,arg);
+					*aarg++ = *carg++;
+				} else {
+					*aarg++ = *carg++;
+					*aarg++ = ++mark;
+
+					slash += dlen;
+
+					sprintf(mark,"-l%s",slash);
+					dot  = strrchr(mark,'.');
+					*dot = 0;
+				}
+			} else {
+				*aarg++ = *carg++;
+			}
+		}
+
+		if (dpath && !fstatat(fdcwd,dpath,&st,0)) {
+			if (!(mapinfo = slbt_map_file(
+					fdcwd,dpath,
+					SLBT_MAP_INPUT)))
+				return slbt_linkcmd_exit(
+					depsmeta,
+					SLBT_SYSTEM_ERROR(dctx,dpath));
+
+			if (!(strncmp(lib,".libs/",6))) {
+				*aarg++ = "-L.libs";
+				lib[1] = 0;
+			} else if ((base = strrchr(lib,'/'))) {
+				if (base - lib == 5) {
+					if (!(strncmp(&base[-5],".libs/",6)))
+						base -= 4;
+
+				} else if (base - lib >= 6) {
+					if (!(strncmp(&base[-6],"/.libs/",7)))
+						base -= 6;
+				}
+
+				*base = 0;
+			} else {
+				lib[0] = '.';
+				lib[1] = 0;
+			}
+
+			while (mapinfo->mark < mapinfo->cap) {
+				if (slbt_mapped_readline(dctx,mapinfo,darg,size))
+					return slbt_linkcmd_exit(
+						depsmeta,
+						SLBT_NESTED_ERROR(dctx));
+
+				*aarg++   = darg;
+				mark      = darg;
+
+				dlen      = strlen(darg);
+				size     -= dlen;
+				darg     += dlen;
+				darg[-1]  = 0;
+
+				/* handle -L... as needed */
+				if ((mark[0] == '-')
+						&& (mark[1] == 'L')
+						&& (mark[2] != '/')) {
+					if (strlen(mark) >= sizeof(depdir) - 1)
+						return slbt_linkcmd_exit(
+							depsmeta,
+							SLBT_BUFFER_ERROR(dctx));
+
+					darg = mark;
+					strcpy(depdir,&mark[2]);
+					sprintf(darg,"-L%s/%s",lib,depdir);
+
+					darg += strlen(darg);
+					darg++;
+
+					if ((ret = slbt_emit_fdwrap_amend_dl_path(
+							dctx,ectx,depsmeta,
+							"%s/%s",lib,depdir)) < 0)
+						return ret;
+
+				} else if ((mark[0] == '-') && (mark[1] == 'L')) {
+					if ((ret = slbt_emit_fdwrap_amend_dl_path(
+							dctx,ectx,depsmeta,
+							"%s",&mark[2])) < 0)
+						return ret;
+				}
+			}
+		}
+	}
+
+	if (dctx->cctx->drvflags & SLBT_DRIVER_EXPORT_DYNAMIC)
+		*aarg++ = "-Wl,--export-dynamic";
+
+	return 0;
+}
+
+
+int slbt_exec_link_finalize_argument_vector(
+	const struct slbt_driver_ctx *	dctx,
+	struct slbt_exec_ctx *		ectx)
+{
+	char *		sargv[1024];
+	char **		sargvbuf;
+	char **		base;
+	char **		parg;
+	char **		aarg;
+	char **		oarg;
+	char **		larg;
+	char **		darg;
+	char **		earg;
+	char **		rarg;
+	char **		aargv;
+	char **		oargv;
+	char **		cap;
+	char **		src;
+	char **		dst;
+	char *		arg;
+	char *		dot;
+	char *		ccwrap;
+	const char *	arsuffix;
+
+	/* vector size */
+	base     = ectx->argv;
+	arsuffix = dctx->cctx->settings.arsuffix;
+
+	for (parg=base; *parg; parg++)
+		(void)0;
+
+	/* buffer */
+	if (parg - base < 512) {
+		aargv    = &sargv[0];
+		oargv    = &sargv[512];
+		aarg     = aargv;
+		oarg     = oargv;
+		sargvbuf = 0;
+
+	} else if (!(sargvbuf = calloc(2*(parg-base+1),sizeof(char *)))) {
+		return SLBT_SYSTEM_ERROR(dctx,0);
+
+	} else {
+		aargv = &sargvbuf[0];
+		oargv = &sargvbuf[parg-base+1];
+		aarg  = aargv;
+		oarg  = oargv;
+	}
+
+	/* (program name) */
+	parg = &base[1];
+
+	/* split object args from all other args, record output */
+	/* annotation, and remove redundant -l arguments       */
+	for (; *parg; ) {
+		if (ectx->lout[0] == parg) {
+			ectx->lout[0] = &aarg[0];
+			ectx->lout[1] = &aarg[1];
+		}
+
+		if (ectx->mout[0] == parg) {
+			ectx->mout[0] = &aarg[0];
+			ectx->mout[1] = &aarg[1];
+		}
+
+		arg = *parg;
+		dot = strrchr(arg,'.');
+
+		/* object input argument? */
+		if (dot && (!strcmp(dot,".o") || !strcmp(dot,".lo"))) {
+			*oarg++ = *parg++;
+
+		/* --whole-archive input argument? */
+		} else if ((arg[0] == '-')
+				&& (arg[1] == 'W')
+				&& (arg[2] == 'l')
+				&& (arg[3] == ',')
+				&& !strcmp(&arg[4],"--whole-archive")
+				&& parg[1] && parg[2]
+				&& !strcmp(parg[2],"-Wl,--no-whole-archive")
+				&& (dot = strrchr(parg[1],'.'))
+				&& !strcmp(dot,arsuffix)) {
+			*oarg++ = *parg++;
+			*oarg++ = *parg++;
+			*oarg++ = *parg++;
+
+		/* local archive input argument? */
+		} else if (dot && !strcmp(dot,arsuffix)) {
+			*oarg++ = *parg++;
+
+		/* -l argument? */
+		} else if ((parg[0][0] == '-') && (parg[0][1] == 'l')) {
+			/* find the previous occurence of this -l argument */
+			for (rarg=0, larg=&aarg[-1]; !rarg && (larg>=aargv); larg--)
+				if (!strcmp(*larg,*parg))
+					rarg = larg;
+
+			/* first occurence of this specific -l argument? */
+			if (!rarg) {
+				*aarg++ = *parg++;
+
+			} else {
+				larg = rarg;
+
+				/* if all -l arguments following the previous */
+				/* occurence had already appeared before the */
+				/* previous argument, then the current      */
+				/* occurence is redundant.                 */
+
+				for (darg=&larg[1]; rarg && darg<aarg; darg++) {
+					/* only test -l arguments */
+					if ((darg[0][0] == '-') && (darg[0][1] == 'l')) {
+						for (rarg=0, earg=aargv; !rarg && earg<larg; earg++)
+							if (!strcmp(*earg,*darg))
+								rarg = darg;
+					}
+				}
+
+				/* final verdict: repeated -l argument? */
+				if (rarg) {
+					parg++;
+
+				} else {
+					*aarg++ = *parg++;
+				}
+			}
+
+		/* -L argument? */
+		} else if ((parg[0][0] == '-') && (parg[0][1] == 'L')) {
+			/* find a previous occurence of this -L argument */
+			for (rarg=0, larg=aargv; !rarg && (larg<aarg); larg++)
+				if (!strcmp(*larg,*parg))
+					rarg = larg;
+
+			/* repeated -L argument? */
+			if (rarg) {
+				parg++;
+			} else {
+				*aarg++ = *parg++;
+			}
+
+		/* placeholder argument? */
+		} else if (!strncmp(*parg,"-USLIBTOOL_PLACEHOLDER_",23)) {
+			parg++;
+
+		/* all other arguments */
+		} else {
+			*aarg++ = *parg++;
+		}
+	}
+
+	/* program name, ccwrap */
+	if ((ccwrap = (char *)dctx->cctx->ccwrap)) {
+		base[1] = base[0];
+		base[0] = ccwrap;
+		base++;
+	}
+
+	/* join object args */
+	src = oargv;
+	cap = oarg;
+	dst = &base[1];
+
+	for (; src<cap; )
+		*dst++ = *src++;
+
+	/* join all other args */
+	src = aargv;
+	cap = aarg;
+
+	for (; src<cap; )
+		*dst++ = *src++;
+
+	/* properly null-terminate argv, accounting for redundant -l arguments */
+	*dst = 0;
+
+	/* output annotation */
+	if (ectx->lout[0]) {
+		ectx->lout[0] = &base[1] + (oarg - oargv) + (ectx->lout[0] - aargv);
+		ectx->lout[1] = ectx->lout[0] + 1;
+	}
+
+	if (ectx->mout[0]) {
+		ectx->mout[0] = &base[1] + (oarg - oargv) + (ectx->mout[0] - aargv);
+		ectx->mout[1] = ectx->mout[0] + 1;
+	}
+
+	/* all done */
+	if (sargvbuf)
+		free(sargvbuf);
+
+	return 0;
+}
diff --git a/src/logic/slbt_exec_link.c b/src/logic/slbt_exec_link.c
index cacbe44..c21af58 100644
--- a/src/logic/slbt_exec_link.c
+++ b/src/logic/slbt_exec_link.c
@@ -77,234 +77,6 @@ static int slbt_exec_link_exit(
 	return ret;
 }
 
-static bool slbt_adjust_object_argument(
-	char *		arg,
-	bool		fpic,
-	bool		fany,
-	int		fdcwd)
-{
-	char *	slash;
-	char *	dot;
-	char	base[PATH_MAX];
-
-	if (*arg == '-')
-		return false;
-
-	/* object argument: foo.lo or foo.o */
-	if (!(dot = strrchr(arg,'.')))
-		return false;
-
-	if ((dot[1]=='l') && (dot[2]=='o') && !dot[3]) {
-		dot[1] = 'o';
-		dot[2] = 0;
-
-	} else if ((dot[1]=='o') && !dot[2]) {
-		(void)0;
-
-	} else {
-		return false;
-	}
-
-	/* foo.o requested and is present? */
-	if (!fpic && !faccessat(fdcwd,arg,0,0))
-		return true;
-
-	/* .libs/foo.o */
-	if ((slash = strrchr(arg,'/')))
-		slash++;
-	else
-		slash = arg;
-
-	if (slbt_snprintf(base,sizeof(base),
-			"%s",slash) < 0)
-		return false;
-
-	sprintf(slash,".libs/%s",base);
-
-	if (!faccessat(fdcwd,arg,0,0))
-		return true;
-
-	/* foo.o requested and neither is present? */
-	if (!fpic) {
-		strcpy(slash,base);
-		return true;
-	}
-
-	/* .libs/foo.o explicitly requested and is not present? */
-	if (!fany)
-		return true;
-
-	/* use foo.o in place of .libs/foo.o */
-	strcpy(slash,base);
-
-	if (faccessat(fdcwd,arg,0,0))
-		sprintf(slash,".libs/%s",base);
-
-	return true;
-}
-
-static bool slbt_adjust_wrapper_argument(
-	char *		arg,
-	bool		fpic)
-{
-	char *	slash;
-	char *	dot;
-	char	base[PATH_MAX];
-
-	if (*arg == '-')
-		return false;
-
-	if (!(dot = strrchr(arg,'.')))
-		return false;
-
-	if (strcmp(dot,".la"))
-		return false;
-
-	if (fpic) {
-		if ((slash = strrchr(arg,'/')))
-			slash++;
-		else
-			slash = arg;
-
-		if (slbt_snprintf(base,sizeof(base),
-				"%s",slash) < 0)
-			return false;
-
-		sprintf(slash,".libs/%s",base);
-		dot = strrchr(arg,'.');
-	}
-
-	strcpy(dot,".a");
-	return true;
-}
-
-static int slbt_adjust_linker_argument(
-	const struct slbt_driver_ctx *	dctx,
-	char *				arg,
-	char **				xarg,
-	bool				fpic,
-	const char *			dsosuffix,
-	const char *			arsuffix,
-	struct slbt_deps_meta * 	depsmeta)
-{
-	int	fdcwd;
-	int	fdlib;
-	char *	slash;
-	char *	dot;
-	char	base[PATH_MAX];
-
-	if (*arg == '-')
-		return 0;
-
-	if (!(dot = strrchr(arg,'.')))
-		return 0;
-
-	if (!(strcmp(dot,arsuffix))) {
-		*xarg = arg;
-		return slbt_get_deps_meta(dctx,arg,1,depsmeta);
-	}
-
-	if (!(strcmp(dot,dsosuffix)))
-		return slbt_get_deps_meta(dctx,arg,1,depsmeta);
-
-	if (strcmp(dot,".la"))
-		return 0;
-
-	if (fpic) {
-		if ((slash = strrchr(arg,'/')))
-			slash++;
-		else
-			slash = arg;
-
-		if (slbt_snprintf(base,sizeof(base),
-				"%s",slash) < 0)
-			return 0;
-
-		sprintf(slash,".libs/%s",base);
-		dot = strrchr(arg,'.');
-	}
-
-	/* fdcwd */
-	fdcwd = slbt_driver_fdcwd(dctx);
-
-	/* shared library dependency? */
-	if (fpic) {
-		sprintf(dot,"%s",dsosuffix);
-
-		if (slbt_symlink_is_a_placeholder(fdcwd,arg))
-			sprintf(dot,"%s",arsuffix);
-		else if ((fdlib = openat(fdcwd,arg,O_RDONLY)) >= 0)
-			close(fdlib);
-		else
-			sprintf(dot,"%s",arsuffix);
-
-		return slbt_get_deps_meta(dctx,arg,0,depsmeta);
-	}
-
-	/* input archive */
-	sprintf(dot,"%s",arsuffix);
-	return slbt_get_deps_meta(dctx,arg,0,depsmeta);
-}
-
-static int slbt_emit_fdwrap_amend_dl_path(
-	const struct slbt_driver_ctx *	dctx,
-	struct slbt_exec_ctx *		ectx,
-	struct slbt_deps_meta * 	depsmeta,
-	const char *			fmt,
-					...)
-{
-	va_list		ap;
-	char *		buf;
-	int		cnt;
-	char		dlpathbuf[2048];
-	int		fdwrap;
-	const char *	fdwrap_fmt;
-	int		size;
-
-	va_start(ap,fmt);
-
-	size = sizeof(dlpathbuf);
-
-	buf  = ((cnt = vsnprintf(dlpathbuf,size,fmt,ap)) < size)
-		? dlpathbuf : malloc((size = cnt + 1));
-
-	va_end(ap);
-
-	if (buf == dlpathbuf) {
-		(void)0;
-
-	} else if (buf) {
-		va_start(ap,fmt);
-		vsprintf(buf,fmt,ap);
-		va_end(ap);
-
-	} else {
-		return slbt_exec_link_exit(
-			depsmeta,
-			SLBT_SYSTEM_ERROR(dctx,0));
-	}
-
-	if ((fdwrap = slbt_exec_get_fdwrapper(ectx)) >= 0) {
-		if (buf[0] == '/') {
-			fdwrap_fmt =
-				"DL_PATH=\"${DL_PATH}${COLON}%s\"\n"
-				"COLON=':'\n\n";
-		} else {
-			fdwrap_fmt =
-				"DL_PATH=\"${DL_PATH}${COLON}${DL_PATH_FIXUP}%s\"\n"
-				"COLON=':'\n\n";
-		}
-
-		if (slbt_dprintf(fdwrap,fdwrap_fmt,buf) < 0) {
-			return slbt_exec_link_exit(
-				depsmeta,
-				SLBT_SYSTEM_ERROR(dctx,0));
-		}
-	}
-
-	return 0;
-}
-
 static void slbt_emit_fdwrap_dl_path_fixup(
 	char *	cwd,
 	char *	dpfixup,
@@ -337,473 +109,6 @@ static void slbt_emit_fdwrap_dl_path_fixup(
 	strncat(dpfixup,"/",dpfixup_size-1);
 }
 
-static int slbt_exec_link_adjust_argument_vector(
-	const struct slbt_driver_ctx *	dctx,
-	struct slbt_exec_ctx *		ectx,
-	struct slbt_deps_meta *		depsmeta,
-	const char *			cwd,
-	bool				flibrary)
-{
-	int			fd;
-	int			fdcwd;
-	char ** 		carg;
-	char ** 		aarg;
-	char *			ldir;
-	char *			slash;
-	char *			mark;
-	char *			darg;
-	char *			dot;
-	char *			base;
-	char *			dpath;
-	int			argc;
-	char			arg[PATH_MAX];
-	char			lib[PATH_MAX];
-	char			depdir  [PATH_MAX];
-	char			rpathdir[PATH_MAX];
-	char			rpathlnk[PATH_MAX];
-	struct stat		st;
-	size_t			size;
-	size_t			dlen;
-	struct slbt_map_info *	mapinfo;
-	bool			fwholearchive = false;
-	int			ret;
-
-	for (argc=0,carg=ectx->cargv; *carg; carg++)
-		argc++;
-
-	if (!(depsmeta->args = calloc(1,depsmeta->infolen)))
-		return SLBT_SYSTEM_ERROR(dctx,0);
-
-	argc *= 3;
-	argc += depsmeta->depscnt;
-
-	if (!(depsmeta->altv = calloc(argc,sizeof(char *))))
-		return slbt_exec_link_exit(
-			depsmeta,
-			SLBT_SYSTEM_ERROR(dctx,0));
-
-	fdcwd = slbt_driver_fdcwd(dctx);
-
-	carg = ectx->cargv;
-	aarg = depsmeta->altv;
-	darg = depsmeta->args;
-	size = depsmeta->infolen;
-
-	for (; *carg; ) {
-		dpath = 0;
-
-		if (!strcmp(*carg,"-Wl,--whole-archive"))
-			fwholearchive = true;
-		else if (!strcmp(*carg,"-Wl,--no-whole-archive"))
-			fwholearchive = false;
-
-
-
-		/* output annotation */
-		if (carg == ectx->lout[0]) {
-			ectx->mout[0] = &aarg[0];
-			ectx->mout[1] = &aarg[1];
-		}
-
-		/* argument translation */
-		mark = *carg;
-
-		if ((mark[0] == '-') && (mark[1] == 'L')) {
-			if (mark[2]) {
-				ldir = &mark[2];
-			} else {
-				*aarg++ = *carg++;
-				ldir    = *carg;
-			}
-
-			mark = ldir + strlen(ldir);
-
-			if (mark[-1] == '/')
-				strcpy(mark,".libs");
-			else
-				strcpy(mark,"/.libs");
-
-			if ((fd = openat(fdcwd,ldir,O_DIRECTORY,0)) < 0)
-				*mark = 0;
-			else {
-				close(fd);
-
-				if ((ret = slbt_emit_fdwrap_amend_dl_path(
-						dctx,ectx,depsmeta,
-						"%s",ldir)) < 0)
-					return ret;
-			}
-
-			*aarg++ = *carg++;
-
-		} else if (**carg == '-') {
-			*aarg++ = *carg++;
-
-		} else if (!(dot = strrchr(*carg,'.'))) {
-			*aarg++ = *carg++;
-
-		} else if (ectx->xargv[carg - ectx->cargv]) {
-			*aarg++ = *carg++;
-
-		} else if (!(strcmp(dot,".a"))) {
-			if (flibrary && !fwholearchive)
-				*aarg++ = "-Wl,--whole-archive";
-
-			dpath = lib;
-			sprintf(lib,"%s.slibtool.deps",*carg);
-			*aarg++ = *carg++;
-
-			if (flibrary && !fwholearchive)
-				*aarg++ = "-Wl,--no-whole-archive";
-
-		} else if (strcmp(dot,dctx->cctx->settings.dsosuffix)) {
-			*aarg++ = *carg++;
-
-		} else if (carg == ectx->lout[1]) {
-			/* ^^^hoppla^^^ */
-			*aarg++ = *carg++;
-		} else {
-			/* -rpath */
-			sprintf(rpathlnk,"%s.slibtool.rpath",*carg);
-
-			if (!fstatat(fdcwd,rpathlnk,&st,AT_SYMLINK_NOFOLLOW)) {
-				if (slbt_readlinkat(
-						fdcwd,
-						rpathlnk,
-						rpathdir,
-						sizeof(rpathdir)))
-					return slbt_exec_link_exit(
-						depsmeta,
-						SLBT_SYSTEM_ERROR(dctx,rpathlnk));
-
-				sprintf(darg,"-Wl,%s",rpathdir);
-				*aarg++ = "-Wl,-rpath";
-				*aarg++ = darg;
-				darg   += strlen(darg);
-				darg++;
-			}
-
-			dpath = lib;
-			sprintf(lib,"%s.slibtool.deps",*carg);
-
-			/* account for {'-','L','-','l'} */
-			if (slbt_snprintf(arg,
-					sizeof(arg) - 4,
-					"%s",*carg) < 0)
-				return slbt_exec_link_exit(
-					depsmeta,
-					SLBT_BUFFER_ERROR(dctx));
-
-			if ((slash = strrchr(arg,'/'))) {
-				sprintf(*carg,"-L%s",arg);
-
-				mark   = strrchr(*carg,'/');
-				*mark  = 0;
-				*slash = 0;
-
-				if ((ret = slbt_emit_fdwrap_amend_dl_path(
-						dctx,ectx,depsmeta,
-						"%s%s%s",
-						((arg[0] == '/') ? "" : cwd),
-						((arg[0] == '/') ? "" : "/"),
-						arg)) < 0) {
-					return ret;
-				}
-
-				dlen = strlen(dctx->cctx->settings.dsoprefix);
-
-				/* -module? (todo: non-portable usage, display warning) */
-				if (strncmp(++slash,dctx->cctx->settings.dsoprefix,dlen)) {
-					*--slash = '/';
-					strcpy(*carg,arg);
-					*aarg++ = *carg++;
-				} else {
-					*aarg++ = *carg++;
-					*aarg++ = ++mark;
-
-					slash += dlen;
-
-					sprintf(mark,"-l%s",slash);
-					dot  = strrchr(mark,'.');
-					*dot = 0;
-				}
-			} else {
-				*aarg++ = *carg++;
-			}
-		}
-
-		if (dpath && !fstatat(fdcwd,dpath,&st,0)) {
-			if (!(mapinfo = slbt_map_file(
-					fdcwd,dpath,
-					SLBT_MAP_INPUT)))
-				return slbt_exec_link_exit(
-					depsmeta,
-					SLBT_SYSTEM_ERROR(dctx,dpath));
-
-			if (!(strncmp(lib,".libs/",6))) {
-				*aarg++ = "-L.libs";
-				lib[1] = 0;
-			} else if ((base = strrchr(lib,'/'))) {
-				if (base - lib == 5) {
-					if (!(strncmp(&base[-5],".libs/",6)))
-						base -= 4;
-
-				} else if (base - lib >= 6) {
-					if (!(strncmp(&base[-6],"/.libs/",7)))
-						base -= 6;
-				}
-
-				*base = 0;
-			} else {
-				lib[0] = '.';
-				lib[1] = 0;
-			}
-
-			while (mapinfo->mark < mapinfo->cap) {
-				if (slbt_mapped_readline(dctx,mapinfo,darg,size))
-					return slbt_exec_link_exit(
-						depsmeta,
-						SLBT_NESTED_ERROR(dctx));
-
-				*aarg++   = darg;
-				mark      = darg;
-
-				dlen      = strlen(darg);
-				size     -= dlen;
-				darg     += dlen;
-				darg[-1]  = 0;
-
-				/* handle -L... as needed */
-				if ((mark[0] == '-')
-						&& (mark[1] == 'L')
-						&& (mark[2] != '/')) {
-					if (strlen(mark) >= sizeof(depdir) - 1)
-						return slbt_exec_link_exit(
-							depsmeta,
-							SLBT_BUFFER_ERROR(dctx));
-
-					darg = mark;
-					strcpy(depdir,&mark[2]);
-					sprintf(darg,"-L%s/%s",lib,depdir);
-
-					darg += strlen(darg);
-					darg++;
-
-					if ((ret = slbt_emit_fdwrap_amend_dl_path(
-							dctx,ectx,depsmeta,
-							"%s/%s",lib,depdir)) < 0)
-						return ret;
-
-				} else if ((mark[0] == '-') && (mark[1] == 'L')) {
-					if ((ret = slbt_emit_fdwrap_amend_dl_path(
-							dctx,ectx,depsmeta,
-							"%s",&mark[2])) < 0)
-						return ret;
-				}
-			}
-		}
-	}
-
-	if (dctx->cctx->drvflags & SLBT_DRIVER_EXPORT_DYNAMIC)
-		*aarg++ = "-Wl,--export-dynamic";
-
-	return 0;
-}
-
-static int slbt_exec_link_finalize_argument_vector(
-	const struct slbt_driver_ctx *	dctx,
-	struct slbt_exec_ctx *		ectx)
-{
-	char *		sargv[1024];
-	char **		sargvbuf;
-	char **		base;
-	char **		parg;
-	char **		aarg;
-	char **		oarg;
-	char **		larg;
-	char **		darg;
-	char **		earg;
-	char **		rarg;
-	char **		aargv;
-	char **		oargv;
-	char **		cap;
-	char **		src;
-	char **		dst;
-	char *		arg;
-	char *		dot;
-	char *		ccwrap;
-	const char *	arsuffix;
-
-	/* vector size */
-	base     = ectx->argv;
-	arsuffix = dctx->cctx->settings.arsuffix;
-
-	for (parg=base; *parg; parg++)
-		(void)0;
-
-	/* buffer */
-	if (parg - base < 512) {
-		aargv    = &sargv[0];
-		oargv    = &sargv[512];
-		aarg     = aargv;
-		oarg     = oargv;
-		sargvbuf = 0;
-
-	} else if (!(sargvbuf = calloc(2*(parg-base+1),sizeof(char *)))) {
-		return SLBT_SYSTEM_ERROR(dctx,0);
-
-	} else {
-		aargv = &sargvbuf[0];
-		oargv = &sargvbuf[parg-base+1];
-		aarg  = aargv;
-		oarg  = oargv;
-	}
-
-	/* (program name) */
-	parg = &base[1];
-
-	/* split object args from all other args, record output */
-	/* annotation, and remove redundant -l arguments       */
-	for (; *parg; ) {
-		if (ectx->lout[0] == parg) {
-			ectx->lout[0] = &aarg[0];
-			ectx->lout[1] = &aarg[1];
-		}
-
-		if (ectx->mout[0] == parg) {
-			ectx->mout[0] = &aarg[0];
-			ectx->mout[1] = &aarg[1];
-		}
-
-		arg = *parg;
-		dot = strrchr(arg,'.');
-
-		/* object input argument? */
-		if (dot && (!strcmp(dot,".o") || !strcmp(dot,".lo"))) {
-			*oarg++ = *parg++;
-
-		/* --whole-archive input argument? */
-		} else if ((arg[0] == '-')
-				&& (arg[1] == 'W')
-				&& (arg[2] == 'l')
-				&& (arg[3] == ',')
-				&& !strcmp(&arg[4],"--whole-archive")
-				&& parg[1] && parg[2]
-				&& !strcmp(parg[2],"-Wl,--no-whole-archive")
-				&& (dot = strrchr(parg[1],'.'))
-				&& !strcmp(dot,arsuffix)) {
-			*oarg++ = *parg++;
-			*oarg++ = *parg++;
-			*oarg++ = *parg++;
-
-		/* local archive input argument? */
-		} else if (dot && !strcmp(dot,arsuffix)) {
-			*oarg++ = *parg++;
-
-		/* -l argument? */
-		} else if ((parg[0][0] == '-') && (parg[0][1] == 'l')) {
-			/* find the previous occurence of this -l argument */
-			for (rarg=0, larg=&aarg[-1]; !rarg && (larg>=aargv); larg--)
-				if (!strcmp(*larg,*parg))
-					rarg = larg;
-
-			/* first occurence of this specific -l argument? */
-			if (!rarg) {
-				*aarg++ = *parg++;
-
-			} else {
-				larg = rarg;
-
-				/* if all -l arguments following the previous */
-				/* occurence had already appeared before the */
-				/* previous argument, then the current      */
-				/* occurence is redundant.                 */
-
-				for (darg=&larg[1]; rarg && darg<aarg; darg++) {
-					/* only test -l arguments */
-					if ((darg[0][0] == '-') && (darg[0][1] == 'l')) {
-						for (rarg=0, earg=aargv; !rarg && earg<larg; earg++)
-							if (!strcmp(*earg,*darg))
-								rarg = darg;
-					}
-				}
-
-				/* final verdict: repeated -l argument? */
-				if (rarg) {
-					parg++;
-
-				} else {
-					*aarg++ = *parg++;
-				}
-			}
-
-		/* -L argument? */
-		} else if ((parg[0][0] == '-') && (parg[0][1] == 'L')) {
-			/* find a previous occurence of this -L argument */
-			for (rarg=0, larg=aargv; !rarg && (larg<aarg); larg++)
-				if (!strcmp(*larg,*parg))
-					rarg = larg;
-
-			/* repeated -L argument? */
-			if (rarg) {
-				parg++;
-			} else {
-				*aarg++ = *parg++;
-			}
-
-		/* placeholder argument? */
-		} else if (!strncmp(*parg,"-USLIBTOOL_PLACEHOLDER_",23)) {
-			parg++;
-
-		/* all other arguments */
-		} else {
-			*aarg++ = *parg++;
-		}
-	}
-
-	/* program name, ccwrap */
-	if ((ccwrap = (char *)dctx->cctx->ccwrap)) {
-		base[1] = base[0];
-		base[0] = ccwrap;
-		base++;
-	}
-
-	/* join object args */
-	src = oargv;
-	cap = oarg;
-	dst = &base[1];
-
-	for (; src<cap; )
-		*dst++ = *src++;
-
-	/* join all other args */
-	src = aargv;
-	cap = aarg;
-
-	for (; src<cap; )
-		*dst++ = *src++;
-
-	/* properly null-terminate argv, accounting for redundant -l arguments */
-	*dst = 0;
-
-	/* output annotation */
-	if (ectx->lout[0]) {
-		ectx->lout[0] = &base[1] + (oarg - oargv) + (ectx->lout[0] - aargv);
-		ectx->lout[1] = ectx->lout[0] + 1;
-	}
-
-	if (ectx->mout[0]) {
-		ectx->mout[0] = &base[1] + (oarg - oargv) + (ectx->mout[0] - aargv);
-		ectx->mout[1] = ectx->mout[0] + 1;
-	}
-
-	/* all done */
-	if (sargvbuf)
-		free(sargvbuf);
-
-	return 0;
-}
-
 static int slbt_exec_link_remove_file(
 	const struct slbt_driver_ctx *	dctx,
 	struct slbt_exec_ctx *		ectx,
-- 
cgit v1.2.3