00001 /* 00002 * $Id$ 00003 * 00004 */ 00005 00006 #include <net-snmp/net-snmp-config.h> 00007 00008 #include <stdio.h> 00009 #if HAVE_STDLIB_H 00010 #include <stdlib.h> 00011 #endif 00012 #if HAVE_MALLOC_H 00013 #include <malloc.h> 00014 #endif 00015 #include <sys/types.h> 00016 #if HAVE_STRING_H 00017 #include <string.h> 00018 #else 00019 #include <strings.h> 00020 #endif 00021 00022 #include <net-snmp/net-snmp-includes.h> 00023 #include <net-snmp/types.h> 00024 #include <net-snmp/library/snmp_api.h> 00025 #include <net-snmp/library/container.h> 00026 #include <net-snmp/library/tools.h> 00027 #include <net-snmp/library/snmp_assert.h> 00028 00029 #include <net-snmp/library/container_iterator.h> 00030 00039 typedef struct iterator_info_s { 00040 /* 00041 * netsnmp_conatiner must be first 00042 */ 00043 netsnmp_container c; 00044 00045 /* 00046 * iterator data 00047 */ 00048 Netsnmp_Iterator_Loop_Key *get_first; 00049 Netsnmp_Iterator_Loop_Key *get_next; 00050 00051 Netsnmp_Iterator_Loop_Data *get_data; 00052 00053 Netsnmp_Iterator_Data *free_user_ctx; 00054 00055 Netsnmp_Iterator_Ctx *init_loop_ctx; 00056 Netsnmp_Iterator_Ctx *cleanup_loop_ctx; 00057 Netsnmp_Iterator_Ctx_Dup *save_pos; 00058 00059 Netsnmp_Iterator_Data * release_data; 00060 Netsnmp_Iterator_Data * insert_data; 00061 Netsnmp_Iterator_Data * remove_data; 00062 00063 Netsnmp_Iterator_Op * get_size; 00064 00065 int sorted; 00066 00069 void *user_ctx; 00070 } iterator_info; 00071 00072 /********************************************************************** 00073 * 00074 * iterator 00075 * 00076 **********************************************************************/ 00077 static void * 00078 _iterator_get(iterator_info *ii, const void *key) 00079 { 00080 int cmp, rc = SNMP_ERR_NOERROR; 00081 netsnmp_ref_void best = { NULL }; 00082 netsnmp_ref_void tmp = { NULL }; 00083 netsnmp_ref_void loop_ctx = { NULL }; 00084 00085 DEBUGMSGT(("container_iterator",">%s\n", "_iterator_get")); 00086 00087 if(ii->init_loop_ctx) 00088 ii->init_loop_ctx(ii->user_ctx, &loop_ctx); 00089 00090 rc = ii->get_first(ii->user_ctx, &loop_ctx, &tmp); 00091 if(SNMP_ERR_NOERROR != rc) { 00092 if(SNMP_ENDOFMIBVIEW != rc) 00093 snmp_log(LOG_ERR, "bad rc %d from get_next\n", rc); 00094 } 00095 else { 00096 for( ; 00097 (NULL != tmp.val) && (SNMP_ERR_NOERROR == rc); 00098 rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp) ) { 00099 00100 /* 00101 * if keys are equal, we are done. 00102 */ 00103 cmp = ii->c.compare(tmp.val, key); 00104 if(0 == cmp) { 00105 best.val = tmp.val; 00106 if(ii->get_data) 00107 ii->get_data(ii->user_ctx, &loop_ctx, &best); 00108 } 00109 00110 /* 00111 * if data is sorted and if key is greater, 00112 * we are done (not found) 00113 */ 00114 if((cmp > 0) && ii->sorted) 00115 break; 00116 } /* end for */ 00117 } 00118 00119 if(ii->cleanup_loop_ctx) 00120 ii->cleanup_loop_ctx(ii->user_ctx,&loop_ctx); 00121 00122 return best.val; 00123 } 00124 00132 static void * 00133 _iterator_get_next(iterator_info *ii, const void *key) 00134 { 00135 int cmp, rc = SNMP_ERR_NOERROR; 00136 netsnmp_ref_void best_val = { NULL }; 00137 netsnmp_ref_void best_ctx = { NULL }; 00138 netsnmp_ref_void tmp = { NULL }; 00139 netsnmp_ref_void loop_ctx = { NULL }; 00140 00141 DEBUGMSGT(("container_iterator",">%s\n", "_iterator_get_next")); 00142 00143 /* 00144 * initialize loop context 00145 */ 00146 if(ii->init_loop_ctx) 00147 ii->init_loop_ctx(ii->user_ctx, &loop_ctx); 00148 00149 /* 00150 * get first item 00151 */ 00152 rc = ii->get_first(ii->user_ctx, &loop_ctx, &tmp); 00153 if(SNMP_ERR_NOERROR == rc) { 00154 /* 00155 * special case: if key is null, find the first item. 00156 * this is each if the container is sorted, since we're 00157 * already done! Otherwise, get the next item for the 00158 * first comparison in the loop below. 00159 */ 00160 if (NULL == key) { 00161 if(ii->get_data) 00162 ii->save_pos(ii->user_ctx, &loop_ctx, &best_ctx, 1); 00163 best_val.val = tmp.val; 00164 if(ii->sorted) 00165 tmp.val = NULL; /* so we skip for loop */ 00166 else 00167 rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp); 00168 } 00169 /* 00170 * loop over remaining items 00171 */ 00172 for( ; 00173 (NULL != tmp.val) && (rc == SNMP_ERR_NOERROR); 00174 rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp) ) { 00175 00176 /* 00177 * if we have a key, this is a get-next, and we need to compare 00178 * the key to the tmp value to see if the tmp value is greater 00179 * than the key, but less than any previous match. 00180 * 00181 * if there is no key, this is a get-first, and we need to 00182 * compare the best value agains the tmp value to see if the 00183 * tmp value is lesser than the best match. 00184 */ 00185 if(key) /* get next */ 00186 cmp = ii->c.compare(tmp.val, key); 00187 else { /* get first */ 00188 /* 00189 * best value and tmp value should never be equal, 00190 * otherwise we'd be comparing a pointer to itself. 00191 * (see note on context reuse in comments above function. 00192 */ 00193 if(best_val.val == tmp.val) { 00194 snmp_log(LOG_ERR,"illegal reuse of data context in " 00195 "container_iterator\n"); 00196 rc = SNMP_ERR_GENERR; 00197 break; 00198 } 00199 cmp = ii->c.compare(best_val.val, tmp.val); 00200 } 00201 if(cmp > 0) { 00202 /* 00203 * if we don't have a key (get-first) or a current best match, 00204 * then the comparison above is all we need to know that 00205 * tmp is the best match. otherwise, compare against the 00206 * current best match. 00207 */ 00208 if((NULL == key) || (NULL == best_val.val) || 00209 ((cmp=ii->c.compare(tmp.val, best_val.val)) < 0) ) { 00210 DEBUGMSGT(("container_iterator:results"," best match\n")); 00211 best_val.val = tmp.val; 00212 if(ii->get_data) 00213 ii->save_pos(ii->user_ctx, &loop_ctx, &best_ctx, 1); 00214 } 00215 } 00216 else if((cmp == 0) && ii->sorted && key) { 00217 /* 00218 * if keys are equal and container is sorted, then we know 00219 * the next key will be the one we want. 00220 * NOTE: if no vars, treat as generr, since we 00221 * went past the end of the container when we know 00222 * the next item is the one we want. (IGN-A) 00223 */ 00224 rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp); 00225 if(SNMP_ERR_NOERROR == rc) { 00226 best_val.val = tmp.val; 00227 if(ii->get_data) 00228 ii->save_pos(ii->user_ctx, &loop_ctx, &best_ctx, 1); 00229 } 00230 else if(SNMP_ENDOFMIBVIEW == rc) 00231 rc = SNMPERR_GENERR; /* not found */ 00232 break; 00233 } 00234 00235 } /* end for */ 00236 } 00237 00238 /* 00239 * no vars is ok, except as noted above (IGN-A) 00240 */ 00241 if(SNMP_ENDOFMIBVIEW == rc) 00242 rc = SNMP_ERR_NOERROR; 00243 00244 /* 00245 * get data, iff necessary 00246 * clear return value iff errors 00247 */ 00248 if(SNMP_ERR_NOERROR == rc) { 00249 if(ii->get_data && best_val.val) { 00250 rc = ii->get_data(ii->user_ctx, &best_ctx, &best_val); 00251 if(SNMP_ERR_NOERROR != rc) { 00252 snmp_log(LOG_ERR, "bad rc %d from get_data\n", rc); 00253 best_val.val = NULL; 00254 } 00255 } 00256 } 00257 else if(SNMP_ENDOFMIBVIEW != rc) { 00258 snmp_log(LOG_ERR, "bad rc %d from get_next\n", rc); 00259 best_val.val = NULL; 00260 } 00261 00262 /* 00263 * if we have a saved loop ctx, clean it up 00264 */ 00265 if((best_ctx.val != NULL) && (best_ctx.val != loop_ctx.val) && 00266 (ii->cleanup_loop_ctx)) 00267 ii->cleanup_loop_ctx(ii->user_ctx,&best_ctx); 00268 00269 /* 00270 * clean up loop ctx 00271 */ 00272 if(ii->cleanup_loop_ctx) 00273 ii->cleanup_loop_ctx(ii->user_ctx,&loop_ctx); 00274 00275 DEBUGMSGT(("container_iterator:results"," returning %p\n", best_val.val)); 00276 return best_val.val; 00277 } 00278 00279 /********************************************************************** 00280 * 00281 * container 00282 * 00283 **********************************************************************/ 00284 static void 00285 _iterator_free(iterator_info *ii) 00286 { 00287 DEBUGMSGT(("container_iterator",">%s\n", "_iterator_free")); 00288 00289 if(NULL == ii) 00290 return; 00291 00292 if(ii->user_ctx) 00293 ii->free_user_ctx(ii->user_ctx,ii->user_ctx); 00294 00295 free(ii); 00296 } 00297 00298 static void * 00299 _iterator_find(iterator_info *ii, const void *data) 00300 { 00301 DEBUGMSGT(("container_iterator",">%s\n", "_iterator_find")); 00302 00303 if((NULL == ii) || (NULL == data)) 00304 return NULL; 00305 00306 return _iterator_get(ii, data); 00307 } 00308 00309 static void * 00310 _iterator_find_next(iterator_info *ii, const void *data) 00311 { 00312 DEBUGMSGT(("container_iterator",">%s\n", "_iterator_find_next")); 00313 00314 if(NULL == ii) 00315 return NULL; 00316 00317 return _iterator_get_next(ii, data); 00318 } 00319 00320 static int 00321 _iterator_insert(iterator_info *ii, const void *data) 00322 { 00323 DEBUGMSGT(("container_iterator",">%s\n", "_iterator_insert")); 00324 00325 if(NULL == ii) 00326 return -1; 00327 00328 if(NULL == ii->insert_data) 00329 return -1; 00330 00331 return ii->insert_data(ii->user_ctx, data); 00332 } 00333 00334 static int 00335 _iterator_remove(iterator_info *ii, const void *data) 00336 { 00337 DEBUGMSGT(("container_iterator",">%s\n", "_iterator_remove")); 00338 00339 if(NULL == ii) 00340 return -1; 00341 00342 if(NULL == ii->remove_data) 00343 return -1; 00344 00345 return ii->remove_data(ii->user_ctx, data); 00346 } 00347 00348 static int 00349 _iterator_release(iterator_info *ii, const void *data) 00350 { 00351 DEBUGMSGT(("container_iterator",">%s\n", "_iterator_release")); 00352 00353 if(NULL == ii) 00354 return -1; 00355 00356 if(NULL == ii->release_data) 00357 return -1; 00358 00359 return ii->release_data(ii->user_ctx, data); 00360 } 00361 00362 static size_t 00363 _iterator_size(iterator_info *ii) 00364 { 00365 size_t count = 0; 00366 int rc = SNMP_ERR_NOERROR; 00367 netsnmp_ref_void loop_ctx = { NULL }; 00368 netsnmp_ref_void tmp = { NULL }; 00369 00370 DEBUGMSGT(("container_iterator",">%s\n", "_iterator_size")); 00371 00372 if(NULL == ii) 00373 return -1; 00374 00375 if(NULL != ii->get_size) 00376 return ii->get_size(ii->user_ctx); 00377 00378 /* 00379 * no get_size. loop and count ourselves 00380 */ 00381 if(ii->init_loop_ctx) 00382 ii->init_loop_ctx(ii->user_ctx, &loop_ctx); 00383 00384 for( rc = ii->get_first(ii->user_ctx, &loop_ctx, &tmp); 00385 NULL != tmp.val; 00386 rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp) ) 00387 ++count; 00388 00389 if(ii->cleanup_loop_ctx) 00390 ii->cleanup_loop_ctx(ii->user_ctx,&loop_ctx); 00391 00392 return count; 00393 } 00394 00395 static void 00396 _iterator_for_each(iterator_info *ii, netsnmp_container_obj_func *f, 00397 void *ctx) 00398 { 00399 int rc = SNMP_ERR_NOERROR; 00400 netsnmp_ref_void loop_ctx = { NULL }; 00401 netsnmp_ref_void tmp = { NULL }; 00402 00403 DEBUGMSGT(("container_iterator",">%s\n", "_iterator_foreach")); 00404 00405 if(NULL == ii) 00406 return; 00407 00408 if(ii->init_loop_ctx) 00409 ii->init_loop_ctx(ii->user_ctx, &loop_ctx); 00410 00411 for( rc = ii->get_first(ii->user_ctx, &loop_ctx, &tmp); 00412 NULL != tmp.val; 00413 rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp) ) 00414 (*f) (tmp.val, ctx); 00415 00416 if(ii->cleanup_loop_ctx) 00417 ii->cleanup_loop_ctx(ii->user_ctx,&loop_ctx); 00418 } 00419 00420 static void 00421 _iterator_clear(netsnmp_container *container, netsnmp_container_obj_func *f, 00422 void *context) 00423 { 00424 snmp_log(LOG_WARNING,"clear is meaningless for iterator container.\n"); 00425 } 00426 00427 /********************************************************************** 00428 * 00429 */ 00430 netsnmp_container* 00431 netsnmp_container_iterator_get(void *iterator_user_ctx, 00432 netsnmp_container_compare * compare, 00433 Netsnmp_Iterator_Loop_Key * get_first, 00434 Netsnmp_Iterator_Loop_Key * get_next, 00435 Netsnmp_Iterator_Loop_Data * get_data, 00436 Netsnmp_Iterator_Ctx_Dup * save_pos, 00437 Netsnmp_Iterator_Ctx * init_loop_ctx, 00438 Netsnmp_Iterator_Ctx * cleanup_loop_ctx, 00439 Netsnmp_Iterator_Data * free_user_ctx, 00440 int sorted) 00441 { 00442 iterator_info *ii; 00443 00444 /* 00445 * sanity checks 00446 */ 00447 if(get_data && ! save_pos) { 00448 snmp_log(LOG_ERR, "save_pos required with get_data\n"); 00449 return NULL; 00450 } 00451 00452 /* 00453 * allocate memory 00454 */ 00455 ii = SNMP_MALLOC_TYPEDEF(iterator_info); 00456 if (NULL==ii) { 00457 snmp_log(LOG_ERR, "couldn't allocate memory\n"); 00458 return NULL; 00459 } 00460 00461 /* 00462 * init container structure with iterator functions 00463 */ 00464 ii->c.cfree = (netsnmp_container_rc*)_iterator_free; 00465 ii->c.compare = compare; 00466 ii->c.get_size = (netsnmp_container_size*)_iterator_size; 00467 ii->c.init = NULL; 00468 ii->c.insert = (netsnmp_container_op*)_iterator_insert; 00469 ii->c.remove = (netsnmp_container_op*)_iterator_remove; 00470 ii->c.release = (netsnmp_container_op*)_iterator_release; 00471 ii->c.find = (netsnmp_container_rtn*)_iterator_find; 00472 ii->c.find_next = (netsnmp_container_rtn*)_iterator_find_next; 00473 ii->c.get_subset = NULL; 00474 ii->c.get_iterator = NULL; 00475 ii->c.for_each = (netsnmp_container_func*)_iterator_for_each; 00476 ii->c.clear = _iterator_clear; 00477 00478 /* 00479 * init iterator structure with user functions 00480 */ 00481 ii->get_first = get_first; 00482 ii->get_next = get_next; 00483 ii->get_data = get_data; 00484 ii->save_pos = save_pos; 00485 ii->init_loop_ctx = init_loop_ctx; 00486 ii->cleanup_loop_ctx = cleanup_loop_ctx; 00487 ii->free_user_ctx = free_user_ctx; 00488 ii->sorted = sorted; 00489 00490 ii->user_ctx = iterator_user_ctx; 00491 00492 return (netsnmp_container*)ii; 00493 } 00494 00495 void 00496 netsnmp_container_iterator_set_data_cb(netsnmp_container *c, 00497 Netsnmp_Iterator_Data * insert_data, 00498 Netsnmp_Iterator_Data * remove_data, 00499 Netsnmp_Iterator_Op * get_size) 00500 { 00501 iterator_info *ii = (iterator_info *)c; 00502 if(NULL == ii) 00503 return; 00504 00505 ii->insert_data = insert_data; 00506 ii->remove_data = remove_data; 00507 ii->get_size = get_size; 00508 }
1.5.7.1
Last modified: Tuesday, 23-Dec-2025 17:22:04 UTC
For questions regarding web content and site functionality, please write to the net-snmp-users mail list.