container_iterator.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:15k
- /*
- * $Id: container_iterator.c,v 5.9 2004/08/28 19:25:47 rstory Exp $
- *
- */
- #include <net-snmp/net-snmp-config.h>
- #include <stdio.h>
- #if HAVE_STDLIB_H
- #include <stdlib.h>
- #endif
- #if HAVE_MALLOC_H
- #include <malloc.h>
- #endif
- #include <sys/types.h>
- #if HAVE_STRING_H
- #include <string.h>
- #else
- #include <strings.h>
- #endif
- #include <net-snmp/net-snmp-includes.h>
- #include <net-snmp/types.h>
- #include <net-snmp/library/snmp_api.h>
- #include <net-snmp/library/container.h>
- #include <net-snmp/library/tools.h>
- #include <net-snmp/library/snmp_assert.h>
- #include <net-snmp/library/container_iterator.h>
- /** @typedef struct iterator_info_s iterator_info
- * Typedefs the iterator_info_s struct into iterator_info */
- /** @struct iterator_info_s
-
- * Holds iterator information containing functions which should be
- called by the iterator_handler to loop over your data set and
- sort it in a SNMP specific manner.
- The iterator_info typedef can be used instead of directly
- calling this struct if you would prefer.
- */
- typedef struct iterator_info_s {
- /*
- * netsnmp_conatiner must be first
- */
- netsnmp_container c;
- /*
- * iterator data
- */
- Netsnmp_Iterator_Loop_Key *get_first;
- Netsnmp_Iterator_Loop_Key *get_next;
-
- Netsnmp_Iterator_Loop_Data *get_data;
- Netsnmp_Iterator_Data *free_user_ctx;
-
- Netsnmp_Iterator_Ctx *init_loop_ctx;
- Netsnmp_Iterator_Ctx *cleanup_loop_ctx;
- Netsnmp_Iterator_Ctx_Dup *save_pos;
-
- Netsnmp_Iterator_Data * release_data;
- Netsnmp_Iterator_Data * insert_data;
- Netsnmp_Iterator_Data * remove_data;
- Netsnmp_Iterator_Op * get_size;
-
- int sorted;
-
- /** This can be used by client handlers to store any
- information they need */
- void *user_ctx;
- } iterator_info;
- /**********************************************************************
- *
- * iterator
- *
- **********************************************************************/
- static void *
- _iterator_get(iterator_info *ii, const void *key)
- {
- int cmp, rc = SNMP_ERR_NOERROR;
- netsnmp_ref_void best = { NULL };
- netsnmp_ref_void tmp = { NULL };
- netsnmp_ref_void loop_ctx = { NULL };
- DEBUGMSGT(("container_iterator",">%sn", "_iterator_get"));
-
- if(ii->init_loop_ctx)
- ii->init_loop_ctx(ii->user_ctx, &loop_ctx);
-
- rc = ii->get_first(ii->user_ctx, &loop_ctx, &tmp);
- if(SNMP_ERR_NOERROR != rc) {
- if(SNMP_ENDOFMIBVIEW != rc)
- snmp_log(LOG_ERR, "bad rc %d from get_nextn", rc);
- }
- else {
- for( ;
- (NULL != tmp.val) && (SNMP_ERR_NOERROR == rc);
- rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp) ) {
-
- /*
- * if keys are equal, we are done.
- */
- cmp = ii->c.compare(tmp.val, key);
- if(0 == cmp) {
- best.val = tmp.val;
- if(ii->get_data)
- ii->get_data(ii->user_ctx, &loop_ctx, &best);
- }
-
- /*
- * if data is sorted and if key is greater,
- * we are done (not found)
- */
- if((cmp > 0) && ii->sorted)
- break;
- } /* end for */
- }
-
- if(ii->cleanup_loop_ctx)
- ii->cleanup_loop_ctx(ii->user_ctx,&loop_ctx);
- return best.val;
- }
- /**
- *
- * NOTE: the returned data context can be reused, to save from
- * having to allocate memory repeatedly. However, in this case,
- * the get_data and get_pos functions must be implemented to
- * return unique memory that will be saved for later comparisons.
- */
- static void *
- _iterator_get_next(iterator_info *ii, const void *key)
- {
- int cmp, rc = SNMP_ERR_NOERROR;
- netsnmp_ref_void best_val = { NULL };
- netsnmp_ref_void best_ctx = { NULL };
- netsnmp_ref_void tmp = { NULL };
- netsnmp_ref_void loop_ctx = { NULL };
- DEBUGMSGT(("container_iterator",">%sn", "_iterator_get_next"));
-
- /*
- * initialize loop context
- */
- if(ii->init_loop_ctx)
- ii->init_loop_ctx(ii->user_ctx, &loop_ctx);
-
- /*
- * get first item
- */
- rc = ii->get_first(ii->user_ctx, &loop_ctx, &tmp);
- if(SNMP_ERR_NOERROR == rc) {
- /*
- * special case: if key is null, find the first item.
- * this is each if the container is sorted, since we're
- * already done! Otherwise, get the next item for the
- * first comparison in the loop below.
- */
- if (NULL == key) {
- if(ii->get_data)
- ii->save_pos(ii->user_ctx, &loop_ctx, &best_ctx, 1);
- best_val.val = tmp.val;
- if(ii->sorted)
- tmp.val = NULL; /* so we skip for loop */
- else
- rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp);
- }
- /*
- * loop over remaining items
- */
- for( ;
- (NULL != tmp.val) && (rc == SNMP_ERR_NOERROR);
- rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp) ) {
-
- /*
- * if we have a key, this is a get-next, and we need to compare
- * the key to the tmp value to see if the tmp value is greater
- * than the key, but less than any previous match.
- *
- * if there is no key, this is a get-first, and we need to
- * compare the best value agains the tmp value to see if the
- * tmp value is lesser than the best match.
- */
- if(key) /* get next */
- cmp = ii->c.compare(tmp.val, key);
- else { /* get first */
- /*
- * best value and tmp value should never be equal,
- * otherwise we'd be comparing a pointer to itself.
- * (see note on context reuse in comments above function.
- */
- if(best_val.val == tmp.val) {
- snmp_log(LOG_ERR,"illegal reuse of data context in "
- "container_iteratorn");
- rc = SNMP_ERR_GENERR;
- break;
- }
- cmp = ii->c.compare(best_val.val, tmp.val);
- }
- if(cmp > 0) {
- /*
- * if we don't have a key (get-first) or a current best match,
- * then the comparison above is all we need to know that
- * tmp is the best match. otherwise, compare against the
- * current best match.
- */
- if((NULL == key) || (NULL == best_val.val) ||
- ((cmp=ii->c.compare(tmp.val, best_val.val)) < 0) ) {
- DEBUGMSGT(("container_iterator:results"," best matchn"));
- best_val.val = tmp.val;
- if(ii->get_data)
- ii->save_pos(ii->user_ctx, &loop_ctx, &best_ctx, 1);
- }
- }
- else if((cmp == 0) && ii->sorted && key) {
- /*
- * if keys are equal and container is sorted, then we know
- * the next key will be the one we want.
- * NOTE: if no vars, treat as generr, since we
- * went past the end of the container when we know
- * the next item is the one we want. (IGN-A)
- */
- rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp);
- if(SNMP_ERR_NOERROR == rc) {
- best_val.val = tmp.val;
- if(ii->get_data)
- ii->save_pos(ii->user_ctx, &loop_ctx, &best_ctx, 1);
- }
- else if(SNMP_ENDOFMIBVIEW == rc)
- rc = SNMPERR_GENERR; /* not found */
- break;
- }
-
- } /* end for */
- }
- /*
- * no vars is ok, except as noted above (IGN-A)
- */
- if(SNMP_ENDOFMIBVIEW == rc)
- rc = SNMP_ERR_NOERROR;
-
- /*
- * get data, iff necessary
- * clear return value iff errors
- */
- if(SNMP_ERR_NOERROR == rc) {
- if(ii->get_data && best_val.val) {
- rc = ii->get_data(ii->user_ctx, &best_ctx, &best_val);
- if(SNMP_ERR_NOERROR != rc) {
- snmp_log(LOG_ERR, "bad rc %d from get_datan", rc);
- best_val.val = NULL;
- }
- }
- }
- else if(SNMP_ENDOFMIBVIEW != rc) {
- snmp_log(LOG_ERR, "bad rc %d from get_nextn", rc);
- best_val.val = NULL;
- }
- /*
- * if we have a saved loop ctx, clean it up
- */
- if((best_ctx.val != NULL) && (best_ctx.val != loop_ctx.val) &&
- (ii->cleanup_loop_ctx))
- ii->cleanup_loop_ctx(ii->user_ctx,&best_ctx);
- /*
- * clean up loop ctx
- */
- if(ii->cleanup_loop_ctx)
- ii->cleanup_loop_ctx(ii->user_ctx,&loop_ctx);
- DEBUGMSGT(("container_iterator:results"," returning %pn", best_val.val));
- return best_val.val;
- }
- /**********************************************************************
- *
- * container
- *
- **********************************************************************/
- static void
- _iterator_free(iterator_info *ii)
- {
- DEBUGMSGT(("container_iterator",">%sn", "_iterator_free"));
-
- if(NULL == ii)
- return;
-
- if(ii->user_ctx)
- ii->free_user_ctx(ii->user_ctx,ii->user_ctx);
-
- free(ii);
- }
- static void *
- _iterator_find(iterator_info *ii, const void *data)
- {
- DEBUGMSGT(("container_iterator",">%sn", "_iterator_find"));
-
- if((NULL == ii) || (NULL == data))
- return NULL;
- return _iterator_get(ii, data);
- }
- static void *
- _iterator_find_next(iterator_info *ii, const void *data)
- {
- DEBUGMSGT(("container_iterator",">%sn", "_iterator_find_next"));
-
- if(NULL == ii)
- return NULL;
- return _iterator_get_next(ii, data);
- }
- static int
- _iterator_insert(iterator_info *ii, const void *data)
- {
- DEBUGMSGT(("container_iterator",">%sn", "_iterator_insert"));
-
- if(NULL == ii)
- return -1;
- if(NULL == ii->insert_data)
- return -1;
- return ii->insert_data(ii->user_ctx, data);
- }
- static int
- _iterator_remove(iterator_info *ii, const void *data)
- {
- DEBUGMSGT(("container_iterator",">%sn", "_iterator_remove"));
-
- if(NULL == ii)
- return -1;
- if(NULL == ii->remove_data)
- return -1;
- return ii->remove_data(ii->user_ctx, data);
- }
- static int
- _iterator_release(iterator_info *ii, const void *data)
- {
- DEBUGMSGT(("container_iterator",">%sn", "_iterator_release"));
-
- if(NULL == ii)
- return -1;
- if(NULL == ii->release_data)
- return -1;
- return ii->release_data(ii->user_ctx, data);
- }
- static size_t
- _iterator_size(iterator_info *ii)
- {
- size_t count = 0;
- int rc = SNMP_ERR_NOERROR;
- netsnmp_ref_void loop_ctx = { NULL };
- netsnmp_ref_void tmp = { NULL };
- DEBUGMSGT(("container_iterator",">%sn", "_iterator_size"));
-
- if(NULL == ii)
- return -1;
- if(NULL != ii->get_size)
- return ii->get_size(ii->user_ctx);
- /*
- * no get_size. loop and count ourselves
- */
- if(ii->init_loop_ctx)
- ii->init_loop_ctx(ii->user_ctx, &loop_ctx);
-
- for( rc = ii->get_first(ii->user_ctx, &loop_ctx, &tmp);
- NULL != tmp.val;
- rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp) )
- ++count;
- if(ii->cleanup_loop_ctx)
- ii->cleanup_loop_ctx(ii->user_ctx,&loop_ctx);
- return count;
- }
- static void
- _iterator_for_each(iterator_info *ii, netsnmp_container_obj_func *f,
- void *ctx)
- {
- int rc = SNMP_ERR_NOERROR;
- netsnmp_ref_void loop_ctx = { NULL };
- netsnmp_ref_void tmp = { NULL };
- DEBUGMSGT(("container_iterator",">%sn", "_iterator_foreach"));
-
- if(NULL == ii)
- return;
- if(ii->init_loop_ctx)
- ii->init_loop_ctx(ii->user_ctx, &loop_ctx);
-
- for( rc = ii->get_first(ii->user_ctx, &loop_ctx, &tmp);
- NULL != tmp.val;
- rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp) )
- (*f) (tmp.val, ctx);
- if(ii->cleanup_loop_ctx)
- ii->cleanup_loop_ctx(ii->user_ctx,&loop_ctx);
- }
- static void
- _iterator_clear(netsnmp_container *container, netsnmp_container_obj_func *f,
- void *context)
- {
- snmp_log(LOG_WARNING,"clear is meaningless for iterator container.n");
- }
- /**********************************************************************
- *
- */
- netsnmp_container*
- netsnmp_container_iterator_get(void *iterator_user_ctx,
- netsnmp_container_compare * compare,
- Netsnmp_Iterator_Loop_Key * get_first,
- Netsnmp_Iterator_Loop_Key * get_next,
- Netsnmp_Iterator_Loop_Data * get_data,
- Netsnmp_Iterator_Ctx_Dup * save_pos,
- Netsnmp_Iterator_Ctx * init_loop_ctx,
- Netsnmp_Iterator_Ctx * cleanup_loop_ctx,
- Netsnmp_Iterator_Data * free_user_ctx,
- int sorted)
- {
- iterator_info *ii;
- /*
- * sanity checks
- */
- if(get_data && ! save_pos) {
- snmp_log(LOG_ERR, "save_pos required with get_datan");
- return NULL;
- }
- /*
- * allocate memory
- */
- ii = SNMP_MALLOC_TYPEDEF(iterator_info);
- if (NULL==ii) {
- snmp_log(LOG_ERR, "couldn't allocate memoryn");
- return NULL;
- }
- /*
- * init container structure with iterator functions
- */
- ii->c.cfree = (netsnmp_container_rc*)_iterator_free;
- ii->c.compare = compare;
- ii->c.get_size = (netsnmp_container_size*)_iterator_size;
- ii->c.init = NULL;
- ii->c.insert = (netsnmp_container_op*)_iterator_insert;
- ii->c.remove = (netsnmp_container_op*)_iterator_remove;
- ii->c.release = (netsnmp_container_op*)_iterator_release;
- ii->c.find = (netsnmp_container_rtn*)_iterator_find;
- ii->c.find_next = (netsnmp_container_rtn*)_iterator_find_next;
- ii->c.get_subset = NULL;
- ii->c.get_iterator = NULL;
- ii->c.for_each = (netsnmp_container_func*)_iterator_for_each;
- ii->c.clear = _iterator_clear;
- /*
- * init iterator structure with user functions
- */
- ii->get_first = get_first;
- ii->get_next = get_next;
- ii->get_data = get_data;
- ii->save_pos = save_pos;
- ii->init_loop_ctx = init_loop_ctx;
- ii->cleanup_loop_ctx = cleanup_loop_ctx;
- ii->free_user_ctx = free_user_ctx;
- ii->sorted = sorted;
- ii->user_ctx = iterator_user_ctx;
- return (netsnmp_container*)ii;
- }
- void
- netsnmp_container_iterator_set_data_cb(netsnmp_container *c,
- Netsnmp_Iterator_Data * insert_data,
- Netsnmp_Iterator_Data * remove_data,
- Netsnmp_Iterator_Op * get_size)
- {
- iterator_info *ii = (iterator_info *)c;
- if(NULL == ii)
- return;
-
- ii->insert_data = insert_data;
- ii->remove_data = remove_data;
- ii->get_size = get_size;
- }