/*
 * 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-string.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_string_node_to_value(
	sm_conf_T			*smc,
	sm_conf_definition_T const	*def,
	sm_conf_node_T			*node,
	void				*data)
{
	char const			*text;
	size_t				text_n;
	int				err;

	SM_IS_CONF_DEF(def);
	err = 0;
	if (def->scd_flags & SM_CONF_FLAG_MULTIPLE)
	{
		/* XXX */
	}
	else
	{
		err = sm_conf_node_to_value(smc, "string",
			node, &text, &text_n);
		if (err != 0)
			return err;

		if (strlen(text) != text_n)
		{
			char loc[SM_CONF_ERROR_BUFFER_SIZE];
			sm_conf_error_add(smc, "%s: NUL in %s '%.*s'",
				sm_conf_node_location(smc, node,
					loc, sizeof loc),
				def->scd_name[0] == '\0'
					? "string" : def->scd_name,
				(int)text_n, text);
			return SM_CONF_ERR_TYPE;
		}

		if (def->scd_size > 0)
		{
			if (text_n >= def->scd_size)
			{
				char loc[SM_CONF_ERROR_BUFFER_SIZE];
				sm_conf_error_add(smc,
					"%s: overflow error: %s '%.*s' "
					"more than %lu character%s long",
					sm_conf_node_location(smc, NULL,
						loc, sizeof loc),
					def->scd_name[0] == '\0'
						? "string"
						: def->scd_name,
					(int)text_n, text,
					(unsigned long)def->scd_size - 1,
					def->scd_size == 2 ? "" : "s");
				return SM_CONF_ERR_TYPE;
			}
			if (data != NULL)
			{
				sm_memcpy(data, text, text_n);
				((char *)data)[text_n] = '\0';
			}
		}
		else
		{
			if (data != NULL)
				*(char const **)data = text;
		}
	}
	return err;
}

static int
sm_conf_type_string_value_check(
	sm_conf_T			*smc,
	sm_conf_definition_T const	*def,
	void const			*data)
{
	SM_IS_CONF_DEF(def);
	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_string_value_null(
	sm_conf_T			*smc,
	sm_conf_definition_T const	*def,
	void				*data)
{
	if (data == NULL)
		return 0;

	SM_IS_CONF_DEF(def);
	if (def->scd_flags & SM_CONF_FLAG_MULTIPLE)
	{
		char const * const	*default_av;

		default_av = (char const * const *)def->scd_default;

		if (def->scd_size == 0)
			*(char const * const **)data = default_av;
		else
		{
			size_t	i = 0;

			/* copy entries from the default until we hit NULL */
			if (default_av != NULL)
				for (; i < def->scd_size
					&& default_av[i] != NULL; i++)
					((char const **)data)[i] = default_av[i];

			while (i < def->scd_size)
			{
				((char const **)data)[i] = NULL;
				i++;
			}
		}
	}
	else
	{
		if (def->scd_size == 0)
			*(char const **)data = def->scd_default;
		else if (def->scd_default != NULL)
		{
			if (strlen(def->scd_default) >= def->scd_size)
			{
				char loc[SM_CONF_ERROR_BUFFER_SIZE];
				sm_conf_error_add(smc,
					"%s: overflow error: %s default '%s' "
					"more than %lu character%s long",
					sm_conf_node_location(smc, NULL,
						loc, sizeof loc),
					def->scd_name[0] == '\0'
						? "string"
						: def->scd_name,
					def->scd_default,
					(unsigned long)def->scd_size - 1,
					def->scd_size == 2 ? "" : "s");
				return SM_CONF_ERR_TYPE;
			}
			strlcpy(data, def->scd_default, def->scd_size);
		}
		else
			sm_memset(data, 0, def->scd_size);
	}
	return 0;
}

sm_conf_type_T const
sm_conf_type_string_data =
{
	sm_conf_type_string_node_to_value,
	sm_conf_type_string_value_check,
	sm_conf_type_string_value_null
};


syntax highlighted by Code2HTML, v. 0.9.1