2
* $Id: container_iterator.c,v 5.5.2.1 2003/12/18 20:25:29 nba Exp $
6
#include <net-snmp/net-snmp-config.h>
15
#include <sys/types.h>
22
#include <net-snmp/net-snmp-includes.h>
23
#include <net-snmp/types.h>
24
#include <net-snmp/library/snmp_api.h>
25
#include <net-snmp/library/container.h>
26
#include <net-snmp/library/tools.h>
27
#include <net-snmp/library/snmp_assert.h>
29
#include <net-snmp/library/container_iterator.h>
31
/** @typedef struct iterator_info_s iterator_info
32
* Typedefs the iterator_info_s struct into iterator_info */
34
/** @struct iterator_info_s
36
* Holds iterator information containing functions which should be
37
called by the iterator_handler to loop over your data set and
38
sort it in a SNMP specific manner.
40
The iterator_info typedef can be used instead of directly
41
calling this struct if you would prefer.
43
typedef struct iterator_info_s {
45
* netsnmp_conatiner must be first
52
Netsnmp_Iterator_Loop_Key *get_first;
53
Netsnmp_Iterator_Loop_Key *get_next;
55
Netsnmp_Iterator_Loop_Data *get_data;
57
Netsnmp_Iterator_Data *free_user_ctx;
59
Netsnmp_Iterator_Ctx *init_loop_ctx;
60
Netsnmp_Iterator_Ctx *cleanup_loop_ctx;
61
Netsnmp_Iterator_Ctx_Dup *save_pos;
63
Netsnmp_Iterator_Data * release_data;
64
Netsnmp_Iterator_Data * insert_data;
65
Netsnmp_Iterator_Data * remove_data;
67
Netsnmp_Iterator_Op * get_size;
71
/** This can be used by client handlers to store any
72
information they need */
76
/**********************************************************************
80
**********************************************************************/
82
_iterator_get(iterator_info *ii, const void *key)
84
int cmp, rc = SNMP_ERR_NOERROR;
85
netsnmp_ref_void best = { NULL };
86
netsnmp_ref_void tmp = { NULL };
87
netsnmp_ref_void loop_ctx = { NULL };
89
DEBUGMSGT(("container_iterator",">%s\n", "_iterator_get"));
92
ii->init_loop_ctx(ii->user_ctx, &loop_ctx);
94
rc = ii->get_first(ii->user_ctx, &loop_ctx, &tmp);
95
if(SNMP_ERR_NOERROR != rc) {
96
if(SNMP_ENDOFMIBVIEW != rc)
97
snmp_log(LOG_ERR, "bad rc %d from get_next\n", rc);
101
(NULL != tmp.val) && (SNMP_ERR_NOERROR == rc);
102
rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp) ) {
105
* if keys are equal, we are done.
107
cmp = ii->c.compare(tmp.val, key);
111
ii->get_data(ii->user_ctx, &loop_ctx, &best);
115
* if data is sorted and if key is greater,
116
* we are done (not found)
118
if((cmp > 0) && ii->sorted)
123
if(ii->cleanup_loop_ctx)
124
ii->cleanup_loop_ctx(ii->user_ctx,&loop_ctx);
131
* NOTE: the returned data context can be reused, to save from
132
* having to allocate memory repeatedly. However, in this case,
133
* the get_data and get_pos functions must be implemented to
134
* return unique memory that will be saved for later comparisons.
137
_iterator_get_next(iterator_info *ii, const void *key)
139
int cmp, rc = SNMP_ERR_NOERROR;
140
netsnmp_ref_void best_val = { NULL };
141
netsnmp_ref_void best_ctx = { NULL };
142
netsnmp_ref_void tmp = { NULL };
143
netsnmp_ref_void loop_ctx = { NULL };
145
DEBUGMSGT(("container_iterator",">%s\n", "_iterator_get_next"));
148
* initialize loop context
150
if(ii->init_loop_ctx)
151
ii->init_loop_ctx(ii->user_ctx, &loop_ctx);
156
rc = ii->get_first(ii->user_ctx, &loop_ctx, &tmp);
157
if(SNMP_ERR_NOERROR == rc) {
159
* special case: if key is null, find the first item.
160
* this is each if the container is sorted, since we're
161
* already done! Otherwise, get the next item for the
162
* first comparison in the loop below.
166
ii->save_pos(ii->user_ctx, &loop_ctx, &best_ctx, 1);
167
best_val.val = tmp.val;
169
tmp.val = NULL; /* so we skip for loop */
171
rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp);
174
* loop over remaining items
177
(NULL != tmp.val) && (rc == SNMP_ERR_NOERROR);
178
rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp) ) {
181
* if we have a key, this is a get-next, and we need to compare
182
* the key to the tmp value to see if the tmp value is greater
183
* than the key, but less than any previous match.
185
* if there is no key, this is a get-first, and we need to
186
* compare the best value agains the tmp value to see if the
187
* tmp value is lesser than the best match.
189
if(key) /* get next */
190
cmp = ii->c.compare(tmp.val, key);
191
else { /* get first */
193
* best value and tmp value should never be equal,
194
* otherwise we'd be comparing a pointer to itself.
195
* (see note on context reuse in comments above function.
197
if(best_val.val == tmp.val) {
198
snmp_log(LOG_ERR,"illegal reuse of data context in "
199
"container_iterator\n");
200
rc = SNMP_ERR_GENERR;
203
cmp = ii->c.compare(best_val.val, tmp.val);
207
* if we don't have a key (get-first) or a current best match,
208
* then the comparison above is all we need to know that
209
* tmp is the best match. otherwise, compare against the
210
* current best match.
212
if((NULL == key) || (NULL == best_val.val) ||
213
((cmp=ii->c.compare(tmp.val, best_val.val)) < 0) ) {
214
DEBUGMSGT(("container_iterator:results"," best match\n"));
215
best_val.val = tmp.val;
217
ii->save_pos(ii->user_ctx, &loop_ctx, &best_ctx, 1);
220
else if((cmp == 0) && ii->sorted && key) {
222
* if keys are equal and container is sorted, then we know
223
* the next key will be the one we want.
224
* NOTE: if no vars, treat as generr, since we
225
* went past the end of the container when we know
226
* the next item is the one we want. (IGN-A)
228
rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp);
229
if(SNMP_ERR_NOERROR == rc) {
230
best_val.val = tmp.val;
232
ii->save_pos(ii->user_ctx, &loop_ctx, &best_ctx, 1);
234
else if(SNMP_ENDOFMIBVIEW == rc)
235
rc = SNMPERR_GENERR; /* not found */
243
* no vars is ok, except as noted above (IGN-A)
245
if(SNMP_ENDOFMIBVIEW == rc)
246
rc = SNMP_ERR_NOERROR;
249
* get data, iff necessary
250
* clear return value iff errors
252
if(SNMP_ERR_NOERROR == rc) {
253
if(ii->get_data && best_val.val) {
254
rc = ii->get_data(ii->user_ctx, &best_ctx, &best_val);
255
if(SNMP_ERR_NOERROR != rc) {
256
snmp_log(LOG_ERR, "bad rc %d from get_data\n", rc);
261
else if(SNMP_ENDOFMIBVIEW != rc) {
262
snmp_log(LOG_ERR, "bad rc %d from get_next\n", rc);
267
* if we have a saved loop ctx, clean it up
269
if((best_ctx.val != NULL) && (best_ctx.val != loop_ctx.val) &&
270
(ii->cleanup_loop_ctx))
271
ii->cleanup_loop_ctx(ii->user_ctx,&best_ctx);
276
if(ii->cleanup_loop_ctx)
277
ii->cleanup_loop_ctx(ii->user_ctx,&loop_ctx);
279
DEBUGMSGT(("container_iterator:results"," returning %p\n", best_val.val));
283
/**********************************************************************
287
**********************************************************************/
289
_iterator_free(iterator_info *ii)
291
DEBUGMSGT(("container_iterator",">%s\n", "_iterator_free"));
297
ii->free_user_ctx(ii->user_ctx,ii->user_ctx);
303
_iterator_find(iterator_info *ii, const void *data)
305
DEBUGMSGT(("container_iterator",">%s\n", "_iterator_find"));
307
if((NULL == ii) || (NULL == data))
310
return _iterator_get(ii, data);
314
_iterator_find_next(iterator_info *ii, const void *data)
316
DEBUGMSGT(("container_iterator",">%s\n", "_iterator_find_next"));
321
return _iterator_get_next(ii, data);
325
_iterator_insert(iterator_info *ii, const void *data)
327
DEBUGMSGT(("container_iterator",">%s\n", "_iterator_insert"));
332
if(NULL == ii->insert_data)
335
return ii->insert_data(ii->user_ctx, data);
339
_iterator_remove(iterator_info *ii, const void *data)
341
DEBUGMSGT(("container_iterator",">%s\n", "_iterator_remove"));
346
if(NULL == ii->remove_data)
349
return ii->remove_data(ii->user_ctx, data);
353
_iterator_release(iterator_info *ii, const void *data)
355
DEBUGMSGT(("container_iterator",">%s\n", "_iterator_release"));
360
if(NULL == ii->release_data)
363
return ii->release_data(ii->user_ctx, data);
367
_iterator_size(iterator_info *ii)
370
int rc = SNMP_ERR_NOERROR;
371
netsnmp_ref_void loop_ctx = { NULL };
372
netsnmp_ref_void tmp = { NULL };
374
DEBUGMSGT(("container_iterator",">%s\n", "_iterator_size"));
379
if(NULL != ii->get_size)
380
return ii->get_size(ii->user_ctx);
383
* no get_size. loop and count ourselves
385
if(ii->init_loop_ctx)
386
ii->init_loop_ctx(ii->user_ctx, &loop_ctx);
388
for( rc = ii->get_first(ii->user_ctx, &loop_ctx, &tmp);
390
rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp) )
393
if(ii->cleanup_loop_ctx)
394
ii->cleanup_loop_ctx(ii->user_ctx,&loop_ctx);
400
_iterator_for_each(iterator_info *ii, netsnmp_container_obj_func *f,
403
int rc = SNMP_ERR_NOERROR;
404
netsnmp_ref_void loop_ctx = { NULL };
405
netsnmp_ref_void tmp = { NULL };
407
DEBUGMSGT(("container_iterator",">%s\n", "_iterator_foreach"));
412
if(ii->init_loop_ctx)
413
ii->init_loop_ctx(ii->user_ctx, &loop_ctx);
415
for( rc = ii->get_first(ii->user_ctx, &loop_ctx, &tmp);
417
rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp) )
420
if(ii->cleanup_loop_ctx)
421
ii->cleanup_loop_ctx(ii->user_ctx,&loop_ctx);
424
/**********************************************************************
428
netsnmp_container_iterator_get(void *iterator_user_ctx,
429
netsnmp_container_compare * compare,
430
Netsnmp_Iterator_Loop_Key * get_first,
431
Netsnmp_Iterator_Loop_Key * get_next,
432
Netsnmp_Iterator_Loop_Data * get_data,
433
Netsnmp_Iterator_Ctx_Dup * save_pos,
434
Netsnmp_Iterator_Ctx * init_loop_ctx,
435
Netsnmp_Iterator_Ctx * cleanup_loop_ctx,
436
Netsnmp_Iterator_Data * free_user_ctx,
444
if(get_data && ! save_pos) {
445
snmp_log(LOG_ERR, "save_pos required with get_data\n");
452
ii = SNMP_MALLOC_TYPEDEF(iterator_info);
454
snmp_log(LOG_ERR, "couldn't allocate memory\n");
459
* init container structure with iterator functions
461
ii->c.cfree = (netsnmp_container_rc*)_iterator_free;
462
ii->c.compare = compare;
463
ii->c.get_size = (netsnmp_container_size*)_iterator_size;
465
ii->c.insert = (netsnmp_container_op*)_iterator_insert;
466
ii->c.remove = (netsnmp_container_op*)_iterator_remove;
467
/* ii->c.release = (netsnmp_container_op*)_iterator_release; */
468
ii->c.find = (netsnmp_container_rtn*)_iterator_find;
469
ii->c.find_next = (netsnmp_container_rtn*)_iterator_find_next;
470
ii->c.get_subset = NULL;
471
ii->c.get_iterator = NULL;
472
ii->c.for_each = (netsnmp_container_func*)_iterator_for_each;
475
* init iterator structure with user functions
477
ii->get_first = get_first;
478
ii->get_next = get_next;
479
ii->get_data = get_data;
480
ii->save_pos = save_pos;
481
ii->init_loop_ctx = init_loop_ctx;
482
ii->cleanup_loop_ctx = cleanup_loop_ctx;
483
ii->free_user_ctx = free_user_ctx;
486
ii->user_ctx = iterator_user_ctx;
488
return (netsnmp_container*)ii;
492
netsnmp_container_iterator_set_data_cb(netsnmp_container *c,
493
Netsnmp_Iterator_Data * insert_data,
494
Netsnmp_Iterator_Data * remove_data,
495
Netsnmp_Iterator_Op * get_size)
497
iterator_info *ii = (iterator_info *)c;
501
ii->insert_data = insert_data;
502
ii->remove_data = remove_data;
503
ii->get_size = get_size;