Blame src/driver/tbnf_driver_ctx.c

02e59c
/**************************************************************/
02e59c
/*  treebnf: a tree oriented bnf library                      */
02e59c
/*  Copyright (C) 2024  SysDeer Technologies, LLC             */
02e59c
/*  Released under GPLv2 and GPLv3; see COPYING.TREEBNF.      */
02e59c
/**************************************************************/
02e59c
02e59c
#include <stdint.h>
02e59c
#include <unistd.h>
02e59c
#include <fcntl.h>
02e59c
02e59c
#define ARGV_DRIVER
02e59c
02e59c
#include <treebnf/treebnf.h>
02e59c
#include "treebnf_version.h"
02e59c
#include "treebnf_driver_impl.h"
02e59c
#include "argv/argv.h"
02e59c
02e59c
/* package info */
02e59c
static const struct tbnf_source_version tbnf_src_version = {
02e59c
	TBNF_TAG_VER_MAJOR,
02e59c
	TBNF_TAG_VER_MINOR,
02e59c
	TBNF_TAG_VER_PATCH,
02e59c
	TREEBNF_GIT_VERSION
02e59c
};
02e59c
02e59c
/* default fd context */
02e59c
static const struct tbnf_fd_ctx tbnf_default_fdctx = {
02e59c
	.fdin  = STDIN_FILENO,
02e59c
	.fdout = STDOUT_FILENO,
02e59c
	.fderr = STDERR_FILENO,
02e59c
	.fdcwd = AT_FDCWD,
02e59c
	.fddst = AT_FDCWD,
02e59c
	.fdlog = (-1),
02e59c
};
02e59c
02e59c
struct tbnf_driver_ctx_alloc {
02e59c
	struct argv_meta *		meta;
02e59c
	struct tbnf_driver_ctx_impl	ctx;
02e59c
	uint64_t			guard;
02e59c
	const char *			units[];
02e59c
};
02e59c
02e59c
static uint32_t tbnf_argv_flags(uint32_t flags)
02e59c
{
02e59c
	uint32_t ret = ARGV_CLONE_VECTOR;
02e59c
02e59c
	if (flags & TBNF_DRIVER_VERBOSITY_NONE)
02e59c
		ret |= ARGV_VERBOSITY_NONE;
02e59c
02e59c
	if (flags & TBNF_DRIVER_VERBOSITY_ERRORS)
02e59c
		ret |= ARGV_VERBOSITY_ERRORS;
02e59c
02e59c
	if (flags & TBNF_DRIVER_VERBOSITY_STATUS)
02e59c
		ret |= ARGV_VERBOSITY_STATUS;
02e59c
02e59c
	return ret;
02e59c
}
02e59c
02e59c
static int tbnf_driver_usage(
02e59c
	int				fdout,
02e59c
	const char *			program,
02e59c
	const char *			arg,
02e59c
	const struct argv_option **	optv,
02e59c
	struct argv_meta *		meta)
02e59c
{
02e59c
	char header[512];
02e59c
02e59c
	snprintf(header,sizeof(header),
02e59c
		"Usage: %s [options] <file>...\n" "Options:\n",
02e59c
		program);
02e59c
02e59c
	argv_usage(fdout,header,optv,arg);
02e59c
	argv_free(meta);
02e59c
02e59c
	return TBNF_USAGE;
02e59c
}
02e59c
02e59c
static struct tbnf_driver_ctx_impl * tbnf_driver_ctx_alloc(
02e59c
	struct argv_meta *		meta,
02e59c
	const struct tbnf_fd_ctx *	fdctx,
02e59c
	const struct tbnf_common_ctx *	cctx,
02e59c
	size_t				nunits)
02e59c
{
02e59c
	struct tbnf_driver_ctx_alloc *	ictx;
02e59c
	size_t				size;
02e59c
	struct argv_entry *		entry;
02e59c
	const char **			units;
02e59c
	int				elements;
02e59c
02e59c
	size =  sizeof(struct tbnf_driver_ctx_alloc);
02e59c
	size += (nunits+1)*sizeof(const char *);
02e59c
02e59c
	if (!(ictx = calloc(1,size)))
02e59c
		return 0;
02e59c
02e59c
	memcpy(&ictx->ctx.fdctx,fdctx,sizeof(*fdctx));
02e59c
	memcpy(&ictx->ctx.cctx,cctx,sizeof(*cctx));
02e59c
02e59c
	elements = sizeof(ictx->ctx.erribuf) / sizeof(*ictx->ctx.erribuf);
02e59c
02e59c
	ictx->ctx.errinfp  = &ictx->ctx.erriptr[0];
02e59c
	ictx->ctx.erricap  = &ictx->ctx.erriptr[--elements];
02e59c
02e59c
	ictx->meta = meta;
02e59c
02e59c
	for (entry=meta->entries,units=ictx->units; entry->fopt || entry->arg; entry++)
02e59c
		if (!entry->fopt)
02e59c
			*units++ = entry->arg;
02e59c
02e59c
	ictx->ctx.fdtmpin   = (-1);
02e59c
	ictx->ctx.ctx.units = ictx->units;
02e59c
	ictx->ctx.ctx.errv  = ictx->ctx.errinfp;
02e59c
	return &ictx->ctx;
02e59c
}
02e59c
02e59c
static int tbnf_get_driver_ctx_fail(struct argv_meta * meta)
02e59c
{
02e59c
	argv_free(meta);
02e59c
	return -1;
02e59c
}
02e59c
02e59c
int tbnf_lib_get_driver_ctx(
02e59c
	char **				argv,
02e59c
	char **				envp,
02e59c
	uint64_t			flags,
02e59c
	const struct tbnf_fd_ctx *	fdctx,
02e59c
	struct tbnf_driver_ctx ** 	pctx)
