Blame src/driver/slbt_driver_ctx.c

9ca8c4
/*******************************************************************/
9ca8c4
/*  slibtool: a skinny libtool implementation, written in C        */
9ca8c4
/*  Copyright (C) 2016  Z. Gilboa                                  */
9ca8c4
/*  Released under the Standard MIT License; see COPYING.SLIBTOOL. */
9ca8c4
/*******************************************************************/
9ca8c4
9ca8c4
#include <stdint.h>
9ca8c4
#include <unistd.h>
9ca8c4
#include <fcntl.h>
9ca8c4
9ca8c4
#define ARGV_DRIVER
9ca8c4
9ca8c4
#include <slibtool/slibtool.h>
9ca8c4
#include "slibtool_driver_impl.h"
9ca8c4
#include "argv/argv.h"
9ca8c4
56cab3
struct slbt_split_vector {
56cab3
	char **		targv;
56cab3
	char **		cargv;
56cab3
};
56cab3
9ca8c4
struct slbt_driver_ctx_alloc {
9ca8c4
	struct argv_meta *		meta;
9ca8c4
	struct slbt_driver_ctx_impl	ctx;
9ca8c4
	uint64_t			guard;
9ca8c4
	const char *			units[];
9ca8c4
};
9ca8c4
9ca8c4
static uint32_t slbt_argv_flags(uint32_t flags)
9ca8c4
{
9ca8c4
	uint32_t ret = 0;
9ca8c4
9ca8c4
	if (flags & SLBT_DRIVER_VERBOSITY_NONE)
9ca8c4
		ret |= ARGV_VERBOSITY_NONE;
9ca8c4
9ca8c4
	if (flags & SLBT_DRIVER_VERBOSITY_ERRORS)
9ca8c4
		ret |= ARGV_VERBOSITY_ERRORS;
9ca8c4
9ca8c4
	if (flags & SLBT_DRIVER_VERBOSITY_STATUS)
9ca8c4
		ret |= ARGV_VERBOSITY_STATUS;
9ca8c4
9ca8c4
	return ret;
9ca8c4
}
9ca8c4
9ca8c4
static int slbt_driver_usage(
9ca8c4
	const char *			program,
9ca8c4
	const char *			arg,
9ca8c4
	const struct argv_option *	options,
9ca8c4
	struct argv_meta *		meta)
9ca8c4
{
9ca8c4
	char header[512];
9ca8c4
9ca8c4
	snprintf(header,sizeof(header),
9ca8c4
		"Usage: %s [options] <file>...\n" "Options:\n",
9ca8c4
		program);
9ca8c4
9ca8c4
	argv_usage(stdout,header,options,arg);
9ca8c4
	argv_free(meta);
9ca8c4
9ca8c4
	return SLBT_USAGE;
9ca8c4
}
9ca8c4
9ca8c4
static struct slbt_driver_ctx_impl * slbt_driver_ctx_alloc(
9ca8c4
	struct argv_meta *		meta,
9ca8c4
	const struct slbt_common_ctx *	cctx,
9ca8c4
	size_t				nunits)
9ca8c4
{
9ca8c4
	struct slbt_driver_ctx_alloc *	ictx;
9ca8c4
	size_t				size;
9ca8c4
	struct argv_entry *		entry;
9ca8c4
	const char **			units;
9ca8c4
9ca8c4
	size =  sizeof(struct slbt_driver_ctx_alloc);
9ca8c4
	size += (nunits+1)*sizeof(const char *);
9ca8c4
9ca8c4
	if (!(ictx = calloc(1,size)))
9ca8c4
		return 0;
9ca8c4
9ca8c4
	if (cctx)
9ca8c4
		memcpy(&ictx->ctx.cctx,cctx,sizeof(*cctx));
9ca8c4
9ca8c4
	for (entry=meta->entries,units=ictx->units; entry->fopt || entry->arg; entry++)
9ca8c4
		if (!entry->fopt)
9ca8c4
			*units++ = entry->arg;
9ca8c4
9ca8c4
	ictx->meta = meta;
9ca8c4
	ictx->ctx.ctx.units = ictx->units;
9ca8c4
	return &ictx->ctx;
9ca8c4
}
9ca8c4
9ca8c4
static int slbt_get_driver_ctx_fail(struct argv_meta * meta)
9ca8c4
{
9ca8c4
	argv_free(meta);
9ca8c4
	return -1;
9ca8c4
}
9ca8c4
56cab3
static int slbt_split_argv(
56cab3
	char **				argv,
56cab3
	uint32_t			flags,
56cab3
	struct slbt_split_vector *	sargv)
