/*
 * Copyright (c) 2004, 2005 Sendmail, Inc. and its suppliers.
 *	All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the sendmail distribution.
 */

#include "sm/generic.h"
SM_RCSID("@(#)$Id: sm-conf-type-argv.c,v 1.9 2005/05/24 17:57:28 ca Exp $")

#if SM_LIBCONF_ALONE
#include <string.h>
#include "sm-conf.h"
#else /* SM_LIBCONF_ALONE */
#include "sm/string.h"
#include "sm/memops.h"
#include "sm/sm-conf.h"
#endif /* SM_LIBCONF_ALONE */

#include "sm-conf-type.h"
#include "sm-conf-state.h"

static int
sm_conf_type_argv_node_to_value(
	sm_conf_T			*smc,
	sm_conf_definition_T const	*def,
	sm_conf_node_T			*node,
	void				*out)
{
	size_t				argv_n;
	int				err;
	char				loc[SM_CONF_ERROR_BUFFER_SIZE];
	char const			* const *argv, * const *p;

	SM_IS_CONF_DEF(def);
	if (sm_conf_node_type(smc, node) == SM_CONF_NODE_SECTION)
	{
		sm_conf_error_add(smc,
			"%s: %s%sexpected string or array, got section",
			sm_conf_node_location(smc, node, loc, sizeof loc),
			def->scd_name,
			def->scd_name[0] == '\0' ? "" : ": ");
		return SM_CONF_ERR_TYPE;
	}

	err = sm_conf_node_argv(smc, (sm_conf_node_T *)node, &argv);
	if (err)
	{
		char errbuf[SM_CONF_ERROR_BUFFER_SIZE];
		sm_conf_error_add(smc,
			"%s: %s%s%s",
			sm_conf_node_location(smc, node, loc, sizeof loc),
			def->scd_name,
			def->scd_name[0] == '\0' ? "" : ": ",
			sm_conf_strerror(err, errbuf, sizeof errbuf));
		return err;
	}

	if (argv == NULL)
		argv_n = 0;
	else
	{
		for (p = argv; *p != NULL; p++)
			;
		argv_n = p - argv;
	}

	if (def->scd_size > 0)
	{
		if (argv_n > def->scd_size)
		{
			sm_conf_error_add(smc, "%s: %s%soverflow -- "
				"too many elements in list",
				sm_conf_node_location(smc, node,
					loc, sizeof loc),
				def->scd_name,
				def->scd_name[0] == '\0' ? "" : ": ");
			return SM_CONF_ERR_TYPE;
		}
		if (out != NULL)
		{
			if (argv_n > 0)
				sm_memcpy(out, argv, argv_n * sizeof(char **));
			while (argv_n < def->scd_size)
				((char const **)out)[argv_n++] = NULL;
		}
	}
	else
	{
		if (out != NULL)
			*(char const * const **)out = argv;
	}
	return err;
}

static int
sm_conf_type_argv_value_check(
	sm_conf_T			*smc,
	sm_conf_definition_T const	*def,
	void const			*data)
{
	SM_IS_CONF_DEF(def);
	SM_REQUIRE(smc != NULL);

	if (data == NULL)
		return 0;

	/* if we have a check function, use it. */
	if (def->scd_check != NULL)
		return (* def->scd_check)(smc, def->scd_check_data, def, data);
	return 0;
}

static int
sm_conf_type_argv_value_null(
	sm_conf_T			*smc,
	sm_conf_definition_T const	*def,
	void				*out)
{
	char const * const		*default_av;
	size_t				i;

	if (out == NULL)
		return 0;
	SM_IS_CONF_DEF(def);
	default_av = (char const * const *)def->scd_default;

	if (def->scd_size == 0)
		*(char const * const **)out = default_av;
	else
	{
		/* copy entries from the default until we hit NULL */
		i = 0;
		if (default_av != NULL)
			while (i < def->scd_size && default_av[i] != NULL)
			{
				((char const **)out)[i] = default_av[i];
				i++;
			}
		while (i < def->scd_size)
		{
			((char const **)out)[i] = NULL;
			i++;
		}
	}
	return 0;
}

sm_conf_type_T const
sm_conf_type_argv_data =
{
	sm_conf_type_argv_node_to_value,
	sm_conf_type_argv_value_check,
	sm_conf_type_argv_value_null
};


syntax highlighted by Code2HTML, v. 0.9.1