/*
 * Copyright (c) 2003-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: maps.c,v 1.14 2006/05/02 17:13:41 ca Exp $")

#include "sm/assert.h"
#include "sm/error.h"
#include "sm/memops.h"
#include "sm/heap.h"
#include "sm/maps.h"
#include "sm/mapc.h"
#include "sm/map.h"

/*
**  SM_MAPS_FREE -- free map class (callback for bht_destroy)
**
**	Parameters:
**		value -- map system context
**		key -- unused
**		ctx -- unused
**
**	Returns:
**		none.
*/

/* ARGSUSED1 */
static void
sm_maps_free(void *value, void *key, void *ctx)
{
	sm_mapc_P mapc;

	SM_REQUIRE(value != NULL);
	mapc = (sm_mapc_P) value;
	SM_IS_MAPC(mapc);
	SM_CSTR_FREE(mapc->sm_mapc_type);
	sm_free_size(mapc, sizeof(*mapc));
}

/*
**  SM_MAPS_TERM -- terminate map system
**
**	Parameters:
**		maps -- map system context
**
**	Returns:
**		usual sm_error code
*/

sm_ret_T
sm_maps_term(sm_maps_P maps)
{
	if (maps == NULL)
		return SM_SUCCESS;
	SM_IS_MAPS(maps);
	if (maps->sm_maps_ht_mapc != NULL)
	{
		/* XXX function to free each element? */
		bht_destroy(maps->sm_maps_ht_mapc, sm_maps_free, NULL);
	}
	if (maps->sm_maps_ht_map != NULL)
		bht_destroy(maps->sm_maps_ht_map, NULL, NULL);
	sm_free_size(maps, sizeof(*maps));
	return SM_SUCCESS;
}

/*
**  SM_MAPS_INIT -- initialize map system
**
**	Parameters:
**		pmaps -- (pointer to) map system context (output)
**	add parameters for hash table sizes?
**
**	Returns:
**		usual sm_error code
*/

sm_ret_T
sm_maps_init(sm_maps_P *pmaps)
{
	sm_maps_P maps;
	sm_ret_T ret;

	SM_REQUIRE(pmaps != NULL);
	*pmaps = NULL;
	maps = (sm_maps_P ) sm_zalloc(sizeof(*maps));
	if (maps == NULL)
		return sm_error_temp(SM_EM_MAPS, ENOMEM);

	maps->sm_maps_ht_mapc = bht_new(16, 1024);
	if (maps->sm_maps_ht_mapc == NULL)
	{
		ret = sm_error_temp(SM_EM_MAPS, ENOMEM);
		goto error;
	}

	maps->sm_maps_ht_map = bht_new(16, 1024);
	if (maps->sm_maps_ht_map == NULL)
	{
		ret = sm_error_temp(SM_EM_MAPS, ENOMEM);
		goto error;
	}

#if SM_MAPS_CHECK
	maps->sm_magic = SM_MAPS_MAGIC;
#endif /* SM_MAPS_CHECK */
	*pmaps = maps;
	return SM_SUCCESS;

  error:
	if (maps->sm_maps_ht_map != NULL)
		bht_destroy(maps->sm_maps_ht_map, NULL, NULL);
	if (maps->sm_maps_ht_mapc != NULL)
		bht_destroy(maps->sm_maps_ht_mapc, NULL, NULL);
	if (maps != NULL)
		sm_free_size(maps, sizeof(*maps));
	return ret;
}

/*
**  SM_MAPS_ADD -- add map class
**
**	Parameters:
**		maps -- map system context
**		mapc -- map class context
**
**	Returns:
**		usual sm_error code
*/

sm_ret_T
sm_maps_add(sm_maps_P maps, sm_mapc_P mapc)
{
	sm_ret_T ret;
	bht_entry_P entry;

	SM_IS_MAPS(maps);
	SM_IS_MAPC(mapc);
	ret = bht_add(maps->sm_maps_ht_mapc,
			(char *)sm_cstr_data(mapc->sm_mapc_type),
			sm_cstr_getlen(mapc->sm_mapc_type),
			mapc, &entry);
	return ret;
}

/*
**  SM_MAPS_RM -- remove map class
**
**	Parameters:
**		maps -- map system context
**		mapc -- map class context
**
**	Returns:
**		usual sm_error code
*/

sm_ret_T
sm_maps_rm(sm_maps_P maps, sm_mapc_P mapc)
{
	SM_IS_MAPS(maps);
	SM_IS_MAPC(mapc);

	/* XXX check for existence and complain if it isn't registered? */
	bht_rm(maps->sm_maps_ht_mapc,
		(const char *)sm_cstr_data(mapc->sm_mapc_type),
		sm_cstr_getlen(mapc->sm_mapc_type), sm_maps_free, NULL);
	return SM_SUCCESS;
}

/*
**  SM_MAPS_FIND -- lookup value
**
**	Parameters:
**		maps -- map system context
**		mapc_type -- map class type
**		mapc -- (pointer to) map class context (output)
**
**	Returns:
**		pointer to value
*/

sm_ret_T
sm_maps_find(sm_maps_P maps, const sm_cstr_P mapc_type, sm_mapc_P *pmapc)
{
	void *ptr;

	SM_IS_MAPS(maps);
	SM_IS_CSTR(mapc_type);
	ptr = bht_find(maps->sm_maps_ht_mapc,
		(const char*)sm_cstr_data(mapc_type),
		sm_cstr_getlen(mapc_type));
	if (ptr == NULL)
		return sm_error_perm(SM_EM_MAP, ENOENT);
	if (pmapc != NULL)
		*pmapc = (sm_mapc_P)ptr;
	return SM_SUCCESS;
}

#if 0
///*
//**  SM_MAPS_WALK - iterate over hash maps, apply a function to each element
//**
//**	Parameters:
//**		maps -- pointer to maps
//**		action -- function to apply
//**		ctx -- context for function.
//**
//**	Returns:
//**		usual sm_error code
//*/
//
//sm_ret_T
//sm_maps_walk(sm_maps_P maps, sm_bhwalk_F action, void *ctx)
//{
//	uint i;
//	sm_maps_entry_P *h, ht, htn;
//	sm_ret_T ret;
//
//	SM_IS_MAPS(maps);
//	i = maps->maps_size;
//	h = maps->maps_data;
//	while (i-- > 0)
//	{
//		for (ht = *h++; ht != NULL; ht = htn)
//		{
//			htn = ht->bhe_next;
//			ret = (*action)(ht, ctx);
//			if (sm_is_err(ret))
//				return ret;
//		}
//	}
//	return SM_SUCCESS;
//}
#endif /* 0 */


syntax highlighted by Code2HTML, v. 0.9.1