56cab3
{
56cab3
	int				i;
56cab3
	int				argc;
56cab3
	const char *			program;
56cab3
	char *				compiler;
56cab3
	char **				targv;
56cab3
	char **				cargv;
56cab3
	struct argv_meta *		meta;
56cab3
	struct argv_entry *		entry;
56cab3
	struct argv_entry *		mode;
56cab3
	const struct argv_option *	option;
56cab3
	const struct argv_option *	options = slbt_default_options;
56cab3
	struct argv_ctx			ctx = {ARGV_VERBOSITY_NONE,
56cab3
						ARGV_MODE_SCAN,
56cab3
						0,0,0,0,0,0,0};
56cab3
56cab3
	program = argv_program_name(argv[0]);
56cab3
56cab3
	/* missing arguments? */
56cab3
	if (!argv[1] && (flags & SLBT_DRIVER_VERBOSITY_USAGE))
56cab3
		return slbt_driver_usage(program,0,options,0);
56cab3
56cab3
	/* initial argv scan: ... --mode=xxx ... <compiler> ... */
56cab3
	argv_scan(argv,options,&ctx,0);
56cab3
56cab3
	/* invalid slibtool arguments? */
56cab3
	if (ctx.erridx && !ctx.unitidx) {
56cab3
		if (flags & SLBT_DRIVER_VERBOSITY_ERRORS)
56cab3
			argv_get(
56cab3
				argv,options,
56cab3
				slbt_argv_flags(flags));
56cab3
		return -1;
56cab3
	}
56cab3
56cab3
	/* missing compiler? */
56cab3
	if (!ctx.unitidx) {
56cab3
		if (flags & SLBT_DRIVER_VERBOSITY_ERRORS)
56cab3
			fprintf(stderr,
56cab3
				"%s: error: <compiler> is missing.\n",
56cab3
				program);
56cab3
		return -1;
56cab3
	}
56cab3
56cab3
	/* obtain slibtool's own arguments */
56cab3
	compiler = argv[ctx.unitidx];
56cab3
	argv[ctx.unitidx] = 0;
56cab3
56cab3
	meta = argv_get(argv,options,ARGV_VERBOSITY_NONE);
56cab3
	argv[ctx.unitidx] = compiler;
56cab3
56cab3
	/* missing --mode? */
56cab3
	for (mode=0, entry=meta->entries; entry->fopt; entry++)
56cab3
		if (entry->tag == TAG_MODE)
56cab3
			mode = entry;
56cab3
56cab3
	argv_free(meta);
56cab3
56cab3
	if (!mode) {
56cab3
		fprintf(stderr,
56cab3
			"%s: error: --mode must be specified.\n",
56cab3
			program);
56cab3
		return -1;
56cab3
	}
56cab3
56cab3
	/* allocate split vectors */
56cab3
	for (argc=0, targv=argv; *targv; targv++)
56cab3
		argc++;
56cab3
56cab3
	if ((sargv->targv = calloc(2*(argc+1),sizeof(char *))))
56cab3
		sargv->cargv = sargv->targv + argc + 1;
56cab3
	else
56cab3
		return -1;
56cab3
56cab3
	/* split vectors: slibtool's own options */
56cab3
	for (i=0; i
56cab3
		sargv->targv[i] = argv[i];
56cab3
56cab3
	/* split vectors: legacy mixture */
56cab3
	options = option_from_tag(
56cab3
			slbt_default_options,
56cab3
			TAG_OUTPUT);
56cab3
56cab3
	targv = sargv->targv + i;
56cab3
	cargv = sargv->cargv;
56cab3
56cab3
	for (; i
56cab3
		if (argv[i][0] != '-')
56cab3
			*cargv++ = argv[i];
56cab3
a288c4
		else if (argv[i][1] == 'o') {
56cab3
			*targv++ = argv[i];
56cab3
a288c4
			if (argv[i][2] == '\0')
a288c4
				*targv++ = argv[++i];
a288c4
		}
a288c4
56cab3
		else if ((argv[i][1] == 'W')  && (argv[i][2] == 'c'))
56cab3
			*cargv++ = argv[i];
56cab3
56cab3
		else if (!(strcmp("Xcompiler",&argv[i][1])))
56cab3
			*cargv++ = argv[++i];
56cab3
56cab3
		else {
56cab3
			for (option=options; option->long_name; option++)
56cab3
				if (!(strcmp(option->long_name,&argv[i][1])))
56cab3
					break;
56cab3
56cab3
			if (option->long_name)
56cab3
				*targv++ = argv[i];
56cab3
			else
56cab3
				*cargv++ = argv[i];
56cab3
		}
56cab3
	}
56cab3
56cab3
	return 0;
56cab3
}
56cab3
9ca8c4
int slbt_get_driver_ctx(
9ca8c4
	char **				argv,
9ca8c4
	char **				envp,
9ca8c4
	uint32_t			flags,
9ca8c4
	struct slbt_driver_ctx **	pctx)
9ca8c4
{
56cab3
	struct slbt_split_vector	sargv;
9ca8c4
	struct slbt_driver_ctx_impl *	ctx;
9ca8c4
	struct slbt_common_ctx		cctx;
9ca8c4
	const struct argv_option *	options;
9ca8c4
	struct argv_meta *		meta;
9ca8c4
	struct argv_entry *		entry;
9ca8c4
	size_t				nunits;
9ca8c4
	const char *			program;
9ca8c4
9ca8c4
	options = slbt_default_options;
9ca8c4
56cab3
	if (slbt_split_argv(argv,flags,&sargv))
56cab3
		return -1;
56cab3
56cab3
	if (!(meta = argv_get(sargv.targv,options,slbt_argv_flags(flags))))
9ca8c4
		return -1;
9ca8c4
9ca8c4
	nunits	= 0;
9ca8c4
	program = argv_program_name(argv[0]);
9ca8c4
	memset(&cctx,0,sizeof(cctx));
9ca8c4
9ca8c4
	/* get options, count units */
9ca8c4
	for (entry=meta->entries; entry->fopt || entry->arg; entry++) {
9ca8c4
		if (entry->fopt) {
9ca8c4
			switch (entry->tag) {
9ca8c4
				case TAG_HELP:
949677
				case TAG_HELP_ALL:
9ca8c4
					if (flags & SLBT_DRIVER_VERBOSITY_USAGE)
9ca8c4
						return slbt_driver_usage(program,entry->arg,options,meta);
9ca8c4
9ca8c4
				case TAG_VERSION:
9ca8c4
					cctx.drvflags |= SLBT_DRIVER_VERSION;
9ca8c4
					break;
667ce2
667ce2
				case TAG_MODE:
667ce2
					if (!strcmp("clean",entry->arg))
667ce2
						cctx.mode = SLBT_MODE_CLEAN;
667ce2
667ce2
					else if (!strcmp("compile",entry->arg))
667ce2
						cctx.mode = SLBT_MODE_COMPILE;
667ce2
667ce2
					else if (!strcmp("execute",entry->arg))
667ce2
						cctx.mode = SLBT_MODE_EXECUTE;
667ce2
667ce2
					else if (!strcmp("finish",entry->arg))
667ce2
						cctx.mode = SLBT_MODE_FINISH;
667ce2
667ce2
					else if (!strcmp("install",entry->arg))
667ce2
						cctx.mode = SLBT_MODE_INSTALL;
667ce2
667ce2
					else if (!strcmp("link",entry->arg))
667ce2
						cctx.mode = SLBT_MODE_LINK;
667ce2
667ce2
					else if (!strcmp("uninstall",entry->arg))
667ce2
						cctx.mode = SLBT_MODE_UNINSTALL;
667ce2
					break;
071d14
071d14
				case TAG_DRY_RUN:
071d14
					cctx.drvflags |= SLBT_DRIVER_DRY_RUN;
071d14
					break;
53f4ec
53f4ec
				case TAG_TAG:
53f4ec
					if (!strcmp("CC",entry->arg))
53f4ec
						cctx.tag = SLBT_TAG_CC;
53f4ec
53f4ec
					else if (!strcmp("CXX",entry->arg))
53f4ec
						cctx.tag = SLBT_TAG_CXX;
53f4ec
					break;
173b54
173b54
				case TAG_CONFIG:
173b54
					cctx.drvflags |= SLBT_DRIVER_CONFIG;
173b54
					break;
173b54
fea1b8
				case TAG_DEBUG:
fea1b8
					cctx.drvflags |= SLBT_DRIVER_DEBUG;
fea1b8
					break;
d03fbc
d03fbc
				case TAG_FEATURES:
d03fbc
					cctx.drvflags |= SLBT_DRIVER_FEATURES;
d03fbc
					break;
6376f0
6376f0
				case TAG_WARNINGS:
6376f0
					if (!strcmp("all",entry->arg))
6376f0
						cctx.tag = SLBT_WARNING_LEVEL_ALL;
6376f0
6376f0
					else if (!strcmp("error",entry->arg))
6376f0
						cctx.tag = SLBT_WARNING_LEVEL_ERROR;
6376f0
6376f0
					else if (!strcmp("none",entry->arg))
6376f0
						cctx.tag = SLBT_WARNING_LEVEL_NONE;
6376f0
					break;
40fabb
40fabb
				case TAG_DEPS:
40fabb
					cctx.drvflags |= SLBT_DRIVER_DEPS;
40fabb
					break;
40fabb
398419
				case TAG_SILENT:
398419
					cctx.drvflags |= SLBT_DRIVER_SILENT;
398419
					break;
25956b
25956b
				case TAG_VERBOSE:
25956b
					cctx.drvflags |= SLBT_DRIVER_VERBOSE;
25956b
					break;
b83b64
b83b64
				case TAG_OUTPUT:
b83b64
					cctx.output = entry->arg;
b83b64
					break;
4f1b20
4f1b20
				case TAG_PREFER_PIC:
4f1b20
					cctx.drvflags |= SLBT_DRIVER_PRO_PIC;
4f1b20
					break;
4f1b20
4f1b20
				case TAG_PREFER_NON_PIC:
4f1b20
					cctx.drvflags |= SLBT_DRIVER_ANTI_PIC;
4f1b20
					break;
9c25c7
9c25c7
				case TAG_SHARED:
9c25c7
					cctx.drvflags |= SLBT_DRIVER_SHARED;
9c25c7
					break;
9c25c7
9c25c7
				case TAG_STATIC:
9c25c7
					cctx.drvflags |= SLBT_DRIVER_STATIC;
9c25c7
					break;
9ca8c4
			}
9ca8c4
		} else
9ca8c4
			nunits++;
9ca8c4
	}
9ca8c4
9ca8c4
	if (!(ctx = slbt_driver_ctx_alloc(meta,&cctx,nunits)))
9ca8c4
		return slbt_get_driver_ctx_fail(meta);
9ca8c4
9ca8c4
	ctx->ctx.program	= program;
9ca8c4
	ctx->ctx.cctx		= &ctx->cctx;
56cab3
	ctx->targv		= sargv.targv;
56cab3
	ctx->cargv		= sargv.cargv;
9ca8c4
a288c4
	ctx->cctx.targv		= sargv.targv;
a288c4
	ctx->cctx.cargv		= sargv.cargv;
a288c4
9ca8c4
	*pctx = &ctx->ctx;
9ca8c4
	return SLBT_OK;
9ca8c4
}
9ca8c4
9ca8c4
int slbt_create_driver_ctx(
9ca8c4
	const struct slbt_common_ctx *	cctx,
9ca8c4
	struct slbt_driver_ctx **	pctx)
9ca8c4
{
9ca8c4
	struct argv_meta *		meta;
9ca8c4
	struct slbt_driver_ctx_impl *	ctx;
9ca8c4
	char *				argv[] = {"slibtool_driver",0};
9ca8c4
9ca8c4
	if (!(meta = argv_get(argv,slbt_default_options,0)))
9ca8c4
		return -1;
9ca8c4
9ca8c4
	if (!(ctx = slbt_driver_ctx_alloc(meta,cctx,0)))
9ca8c4
		return slbt_get_driver_ctx_fail(0);
9ca8c4
9ca8c4
	ctx->ctx.cctx = &ctx->cctx;
9ca8c4
	memcpy(&ctx->cctx,cctx,sizeof(*cctx));
9ca8c4
	*pctx = &ctx->ctx;
9ca8c4
	return SLBT_OK;
9ca8c4
}
9ca8c4
9ca8c4
static void slbt_free_driver_ctx_impl(struct slbt_driver_ctx_alloc * ictx)
9ca8c4
{
56cab3
	if (ictx->ctx.targv)
56cab3
		free(ictx->ctx.targv);
56cab3
9ca8c4
	argv_free(ictx->meta);
9ca8c4
	free(ictx);
9ca8c4
}
9ca8c4
9ca8c4
void slbt_free_driver_ctx(struct slbt_driver_ctx * ctx)
9ca8c4
{
9ca8c4
	struct slbt_driver_ctx_alloc *	ictx;
9ca8c4
	uintptr_t			addr;
9ca8c4
9ca8c4
	if (ctx) {
9ca8c4
		addr = (uintptr_t)ctx - offsetof(struct slbt_driver_ctx_alloc,ctx);
9ca8c4
		addr = addr - offsetof(struct slbt_driver_ctx_impl,ctx);
9ca8c4
		ictx = (struct slbt_driver_ctx_alloc *)addr;
9ca8c4
		slbt_free_driver_ctx_impl(ictx);
9ca8c4
	}
9ca8c4
}