/*
 * Copyright (c) 2001, 2002, 2003, 2004, 2005  Netli, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $Id: ncnf_find.c,v 1.1 2005/05/26 12:08:19 vlm Exp $
 */
#include "headers.h"
#include "ncnf_find.h"

struct ncnf_obj_s *
_na_find_objects(struct ncnf_obj_s *start_level,
	char *types_tree,
	int (*opt_filter)(struct ncnf_obj_s *, void *),
	void *opt_key)
{
	ncnf_sf_svect *tt;	/* types tokens */
	struct ncnf_obj_s *result_iter = NULL;
	struct ncnf_obj_s *iter;

	assert(start_level);
	assert(types_tree);

	/*
	 * Initialize necessary structures.
	 */

	tt = ncnf_sf_split(types_tree, "/", 0);
	if(tt == NULL)
		/* ENOMEM */
		return NULL;
	if(tt->count == 0) {
		ncnf_sf_sfree(tt);
		errno = EINVAL;
		return NULL;
	}

	assert(tt->count);

	result_iter = _ncnf_obj_new(0, NOBJ_ITERATOR, NULL, NULL, 0);
	if(result_iter == NULL)
		/* ENOMEM */
		goto fail;

	/*
	 * Find all interesting elements at this level.
	 */
	iter = _ncnf_get_obj(start_level, tt->list[0], NULL,
		NCNF_ITER_OBJECTS, _NGF_NOFLAGS);
	if(iter == NULL) {
		if(errno != ESRCH)
			goto fail;
	} else {
		struct ncnf_obj_s *obj;
		int is_last_level;

		is_last_level = (tt->count == 1);

		while((obj = _ncnf_iter_next(iter))) {

			if(opt_filter) {
				int ret;
				int tmp_errno = errno;

				errno = -2;
				ret = opt_filter(obj, opt_key);
				if(ret < 0) {
					assert(errno != -2);
					if(errno == -2) {
						errno = EFAULT;
					}
					break;
				}
				errno = tmp_errno;
				if(ret > 0)
					continue;
			}

			if(is_last_level) {
				if(_ncnf_coll_insert(result_iter->mr,
					&result_iter->m_iterator_collection,
					obj, MERGE_NOFLAGS)
				)
					break;
			} else {
				struct ncnf_obj_s *ll_result;
				size_t combined_len = 0;
				char *new_tree;
				int cnt;
				char *p;

				/* Compute the length */
				for(cnt = 1; cnt < tt->count; cnt++)
					combined_len += 1 + tt->lens[cnt];

				p = new_tree = alloca(combined_len + 1);
				for(cnt = 1; cnt < tt->count; cnt++) {
					memcpy(p, tt->list[cnt], tt->lens[cnt]);
					p += tt->lens[cnt];
					*p = '/';
					if(cnt < (tt->count - 1))
						p++;
				}
				*p = '\0';

				ll_result = _na_find_objects(obj, new_tree,
					opt_filter, opt_key);
				if(ll_result == NULL) {
					if(errno == ESRCH)
						continue;
					break;
				}
				if(_ncnf_coll_join(result_iter->mr,
					&result_iter->m_iterator_collection,
					&ll_result->m_iterator_collection,
					NULL, MERGE_NOFLAGS))
					break;
				_ncnf_obj_destroy(ll_result);
			}
		}

		_ncnf_obj_destroy(iter);

		if(obj != NULL)
			goto fail;
	}

	ncnf_sf_sfree(tt);

	/* Remove envelope if there is no data */
	if(result_iter->m_iterator_collection.entries == 0) {
		_ncnf_obj_destroy(result_iter);
		errno = ESRCH;
		return NULL;
	}

	return result_iter;

fail:

	if(result_iter)
		_ncnf_obj_destroy(result_iter);

	ncnf_sf_sfree(tt);
	return NULL;
}



syntax highlighted by Code2HTML, v. 0.9.1