Blame snmplib/container_list_ssll.c

Packit fcad23
/*
Packit fcad23
 * container_list_sl.c
Packit fcad23
 * $Id$
Packit fcad23
 *
Packit fcad23
 */
Packit fcad23
#include <net-snmp/net-snmp-config.h>
Packit fcad23
#include <net-snmp/net-snmp-features.h>
Packit fcad23
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/tools.h>
Packit fcad23
#include <net-snmp/library/snmp_assert.h>
Packit fcad23
Packit fcad23
#include <net-snmp/library/container_list_ssll.h>
Packit fcad23
Packit fcad23
netsnmp_feature_child_of(container_linked_list, container_types)
Packit fcad23
netsnmp_feature_child_of(container_fifo, container_types)
Packit fcad23
netsnmp_feature_child_of(container_lifo, container_types)
Packit fcad23
Packit fcad23
/* this is a fancy way of cleaning up ifdefs */
Packit fcad23
#ifdef NETSNMP_FEATURE_REQUIRE_CONTAINER_FIFO
Packit fcad23
netsnmp_feature_require(container_linked_list)
Packit fcad23
#endif /* NETSNMP_FEATURE_REQUIRE_CONTAINER_FIFO */
Packit fcad23
#ifdef NETSNMP_FEATURE_REQUIRE_CONTAINER_LIFO
Packit fcad23
netsnmp_feature_require(container_linked_list)
Packit fcad23
#endif /* NETSNMP_FEATURE_REQUIRE_CONTAINER_LIFO */
Packit fcad23
Packit fcad23
#ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_LINKED_LIST
Packit fcad23
typedef struct sl_node {
Packit fcad23
   void           *data;
Packit fcad23
   struct sl_node *next;
Packit fcad23
} sl_node;
Packit fcad23
Packit fcad23
typedef struct sl_container_s {
Packit fcad23
   netsnmp_container          c;
Packit fcad23
   
Packit fcad23
   size_t                     count;      /* Index of the next free entry */
Packit fcad23
   sl_node                   *head;       /* head of list */
Packit fcad23
Packit fcad23
   int                        unsorted;   /* unsorted list? */
Packit fcad23
   int                        fifo;       /* lifo or fifo? */
Packit fcad23
Packit fcad23
} sl_container;
Packit fcad23
Packit fcad23
typedef struct ssll_iterator_s {
Packit fcad23
    netsnmp_iterator base;
Packit fcad23
 
Packit fcad23
    sl_node         *pos;
Packit fcad23
    sl_node         *last;
Packit fcad23
} ssll_iterator;
Packit fcad23
Packit fcad23
static netsnmp_iterator *_ssll_iterator_get(netsnmp_container *c);
Packit fcad23
Packit fcad23
Packit fcad23
static void *
Packit fcad23
_get(netsnmp_container *c, const void *key, int exact)
Packit fcad23
{
Packit fcad23
    sl_container *sl = (sl_container*)c;
Packit fcad23
    sl_node  *curr = sl->head;
Packit fcad23
    int rc = 0;
Packit fcad23
    
Packit fcad23
    /*
Packit fcad23
     * note: get-next on unsorted list is meaningless. we
Packit fcad23
     * don't try to search whole array, looking for the next highest.
Packit fcad23
     */
Packit fcad23
    if( (NULL != curr) && (NULL != key)) {
Packit fcad23
        while (curr) {
Packit fcad23
            rc = sl->c.compare(curr->data, key);
Packit fcad23
            if (rc == 0)
Packit fcad23
                break;
Packit fcad23
            else if (rc > 0) {
Packit fcad23
                if (0 == sl->unsorted) {
Packit fcad23
                    /*
Packit fcad23
                     * if sorted, we can stop.
Packit fcad23
                     */
Packit fcad23
                    break;
Packit fcad23
                }
Packit fcad23
            }
Packit fcad23
            curr = curr->next;
Packit fcad23
        }
Packit fcad23
        
Packit fcad23
        if((curr) && (!exact) && (rc == 0)) {
Packit fcad23
            curr = curr->next;
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
    
Packit fcad23
    return curr ? curr->data : NULL;
Packit fcad23
}
Packit fcad23
Packit fcad23
/**********************************************************************
Packit fcad23
 *
Packit fcad23
 *
Packit fcad23
 *
Packit fcad23
 **********************************************************************/
Packit fcad23
static int
Packit fcad23
_ssll_free(netsnmp_container *c)
Packit fcad23
{
Packit fcad23
    if(c) {
Packit fcad23
        free(c);
Packit fcad23
    }
Packit fcad23
    return 0;
Packit fcad23
}
Packit fcad23
Packit fcad23
static void *
Packit fcad23
_ssll_find(netsnmp_container *c, const void *data)
Packit fcad23
{
Packit fcad23
    if((NULL == c) || (NULL == data))
Packit fcad23
        return NULL;
Packit fcad23
Packit fcad23
    return _get(c, data, 1);
Packit fcad23
}
Packit fcad23
Packit fcad23
static void *
Packit fcad23
_ssll_find_next(netsnmp_container *c, const void *data)
Packit fcad23
{
Packit fcad23
    if(NULL == c)
Packit fcad23
        return NULL;
Packit fcad23
Packit fcad23
    return _get(c, data, 0);
Packit fcad23
}
Packit fcad23
Packit fcad23
static int
Packit fcad23
_ssll_insert(netsnmp_container *c, const void *data)
Packit fcad23
{
Packit fcad23
    sl_container *sl = (sl_container*)c;
Packit fcad23
    sl_node  *new_node, *curr;
Packit fcad23
    
Packit fcad23
    if (c == NULL)
Packit fcad23
        return -1;
Packit fcad23
Packit fcad23
    curr = sl->head;
Packit fcad23
Packit fcad23
    new_node = SNMP_MALLOC_TYPEDEF(sl_node);
Packit fcad23
    if (new_node == NULL)
Packit fcad23
        return -1;
Packit fcad23
    new_node->data = NETSNMP_REMOVE_CONST(void *, data);
Packit fcad23
    ++sl->count;
Packit fcad23
    ++c->sync;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * first node?
Packit fcad23
     */
Packit fcad23
    if(NULL == sl->head) {
Packit fcad23
        sl->head = new_node;
Packit fcad23
        return 0;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * sorted or unsorted insert?
Packit fcad23
     */
Packit fcad23
    if (1 == sl->unsorted) {
Packit fcad23
        /*
Packit fcad23
         * unsorted: fifo, or lifo?
Packit fcad23
         */
Packit fcad23
        if (1 == sl->fifo) {
Packit fcad23
            /*
Packit fcad23
             * fifo: insert at tail
Packit fcad23
             */
Packit fcad23
            while(NULL != curr->next)
Packit fcad23
                curr = curr->next;
Packit fcad23
            curr->next = new_node;
Packit fcad23
        }
Packit fcad23
        else {
Packit fcad23
            /*
Packit fcad23
             * lifo: insert at head
Packit fcad23
             */
Packit fcad23
            new_node->next = sl->head;
Packit fcad23
            sl->head = new_node;
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
    else {
Packit fcad23
        /*
Packit fcad23
         * sorted
Packit fcad23
         */
Packit fcad23
        sl_node *last = NULL;
Packit fcad23
        for( ; curr; last = curr, curr = curr->next) {
Packit fcad23
            if(sl->c.compare(curr->data, data) > 0)
Packit fcad23
                break;
Packit fcad23
        }
Packit fcad23
        if(NULL == last) {
Packit fcad23
            new_node->next = sl->head;
Packit fcad23
            sl->head = new_node;
Packit fcad23
        }
Packit fcad23
        else {
Packit fcad23
            new_node->next = last->next;
Packit fcad23
            last->next = new_node;
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
    
Packit fcad23
    return 0;
Packit fcad23
}
Packit fcad23
Packit fcad23
static int
Packit fcad23
_ssll_remove(netsnmp_container *c, const void *data)
Packit fcad23
{
Packit fcad23
    sl_container *sl = (sl_container*)c;
Packit fcad23
    sl_node  *curr;
Packit fcad23
    
Packit fcad23
    if (c == NULL)
Packit fcad23
        return -1;
Packit fcad23
Packit fcad23
    curr = sl->head;
Packit fcad23
    if (curr == NULL)
Packit fcad23
        return -1;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * special case for NULL data, act like stack
Packit fcad23
     */
Packit fcad23
    if ((NULL == data) ||
Packit fcad23
        (sl->c.compare(sl->head->data, data) == 0)) {
Packit fcad23
        curr = sl->head;
Packit fcad23
        sl->head = sl->head->next;
Packit fcad23
    }
Packit fcad23
    else {
Packit fcad23
        sl_node *last = sl->head;
Packit fcad23
        int rc;
Packit fcad23
        for(curr = sl->head->next ; curr; last = curr, curr = curr->next) {
Packit fcad23
            rc = sl->c.compare(curr->data, data);
Packit fcad23
            if (rc == 0) {
Packit fcad23
                last->next = curr->next;
Packit fcad23
                break;
Packit fcad23
            }
Packit fcad23
            else if ((rc > 0) && (0 == sl->unsorted)) {
Packit fcad23
                /*
Packit fcad23
                 * if sorted and rc > 0, didn't find entry
Packit fcad23
                 */
Packit fcad23
                curr = NULL;
Packit fcad23
                break;
Packit fcad23
            }
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if(NULL == curr)
Packit fcad23
        return -2;
Packit fcad23
    
Packit fcad23
    /*
Packit fcad23
     * free our node structure, but not the data
Packit fcad23
     */
Packit fcad23
    free(curr);
Packit fcad23
    --sl->count;
Packit fcad23
    ++c->sync;
Packit fcad23
    
Packit fcad23
    return 0;
Packit fcad23
}
Packit fcad23
Packit fcad23
static size_t
Packit fcad23
_ssll_size(netsnmp_container *c)
Packit fcad23
{
Packit fcad23
    sl_container *sl = (sl_container*)c;
Packit fcad23
    
Packit fcad23
    if(NULL == c)
Packit fcad23
        return 0;
Packit fcad23
Packit fcad23
    return sl->count;
Packit fcad23
}
Packit fcad23
Packit fcad23
static void
Packit fcad23
_ssll_for_each(netsnmp_container *c, netsnmp_container_obj_func *f,
Packit fcad23
             void *context)
Packit fcad23
{
Packit fcad23
    sl_container *sl = (sl_container*)c;
Packit fcad23
    sl_node  *curr;
Packit fcad23
    
Packit fcad23
    if(NULL == c)
Packit fcad23
        return;
Packit fcad23
    
Packit fcad23
    for(curr = sl->head; curr; curr = curr->next)
Packit fcad23
        (*f) ((void *)curr->data, context);
Packit fcad23
}
Packit fcad23
Packit fcad23
static void
Packit fcad23
_ssll_clear(netsnmp_container *c, netsnmp_container_obj_func *f,
Packit fcad23
             void *context)
Packit fcad23
{
Packit fcad23
    sl_container *sl = (sl_container*)c;
Packit fcad23
    sl_node  *curr, *next;
Packit fcad23
    
Packit fcad23
    if(NULL == c)
Packit fcad23
        return;
Packit fcad23
    
Packit fcad23
    for(curr = sl->head; curr; curr = next) {
Packit fcad23
Packit fcad23
        next = curr->next;
Packit fcad23
Packit fcad23
        if( NULL != f ) {
Packit fcad23
            curr->next = NULL;
Packit fcad23
            (*f) ((void *)curr->data, context);
Packit fcad23
        }
Packit fcad23
Packit fcad23
        /*
Packit fcad23
         * free our node structure, but not the data
Packit fcad23
         */
Packit fcad23
        free(curr);
Packit fcad23
    }
Packit fcad23
    sl->head = NULL;
Packit fcad23
    sl->count = 0;
Packit fcad23
    ++c->sync;
Packit fcad23
}
Packit fcad23
Packit fcad23
/**********************************************************************
Packit fcad23
 *
Packit fcad23
 *
Packit fcad23
 *
Packit fcad23
 **********************************************************************/
Packit fcad23
netsnmp_container *
Packit fcad23
netsnmp_container_get_ssll(void)
Packit fcad23
{
Packit fcad23
    /*
Packit fcad23
     * allocate memory
Packit fcad23
     */
Packit fcad23
    sl_container *sl = SNMP_MALLOC_TYPEDEF(sl_container);
Packit fcad23
    if (NULL==sl) {
Packit fcad23
        snmp_log(LOG_ERR, "couldn't allocate memory\n");
Packit fcad23
        return NULL;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    netsnmp_init_container((netsnmp_container *)sl, NULL, _ssll_free,
Packit fcad23
                           _ssll_size, NULL, _ssll_insert, _ssll_remove,
Packit fcad23
                           _ssll_find);
Packit fcad23
    sl->c.find_next = _ssll_find_next;
Packit fcad23
    sl->c.get_subset = NULL;
Packit fcad23
    sl->c.get_iterator =_ssll_iterator_get;
Packit fcad23
    sl->c.for_each = _ssll_for_each;
Packit fcad23
    sl->c.clear = _ssll_clear;
Packit fcad23
Packit fcad23
       
Packit fcad23
    return (netsnmp_container*)sl;
Packit fcad23
}
Packit fcad23
Packit fcad23
netsnmp_factory *
Packit fcad23
netsnmp_container_get_ssll_factory(void)
Packit fcad23
{
Packit fcad23
    static netsnmp_factory f = {"sorted_singly_linked_list",
Packit fcad23
                                (netsnmp_factory_produce_f*)
Packit fcad23
                                netsnmp_container_get_ssll };
Packit fcad23
    
Packit fcad23
    return &f;
Packit fcad23
}
Packit fcad23
Packit fcad23
Packit fcad23
netsnmp_container *
Packit fcad23
netsnmp_container_get_usll(void)
Packit fcad23
{
Packit fcad23
    /*
Packit fcad23
     * allocate memory
Packit fcad23
     */
Packit fcad23
    sl_container *sl = (sl_container *)netsnmp_container_get_ssll();
Packit fcad23
    if (NULL==sl)
Packit fcad23
        return NULL; /* msg already logged */
Packit fcad23
Packit fcad23
    sl->unsorted = 1;
Packit fcad23
Packit fcad23
    return (netsnmp_container*)sl;
Packit fcad23
}
Packit fcad23
Packit fcad23
netsnmp_container *
Packit fcad23
netsnmp_container_get_singly_linked_list(int fifo)
Packit fcad23
{
Packit fcad23
    sl_container *sl = (sl_container *)netsnmp_container_get_usll();
Packit fcad23
    if (NULL == sl)
Packit fcad23
        return NULL; /* error already logged */
Packit fcad23
Packit fcad23
    sl->fifo = fifo;
Packit fcad23
Packit fcad23
    return (netsnmp_container *)sl;
Packit fcad23
}
Packit fcad23
Packit fcad23
netsnmp_container *
Packit fcad23
netsnmp_container_get_fifo(void)
Packit fcad23
{
Packit fcad23
    return netsnmp_container_get_singly_linked_list(1);
Packit fcad23
}
Packit fcad23
Packit fcad23
netsnmp_factory *
Packit fcad23
netsnmp_container_get_usll_factory(void)
Packit fcad23
{
Packit fcad23
    static netsnmp_factory f = {"unsorted_singly_linked_list-lifo",
Packit fcad23
                                (netsnmp_factory_produce_f*)
Packit fcad23
                                netsnmp_container_get_usll };
Packit fcad23
    
Packit fcad23
    return &f;
Packit fcad23
}
Packit fcad23
Packit fcad23
netsnmp_factory *
Packit fcad23
netsnmp_container_get_fifo_factory(void)
Packit fcad23
{
Packit fcad23
    static netsnmp_factory f = {"unsorted_singly_linked_list-fifo",
Packit fcad23
                                (netsnmp_factory_produce_f*)
Packit fcad23
                                netsnmp_container_get_fifo };
Packit fcad23
    
Packit fcad23
    return &f;
Packit fcad23
}
Packit fcad23
Packit fcad23
void
Packit fcad23
netsnmp_container_ssll_init(void)
Packit fcad23
{
Packit fcad23
    netsnmp_container_register("sorted_singly_linked_list",
Packit fcad23
                               netsnmp_container_get_ssll_factory());
Packit fcad23
    netsnmp_container_register("unsorted_singly_linked_list",
Packit fcad23
                               netsnmp_container_get_usll_factory());
Packit fcad23
    netsnmp_container_register("lifo",
Packit fcad23
                               netsnmp_container_get_usll_factory());
Packit fcad23
    netsnmp_container_register("fifo",
Packit fcad23
                               netsnmp_container_get_fifo_factory());
Packit fcad23
}
Packit fcad23
Packit fcad23
Packit fcad23
/**********************************************************************
Packit fcad23
 *
Packit fcad23
 * iterator
Packit fcad23
 *
Packit fcad23
 */
Packit fcad23
NETSNMP_STATIC_INLINE sl_container *
Packit fcad23
_ssll_it2cont(ssll_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
    if(NULL == it->base.container) {
Packit fcad23
        netsnmp_assert(NULL != it->base.container);
Packit fcad23
        return NULL;
Packit fcad23
    }
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
    return (sl_container *)it->base.container;
Packit fcad23
}
Packit fcad23
Packit fcad23
static void *
Packit fcad23
_ssll_iterator_curr(ssll_iterator *it)
Packit fcad23
{
Packit fcad23
    sl_container *t = _ssll_it2cont(it);
Packit fcad23
    if ((NULL == t) || (NULL == it->pos))
Packit fcad23
        return NULL;
Packit fcad23
Packit fcad23
    return it->pos->data;
Packit fcad23
}
Packit fcad23
Packit fcad23
static void *
Packit fcad23
_ssll_iterator_first(ssll_iterator *it)
Packit fcad23
{
Packit fcad23
    sl_container *t = _ssll_it2cont(it);
Packit fcad23
    if ((NULL == t) || (NULL == t->head))
Packit fcad23
        return NULL;
Packit fcad23
Packit fcad23
    return t->head->data;
Packit fcad23
}
Packit fcad23
Packit fcad23
static void *
Packit fcad23
_ssll_iterator_next(ssll_iterator *it)
Packit fcad23
{
Packit fcad23
    sl_container *t = _ssll_it2cont(it);
Packit fcad23
    if ((NULL == t) || (NULL == it->pos))
Packit fcad23
        return NULL;
Packit fcad23
Packit fcad23
    it->pos = it->pos->next;
Packit fcad23
    if (NULL == it->pos)
Packit fcad23
        return NULL;
Packit fcad23
Packit fcad23
    return it->pos->data;
Packit fcad23
}
Packit fcad23
Packit fcad23
static void *
Packit fcad23
_ssll_iterator_last(ssll_iterator *it)
Packit fcad23
{
Packit fcad23
    sl_node      *n;
Packit fcad23
    sl_container *t = _ssll_it2cont(it);
Packit fcad23
    if(NULL == t)
Packit fcad23
        return NULL;
Packit fcad23
    
Packit fcad23
    if (it->last)
Packit fcad23
        return it->last;
Packit fcad23
Packit fcad23
    n = it->pos ? it->pos : t->head;
Packit fcad23
    if (NULL == n)
Packit fcad23
        return NULL;
Packit fcad23
Packit fcad23
    while (n->next)
Packit fcad23
        n = n->next;
Packit fcad23
Packit fcad23
    it->last = n;
Packit fcad23
Packit fcad23
    return it->last->data;
Packit fcad23
}
Packit fcad23
Packit fcad23
static int
Packit fcad23
_ssll_iterator_reset(ssll_iterator *it)
Packit fcad23
{
Packit fcad23
    sl_container *t;
Packit fcad23
Packit fcad23
    /** can't use it2conf cuz we might be out of sync */
Packit fcad23
    if(NULL == it) {
Packit fcad23
        netsnmp_assert(NULL != it);
Packit fcad23
        return 0;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if(NULL == it->base.container) {
Packit fcad23
        netsnmp_assert(NULL != it->base.container);
Packit fcad23
        return 0;
Packit fcad23
    }
Packit fcad23
    t = (sl_container *)it->base.container;
Packit fcad23
    if(NULL == t)
Packit fcad23
        return -1;
Packit fcad23
Packit fcad23
    it->last = NULL;
Packit fcad23
    it->pos = t->head;
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
    return 0;
Packit fcad23
}
Packit fcad23
Packit fcad23
static int
Packit fcad23
_ssll_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
_ssll_iterator_get(netsnmp_container *c)
Packit fcad23
{
Packit fcad23
    ssll_iterator* it;
Packit fcad23
Packit fcad23
    if(NULL == c)
Packit fcad23
        return NULL;
Packit fcad23
Packit fcad23
    it = SNMP_MALLOC_TYPEDEF(ssll_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*)_ssll_iterator_first;
Packit fcad23
    it->base.next = (netsnmp_iterator_rtn*)_ssll_iterator_next;
Packit fcad23
    it->base.curr = (netsnmp_iterator_rtn*)_ssll_iterator_curr;
Packit fcad23
    it->base.last = (netsnmp_iterator_rtn*)_ssll_iterator_last;
Packit fcad23
    it->base.reset = (netsnmp_iterator_rc*)_ssll_iterator_reset;
Packit fcad23
    it->base.release = (netsnmp_iterator_rc*)_ssll_iterator_release;
Packit fcad23
Packit fcad23
    (void)_ssll_iterator_reset(it);
Packit fcad23
Packit fcad23
    return (netsnmp_iterator *)it;
Packit fcad23
}
Packit fcad23
#else /* NETSNMP_FEATURE_REMOVE_CONTAINER_LINKED_LIST */
Packit fcad23
netsnmp_feature_unused(container_linked_list);
Packit fcad23
#endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_LINKED_LIST */