/*
* 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_coll.c,v 1.1 2005/05/26 12:08:19 vlm Exp $
*/
/*
* Implementation of object Collection structure.
*/
#include "headers.h"
#include "ncnf_int.h"
/*
* Adjust storage size of the collection.
*/
int
_ncnf_coll_adjust_size(void *mr, collection_t *coll, int new_count) {
if(new_count > coll->entries) {
/*
* Allocate and clear a few more entries.
*/
if(new_count > coll->size) {
void *p;
size_t new_size = mr
? (coll->size + ((new_count + 3) & ~3))
: new_count;
p = realloc(coll->entry,
new_size * sizeof(collection_entry));
if(p == NULL)
return -1;
coll->entry = p;
coll->size = new_size;
}
memset(&coll->entry[coll->entries],
0,
(new_count - coll->entries)
* sizeof(collection_entry));
} else {
/*
* Destroy all inserted objects.
*/
for(; coll->entries > new_count;) {
int num = --coll->entries;
struct ncnf_obj_s *obj;
obj = coll->entry[num].object;
coll->entry[num].object = NULL;
_ncnf_obj_destroy(obj);
}
if(new_count == 0) {
if(coll->entry) {
free(coll->entry);
coll->entry = NULL;
coll->size = 0;
}
}
}
return 0;
}
/*
* Insert new object into collection.
*/
int
_ncnf_coll_insert(void *mr, collection_t *coll, struct ncnf_obj_s *obj, enum merge_flags merge_flags) {
/* Check for duplicates */
if(merge_flags & MERGE_DUPCHECK) {
if(_ncnf_coll_get(coll,
CG_TYPE_NOCASE | CG_NAME_NOCASE,
(obj->obj_class == NOBJ_ATTRIBUTE
|| obj->obj_class == NOBJ_LAZY_NOTIF)
? obj->type
: NULL,
obj->value, NULL)) {
errno = EEXIST;
return -1;
}
}
if(merge_flags & MERGE_PTRCHECK) {
int ent;
for(ent = 0; ent < coll->entries; ent++) {
if(coll->entry[ent].object == obj) {
errno = EEXIST;
return -1;
}
}
}
if(_ncnf_coll_adjust_size(mr, coll, coll->entries + 1))
/* ENOMEM */
return -1;
coll->entry[coll->entries++].object = obj;
return 0;
}
/*
* Add contents of the second collection to the first collection.
*/
int
_ncnf_coll_join(void *mr, collection_t *to, collection_t *from, struct ncnf_obj_s *parent, enum merge_flags merge_flags) {
int to_idx, from_idx;
/* Check for duplicates */
if(merge_flags & MERGE_DUPCHECK) {
for(from_idx = 0; from_idx < from->entries; from_idx++) {
struct ncnf_obj_s *obj = from->entry[from_idx].object;
if(_ncnf_coll_get(to,
CG_TYPE_NOCASE | CG_NAME_NOCASE,
(obj->obj_class == NOBJ_ATTRIBUTE
|| obj->obj_class == NOBJ_LAZY_NOTIF)
? obj->type
: NULL,
obj->value, NULL)) {
errno = EEXIST;
return -1;
}
}
}
if(_ncnf_coll_adjust_size(mr, to, to->entries + from->entries))
/* ENOMEM */
return -1;
for(to_idx = to->entries, from_idx = 0;
from_idx < from->entries;
to_idx++, from_idx++) {
to->entry[to_idx] = from->entry[from_idx];
if(parent)
to->entry[to_idx].object->parent = parent;
}
to->entries += from->entries;
if(merge_flags & MERGE_EMPTYSRC)
/* Empty the source collection */
_ncnf_coll_clear(mr, from, 0);
return 0;
}
/*
* Clear specified collection.
*/
void
_ncnf_coll_clear(void *mr, collection_t *coll, int destroy) {
/* [Martin 03/03/05]: bug 1917. memory leak.
* we must do this before _ncnf_coll_adjust_size
*/
if(destroy == 0)
coll->entries = 0;
_ncnf_coll_adjust_size(mr, coll, 0);
coll->entries = 0;
}
/*
* Search in given collection for object specified by type or value or both.
*/
struct ncnf_obj_s *
_ncnf_coll_get(collection_t *coll, enum cget_flags flags,
const char *opt_type, const char *opt_name,
void *iterator) {
struct ncnf_obj_s *found = NULL;
struct ncnf_obj_s *found_last = NULL;
int (*type_compare)(const char *, const char *);
int (*name_compare)(const char *, const char *);
int ignore_class;
int opt_type_len;
int opt_name_len;
int entries;
int i;
type_compare = (flags & CG_TYPE_NOCASE) ? strcasecmp : strcmp;
name_compare = (flags & CG_NAME_NOCASE) ? strcasecmp : strcmp;
ignore_class = (flags & CG_IGNORE_REFERENCES)
? NOBJ_REFERENCE
: -1;
opt_type_len = opt_type ? strlen(opt_type) : 0;
opt_name_len = opt_name ? strlen(opt_name) : 0;
for(i = 0, entries = coll->entries; i < entries; i++) {
struct ncnf_obj_s *cur = coll->entry[i].object;
/*
* Filters.
*/
if(opt_type)
if(bstr_len(cur->type) != opt_type_len
|| type_compare(cur->type, opt_type))
continue;
if(opt_name)
if(bstr_len(cur->value) != opt_name_len
|| name_compare(cur->value, opt_name))
continue;
if(ignore_class == coll->entry[i].object->obj_class)
continue;
if(coll->entry[i].ignore_in_search)
continue;
/*
* Found something.
*/
if((flags & CG_MARK_UNSEARCHABLE))
coll->entry[i].ignore_in_search = 1;
if(iterator) {
if(flags & CG_RETURN_POSITION) {
*(int *)iterator = i;
return cur;
} else {
struct ncnf_obj_s *iterator_obj
= (struct ncnf_obj_s *)iterator;
if(_ncnf_coll_insert(0,
&iterator_obj->m_iterator_collection,
cur, MERGE_NOFLAGS)) {
return NULL;
}
found = iterator;
}
} else {
if((flags & CG_RETURN_CHAIN)) {
if(found) {
found_last->chain_next = cur;
} else {
found = cur;
}
found_last = cur;
found_last->chain_next = NULL;
found_last->chain_cur = NULL;
} else {
return cur;
}
}
}
if(found == NULL)
errno = ESRCH;
return found;
}
/*
* Remove all objects with mark equal to match_mark
* from the collection.
*/
void
_ncnf_coll_remove_marked(collection_t *coll, int match_mark) {
int shift = 0;
int k;
assert(coll && match_mark);
for(k = 0; k < coll->entries; k++) {
ncnf_obj *obj;
if(shift)
coll->entry[k] = coll->entry[k + shift];
obj = coll->entry[k].object;
if(obj->mark == match_mark) {
/* Squeeze a little tighter */
shift++;
coll->entries--;
coll->entry[k].object = NULL;
_ncnf_obj_destroy(obj);
k--;
}
}
}
int ncnf_coll_get_nentry(collection_t *coll)
{
if(coll) {
return coll->entries;
} else {
errno = EINVAL;
return 0;
}
}
struct ncnf_obj_s* ncnf_coll_get_obj_at(collection_t *coll, int idx)
{
if(coll && idx < coll->entries && idx >= 0) {
return coll->entry[idx].object;
} else {
errno = EINVAL;
return NULL;
}
}
#ifdef MODULE_TEST
int
main(int ac, char **av) {
static collection_t coll;
struct ncnf_obj_s *obj;
int ret;
/*
* Test 1
*/
/* Mark */
obj = _ncnf_obj_new(0, NOBJ_ATTRIBUTE, NULL, NULL, 0);
assert(obj);
obj->mark = 1;
ret = _ncnf_coll_insert(0, &coll, obj, MERGE_DUPCHECK);
assert(ret == 0);
_ncnf_coll_remove_marked(&coll, 1);
assert(coll.entries == 0);
/*
* Test 2
*/
/* Mark */
obj = _ncnf_obj_new(0, NOBJ_ATTRIBUTE,
str2bstr("a", -1), str2bstr("marked", -1), 0);
assert(obj);
obj->mark = 1;
ret = _ncnf_coll_insert(0, &coll, obj, MERGE_DUPCHECK);
assert(ret == 0);
/* Zero */
obj = _ncnf_obj_new(0, NOBJ_ATTRIBUTE,
str2bstr("b", -1), str2bstr("unmarked", -1), 0);
assert(obj);
obj->mark = 0;
ret = _ncnf_coll_insert(0, &coll, obj, MERGE_DUPCHECK);
assert(ret == 0);
/* Mark */
obj = _ncnf_obj_new(0, NOBJ_ATTRIBUTE,
str2bstr("c", -1), str2bstr("marked", -1), 0);
assert(obj);
obj->mark = 1;
ret = _ncnf_coll_insert(0, &coll, obj, MERGE_DUPCHECK);
assert(ret == 0);
_ncnf_coll_remove_marked(&coll, 1);
assert(coll.entries == 1);
assert(coll.entry[0].object->mark != 1);
assert(!strcmp(coll.entry[0].object->type, "b"));
/*
* Test 3
*/
/* Zero */
obj = _ncnf_obj_new(0, NOBJ_ATTRIBUTE,
str2bstr("c", -1), str2bstr("unmarked", -1), 0);
assert(obj);
obj->mark = 0;
ret = _ncnf_coll_insert(0, &coll, obj, MERGE_DUPCHECK);
assert(ret == 0);
assert(coll.entries == 2);
/* Mark */
obj = _ncnf_obj_new(0, NOBJ_ATTRIBUTE,
str2bstr("d", -1), str2bstr("marked", -1), 0);
assert(obj);
obj->mark = 1;
ret = _ncnf_coll_insert(0, &coll, obj, MERGE_DUPCHECK);
assert(ret == 0);
/* Zero */
obj = _ncnf_obj_new(0, NOBJ_ATTRIBUTE,
str2bstr("g", -1), str2bstr("unmarked", -1), 0);
assert(obj);
obj->mark = 0;
ret = _ncnf_coll_insert(0, &coll, obj, MERGE_DUPCHECK);
assert(ret == 0);
_ncnf_coll_remove_marked(&coll, 1);
assert(coll.entries == 3);
_ncnf_coll_adjust_size(0, &coll, 0);
assert(coll.entries == 0);
return 0;
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1