1 : #ifndef NETSNMP_CONTAINER_H
2 : #define NETSNMP_CONTAINER_H
3 :
4 : /*
5 : * $Id: container.h 13803 2005-12-04 18:43:04Z rstory $
6 : *
7 : * WARNING: This is a recently created file, and all of it's contents are
8 : * subject to change at any time.
9 : *
10 : * A basic container template. A generic way for code to store and
11 : * retrieve data. Allows for interchangable storage algorithms.
12 : */
13 : #ifndef NET_SNMP_CONFIG_H
14 : #error "Please include <net-snmp/net-snmp-config.h> before this file"
15 : #endif
16 :
17 : #include <net-snmp/types.h>
18 : #include <net-snmp/library/factory.h>
19 : #include <net-snmp/library/snmp_logging.h>
20 :
21 : #ifdef __cplusplus
22 : extern "C" {
23 : #endif
24 :
25 : /*************************************************************************
26 : *
27 : * function pointer definitions
28 : *
29 : *************************************************************************/
30 : struct netsnmp_iterator_s; /** forward declare */
31 : struct netsnmp_container_s; /** forward declare */
32 :
33 : /*
34 : * function returning an int for an operation on a container
35 : */
36 : typedef int (netsnmp_container_option)(struct netsnmp_container_s *,
37 : int set, u_int flags);
38 :
39 : /*
40 : * function returning an int for an operation on a container
41 : */
42 : typedef int (netsnmp_container_rc)(struct netsnmp_container_s *);
43 :
44 : /*
45 : * function returning an iterator for a container
46 : */
47 : typedef struct netsnmp_iterator_s * (netsnmp_container_it)
48 : (struct netsnmp_container_s *);
49 :
50 : /*
51 : * function returning a size_t for an operation on a container
52 : */
53 : typedef size_t (netsnmp_container_size)(struct netsnmp_container_s *);
54 :
55 : /*
56 : * function returning an int for an operation on an object and
57 : * a container
58 : */
59 : typedef int (netsnmp_container_op)(struct netsnmp_container_s *,
60 : const void *data);
61 :
62 : /*
63 : * function returning an oject for an operation on an object and a
64 : * container
65 : */
66 : typedef void * (netsnmp_container_rtn)(struct netsnmp_container_s *,
67 : const void *data);
68 :
69 : /*
70 : * function with no return which acts on an object
71 : */
72 : typedef void (netsnmp_container_obj_func)(void *data, void *context);
73 :
74 : /*
75 : * function with no return which calls a function on an object
76 : */
77 : typedef void (netsnmp_container_func)(struct netsnmp_container_s *,
78 : netsnmp_container_obj_func *,
79 : void *context);
80 :
81 : /*
82 : * function returning an array of objects for an operation on an
83 : * ojbect and a container
84 : */
85 : typedef netsnmp_void_array * (netsnmp_container_set)
86 : (struct netsnmp_container_s *, void *data);
87 :
88 : /*
89 : * function returning an int for a comparison between two objects
90 : */
91 : typedef int (netsnmp_container_compare)(const void *lhs,
92 : const void *rhs);
93 :
94 : /*************************************************************************
95 : *
96 : * Basic container
97 : *
98 : *************************************************************************/
99 : typedef struct netsnmp_container_s {
100 :
101 : /*
102 : * pointer for container implementation
103 : */
104 : void * container_data;
105 :
106 : /*
107 : * returns the number of items in a container
108 : */
109 : netsnmp_container_size *get_size;
110 :
111 : /*
112 : * initialize a container
113 : */
114 : netsnmp_container_rc *init;
115 :
116 : /*
117 : * release memory used by a container.
118 : *
119 : * Note: if your data structures contained allocated
120 : * memory, you are responsible for releasing that
121 : * memory before calling this function!
122 : */
123 : netsnmp_container_rc *cfree;
124 :
125 : /*
126 : * add an entry to the container
127 : */
128 : netsnmp_container_op *insert;
129 :
130 : /*
131 : * remove an entry from the container
132 : */
133 : netsnmp_container_op *remove;
134 :
135 : /*
136 : * release memory for an entry from the container
137 : */
138 : netsnmp_container_op *release;
139 :
140 : /*
141 : * Note: do not change the key! If you need to
142 : * change a key, remove the entry, change the key,
143 : * and the re-add the entry.
144 : */
145 :
146 : /*
147 : * find the entry in the container with the same key
148 : *
149 : */
150 : netsnmp_container_rtn *find;
151 :
152 : /*
153 : * find the entry in the container with the next highest key
154 : *
155 : * If the key is NULL, return the first item in the container.
156 : */
157 : netsnmp_container_rtn *find_next;
158 :
159 : /*
160 : * find all entries in the container which match the partial key
161 : * returns allocated memory (netsnmp_void_array). User is responsible
162 : * for releasing this memory (free(array->array), free(array)).
163 : * DO NOT FREE ELEMENTS OF THE ARRAY, because they are the same pointers
164 : * stored in the container.
165 : */
166 : netsnmp_container_set *get_subset;
167 :
168 : /*
169 : * function to return an iterator for the container
170 : */
171 : netsnmp_container_it *get_iterator;
172 :
173 : /*
174 : * function to call another function for each object in the container
175 : */
176 : netsnmp_container_func *for_each;
177 :
178 : /*
179 : * specialized version of for_each used to optimize cleanup.
180 : * clear the container, optionally calling a function for each item.
181 : */
182 : netsnmp_container_func *clear;
183 :
184 : /*
185 : * OPTIONAL function to filter inserts to the container
186 : * (intended for a secondary container, which only wants
187 : * a sub-set of the objects in the primary/parent container)
188 : * Returns:
189 : * 1 : filter matched (don't insert)
190 : * 0 : no match (insert)
191 : */
192 : netsnmp_container_op *insert_filter;
193 :
194 : /*
195 : * function to compare two object stored in the container.
196 : *
197 : * Returns:
198 : *
199 : * -1 LHS < RHS
200 : * 0 LHS = RHS
201 : * 1 LHS > RHS
202 : */
203 : netsnmp_container_compare *compare;
204 :
205 : /*
206 : * same as compare, but RHS will be a partial key
207 : */
208 : netsnmp_container_compare *ncompare;
209 :
210 : /*
211 : * function to set container options
212 : */
213 : netsnmp_container_option *options;
214 :
215 : /*
216 : * unique name for finding a particular container in a list
217 : */
218 : char *container_name;
219 :
220 : /*
221 : * sort count, for iterators to track (insert/delete
222 : * bumps coutner, invalidates iterator
223 : */
224 : u_long sync;
225 :
226 : /*
227 : * containers can contain other containers (additional indexes)
228 : */
229 : struct netsnmp_container_s *next, *prev;
230 :
231 : } netsnmp_container;
232 :
233 : /*
234 : * initialize/free a container of container factories. used by
235 : * netsnmp_container_find* functions.
236 : */
237 : void netsnmp_container_init_list(void);
238 : void netsnmp_container_free_list(void);
239 :
240 : /*
241 : * register a new container factory
242 : */
243 : int netsnmp_container_register_with_compare(const char* name,
244 : netsnmp_factory *f,
245 : netsnmp_container_compare *c);
246 : int netsnmp_container_register(const char* name, netsnmp_factory *f);
247 :
248 : /*
249 : * search for and create a container from a list of types or a
250 : * specific type.
251 : */
252 : netsnmp_container * netsnmp_container_find(const char *type_list);
253 : netsnmp_container * netsnmp_container_get(const char *type);
254 :
255 : /*
256 : * utility routines
257 : */
258 : void netsnmp_container_add_index(netsnmp_container *primary,
259 : netsnmp_container *new_index);
260 :
261 :
262 : netsnmp_factory *netsnmp_container_get_factory(const char *type);
263 :
264 : /*
265 : * common comparison routines
266 : */
267 : /** first data element is a 'netsnmp_index' */
268 : int netsnmp_compare_netsnmp_index(const void *lhs, const void *rhs);
269 : int netsnmp_ncompare_netsnmp_index(const void *lhs, const void *rhs);
270 :
271 : /** first data element is a 'char *' */
272 : int netsnmp_compare_cstring(const void * lhs, const void * rhs);
273 : int netsnmp_ncompare_cstring(const void * lhs, const void * rhs);
274 :
275 : /** useful for octet strings */
276 : int netsnmp_compare_mem(const char * lhs, size_t lhs_len,
277 : const char * rhs, size_t rhs_len);
278 :
279 : /** for_each callback to call free on data item */
280 : void netsnmp_container_simple_free(void *data, void *context);
281 :
282 : /*
283 : * container optionflags
284 : */
285 : #define CONTAINER_KEY_ALLOW_DUPLICATES 0x00000001
286 : #define CONTAINER_KEY_UNSORTED 0x00000002
287 :
288 : #define CONTAINER_SET_OPTIONS(x,o,rc) do { \
289 : if (NULL==(x)->options) \
290 : rc = -1; \
291 : else \
292 : rc = (x)->options(x, 1, o); \
293 : } while(0)
294 :
295 : #define CONTAINER_CHECK_OPTION(x,o,rc) do { \
296 : if (NULL==(x)->options) \
297 : rc = -1; \
298 : else \
299 : rc = (x)->options(x,0, o); \
300 : } while(0)
301 :
302 :
303 : /*
304 : * useful macros (x = container; k = key; c = user context)
305 : */
306 : #define CONTAINER_FIRST(x) (x)->find_next(x,NULL)
307 : #define CONTAINER_FIND(x,k) (x)->find(x,k)
308 : #define CONTAINER_NEXT(x,k) (x)->find_next(x,k)
309 : /*
310 : * GET_SUBSET returns allocated memory (netsnmp_void_array). User is responsible
311 : * for releasing this memory (free(array->array), free(array)).
312 : * DO NOT FREE ELEMENTS OF THE ARRAY, because they are the same pointers
313 : * stored in the container.
314 : */
315 : #define CONTAINER_GET_SUBSET(x,k) (x)->get_subset(x,k)
316 : #define CONTAINER_SIZE(x) (x)->get_size(x)
317 : #define CONTAINER_ITERATOR(x) (x)->get_iterator(x)
318 : #define CONTAINER_COMPARE(x,l,r) (x)->compare(l,r)
319 : #define CONTAINER_FOR_EACH(x,f,c) (x)->for_each(x,f,c)
320 :
321 : /*
322 : * if you are getting multiple definitions of these three
323 : * inline functions, you most likely have optimizations turned off.
324 : * Either turn them back on, or define NETSNMP_NO_INLINE
325 : */
326 : #ifndef NETSNMP_USE_INLINE /* default is to inline */
327 : /*
328 : * insert k into all containers
329 : */
330 : int CONTAINER_INSERT(netsnmp_container *x, const void *k);
331 :
332 : /*
333 : * check if k is in any container and insert it into all if not
334 : */
335 : int CONTAINER_TRY_INSERT(netsnmp_container *x, const void *k);
336 :
337 : /*
338 : * remove k from all containers
339 : */
340 : int CONTAINER_REMOVE(netsnmp_container *x, const void *k);
341 :
342 : /*
343 : * clear all containers. When clearing the *first* container, and
344 : * *only* the first container, call the function f for each item.
345 : * After calling this function, all containers should be empty.
346 : */
347 : void CONTAINER_CLEAR(netsnmp_container *x, netsnmp_container_obj_func *f,
348 : void *c);
349 : /*
350 : * free all containers
351 : */
352 : int CONTAINER_FREE(netsnmp_container *x);
353 : #else
354 : /*------------------------------------------------------------------
355 : * These functions should EXACTLY match the function version in
356 : * container.c. If you change one, change them both.
357 : */
358 : NETSNMP_STATIC_INLINE /* gcc docs recommend static w/inline */
359 : int CONTAINER_INSERT(netsnmp_container *x, const void *k)
360 0 : {
361 0 : int rc2, rc = 0;
362 :
363 : /** start at first container */
364 0 : while(x->prev)
365 0 : x = x->prev;
366 0 : for(; x; x = x->next) {
367 0 : if ((NULL != x->insert_filter) &&
368 : (x->insert_filter(x,k) == 1))
369 0 : continue;
370 0 : rc2 = x->insert(x,k);
371 0 : if (rc2) {
372 0 : snmp_log(LOG_ERR,"error on subcontainer '%s' insert (%d)\n",
373 : x->container_name ? x->container_name : "", rc2);
374 0 : rc = rc2;
375 : }
376 : }
377 0 : return rc;
378 : }
379 :
380 :
381 : NETSNMP_STATIC_INLINE /* gcc docs recommend static w/inline */
382 : int CONTAINER_TRY_INSERT(netsnmp_container *x, const void *k)
383 0 : {
384 0 : const void *res = NULL;
385 :
386 : netsnmp_container *start;
387 : /** start at first container */
388 0 : while(x->prev)
389 0 : x = x->prev;
390 :
391 0 : start = x;
392 :
393 0 : for(; x; x = x->next) {
394 0 : if ((NULL != x->insert_filter) &&
395 : (x->insert_filter(x,k) == 1))
396 0 : continue;
397 0 : res = x->find(x,k);
398 0 : if (res) {
399 0 : return -1;
400 : }
401 : }
402 0 : return CONTAINER_INSERT(start, k);
403 : }
404 :
405 : /*------------------------------------------------------------------
406 : * These functions should EXACTLY match the function version in
407 : * container.c. If you change one, change them both.
408 : */
409 : NETSNMP_STATIC_INLINE /* gcc docs recommend static w/inline */
410 : int CONTAINER_REMOVE(netsnmp_container *x, const void *k)
411 0 : {
412 0 : int rc2, rc = 0;
413 :
414 : /** start at last container */
415 0 : while(x->next)
416 0 : x = x->next;
417 0 : while(x) {
418 0 : rc2 = x->remove(x,k);
419 : /** ignore remove errors if there is a filter in place */
420 0 : if ((rc2) && (NULL == x->insert_filter)) {
421 0 : snmp_log(LOG_ERR,"error on subcontainer remove (%d)\n", rc2);
422 0 : rc = rc2;
423 : }
424 0 : x = x->prev;
425 :
426 : }
427 0 : return rc;
428 : }
429 :
430 : /*------------------------------------------------------------------
431 : * These functions should EXACTLY match the function version in
432 : * container.c. If you change one, change them both.
433 : */
434 : NETSNMP_STATIC_INLINE /* gcc docs recommend static w/inline */
435 : int CONTAINER_FREE(netsnmp_container *x)
436 0 : {
437 0 : int rc2, rc = 0;
438 :
439 : /** start at last container */
440 0 : while(x->next)
441 0 : x = x->next;
442 0 : while(x) {
443 : netsnmp_container *tmp;
444 0 : tmp = x->prev;
445 0 : if (NULL != x->container_name)
446 0 : SNMP_FREE(x->container_name);
447 0 : rc2 = x->cfree(x);
448 0 : if (rc2) {
449 0 : snmp_log(LOG_ERR,"error on subcontainer cfree (%d)\n", rc2);
450 0 : rc = rc2;
451 : }
452 0 : x = tmp;
453 : }
454 0 : return rc;
455 : }
456 :
457 : /*------------------------------------------------------------------
458 : * These functions should EXACTLY match the function version in
459 : * container.c. If you change one, change them both.
460 : */
461 : /*
462 : * clear all containers. When clearing the *first* container, and
463 : * *only* the first container, call the function f for each item.
464 : * After calling this function, all containers should be empty.
465 : */
466 : NETSNMP_STATIC_INLINE /* gcc docs recommend static w/inline */
467 : void CONTAINER_CLEAR(netsnmp_container *x, netsnmp_container_obj_func *f,
468 : void *c)
469 0 : {
470 : /** start at last container */
471 0 : while(x->next)
472 0 : x = x->next;
473 0 : while(x->prev) {
474 0 : x->clear(x, NULL, c);
475 0 : x = x->prev;
476 : }
477 0 : x->clear(x, f, c);
478 0 : }
479 :
480 : /*------------------------------------------------------------------
481 : * These functions should EXACTLY match the function version in
482 : * container.c. If you change one, change them both.
483 : */
484 : /*
485 : * Find a sub-container with the given name
486 : */
487 : NETSNMP_STATIC_INLINE /* gcc docs recommend static w/inline */
488 : netsnmp_container *SUBCONTAINER_FIND(netsnmp_container *x,
489 : const char* name)
490 0 : {
491 0 : if ((NULL == x) || (NULL == name))
492 0 : return NULL;
493 :
494 : /** start at first container */
495 0 : while(x->prev)
496 0 : x = x->prev;
497 0 : while(x) {
498 0 : if ((NULL != x->container_name) &&
499 : (0 == strcmp(name,x->container_name)))
500 0 : break;
501 0 : x = x->next;
502 : }
503 0 : return x;
504 : }
505 :
506 : #endif
507 :
508 : /*************************************************************************
509 : *
510 : * container iterator
511 : *
512 : *************************************************************************/
513 : /*
514 : * function returning an int for an operation on an iterator
515 : */
516 : typedef int (netsnmp_iterator_rc)(struct netsnmp_iterator_s *);
517 :
518 : /*
519 : * function returning an oject for an operation on an iterator
520 : */
521 : typedef void * (netsnmp_iterator_rtn)(struct netsnmp_iterator_s *);
522 :
523 :
524 : /*
525 : * iterator structure
526 : */
527 : typedef struct netsnmp_iterator_s {
528 :
529 : netsnmp_container *container;
530 :
531 : /*
532 : * sync from container when iterator created. used to invalidate
533 : * the iterator when the container changes.
534 : */
535 : u_long sync;
536 :
537 : /*
538 : * reset iterator position to beginning of container.
539 : */
540 : netsnmp_iterator_rc *reset;
541 :
542 : /*
543 : * release iterator and memory it uses
544 : */
545 : netsnmp_iterator_rc *release;
546 :
547 : /*
548 : * first, last and current DO NOT advance the iterator
549 : */
550 : netsnmp_iterator_rtn *first;
551 : netsnmp_iterator_rtn *curr;
552 : netsnmp_iterator_rtn *last;
553 :
554 : netsnmp_iterator_rtn *next;
555 :
556 : } netsnmp_iterator;
557 :
558 :
559 : #define ITERATOR_FIRST(x) x->first(x)
560 : #define ITERATOR_NEXT(x) x->next(x)
561 : #define ITERATOR_LAST(x) x->last(x)
562 : #define ITERATOR_RELEASE(x) do { x->release(x); x = NULL; } while(0)
563 :
564 : #ifdef __cplusplus
565 : }
566 : #endif
567 :
568 : #endif /** NETSNMP_CONTAINER_H */
|