02e59c
{
02e59c
	struct tbnf_driver_ctx_impl *	ctx;
02e59c
	struct tbnf_common_ctx		cctx;
02e59c
	const struct argv_option *	optv[TBNF_OPTV_ELEMENTS];
02e59c
	struct argv_meta *		meta;
02e59c
	struct argv_entry *		entry;
02e59c
	size_t				nunits;
02e59c
	const char *			program;
02e59c
02e59c
	(void)envp;
02e59c
02e59c
	if (!fdctx)
02e59c
		fdctx = &tbnf_default_fdctx;
02e59c
02e59c
	argv_optv_init(tbnf_default_options,optv);
02e59c
02e59c
	if (!(meta = argv_get(
02e59c
			argv,optv,
02e59c
			tbnf_argv_flags(flags),
02e59c
			fdctx->fderr)))
02e59c
		return -1;
02e59c
02e59c
	nunits	= 0;
02e59c
	program = argv_program_name(argv[0]);
02e59c
	memset(&cctx,0,sizeof(cctx));
02e59c
	cctx.drvflags = flags;
02e59c
02e59c
	if (!argv[1] && (flags & TBNF_DRIVER_VERBOSITY_USAGE))
02e59c
		return tbnf_driver_usage(
02e59c
			fdctx->fderr,
02e59c
			program,
02e59c
			0,optv,meta);
02e59c
02e59c
	/* get options, count units */
02e59c
	for (entry=meta->entries; entry->fopt || entry->arg; entry++) {
02e59c
		if (entry->fopt) {
02e59c
			switch (entry->tag) {
02e59c
				case TAG_HELP:
02e59c
					if (flags & TBNF_DRIVER_VERBOSITY_USAGE)
02e59c
						return tbnf_driver_usage(
02e59c
							fdctx->fdout,
02e59c
							program,entry->arg,
02e59c
							optv,meta);
02e59c
					break;
02e59c
02e59c
				case TAG_VERSION:
02e59c
					cctx.drvflags |= TBNF_DRIVER_VERSION;
02e59c
					break;
02e59c
			}
02e59c
		} else {
02e59c
			nunits++;
02e59c
		}
02e59c
	}
02e59c
02e59c
	if (!(ctx = tbnf_driver_ctx_alloc(meta,fdctx,&cctx,nunits)))
02e59c
		return tbnf_get_driver_ctx_fail(meta);
02e59c
02e59c
	ctx->ctx.program = program;
02e59c
	ctx->ctx.cctx    = &ctx->cctx;
02e59c
02e59c
	*pctx = &ctx->ctx;
02e59c
02e59c
	return TBNF_OK;
02e59c
}
02e59c
02e59c
static void tbnf_free_driver_ctx_impl(struct tbnf_driver_ctx_alloc * ictx)
02e59c
{
02e59c
	if (ictx->ctx.fdtmpin)
02e59c
		close(ictx->ctx.fdtmpin);
02e59c
02e59c
	argv_free(ictx->meta);
02e59c
	free(ictx);
02e59c
}
02e59c
02e59c
void tbnf_lib_free_driver_ctx(struct tbnf_driver_ctx * ctx)
02e59c
{
02e59c
	struct tbnf_driver_ctx_alloc *	ictx;
02e59c
	uintptr_t			addr;
02e59c
02e59c
	if (ctx) {
02e59c
		addr = (uintptr_t)ctx - offsetof(struct tbnf_driver_ctx_impl,ctx);
02e59c
		addr = addr - offsetof(struct tbnf_driver_ctx_alloc,ctx);
02e59c
		ictx = (struct tbnf_driver_ctx_alloc *)addr;
02e59c
		tbnf_free_driver_ctx_impl(ictx);
02e59c
	}
02e59c
}
02e59c
02e59c
const struct tbnf_source_version * tbnf_api_source_version(void)
02e59c
{
02e59c
	return &tbnf_src_version;
02e59c
}
02e59c
02e59c
int tbnf_lib_get_driver_fdctx(
02e59c
	const struct tbnf_driver_ctx *	dctx,
02e59c
	struct tbnf_fd_ctx *		fdctx)
02e59c
{
02e59c
	struct tbnf_driver_ctx_impl *	ictx;
02e59c
02e59c
	ictx = tbnf_get_driver_ictx(dctx);
02e59c
02e59c
	fdctx->fdin  = ictx->fdctx.fdin;
02e59c
	fdctx->fdout = ictx->fdctx.fdout;
02e59c
	fdctx->fderr = ictx->fdctx.fderr;
02e59c
	fdctx->fdlog = ictx->fdctx.fdlog;
02e59c
	fdctx->fdcwd = ictx->fdctx.fdcwd;
02e59c
	fdctx->fddst = ictx->fdctx.fddst;
02e59c
02e59c
	return 0;
02e59c
}
02e59c
02e59c
int tbnf_lib_set_driver_fdctx(
02e59c
	struct tbnf_driver_ctx *	dctx,
02e59c
	const struct tbnf_fd_ctx *	fdctx)
02e59c
{
02e59c
	struct tbnf_driver_ctx_impl *	ictx;
02e59c
02e59c
	ictx = tbnf_get_driver_ictx(dctx);
02e59c
02e59c
	ictx->fdctx.fdin  = fdctx->fdin;
02e59c
	ictx->fdctx.fdout = fdctx->fdout;
02e59c
	ictx->fdctx.fderr = fdctx->fderr;
02e59c
	ictx->fdctx.fdlog = fdctx->fdlog;
02e59c
	ictx->fdctx.fdcwd = fdctx->fdcwd;
02e59c
	ictx->fdctx.fddst = fdctx->fddst;
02e59c
02e59c
	return 0;
02e59c
}