File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libpdel / tmpl / tmpl_ctx.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:25:53 2012 UTC (12 years, 8 months ago) by misho
Branches: libpdel, MAIN
CVS tags: v0_5_3, HEAD
libpdel


/*
 * Copyright (c) 2001-2002 Packet Design, LLC.
 * All rights reserved.
 * 
 * Subject to the following obligations and disclaimer of warranty,
 * use and redistribution of this software, in source or object code
 * forms, with or without modifications are expressly permitted by
 * Packet Design; provided, however, that:
 * 
 *    (i)  Any and all reproductions of the source or object code
 *         must include the copyright notice above and the following
 *         disclaimer of warranties; and
 *    (ii) No rights are granted, in any manner or form, to use
 *         Packet Design trademarks, including the mark "PACKET DESIGN"
 *         on advertising, endorsements, or otherwise except as such
 *         appears in the above copyright notice or in the software.
 * 
 * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
 * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
 * OR NON-INFRINGEMENT.  PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
 * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
 * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
 * RELIABILITY OR OTHERWISE.  IN NO EVENT SHALL PACKET DESIGN BE
 * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
 * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
 * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
 * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
 * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Author: Archie Cobbs <archie@freebsd.org>
 */

#include "tmpl_internal.h"

/*
 * Internal functions
 */
static void	tmpl_free_vars(struct tmpl_ctx *ctx);
static void	tmpl_free_funcs(struct tmpl_ctx *ctx);
static int	tmpl_userfunc_cmp(const void *v1, const void *v2);

/*
 * Create a template context.
 */
struct tmpl_ctx *
tmpl_ctx_create(void *arg, const char *mtype,
	tmpl_handler_t *handler, tmpl_errfmtr_t *errfmtr)
{
	struct tmpl_ctx *ctx;

	/* Initialize template file */
	if ((ctx = MALLOC(mtype, sizeof(*ctx))) == NULL)
		return (NULL);
	memset(ctx, 0, sizeof(*ctx));
	if (mtype != NULL) {
		strlcpy(ctx->mtype_buf, mtype, sizeof(ctx->mtype_buf));
		ctx->mtype = ctx->mtype_buf;
	}
	ctx->arg = arg;
	ctx->handler = handler;
	ctx->errfmtr = errfmtr;

	/* Done */
	return (ctx);
}

/*
 * Get context argument.
 */
void *
tmpl_ctx_get_arg(struct tmpl_ctx *ctx)
{
	return (ctx->arg);
}
        
/*
 * Get context memory type.
 */
const char *
tmpl_ctx_get_mtype(struct tmpl_ctx *ctx)
{
	return (ctx->mtype);
}

/*
 * Handler for handling a fixed list of user functions.
 */
char *
tmpl_list_handler(struct tmpl_ctx *ctx, const struct tmpl_func *userfuncs,
	u_int uflen, char **errmsgp, int ac, char **av)
{
	const char *const mtype = tmpl_ctx_get_mtype(ctx);
	struct tmpl_func key;
	struct tmpl_func *f;
	char buf[256];
	char *s;
	int i;

	/* If no userfunc's supplied, bail */
	if (userfuncs == NULL) {
		*errmsgp = STRDUP(mtype, "unknown template function");
		goto error;
	}

	/* Find function in user-supplied list */
	key.name = av[0];
	if ((f = bsearch(&key, userfuncs, uflen,
	    sizeof(*userfuncs), tmpl_userfunc_cmp)) == NULL) {
		*errmsgp = STRDUP(mtype, "unknown template function");
		goto error;
	}

	/* Check number of arguments */
	if (ac - 1 < f->min_args) {
		ASPRINTF(mtype, errmsgp,
		    "at %s %d argument%s %s for \"@%s\"",
		    "least", f->min_args, f->min_args == 1 ? "" : "s",
		    "required", f->name);
		goto error;
	}
	if (ac - 1 > f->max_args) {
		ASPRINTF(mtype, errmsgp,
		    "at %s %d argument%s %s for \"@%s\"",
		    "most", f->max_args, f->max_args == 1 ? "" : "s",
		    "allowed", f->name);
		goto error;
	}

	/* Invoke handler */
	if ((s = (*f->handler)(ctx, errmsgp, ac, av)) != NULL)
		return (s);

error:
	/* Handle errors by showing the function that generated the error */
	snprintf(buf, sizeof(buf), "@%s(", av[0]);
	for (i = 1; i < ac; i++) {
		snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
		    "%s%s", (i > 1) ? ", " : "", av[i]);
	}
	snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "): %s",
	    (*errmsgp != NULL) ? *errmsgp : strerror(errno));
	if (*errmsgp != NULL)
		FREE(mtype, *errmsgp);
	*errmsgp = STRDUP(mtype, buf);
	return (NULL);
}

/*
 * Destroy a template context.
 */
void
tmpl_ctx_destroy(struct tmpl_ctx **ctxp)
{
	struct tmpl_ctx *const ctx = *ctxp;

	/* Sanity check */
	if (ctx == NULL)
		return;
	*ctxp = NULL;

	/* Free run-time state */
	tmpl_ctx_reset(ctx);

	/* Free context */
	FREE(ctx->mtype, ctx);
}

/*
 * Do the things we need in order to reset a template context.
 */
void
tmpl_ctx_reset(struct tmpl_ctx *ctx)
{
	tmpl_free_vars(ctx);
	tmpl_free_funcs(ctx);
}

/*
 * Free up the vars part of a template context.
 */
static void
tmpl_free_vars(struct tmpl_ctx *ctx)
{
	int i;

	/* Free variables */
	for (i = 0; i < ctx->num_vars; i++) {
		struct exec_var *const var = &ctx->vars[i];

		FREE(ctx->mtype, var->name);
		FREE(ctx->mtype, var->value);
	}
	FREE(ctx->mtype, ctx->vars);

	ctx->num_vars = 0;
	ctx->vars = NULL;
}

/*
 * Free up the funcs part of a template context.
 */
static void
tmpl_free_funcs(struct tmpl_ctx *ctx)
{
	int i;

	/* Free run-time functions */
	for (i = 0; i < ctx->num_funcs; i++)
		_tmpl_free_func(ctx, &ctx->funcs[i]);
	FREE(ctx->mtype, ctx->funcs);

	ctx->num_funcs = 0;
	ctx->funcs = NULL;
}

/*
 * Compare two struct tmpl_func's.
 */
static int
tmpl_userfunc_cmp(const void *v1, const void *v2)
{
	const struct tmpl_func *const f1 = v1;
	const struct tmpl_func *const f2 = v2;

	return (strcmp(f1->name, f2->name));
}


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>