blob: 30b82f1577786660310ae046d08132ebefae9da9 [file] [log] [blame]
/* Portions of this file are subject to the following copyright(s). See
* the Net-SNMP's COPYING file for more details and other copyrights
* that may apply:
*/
/*
* Portions of this file are copyrighted by:
* Copyright (C) 2007 Apple, Inc. All rights reserved.
* Use is subject to license terms specified in the COPYING file
* distributed with the Net-SNMP package.
*/
#ifndef NETSNMP_CONTAINER_H
#define NETSNMP_CONTAINER_H
/*
* $Id$
*
* WARNING: This is a recently created file, and all of it's contents are
* subject to change at any time.
*
* A basic container template. A generic way for code to store and
* retrieve data. Allows for interchangable storage algorithms.
*/
#ifndef NET_SNMP_CONFIG_H
#error "Please include <net-snmp/net-snmp-config.h> before this file"
#endif
#include <stdlib.h> /* free() */
#include <net-snmp/types.h>
#include <net-snmp/library/factory.h>
#include <net-snmp/library/snmp_logging.h>
#include <net-snmp/library/tools.h>
#ifdef __cplusplus
extern "C" {
#endif
/*************************************************************************
*
* function pointer definitions
*
*************************************************************************/
struct netsnmp_iterator_s; /** forward declare */
struct netsnmp_container_s; /** forward declare */
/*
* function for performing an operation on a container which
* returns (maybe the same) container.
*/
typedef struct netsnmp_container_s* (netsnmp_container_mod_op)
(struct netsnmp_container_s *, void *context, u_int flags);
/*
* function for setting an option on a container
*/
typedef int (netsnmp_container_option)(struct netsnmp_container_s *,
int set, u_int flags);
/*
* function returning an int for an operation on a container
*/
typedef int (netsnmp_container_rc)(struct netsnmp_container_s *);
/*
* function returning an iterator for a container
*/
typedef struct netsnmp_iterator_s * (netsnmp_container_it)
(struct netsnmp_container_s *);
/*
* function returning a size_t for an operation on a container
*/
typedef size_t (netsnmp_container_size)(struct netsnmp_container_s *);
/*
* function returning an int for an operation on an object and
* a container
*/
typedef int (netsnmp_container_op)(struct netsnmp_container_s *,
const void *data);
/*
* function returning an oject for an operation on an object and a
* container
*/
typedef void * (netsnmp_container_rtn)(struct netsnmp_container_s *,
const void *data);
/*
* function with no return which acts on an object
*/
typedef void (netsnmp_container_obj_func)(void *data, void *context);
/*
* function with no return which calls a function on an object
*/
typedef void (netsnmp_container_func)(struct netsnmp_container_s *,
netsnmp_container_obj_func *,
void *context);
/*
* function returning an array of objects for an operation on an
* ojbect and a container
*/
typedef netsnmp_void_array * (netsnmp_container_set)
(struct netsnmp_container_s *, void *data);
/*
* function returning an int for a comparison between two objects
*/
typedef int (netsnmp_container_compare)(const void *lhs,
const void *rhs);
/*************************************************************************
*
* Basic container
*
*************************************************************************/
typedef struct netsnmp_container_s {
/*
* pointer for container implementation
*/
void * container_data;
/*
* returns the number of items in a container
*/
netsnmp_container_size *get_size;
/*
* initialize a container
*/
netsnmp_container_rc *init;
/*
* release memory used by a container.
*
* Note: if your data structures contained allocated
* memory, you are responsible for releasing that
* memory before calling this function!
*/
netsnmp_container_rc *cfree;
/*
* add an entry to the container
*/
netsnmp_container_op *insert;
/*
* remove an entry from the container
*/
netsnmp_container_op *remove;
/*
* release memory for an entry from the container
*/
netsnmp_container_op *release; /* NOTE: deprecated. Use free_item */
netsnmp_container_obj_func *free_item;
/*
* find the entry in the container with the same key
*
* Note: do not change the key! If you need to
* change a key, remove the entry, change the key,
* and the re-add the entry.
*/
netsnmp_container_rtn *find;
/*
* find the entry in the container with the next highest key
*
* If the key is NULL, return the first item in the container.
*/
netsnmp_container_rtn *find_next;
/*
* find all entries in the container which match the partial key
* returns allocated memory (netsnmp_void_array). User is responsible
* for releasing this memory (free(array->array), free(array)).
* DO NOT FREE ELEMENTS OF THE ARRAY, because they are the same pointers
* stored in the container.
*/
netsnmp_container_set *get_subset;
/*
* function to return an iterator for the container
*/
netsnmp_container_it *get_iterator;
/*
* function to call another function for each object in the container
*/
netsnmp_container_func *for_each;
/*
* specialized version of for_each used to optimize cleanup.
* clear the container, optionally calling a function for each item.
*/
netsnmp_container_func *clear;
/*
* OPTIONAL function to filter inserts to the container
* (intended for a secondary container, which only wants
* a sub-set of the objects in the primary/parent container)
* Returns:
* 1 : filter matched (don't insert)
* 0 : no match (insert)
*/
netsnmp_container_op *insert_filter;
/*
* OPTIONAL function to duplicate a container. Defaults to a shallow
* copy. Only the specified container is copied (i.e. sub-containers
* not included).
*/
netsnmp_container_mod_op *duplicate;
/*
* function to compare two object stored in the container.
*
* Returns:
*
* -1 LHS < RHS
* 0 LHS = RHS
* 1 LHS > RHS
*/
netsnmp_container_compare *compare;
/*
* same as compare, but RHS will be a partial key
*/
netsnmp_container_compare *ncompare;
/*
* function to set container options
*/
netsnmp_container_option *options;
/*
* unique name for finding a particular container in a list
*/
char *container_name;
/*
* sort count, for iterators to track (insert/delete
* bumps counter, invalidates iterator)
*/
u_long sync;
/*
* flags
*/
u_int flags;
/*
* containers can contain other containers (additional indexes)
*/
struct netsnmp_container_s *next, *prev;
} netsnmp_container;
/*
* initialize/free a container of container factories. used by
* netsnmp_container_find* functions.
*/
NETSNMP_IMPORT
void netsnmp_container_init_list(void);
NETSNMP_IMPORT
void netsnmp_container_free_list(void);
/*
* register a new container factory
*/
int netsnmp_container_register_with_compare(const char* name,
netsnmp_factory *f,
netsnmp_container_compare *c);
int netsnmp_container_register(const char* name, netsnmp_factory *f);
/*
* search for and create a container from a list of types or a
* specific type.
*/
NETSNMP_IMPORT
netsnmp_container * netsnmp_container_find(const char *type_list);
netsnmp_container * netsnmp_container_get(const char *type);
/*
* utility routines
*/
NETSNMP_IMPORT
void netsnmp_container_add_index(netsnmp_container *primary,
netsnmp_container *new_index);
netsnmp_factory *netsnmp_container_get_factory(const char *type);
/*
* common comparison routines
*/
/** first data element is a 'netsnmp_index' */
NETSNMP_IMPORT
int netsnmp_compare_netsnmp_index(const void *lhs, const void *rhs);
NETSNMP_IMPORT
int netsnmp_ncompare_netsnmp_index(const void *lhs, const void *rhs);
/** first data element is a 'char *' */
int netsnmp_compare_cstring(const void * lhs, const void * rhs);
int netsnmp_ncompare_cstring(const void * lhs, const void * rhs);
/** useful for octet strings */
int netsnmp_compare_mem(const char * lhs, size_t lhs_len,
const char * rhs, size_t rhs_len);
/** no structure, just 'char *' pointers */
int netsnmp_compare_direct_cstring(const void * lhs, const void * rhs);
int netsnmp_compare_long(const void * lhs, const void * rhs);
int netsnmp_compare_ulong(const void * lhs, const void * rhs);
int netsnmp_compare_int32(const void * lhs, const void * rhs);
int netsnmp_compare_uint32(const void * lhs, const void * rhs);
/** for_each callback to call free on data item */
NETSNMP_IMPORT
void netsnmp_container_simple_free(void *data, void *context);
/*
* container optionflags
*/
#define CONTAINER_KEY_ALLOW_DUPLICATES 0x00000001
#define CONTAINER_KEY_UNSORTED 0x00000002
#define CONTAINER_SET_OPTIONS(x,o,rc) do { \
if (NULL==(x)->options) \
rc = -1; \
else { \
rc = (x)->options(x, 1, o); \
if (rc != -1 ) \
(x)->flags |= o; \
} \
} while(0)
#define CONTAINER_CHECK_OPTION(x,o,rc) do { \
rc = x->flags & 0; \
} while(0)
/*
* useful macros (x = container; k = key; c = user context)
*/
#define CONTAINER_FIRST(x) (x)->find_next(x,NULL)
#define CONTAINER_FIND(x,k) (x)->find(x,k)
#define CONTAINER_NEXT(x,k) (x)->find_next(x,k)
/*
* GET_SUBSET returns allocated memory (netsnmp_void_array). User is responsible
* for releasing this memory (free(array->array), free(array)).
* DO NOT FREE ELEMENTS OF THE ARRAY, because they are the same pointers
* stored in the container.
*/
#define CONTAINER_GET_SUBSET(x,k) (x)->get_subset(x,k)
#define CONTAINER_SIZE(x) (x)->get_size(x)
#define CONTAINER_ITERATOR(x) (x)->get_iterator(x)
#define CONTAINER_COMPARE(x,l,r) (x)->compare(l,r)
#define CONTAINER_FOR_EACH(x,f,c) (x)->for_each(x,f,c)
/*
* if you are getting multiple definitions of these three
* inline functions, you most likely have optimizations turned off.
* Either turn them back on, or define NETSNMP_NO_INLINE
*/
#ifndef NETSNMP_USE_INLINE /* default is to inline */
/*
* insert k into all containers
*/
int CONTAINER_INSERT(netsnmp_container *x, const void *k);
/*
* remove k from all containers
*/
int CONTAINER_REMOVE(netsnmp_container *x, const void *k);
/*
* duplicate container
*/
netsnmp_container *CONTAINER_DUP(netsnmp_container *x, void *ctx,
u_int flags);
/*
* clear all containers. When clearing the *first* container, and
* *only* the first container, call the function f for each item.
* After calling this function, all containers should be empty.
*/
void CONTAINER_CLEAR(netsnmp_container *x, netsnmp_container_obj_func *f,
void *c);
/*
* clear all containers. When clearing the *first* container, and
* *only* the first container, call the free_item function for each item.
* After calling this function, all containers should be empty.
*/
void CONTAINER_FREE_ALL(netsnmp_container *x, void *c);
/*
* free all containers
*/
int CONTAINER_FREE(netsnmp_container *x);
netsnmp_container *SUBCONTAINER_FIND(netsnmp_container *x,
const char* name);
#else
/*------------------------------------------------------------------
* These functions should EXACTLY match the function version in
* container.c. If you change one, change them both.
*/
NETSNMP_STATIC_INLINE /* gcc docs recommend static w/inline */
int CONTAINER_INSERT_HELPER(netsnmp_container* x, const void* k)
{
while(x && x->insert_filter && x->insert_filter(x,k) == 1)
x = x->next;
if(x) {
int rc = x->insert(x,k);
if(rc)
snmp_log(LOG_DEBUG,"error on subcontainer '%s' insert (%d)\n",
x->container_name ? x->container_name : "", rc);
else {
rc = CONTAINER_INSERT_HELPER(x->next, k);
if(rc)
x->remove(x,k);
}
return rc;
}
return 0;
}
/*------------------------------------------------------------------
* These functions should EXACTLY match the function version in
* container.c. If you change one, change them both.
*/
NETSNMP_STATIC_INLINE /* gcc docs recommend static w/inline */
int CONTAINER_INSERT(netsnmp_container* x, const void* k)
{
/** start at first container */
while(x->prev)
x = x->prev;
return CONTAINER_INSERT_HELPER(x, k);
}
/*------------------------------------------------------------------
* These functions should EXACTLY match the function version in
* container.c. If you change one, change them both.
*/
NETSNMP_STATIC_INLINE /* gcc docs recommend static w/inline */
int CONTAINER_REMOVE(netsnmp_container *x, const void *k)
{
int rc2, rc = 0;
/** start at last container */
while(x->next)
x = x->next;
while(x) {
rc2 = x->remove(x,k);
/** ignore remove errors if there is a filter in place */
if ((rc2) && (NULL == x->insert_filter)) {
snmp_log(LOG_ERR,"error on subcontainer '%s' remove (%d)\n",
x->container_name ? x->container_name : "", rc2);
rc = rc2;
}
x = x->prev;
}
return rc;
}
/*------------------------------------------------------------------
* These functions should EXACTLY match the function version in
* container.c. If you change one, change them both.
*/
NETSNMP_STATIC_INLINE /* gcc docs recommend static w/inline */
netsnmp_container *CONTAINER_DUP(netsnmp_container *x, void *ctx,
u_int flags)
{
if (NULL == x->duplicate) {
snmp_log(LOG_ERR, "container '%s' does not support duplicate\n",
x->container_name ? x->container_name : "");
return NULL;
}
return x->duplicate(x, ctx, flags);
}
/*------------------------------------------------------------------
* These functions should EXACTLY match the function version in
* container.c. If you change one, change them both.
*/
NETSNMP_STATIC_INLINE /* gcc docs recommend static w/inline */
int CONTAINER_FREE(netsnmp_container *x)
{
int rc2, rc = 0;
/** start at last container */
while(x->next)
x = x->next;
while(x) {
netsnmp_container *tmp;
char *name;
tmp = x->prev;
name = x->container_name;
x->container_name = NULL;
rc2 = x->cfree(x);
if (rc2) {
snmp_log(LOG_ERR,"error on subcontainer '%s' cfree (%d)\n",
name ? name : "", rc2);
rc = rc2;
}
SNMP_FREE(name);
x = tmp;
}
return rc;
}
/*------------------------------------------------------------------
* These functions should EXACTLY match the function version in
* container.c. If you change one, change them both.
*/
/*
* clear all containers. When clearing the *first* container, and
* *only* the first container, call the function f for each item.
* After calling this function, all containers should be empty.
*/
NETSNMP_STATIC_INLINE /* gcc docs recommend static w/inline */
void CONTAINER_CLEAR(netsnmp_container *x, netsnmp_container_obj_func *f,
void *c)
{
/** start at last container */
while(x->next)
x = x->next;
while(x->prev) {
x->clear(x, NULL, c);
x = x->prev;
}
x->clear(x, f, c);
}
/*
* clear all containers. When clearing the *first* container, and
* *only* the first container, call the free_item function for each item.
* After calling this function, all containers should be empty.
*/
NETSNMP_STATIC_INLINE /* gcc docs recommend static w/inline */
void CONTAINER_FREE_ALL(netsnmp_container *x, void *c)
{
CONTAINER_CLEAR(x, x->free_item, c);
}
/*------------------------------------------------------------------
* These functions should EXACTLY match the function version in
* container.c. If you change one, change them both.
*/
/*
* Find a sub-container with the given name
*/
NETSNMP_STATIC_INLINE /* gcc docs recommend static w/inline */
netsnmp_container *SUBCONTAINER_FIND(netsnmp_container *x,
const char* name)
{
if ((NULL == x) || (NULL == name))
return NULL;
/** start at first container */
while(x->prev)
x = x->prev;
while(x) {
if ((NULL != x->container_name) &&
(0 == strcmp(name,x->container_name)))
break;
x = x->next;
}
return x;
}
#endif
/*
* INTERNAL utility routines for container implementations
*/
void netsnmp_init_container(netsnmp_container *c,
netsnmp_container_rc *init,
netsnmp_container_rc *cfree,
netsnmp_container_size *size,
netsnmp_container_compare *cmp,
netsnmp_container_op *ins,
netsnmp_container_op *rem,
netsnmp_container_rtn *fnd);
/** Duplicate container meta-data. */
int netsnmp_container_data_dup(netsnmp_container *dup,
netsnmp_container *c);
/*************************************************************************
*
* container iterator
*
*************************************************************************/
/*
* function returning an int for an operation on an iterator
*/
typedef int (netsnmp_iterator_rc)(struct netsnmp_iterator_s *);
/*
* function returning an oject for an operation on an iterator
*/
typedef void * (netsnmp_iterator_rtn)(struct netsnmp_iterator_s *);
/*
* iterator structure
*/
typedef struct netsnmp_iterator_s {
netsnmp_container *container;
/*
* sync from container when iterator created. used to invalidate
* the iterator when the container changes.
*/
u_long sync;
/*
* reset iterator position to beginning of container.
*/
netsnmp_iterator_rc *reset;
/*
* release iterator and memory it uses
*/
netsnmp_iterator_rc *release;
/*
* first, last and current DO NOT advance the iterator
*/
netsnmp_iterator_rtn *first;
netsnmp_iterator_rtn *curr;
netsnmp_iterator_rtn *last;
netsnmp_iterator_rtn *next;
/*
* remove will remove the item at the current position, then back up
* the iterator to the previous item. That way next will move to the
* item (the one that replaced the removed item.
*/
netsnmp_iterator_rc *remove;
} netsnmp_iterator;
#define ITERATOR_FIRST(x) x->first(x)
#define ITERATOR_NEXT(x) x->next(x)
#define ITERATOR_LAST(x) x->last(x)
#define ITERATOR_REMOVE(x) x->remove(x)
#define ITERATOR_RELEASE(x) do { x->release(x); x = NULL; } while(0)
#ifdef __cplusplus
}
#endif
#endif /** NETSNMP_CONTAINER_H */