/*
 * 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-bool.c,v 1.9 2005/05/24 17:57:28 ca Exp $")


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

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

static int
bool_write(
	sm_conf_definition_T const	*def,
	void				*data,
	int				val)
{
	SM_IS_CONF_DEF(def);
	SM_REQUIRE(data != NULL);

	if (def->scd_size == 1)
		*(unsigned char *)data = val;
	else if (def->scd_size == sizeof(unsigned short))
		*(unsigned short *)data = val;
	else if (def->scd_size == sizeof(unsigned int))
		*(unsigned int *)data = val;
	else if (def->scd_size == sizeof(unsigned long))
		*(unsigned long *)data = val;
	else
		return SM_CONF_ERR_INVALID;

	return 0;
}

static int
bool_scan(
	sm_conf_T			*smc,
	sm_conf_node_T const		*node,
	sm_conf_definition_T const	*def,
	char const			*text,
	size_t				text_n,
	int				*val_out)
{
	char				loc[SM_CONF_ERROR_BUFFER_SIZE];

	SM_IS_CONF_DEF(def);
	SM_REQUIRE(val_out != NULL);
	if (  text_n == 0
	   || text == NULL
	   || *text == '0'
	   || tolower(*text) == 'f'
	   || tolower(*text) == 'n'
	   || sm_memncaseeq(text, text_n, "off", 3))
	{
		*val_out = 0;
	}
	else if ((  text_n > 0
		&& (  *text == '1'
		   || tolower(*text) == 't'
		   || tolower(*text) == 'y'))
		   || sm_memncaseeq(text, text_n, "on", 2))
	{
		*val_out = 1;
	}
	else
	{
		sm_conf_error_add(smc, "%s: expected %s \"yes\"/\"no\" "
			"(or on/off, t*/f*, 0/1); got %.*s",
			sm_conf_node_location(smc, node, loc, sizeof loc),
			def->scd_name[0] == '\0' ? "boolean" : def->scd_name,
			(int)text_n, text);
		return SM_CONF_ERR_TYPE;
	}
	return 0;
}

static int
sm_conf_type_bool_node_to_value(
	sm_conf_T			*smc,
	sm_conf_definition_T const	*def,
	sm_conf_node_T			*node,
	void				*out)
{
	char const		*text;
	size_t			text_n;
	int			err, val;

	SM_IS_CONF_DEF(def);
	err = sm_conf_node_to_value(smc, "boolean", node, &text, &text_n);
	if (err != 0)
		return err;

	err = bool_scan(smc, node, def, text, text_n, &val);
	if (err != 0)
		return err;

	if (out != NULL)
		err = bool_write(def, out, val);

	return err;
}

static int
sm_conf_type_bool_value_check(
	sm_conf_T			*smc,
	sm_conf_definition_T const	*def,
	void const			*data)
{
	return 0;
}

static int
sm_conf_type_bool_value_null(
	sm_conf_T			*smc,
	sm_conf_definition_T const	*def,
	void				*data)
{
	int				val;
	int				err;

	SM_IS_CONF_DEF(def);
	if (data != NULL)
	{
		val = 0;
		if (def->scd_default != NULL)
		{
			err = bool_scan(smc, NULL, def, def->scd_default,
				strlen(def->scd_default), &val);
			if (err != 0)
				return err;
		}

		err = bool_write(def, data, val);
		if (err != 0)
			return err;
	}
	return 0;
}

sm_conf_type_T const
sm_conf_type_bool_data =
{
	sm_conf_type_bool_node_to_value,
	sm_conf_type_bool_value_check,
	sm_conf_type_bool_value_null
};


syntax highlighted by Code2HTML, v. 0.9.1