/*
 * Copyright (c) 2004 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-util.c,v 1.10 2004/08/02 22:33:52 ca Exp $")

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

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

#if SM_LIBCONF_ALONE
/* strncasecmp that doesn't stop at \0 */
bool sm_memncaseeq(
	char const	*a,
	size_t		a_size,
	char const	*b,
	size_t		b_size)
{
	size_t		i;

	if (a_size != b_size)
		return false;

	for (i = 0; i < a_size; i++, a++, b++)
	{
		if (isascii(*a) && isascii(*b))
		{
			if (tolower(*a) != tolower(*b))
				return false;
		}
		else
		{
			if ((unsigned char)*a != (unsigned char)*b)
				return false;
		}
	}
	return true;
}
#endif /* SM_LIBCONF_ALONE */

/*
**  SM_CONF_SUBDEF_PREFIX -- return the longest matching prefix in <name>.
**
**	The up to <name_n> bytes pointed to by <name> may be
**	a prefix.  All definition records in <def> with type
**	<type> name possible prefixes.  Find the longest prefix
**	that occurs at the start of <name> and return it and its length.
**
**	Parameters:
**		def -- the resource list of the containing type;
**			terminated by a record with NULL name.
**		type -- the type of prefix we're looking at.
**			Resources in the definition list that don't
**			have type <type> are ignored.
**		name -- string we're trying to match a suffix in
**		name_n -- # of bytes we can access, at most.
**		len -- out: how many bytes did we actually match?
**
**	Returns:
**		NULL if no suffix was found, otherwise a pointer
**		to the matching definition record.
**
**	Last code review:
**	Last code change: 2004-07-12 15:42:47	jutta
*/

sm_conf_definition_T const *
sm_conf_subdef_prefix(
	sm_conf_definition_T const	*def,
	sm_conf_type_T const		*type,
	char const			*name,
	size_t				name_n,
	size_t				*len)
{
	sm_conf_definition_T const	*best_def = NULL;
	size_t				best_len  = 0;

	if (name_n != 0 && def != NULL)
	{
		size_t n;

		SM_IS_CONF_DEF(def);
		while (def->scd_name != NULL)
		{
			n = strlen(def->scd_name);
			if (n <= name_n
			    && sm_memncaseeq(
					def->scd_name, strlen(def->scd_name),
					name, n)
			    && def->scd_type == type)
			{
				if (  best_def == NULL
				   || best_len < n)
				{
					best_def = def;
					best_len = n;
				}
			}
			def++;
		}
	}

	*len = best_len;
	return best_def;
}

/*
**  SM_CONF_SUBDEF -- return a subdefinition with a name and type
**
**	Parameters:
**		def -- NULL or start of a sentinel-terminated array
**			of subdefinitions.  Those with type <type>
**			are the possible values
**
**		type -- if non-NULL, only entries of this type are
**			taken into account
**		name -- if non-NULL, name we're looking for
**		name_n -- length of <name> in bytes.
**
**	Returns:
**		NULL on failure, otherwise a pointer to the
**		first record on or after <def> whose type is <type>
**		and whose name is <name>[0...<name_n>-1].
*/

sm_conf_definition_T const *
sm_conf_subdef(
	sm_conf_definition_T const	*def,
	sm_conf_type_T const		*type,
	char const			*name,
	size_t				name_n)
{
	if (def != NULL)
	{
		SM_IS_CONF_DEF(def);
		while (def->scd_name != NULL)
		{
			if (  (name == NULL || sm_memncaseeq(
				def->scd_name, strlen(def->scd_name),
				name, name_n))
			   && (type == NULL || def->scd_type == type))
				return def;

			def++;
		}
	}
	return NULL;
}



syntax highlighted by Code2HTML, v. 0.9.1