Blame snmplib/container_binary_array.c

Packit fcad23
/*
Packit fcad23
 * container_binary_array.c
Packit fcad23
 *
Packit fcad23
 * see comments in header file.
Packit fcad23
 *
Packit fcad23
 * Portions of this file are subject to the following copyright(s).  See
Packit fcad23
 * the Net-SNMP's COPYING file for more details and other copyrights
Packit fcad23
 * that may apply:
Packit fcad23
 *
Packit fcad23
 * Portions of this file are copyrighted by:
Packit fcad23
 * Copyright (c) 2016 VMware, Inc. All rights reserved.
Packit fcad23
 * Use is subject to license terms specified in the COPYING file
Packit fcad23
 * distributed with the Net-SNMP package.
Packit fcad23
 */
Packit fcad23
Packit fcad23
#include <net-snmp/net-snmp-config.h>
Packit fcad23
Packit fcad23
#if HAVE_IO_H
Packit fcad23
#include <io.h>
Packit fcad23
#endif
Packit fcad23
#include <stdio.h>
Packit fcad23
#if HAVE_STDLIB_H
Packit fcad23
#include <stdlib.h>
Packit fcad23
#endif
Packit fcad23
#if HAVE_MALLOC_H
Packit fcad23
#include <malloc.h>
Packit fcad23
#endif
Packit fcad23
#include <sys/types.h>
Packit fcad23
#if HAVE_STRING_H
Packit fcad23
#include <string.h>
Packit fcad23
#else
Packit fcad23
#include <strings.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#include <net-snmp/net-snmp-includes.h>
Packit fcad23
#include <net-snmp/types.h>
Packit fcad23
#include <net-snmp/library/snmp_api.h>
Packit fcad23
#include <net-snmp/library/container.h>
Packit fcad23
#include <net-snmp/library/container_binary_array.h>
Packit fcad23
#include <net-snmp/library/tools.h>
Packit fcad23
#include <net-snmp/library/snmp_assert.h>
Packit fcad23
Packit fcad23
typedef struct binary_array_table_s {
Packit fcad23
    size_t                     max_size;   /* Size of the current data table */
Packit fcad23
    size_t                     count;      /* Index of the next free entry */
Packit fcad23
    int                        dirty;
Packit fcad23
    void                     **data;       /* The table itself */
Packit fcad23
} binary_array_table;
Packit fcad23
Packit fcad23
typedef struct binary_array_iterator_s {
Packit fcad23
    netsnmp_iterator base;
Packit fcad23
Packit fcad23
    size_t           pos;
Packit fcad23
} binary_array_iterator;
Packit fcad23
Packit fcad23
static netsnmp_iterator *_ba_iterator_get(netsnmp_container *c);
Packit fcad23
Packit fcad23
/**********************************************************************
Packit fcad23
 *
Packit fcad23
 * 
Packit fcad23
 *
Packit fcad23
 */
Packit fcad23
static void
Packit fcad23
array_qsort(void **data, int first, int last, netsnmp_container_compare *f)
Packit fcad23
{
Packit fcad23
    int i, j;
Packit fcad23
    void *mid, *tmp;
Packit fcad23
    
Packit fcad23
    i = first;
Packit fcad23
    j = last;
Packit fcad23
    mid = data[(first+last)/2];
Packit fcad23
    
Packit fcad23
    do {
Packit fcad23
        while (i < last && (*f)(data[i], mid) < 0)
Packit fcad23
            ++i;
Packit fcad23
        while (j > first && (*f)(mid, data[j]) < 0)
Packit fcad23
            --j;
Packit fcad23
Packit fcad23
        if(i < j) {
Packit fcad23
            tmp = data[i];
Packit fcad23
            data[i] = data[j];
Packit fcad23
            data[j] = tmp;
Packit fcad23
            ++i;
Packit fcad23
            --j;
Packit fcad23
        }
Packit fcad23
        else if (i == j) {
Packit fcad23
            ++i;
Packit fcad23
            --j;
Packit fcad23
            break;
Packit fcad23
        }
Packit fcad23
    } while(i <= j);
Packit fcad23
Packit fcad23
    if (j > first)
Packit fcad23
        array_qsort(data, first, j, f);
Packit fcad23
    
Packit fcad23
    if (i < last)
Packit fcad23
        array_qsort(data, i, last, f);
Packit fcad23
}
Packit fcad23
Packit fcad23
static int
Packit fcad23
Sort_Array(netsnmp_container *c)
Packit fcad23
{
Packit fcad23
    binary_array_table *t = (binary_array_table*)c->container_data;
Packit fcad23
    netsnmp_assert(t!=NULL);
Packit fcad23
    netsnmp_assert(c->compare!=NULL);
Packit fcad23
Packit fcad23
    if (c->flags & CONTAINER_KEY_UNSORTED)
Packit fcad23
        return 0;
Packit fcad23
Packit fcad23
    if (t->dirty) {
Packit fcad23
        /*
Packit fcad23
         * Sort the table 
Packit fcad23
         */
Packit fcad23
        if (t->count > 1)
Packit fcad23
            array_qsort(t->data, 0, t->count - 1, c->compare);
Packit fcad23
        t->dirty = 0;
Packit fcad23
Packit fcad23
        /*
Packit fcad23
         * no way to know if it actually changed... just assume so.
Packit fcad23
         */
Packit fcad23
        ++c->sync;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    return 1;
Packit fcad23
}
Packit fcad23
Packit fcad23
static int
Packit fcad23
linear_search(const void *val, netsnmp_container *c)
Packit fcad23
{
Packit fcad23
    binary_array_table *t = (binary_array_table*)c->container_data;
Packit fcad23
    size_t             pos = 0;
Packit fcad23
Packit fcad23
    if (!t->count)
Packit fcad23
        return -1;
Packit fcad23
Packit fcad23
    if (! (c->flags & CONTAINER_KEY_UNSORTED)) {
Packit fcad23
        snmp_log(LOG_ERR, "linear search on sorted container %s?!?\n",
Packit fcad23
                 c->container_name);
Packit fcad23
        return -1;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    for (; pos < t->count; ++pos) {
Packit fcad23
        if (c->compare(t->data[pos], val) == 0)
Packit fcad23
            break;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (pos >= t->count)
Packit fcad23
        return -1;
Packit fcad23
Packit fcad23
    return pos;
Packit fcad23
}
Packit fcad23
Packit fcad23
static int
Packit fcad23
binary_search(const void *val, netsnmp_container *c, int exact, size_t *next)
Packit fcad23
{
Packit fcad23
    binary_array_table *t = (binary_array_table*)c->container_data;
Packit fcad23
    size_t             len = t->count;
Packit fcad23
    size_t             half;
Packit fcad23
    size_t             first = 0;
Packit fcad23
    size_t             middle = 0; /* init not needed; keeps compiler happy */
Packit fcad23
    int                result = 0; /* init not needed; keeps compiler happy */
Packit fcad23
Packit fcad23
    if (!len) {
Packit fcad23
        if (NULL != next)
Packit fcad23
            *next = 0;
Packit fcad23
        return -1;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (c->flags & CONTAINER_KEY_UNSORTED) {
Packit fcad23
        if (!exact) {
Packit fcad23
            snmp_log(LOG_ERR, "non-exact search on unsorted container %s?!?\n",
Packit fcad23
                     c->container_name);
Packit fcad23
            return -1;
Packit fcad23
        }
Packit fcad23
        return linear_search(val, c);
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (t->dirty)
Packit fcad23
        Sort_Array(c);
Packit fcad23
Packit fcad23
    while (len > 0) {
Packit fcad23
        half = len >> 1;
Packit fcad23
        middle = first + half;
Packit fcad23
        if ((result = c->compare(t->data[middle], val)) < 0) {
Packit fcad23
            first = middle + 1;
Packit fcad23
            len = len - half - 1;
Packit fcad23
        } else if (result == 0) {
Packit fcad23
            first = middle;
Packit fcad23
            break;
Packit fcad23
        } else {
Packit fcad23
            len = half;
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (first >= t->count) {
Packit fcad23
        if (exact && NULL != next)
Packit fcad23
            *next = t->count;
Packit fcad23
        return -1;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (first != middle) {
Packit fcad23
        /* last compare wasn't against first, so get actual result */
Packit fcad23
        result = c->compare(t->data[first], val);
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if(result == 0) {
Packit fcad23
        if (exact && NULL != next)
Packit fcad23
            *next = first+1;
Packit fcad23
        else if (!exact && ++first == t->count) {
Packit fcad23
            if (NULL != next)
Packit fcad23
                *next = first;
Packit fcad23
            first = -1;
Packit fcad23
        }
Packit fcad23
    } else if(exact) {
Packit fcad23
        if (NULL != next) {
Packit fcad23
            if (result > 0)
Packit fcad23
                *next = first;
Packit fcad23
            else
Packit fcad23
                *next = t->count;
Packit fcad23
        }
Packit fcad23
        first = -1;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    return first;
Packit fcad23
}
Packit fcad23
Packit fcad23
NETSNMP_STATIC_INLINE binary_array_table *
Packit fcad23
netsnmp_binary_array_initialize(void)
Packit fcad23
{
Packit fcad23
    binary_array_table *t;
Packit fcad23
Packit fcad23
    t = SNMP_MALLOC_TYPEDEF(binary_array_table);
Packit fcad23
    if (t == NULL)
Packit fcad23
        return NULL;
Packit fcad23
Packit fcad23
    t->max_size = 0;
Packit fcad23
    t->count = 0;
Packit fcad23
    t->dirty = 0;
Packit fcad23
    t->data = NULL;
Packit fcad23
Packit fcad23
    return t;
Packit fcad23
}
Packit fcad23
Packit fcad23
void
Packit fcad23
netsnmp_binary_array_release(netsnmp_container *c)
Packit fcad23
{
Packit fcad23
    binary_array_table *t = (binary_array_table*)c->container_data;
Packit fcad23
    SNMP_FREE(t->data);
Packit fcad23
    SNMP_FREE(t);
Packit fcad23
    SNMP_FREE(c);
Packit fcad23
}
Packit fcad23
Packit fcad23
int
Packit fcad23
netsnmp_binary_array_options_set(netsnmp_container *c, int set, u_int flags)
Packit fcad23
{
Packit fcad23
#define BA_FLAGS (CONTAINER_KEY_ALLOW_DUPLICATES|CONTAINER_KEY_UNSORTED)
Packit fcad23
Packit fcad23
    if (set) {
Packit fcad23
        if ((flags & BA_FLAGS) == flags) {
Packit fcad23
            /** if turning off unsorted, do sort */
Packit fcad23
            int sort = ((c->flags & CONTAINER_KEY_UNSORTED) &&
Packit fcad23
                        ! (flags & CONTAINER_KEY_UNSORTED));
Packit fcad23
            c->flags = flags;
Packit fcad23
            if (sort) {
Packit fcad23
                binary_array_table *t = (binary_array_table*)c->container_data;
Packit fcad23
                t->dirty = 1; /* force sort */
Packit fcad23
                Sort_Array(c);
Packit fcad23
            }
Packit fcad23
        } else
Packit fcad23
            flags = (u_int)-1; /* unsupported flag */
Packit fcad23
    }
Packit fcad23
    else
Packit fcad23
        return ((c->flags & flags) == flags);
Packit fcad23
    return flags;
Packit fcad23
}
Packit fcad23
Packit fcad23
NETSNMP_STATIC_INLINE size_t
Packit fcad23
netsnmp_binary_array_count(netsnmp_container *c)
Packit fcad23
{
Packit fcad23
    binary_array_table *t = (binary_array_table*)c->container_data;
Packit fcad23
    /*
Packit fcad23
     * return count
Packit fcad23
     */
Packit fcad23
    return t ? t->count : 0;
Packit fcad23
}
Packit fcad23
Packit fcad23
NETSNMP_STATIC_INLINE void           *
Packit fcad23
netsnmp_binary_array_get(netsnmp_container *c, const void *key, int exact)
Packit fcad23
{
Packit fcad23
    binary_array_table *t = (binary_array_table*)c->container_data;
Packit fcad23
    int             index = 0;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * if there is no data, return NULL;
Packit fcad23
     */
Packit fcad23
    if (!t->count)
Packit fcad23
        return NULL;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * if the table is dirty, sort it.
Packit fcad23
     */
Packit fcad23
    if (t->dirty)
Packit fcad23
        Sort_Array(c);
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * if there is a key, search. Otherwise default is 0;
Packit fcad23
     */
Packit fcad23
    if (key) {
Packit fcad23
        if ((index = binary_search(key, c, exact, NULL)) == -1)
Packit fcad23
            return NULL;
Packit fcad23
        if (!exact &&
Packit fcad23
            c->flags & CONTAINER_KEY_ALLOW_DUPLICATES) {
Packit fcad23
            int result;
Packit fcad23
Packit fcad23
            /*
Packit fcad23
             * If duplicates are allowed, we have to be extra
Packit fcad23
             * sure that we didn't just increment to a duplicate,
Packit fcad23
             * thus causing a getnext loop.
Packit fcad23
             */
Packit fcad23
            result = c->compare(t->data[index], key);
Packit fcad23
            while (result == 0) {
Packit fcad23
		DEBUGMSGTL(("container","skipping duplicate key in %s\n",
Packit fcad23
					    c->container_name));
Packit fcad23
                if (++index == t->count)
Packit fcad23
                   return NULL;
Packit fcad23
                result = c->compare(t->data[index], key);
Packit fcad23
            }
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
Packit fcad23
    return t->data[index];
Packit fcad23
}
Packit fcad23
Packit fcad23
static int
Packit fcad23
netsnmp_binary_array_get_at(netsnmp_container *c, size_t pos, void **entry)
Packit fcad23
{
Packit fcad23
    binary_array_table *t = (binary_array_table*)c->container_data;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * if there is no data, return NULL;
Packit fcad23
     */
Packit fcad23
    if (!t->count || pos >= t->count || NULL == entry)
Packit fcad23
        return -1;
Packit fcad23
Packit fcad23
    *entry = t->data[pos];
Packit fcad23
Packit fcad23
    return 0;
Packit fcad23
}
Packit fcad23
Packit fcad23
int
Packit fcad23
netsnmp_binary_array_remove_at(netsnmp_container *c, size_t index, void **save)
Packit fcad23
{
Packit fcad23
    binary_array_table *t = (binary_array_table*)c->container_data;
Packit fcad23
Packit fcad23
    if (save)
Packit fcad23
        *save = NULL;
Packit fcad23
    
Packit fcad23
    /*
Packit fcad23
     * if there is no data, return NULL;
Packit fcad23
     */
Packit fcad23
    if (!t->count)
Packit fcad23
        return -1;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * find old data and save it, if ptr provided
Packit fcad23
     */
Packit fcad23
    if (save)
Packit fcad23
        *save = t->data[index];
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * if entry was last item, just decrement count
Packit fcad23
     */
Packit fcad23
    --t->count;
Packit fcad23
    if (index != t->count) {
Packit fcad23
        /*
Packit fcad23
         * otherwise, shift array down
Packit fcad23
         */
Packit fcad23
        memmove(&t->data[index], &t->data[index+1],
Packit fcad23
                sizeof(void*) * (t->count - index));
Packit fcad23
Packit fcad23
        ++c->sync;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    return 0;
Packit fcad23
}
Packit fcad23
Packit fcad23
int
Packit fcad23
netsnmp_binary_array_remove(netsnmp_container *c, const void *key, void **save)
Packit fcad23
{
Packit fcad23
    binary_array_table *t = (binary_array_table*)c->container_data;
Packit fcad23
    int                index = 0;
Packit fcad23
Packit fcad23
    if (save)
Packit fcad23
        *save = NULL;
Packit fcad23
    
Packit fcad23
    /*
Packit fcad23
     * if there is no data, return NULL;
Packit fcad23
     */
Packit fcad23
    if (!t->count)
Packit fcad23
        return 0;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * if the table is dirty, sort it.
Packit fcad23
     */
Packit fcad23
    if (t->dirty)
Packit fcad23
        Sort_Array(c);
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * search
Packit fcad23
     */
Packit fcad23
    if ((index = binary_search(key, c, 1, NULL)) == -1)
Packit fcad23
        return -1;
Packit fcad23
Packit fcad23
    return netsnmp_binary_array_remove_at(c, (size_t)index, save);
Packit fcad23
}
Packit fcad23
Packit fcad23
NETSNMP_STATIC_INLINE void
Packit fcad23
netsnmp_binary_array_for_each(netsnmp_container *c,
Packit fcad23
                              netsnmp_container_obj_func *fe,
Packit fcad23
                              void *context, int sort)
Packit fcad23
{
Packit fcad23
    binary_array_table *t = (binary_array_table*)c->container_data;
Packit fcad23
    size_t             i;
Packit fcad23
Packit fcad23
    if (sort && t->dirty)
Packit fcad23
        Sort_Array(c);
Packit fcad23
Packit fcad23
    for (i = 0; i < t->count; ++i)
Packit fcad23
        (*fe) (t->data[i], context);
Packit fcad23
}
Packit fcad23
Packit fcad23
NETSNMP_STATIC_INLINE void
Packit fcad23
netsnmp_binary_array_clear(netsnmp_container *c,
Packit fcad23
                           netsnmp_container_obj_func *fe,
Packit fcad23
                           void *context)
Packit fcad23
{
Packit fcad23
    binary_array_table *t = (binary_array_table*)c->container_data;
Packit fcad23
Packit fcad23
    if( NULL != fe ) {
Packit fcad23
        size_t             i;
Packit fcad23
Packit fcad23
        for (i = 0; i < t->count; ++i)
Packit fcad23
            (*fe) (t->data[i], context);
Packit fcad23
    }
Packit fcad23
Packit fcad23
    t->count = 0;
Packit fcad23
    t->dirty = 0;
Packit fcad23
    ++c->sync;
Packit fcad23
}
Packit fcad23
Packit fcad23
static int
Packit fcad23
_ba_resize_check(binary_array_table *t)
Packit fcad23
{
Packit fcad23
    size_t new_max;
Packit fcad23
    void ** new_data;
Packit fcad23
    if (t->max_size > t->count)
Packit fcad23
        return 0; /* resize not needed */
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * Table is full, so extend it to double the size, or use 10 elements
Packit fcad23
     * if it is empty.
Packit fcad23
     */
Packit fcad23
    new_max = t->max_size > 0 ? 2 * t->max_size : 10;
Packit fcad23
    new_data = (void**) realloc(t->data, new_max * sizeof(void*));
Packit fcad23
    if (new_data == NULL) {
Packit fcad23
        snmp_log(LOG_ERR, "malloc failed in _ba_resize_check\n");
Packit fcad23
        return -1; /* error */
Packit fcad23
    }
Packit fcad23
Packit fcad23
    memset(new_data + t->max_size, 0x0,
Packit fcad23
           (new_max - t->max_size) * sizeof(void*));
Packit fcad23
Packit fcad23
    t->data = new_data;
Packit fcad23
    t->max_size = new_max;
Packit fcad23
Packit fcad23
    return 1; /* resized */
Packit fcad23
}
Packit fcad23
Packit fcad23
static int
Packit fcad23
netsnmp_binary_array_insert_before(netsnmp_container *c, size_t index,
Packit fcad23
                                   const void *entry, int dirty)
Packit fcad23
{
Packit fcad23
    binary_array_table *t = (binary_array_table*)c->container_data;
Packit fcad23
Packit fcad23
    if (NULL == entry)
Packit fcad23
        return -1;
Packit fcad23
Packit fcad23
    if (index > (t->count + 1)) {
Packit fcad23
        DEBUGMSGTL(("container:insert:before", "index out of range\n"));
Packit fcad23
        return -1;
Packit fcad23
    }
Packit fcad23
Packit fcad23
     /*
Packit fcad23
      * check if we need to resize the array
Packit fcad23
      */
Packit fcad23
    _ba_resize_check(t);
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * shift array
Packit fcad23
     */
Packit fcad23
    memmove(&t->data[index+1], &t->data[index],
Packit fcad23
            sizeof(void*) * (t->count - index));
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * Insert the new entry into the data array
Packit fcad23
     */
Packit fcad23
    t->data[index] = NETSNMP_REMOVE_CONST(void *, entry);
Packit fcad23
    ++t->count;
Packit fcad23
Packit fcad23
    if (dirty)
Packit fcad23
        t->dirty = 1;
Packit fcad23
Packit fcad23
    ++c->sync;
Packit fcad23
Packit fcad23
    return 0;
Packit fcad23
}
Packit fcad23
Packit fcad23
NETSNMP_STATIC_INLINE int
Packit fcad23
netsnmp_binary_array_insert(netsnmp_container *c, const void *const_entry)
Packit fcad23
{
Packit fcad23
    binary_array_table *t = (binary_array_table*)c->container_data;
Packit fcad23
    int             dirty = 0, i = -2;
Packit fcad23
    size_t          next, pos;
Packit fcad23
    void           *entry = NETSNMP_REMOVE_CONST(void *, const_entry);
Packit fcad23
Packit fcad23
    if (NULL == entry)
Packit fcad23
        return -1;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * check key if we have at least 1 item and duplicates aren't allowed
Packit fcad23
     */
Packit fcad23
    if (! (c->flags & CONTAINER_KEY_ALLOW_DUPLICATES) && t->count) {
Packit fcad23
        i = binary_search(entry, c, 1, &next;;
Packit fcad23
        if (i > 0) {
Packit fcad23
            DEBUGMSGTL(("container","not inserting duplicate key\n"));
Packit fcad23
            return -1;
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
 
Packit fcad23
    /*
Packit fcad23
     * if unsorted, just add at the end
Packit fcad23
     */
Packit fcad23
    if (c->flags & CONTAINER_KEY_UNSORTED) {
Packit fcad23
        pos = t->count;
Packit fcad23
        dirty = 1;
Packit fcad23
    } else {
Packit fcad23
        /** if we haven't searched for key yet, do it now */
Packit fcad23
        if (-2 == i) {
Packit fcad23
            if (0 == t->count) {
Packit fcad23
                next = 0;
Packit fcad23
                i = -1;
Packit fcad23
            } else
Packit fcad23
                i = binary_search(entry, c, 1, &next;;
Packit fcad23
        }
Packit fcad23
Packit fcad23
        pos = next;
Packit fcad23
        if ( i > 0 )  /* if key found, advance past any dups */
Packit fcad23
            while (pos < t->count && c->compare(t->data[pos], entry) == 0)
Packit fcad23
                ++pos;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    return netsnmp_binary_array_insert_before(c, pos, entry, dirty);
Packit fcad23
}
Packit fcad23
Packit fcad23
/**********************************************************************
Packit fcad23
 *
Packit fcad23
 * Special case support for subsets
Packit fcad23
 *
Packit fcad23
 */
Packit fcad23
static int
Packit fcad23
binary_search_for_start(netsnmp_index *val, netsnmp_container *c)
Packit fcad23
{
Packit fcad23
    binary_array_table *t = (binary_array_table*)c->container_data;
Packit fcad23
    size_t             len = t->count;
Packit fcad23
    size_t             half;
Packit fcad23
    size_t             middle;
Packit fcad23
    size_t             first = 0;
Packit fcad23
    int                result = 0;
Packit fcad23
Packit fcad23
    if (!len)
Packit fcad23
        return -1;
Packit fcad23
Packit fcad23
    if (t->dirty)
Packit fcad23
        Sort_Array(c);
Packit fcad23
Packit fcad23
    while (len > 0) {
Packit fcad23
        half = len >> 1;
Packit fcad23
        middle = first + half;
Packit fcad23
        if ((result = c->ncompare(t->data[middle], val)) < 0) {
Packit fcad23
            first = middle + 1;
Packit fcad23
            len = len - half - 1;
Packit fcad23
        } else
Packit fcad23
            len = half;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if ((first >= t->count) ||
Packit fcad23
        c->ncompare(t->data[first], val) != 0)
Packit fcad23
        return -1;
Packit fcad23
Packit fcad23
    return first;
Packit fcad23
}
Packit fcad23
Packit fcad23
void          **
Packit fcad23
netsnmp_binary_array_get_subset(netsnmp_container *c, void *key, int *len)
Packit fcad23
{
Packit fcad23
    binary_array_table *t;
Packit fcad23
    void          **subset;
Packit fcad23
    int             start, end;
Packit fcad23
    size_t          i;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * if there is no data, return NULL;
Packit fcad23
     */
Packit fcad23
    if (!c || !key || !len)
Packit fcad23
        return NULL;
Packit fcad23
Packit fcad23
    t = (binary_array_table*)c->container_data;
Packit fcad23
    netsnmp_assert(c->ncompare);
Packit fcad23
    if (!t->count || !c->ncompare)
Packit fcad23
        return NULL;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * if the table is dirty, sort it.
Packit fcad23
     */
Packit fcad23
    if (t->dirty)
Packit fcad23
        Sort_Array(c);
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * find matching items
Packit fcad23
     */
Packit fcad23
    start = end = binary_search_for_start((netsnmp_index *)key, c);
Packit fcad23
    if (start == -1)
Packit fcad23
        return NULL;
Packit fcad23
Packit fcad23
    for (i = start + 1; i < t->count; ++i) {
Packit fcad23
        if (0 != c->ncompare(t->data[i], key))
Packit fcad23
            break;
Packit fcad23
        ++end;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    *len = end - start + 1;
Packit fcad23
    if (*len <= 0)
Packit fcad23
        return NULL;
Packit fcad23
Packit fcad23
    subset = (void **)malloc((*len) * sizeof(void*));
Packit fcad23
    if (subset)
Packit fcad23
        memcpy(subset, &t->data[start], sizeof(void*) * (*len));
Packit fcad23
Packit fcad23
    return subset;
Packit fcad23
}
Packit fcad23
Packit fcad23
/**********************************************************************
Packit fcad23
 *
Packit fcad23
 * container
Packit fcad23
 *
Packit fcad23
 */
Packit fcad23
static void *
Packit fcad23
_ba_find(netsnmp_container *container, const void *data)
Packit fcad23
{
Packit fcad23
    return netsnmp_binary_array_get(container, data, 1);
Packit fcad23
}
Packit fcad23
Packit fcad23
static void *
Packit fcad23
_ba_find_next(netsnmp_container *container, const void *data)
Packit fcad23
{
Packit fcad23
    return netsnmp_binary_array_get(container, data, 0);
Packit fcad23
}
Packit fcad23
Packit fcad23
static int
Packit fcad23
_ba_insert(netsnmp_container *container, const void *data)
Packit fcad23
{
Packit fcad23
    return netsnmp_binary_array_insert(container, data);
Packit fcad23
}
Packit fcad23
Packit fcad23
static int
Packit fcad23
_ba_insert_before(netsnmp_container *container, size_t index, void *data)
Packit fcad23
{
Packit fcad23
    /** don't trust users direct-acces inserts, mark array dirty */
Packit fcad23
    return netsnmp_binary_array_insert_before(container, index, data, 1);
Packit fcad23
}
Packit fcad23
Packit fcad23
static int
Packit fcad23
_ba_remove(netsnmp_container *container, const void *data)
Packit fcad23
{
Packit fcad23
    return netsnmp_binary_array_remove(container,data, NULL);
Packit fcad23
}
Packit fcad23
Packit fcad23
static int
Packit fcad23
_ba_free(netsnmp_container *container)
Packit fcad23
{
Packit fcad23
    netsnmp_binary_array_release(container);
Packit fcad23
    return 0;
Packit fcad23
}
Packit fcad23
Packit fcad23
static size_t
Packit fcad23
_ba_size(netsnmp_container *container)
Packit fcad23
{
Packit fcad23
    return netsnmp_binary_array_count(container);
Packit fcad23
}
Packit fcad23
Packit fcad23
static void
Packit fcad23
_ba_for_each(netsnmp_container *container, netsnmp_container_obj_func *f,
Packit fcad23
             void *context)
Packit fcad23
{
Packit fcad23
    netsnmp_binary_array_for_each(container, f, context, 1);
Packit fcad23
}
Packit fcad23
Packit fcad23
static void
Packit fcad23
_ba_clear(netsnmp_container *container, netsnmp_container_obj_func *f,
Packit fcad23
             void *context)
Packit fcad23
{
Packit fcad23
    netsnmp_binary_array_clear(container, f, context);
Packit fcad23
}
Packit fcad23
Packit fcad23
static netsnmp_void_array *
Packit fcad23
_ba_get_subset(netsnmp_container *container, void *data)
Packit fcad23
{
Packit fcad23
    netsnmp_void_array * va;
Packit fcad23
    void ** rtn;
Packit fcad23
    int len;
Packit fcad23
Packit fcad23
    rtn = netsnmp_binary_array_get_subset(container, data, &len;;
Packit fcad23
    if (NULL==rtn)
Packit fcad23
        return NULL;
Packit fcad23
    
Packit fcad23
    va = SNMP_MALLOC_TYPEDEF(netsnmp_void_array);
Packit fcad23
    if (va == NULL) {
Packit fcad23
        free(rtn);
Packit fcad23
        return NULL;
Packit fcad23
    }
Packit fcad23
    
Packit fcad23
    va->size = len;
Packit fcad23
    va->array = rtn;
Packit fcad23
Packit fcad23
    return va;
Packit fcad23
}
Packit fcad23
Packit fcad23
static int _ba_options(netsnmp_container *c, int set, u_int flags)
Packit fcad23
{
Packit fcad23
    return netsnmp_binary_array_options_set(c, set, flags);
Packit fcad23
}
Packit fcad23
Packit fcad23
static netsnmp_container *
Packit fcad23
_ba_duplicate(netsnmp_container *c, void *ctx, u_int flags)
Packit fcad23
{
Packit fcad23
    netsnmp_container *dup;
Packit fcad23
    binary_array_table *dupt, *t;
Packit fcad23
Packit fcad23
    if (flags) {
Packit fcad23
        snmp_log(LOG_ERR, "binary arry duplicate does not supprt flags yet\n");
Packit fcad23
        return NULL;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    dup = netsnmp_container_get_binary_array();
Packit fcad23
    if (NULL == dup) {
Packit fcad23
        snmp_log(LOG_ERR," no memory for binary array duplicate\n");
Packit fcad23
        return NULL;
Packit fcad23
    }
Packit fcad23
    /*
Packit fcad23
     * deal with container stuff
Packit fcad23
     */
Packit fcad23
    if (netsnmp_container_data_dup(dup, c) != 0) {
Packit fcad23
        netsnmp_binary_array_release(dup);
Packit fcad23
        return NULL;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * deal with data
Packit fcad23
     */
Packit fcad23
    dupt = (binary_array_table*)dup->container_data;
Packit fcad23
    t = (binary_array_table*)c->container_data;
Packit fcad23
Packit fcad23
    dupt->max_size = t->max_size;
Packit fcad23
    dupt->count = t->count;
Packit fcad23
    dupt->dirty = t->dirty;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * shallow copy
Packit fcad23
     */
Packit fcad23
    dupt->data = (void**) malloc(dupt->max_size * sizeof(void*));
Packit fcad23
    if (NULL == dupt->data) {
Packit fcad23
        snmp_log(LOG_ERR, "no memory for binary array duplicate\n");
Packit fcad23
        netsnmp_binary_array_release(dup);
Packit fcad23
        return NULL;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    memcpy(dupt->data, t->data, dupt->max_size * sizeof(void*));
Packit fcad23
Packit fcad23
    return dup;
Packit fcad23
}
Packit fcad23
Packit fcad23
netsnmp_container *
Packit fcad23
netsnmp_container_get_binary_array(void)
Packit fcad23
{
Packit fcad23
    /*
Packit fcad23
     * allocate memory
Packit fcad23
     */
Packit fcad23
    netsnmp_container *c = SNMP_MALLOC_TYPEDEF(netsnmp_container);
Packit fcad23
    if (NULL==c) {
Packit fcad23
        snmp_log(LOG_ERR, "couldn't allocate memory\n");
Packit fcad23
        return NULL;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    c->container_data = netsnmp_binary_array_initialize();
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * NOTE: CHANGES HERE MUST BE DUPLICATED IN duplicate AS WELL!!
Packit fcad23
     */
Packit fcad23
    netsnmp_init_container(c, NULL, _ba_free, _ba_size, NULL, _ba_insert,
Packit fcad23
                           _ba_remove, _ba_find);
Packit fcad23
    c->find_next = _ba_find_next;
Packit fcad23
    c->get_subset = _ba_get_subset;
Packit fcad23
    c->get_iterator = _ba_iterator_get;
Packit fcad23
    c->for_each = _ba_for_each;
Packit fcad23
    c->clear = _ba_clear;
Packit fcad23
    c->options = _ba_options;
Packit fcad23
    c->duplicate = _ba_duplicate;
Packit fcad23
    c->get_at = netsnmp_binary_array_get_at;
Packit fcad23
    c->remove_at = netsnmp_binary_array_remove_at;
Packit fcad23
    c->insert_before = _ba_insert_before;
Packit fcad23
Packit fcad23
    return c;
Packit fcad23
}
Packit fcad23
Packit fcad23
netsnmp_factory *
Packit fcad23
netsnmp_container_get_binary_array_factory(void)
Packit fcad23
{
Packit fcad23
    static netsnmp_factory f = { "binary_array",
Packit fcad23
                                 (netsnmp_factory_produce_f*)
Packit fcad23
                                 netsnmp_container_get_binary_array };
Packit fcad23
    
Packit fcad23
    return &f;
Packit fcad23
}
Packit fcad23
Packit fcad23
void
Packit fcad23
netsnmp_container_binary_array_init(void)
Packit fcad23
{
Packit fcad23
    netsnmp_container_register("binary_array",
Packit fcad23
                               netsnmp_container_get_binary_array_factory());
Packit fcad23
}
Packit fcad23
Packit fcad23
/**********************************************************************
Packit fcad23
 *
Packit fcad23
 * iterator
Packit fcad23
 *
Packit fcad23
 */
Packit fcad23
NETSNMP_STATIC_INLINE binary_array_table *
Packit fcad23
_ba_it2cont(binary_array_iterator *it)
Packit fcad23
{
Packit fcad23
    if(NULL == it) {
Packit fcad23
        netsnmp_assert(NULL != it);
Packit fcad23
        return NULL;
Packit fcad23
    }
Packit fcad23
    if(NULL == it->base.container) {
Packit fcad23
        netsnmp_assert(NULL != it->base.container);
Packit fcad23
        return NULL;
Packit fcad23
    }
Packit fcad23
    if(NULL == it->base.container->container_data) {
Packit fcad23
        netsnmp_assert(NULL != it->base.container->container_data);
Packit fcad23
        return NULL;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    return (binary_array_table*)(it->base.container->container_data);
Packit fcad23
}
Packit fcad23
Packit fcad23
NETSNMP_STATIC_INLINE void *
Packit fcad23
_ba_iterator_position(binary_array_iterator *it, size_t pos)
Packit fcad23
{
Packit fcad23
    binary_array_table *t = _ba_it2cont(it);
Packit fcad23
    if (NULL == t)
Packit fcad23
        return t; /* msg already logged */
Packit fcad23
Packit fcad23
    if(it->base.container->sync != it->base.sync) {
Packit fcad23
        DEBUGMSGTL(("container:iterator", "out of sync\n"));
Packit fcad23
        return NULL;
Packit fcad23
    }
Packit fcad23
    
Packit fcad23
    if(0 == t->count) {
Packit fcad23
        DEBUGMSGTL(("container:iterator", "empty\n"));
Packit fcad23
        return NULL;
Packit fcad23
    }
Packit fcad23
    else if(pos >= t->count) {
Packit fcad23
        DEBUGMSGTL(("container:iterator", "end of container\n"));
Packit fcad23
        return NULL;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    return t->data[ pos ];
Packit fcad23
}
Packit fcad23
Packit fcad23
static void *
Packit fcad23
_ba_iterator_curr(binary_array_iterator *it)
Packit fcad23
{
Packit fcad23
    if(NULL == it) {
Packit fcad23
        netsnmp_assert(NULL != it);
Packit fcad23
        return NULL;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    return _ba_iterator_position(it, it->pos);
Packit fcad23
}
Packit fcad23
Packit fcad23
static void *
Packit fcad23
_ba_iterator_first(binary_array_iterator *it)
Packit fcad23
{
Packit fcad23
    return _ba_iterator_position(it, 0);
Packit fcad23
}
Packit fcad23
Packit fcad23
static void *
Packit fcad23
_ba_iterator_next(binary_array_iterator *it)
Packit fcad23
{
Packit fcad23
    if(NULL == it) {
Packit fcad23
        netsnmp_assert(NULL != it);
Packit fcad23
        return NULL;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    ++it->pos;
Packit fcad23
Packit fcad23
    return _ba_iterator_position(it, it->pos);
Packit fcad23
}
Packit fcad23
Packit fcad23
static void *
Packit fcad23
_ba_iterator_last(binary_array_iterator *it)
Packit fcad23
{
Packit fcad23
    binary_array_table* t = _ba_it2cont(it);
Packit fcad23
    if(NULL == t) {
Packit fcad23
        netsnmp_assert(NULL != t);
Packit fcad23
        return NULL;
Packit fcad23
    }
Packit fcad23
    
Packit fcad23
    return _ba_iterator_position(it, t->count - 1 );
Packit fcad23
}
Packit fcad23
Packit fcad23
static int
Packit fcad23
_ba_iterator_remove(binary_array_iterator *it)
Packit fcad23
{
Packit fcad23
    binary_array_table* t = _ba_it2cont(it);
Packit fcad23
    if(NULL == t) {
Packit fcad23
        netsnmp_assert(NULL != t);
Packit fcad23
        return -1;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * since this iterator was used for the remove, keep it in sync with
Packit fcad23
     * the container. Also, back up one so that next will be the position
Packit fcad23
     * that was just removed.
Packit fcad23
     */
Packit fcad23
    ++it->base.sync;
Packit fcad23
    return netsnmp_binary_array_remove_at(it->base.container, it->pos--, NULL);
Packit fcad23
Packit fcad23
}
Packit fcad23
Packit fcad23
static int
Packit fcad23
_ba_iterator_reset(binary_array_iterator *it)
Packit fcad23
{
Packit fcad23
    binary_array_table* t = _ba_it2cont(it);
Packit fcad23
    if(NULL == t) {
Packit fcad23
        netsnmp_assert(NULL != t);
Packit fcad23
        return -1;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (t->dirty)
Packit fcad23
        Sort_Array(it->base.container);
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * save sync count, to make sure container doesn't change while
Packit fcad23
     * iterator is in use.
Packit fcad23
     */
Packit fcad23
    it->base.sync = it->base.container->sync;
Packit fcad23
Packit fcad23
    it->pos = 0;
Packit fcad23
Packit fcad23
    return 0;
Packit fcad23
}
Packit fcad23
Packit fcad23
static int
Packit fcad23
_ba_iterator_release(netsnmp_iterator *it)
Packit fcad23
{
Packit fcad23
    free(it);
Packit fcad23
Packit fcad23
    return 0;
Packit fcad23
}
Packit fcad23
Packit fcad23
static netsnmp_iterator *
Packit fcad23
_ba_iterator_get(netsnmp_container *c)
Packit fcad23
{
Packit fcad23
    binary_array_iterator* it;
Packit fcad23
Packit fcad23
    if(NULL == c)
Packit fcad23
        return NULL;
Packit fcad23
Packit fcad23
    it = SNMP_MALLOC_TYPEDEF(binary_array_iterator);
Packit fcad23
    if(NULL == it)
Packit fcad23
        return NULL;
Packit fcad23
Packit fcad23
    it->base.container = c;
Packit fcad23
    
Packit fcad23
    it->base.first = (netsnmp_iterator_rtn*)_ba_iterator_first;
Packit fcad23
    it->base.next = (netsnmp_iterator_rtn*)_ba_iterator_next;
Packit fcad23
    it->base.curr = (netsnmp_iterator_rtn*)_ba_iterator_curr;
Packit fcad23
    it->base.last = (netsnmp_iterator_rtn*)_ba_iterator_last;
Packit fcad23
    it->base.remove = (netsnmp_iterator_rc*)_ba_iterator_remove;
Packit fcad23
    it->base.reset = (netsnmp_iterator_rc*)_ba_iterator_reset;
Packit fcad23
    it->base.release = (netsnmp_iterator_rc*)_ba_iterator_release;
Packit fcad23
Packit fcad23
    (void)_ba_iterator_reset(it);
Packit fcad23
Packit fcad23
    return (netsnmp_iterator *)it;
Packit fcad23
}