~ubuntu-branches/ubuntu/trusty/net-snmp/trusty

« back to all changes in this revision

Viewing changes to snmplib/container_iterator.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2004-09-13 12:06:21 UTC
  • Revision ID: james.westby@ubuntu.com-20040913120621-g952ntonlleihcvm
Tags: upstream-5.1.1
ImportĀ upstreamĀ versionĀ 5.1.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: container_iterator.c,v 5.5.2.1 2003/12/18 20:25:29 nba Exp $
 
3
 *
 
4
 */
 
5
 
 
6
#include <net-snmp/net-snmp-config.h>
 
7
 
 
8
#include <stdio.h>
 
9
#if HAVE_STDLIB_H
 
10
#include <stdlib.h>
 
11
#endif
 
12
#if HAVE_MALLOC_H
 
13
#include <malloc.h>
 
14
#endif
 
15
#include <sys/types.h>
 
16
#if HAVE_STRING_H
 
17
#include <string.h>
 
18
#else
 
19
#include <strings.h>
 
20
#endif
 
21
 
 
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>
 
28
 
 
29
#include <net-snmp/library/container_iterator.h>
 
30
 
 
31
/** @typedef struct iterator_info_s iterator_info
 
32
 * Typedefs the iterator_info_s struct into iterator_info */
 
33
 
 
34
/** @struct iterator_info_s
 
35
    
 
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.
 
39
 
 
40
The iterator_info typedef can be used instead of directly
 
41
calling this struct if you would prefer.
 
42
*/
 
43
typedef struct iterator_info_s {
 
44
   /*
 
45
    * netsnmp_conatiner  must be first
 
46
    */
 
47
   netsnmp_container c;
 
48
 
 
49
   /*
 
50
    * iterator data
 
51
    */
 
52
   Netsnmp_Iterator_Loop_Key *get_first;
 
53
   Netsnmp_Iterator_Loop_Key *get_next;
 
54
   
 
55
   Netsnmp_Iterator_Loop_Data *get_data;
 
56
 
 
57
   Netsnmp_Iterator_Data *free_user_ctx;
 
58
   
 
59
   Netsnmp_Iterator_Ctx *init_loop_ctx;
 
60
   Netsnmp_Iterator_Ctx *cleanup_loop_ctx;
 
61
   Netsnmp_Iterator_Ctx_Dup *save_pos;
 
62
   
 
63
   Netsnmp_Iterator_Data * release_data;
 
64
   Netsnmp_Iterator_Data * insert_data;
 
65
   Netsnmp_Iterator_Data * remove_data;
 
66
 
 
67
   Netsnmp_Iterator_Op * get_size;
 
68
   
 
69
   int             sorted;
 
70
   
 
71
   /** This can be used by client handlers to store any
 
72
       information they need */
 
73
   void           *user_ctx;
 
74
} iterator_info;
 
75
 
 
76
/**********************************************************************
 
77
 *
 
78
 * iterator
 
79
 *
 
80
 **********************************************************************/
 
81
static void *
 
82
_iterator_get(iterator_info *ii, const void *key)
 
83
{
 
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 };
 
88
 
 
89
    DEBUGMSGT(("container_iterator",">%s\n", "_iterator_get"));
 
90
    
 
91
    if(ii->init_loop_ctx)
 
92
        ii->init_loop_ctx(ii->user_ctx, &loop_ctx);
 
93
    
 
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);
 
98
    }
 
99
    else {
 
100
        for( ;
 
101
             (NULL != tmp.val) && (SNMP_ERR_NOERROR == rc);
 
102
             rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp) ) {
 
103
            
 
104
            /*
 
105
             * if keys are equal, we are done.
 
106
             */
 
107
            cmp = ii->c.compare(tmp.val, key);
 
108
            if(0 == cmp) {
 
109
                best.val = tmp.val;
 
110
                if(ii->get_data)
 
111
                    ii->get_data(ii->user_ctx, &loop_ctx, &best);
 
112
            }
 
113
            
 
114
            /*
 
115
             * if data is sorted and if key is greater,
 
116
             * we are done (not found)
 
117
             */
 
118
            if((cmp > 0) && ii->sorted)
 
119
                break;
 
120
        } /* end for */
 
121
    }
 
122
    
 
123
    if(ii->cleanup_loop_ctx)
 
124
        ii->cleanup_loop_ctx(ii->user_ctx,&loop_ctx);
 
125
 
 
126
    return best.val;
 
127
}
 
128
 
 
129
/**
 
130
 *
 
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.
 
135
 */
 
136
static void *
 
137
_iterator_get_next(iterator_info *ii, const void *key)
 
138
{
 
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 };
 
144
 
 
145
    DEBUGMSGT(("container_iterator",">%s\n", "_iterator_get_next"));
 
146
    
 
147
    /*
 
148
     * initialize loop context
 
149
     */
 
150
    if(ii->init_loop_ctx)
 
151
        ii->init_loop_ctx(ii->user_ctx, &loop_ctx);
 
152
    
 
153
    /*
 
154
     * get first item
 
155
     */
 
156
    rc = ii->get_first(ii->user_ctx, &loop_ctx, &tmp);
 
157
    if(SNMP_ERR_NOERROR == rc) {
 
158
        /*
 
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.
 
163
         */
 
164
        if (NULL == key) {
 
165
            if(ii->get_data)
 
166
                ii->save_pos(ii->user_ctx, &loop_ctx, &best_ctx, 1);
 
167
            best_val.val = tmp.val;
 
168
            if(ii->sorted)
 
169
                tmp.val = NULL; /* so we skip for loop */
 
170
            else
 
171
                rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp);
 
172
        }
 
173
        /*
 
174
         * loop over remaining items
 
175
         */
 
176
        for( ;
 
177
             (NULL != tmp.val) && (rc == SNMP_ERR_NOERROR);
 
178
             rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp) ) {
 
179
            
 
180
            /*
 
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.
 
184
             *
 
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.
 
188
             */
 
189
            if(key) /* get next */
 
190
                cmp = ii->c.compare(tmp.val, key);
 
191
            else { /* get first */
 
192
                /*
 
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.
 
196
                 */
 
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;
 
201
                    break;
 
202
                }
 
203
                cmp = ii->c.compare(best_val.val, tmp.val);
 
204
            }
 
205
            if(cmp > 0) {
 
206
                /*
 
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.
 
211
                 */
 
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;
 
216
                    if(ii->get_data)
 
217
                        ii->save_pos(ii->user_ctx, &loop_ctx, &best_ctx, 1);
 
218
                }
 
219
            }
 
220
            else if((cmp == 0) && ii->sorted && key) {
 
221
                /*
 
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)
 
227
                 */
 
228
                rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp);
 
229
                if(SNMP_ERR_NOERROR == rc) {
 
230
                    best_val.val = tmp.val;
 
231
                    if(ii->get_data)
 
232
                        ii->save_pos(ii->user_ctx, &loop_ctx, &best_ctx, 1);
 
233
                }
 
234
                else if(SNMP_ENDOFMIBVIEW == rc)
 
235
                    rc = SNMPERR_GENERR; /* not found */
 
236
                break;
 
237
            }
 
238
            
 
239
        } /* end for */
 
240
    }
 
241
 
 
242
    /*
 
243
     * no vars is ok, except as noted above (IGN-A)
 
244
     */
 
245
    if(SNMP_ENDOFMIBVIEW == rc)
 
246
        rc = SNMP_ERR_NOERROR;
 
247
            
 
248
    /*
 
249
     * get data, iff necessary
 
250
     * clear return value iff errors
 
251
     */
 
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);
 
257
                best_val.val = NULL;
 
258
            }
 
259
        }
 
260
    }
 
261
    else if(SNMP_ENDOFMIBVIEW != rc) {
 
262
        snmp_log(LOG_ERR, "bad rc %d from get_next\n", rc);
 
263
        best_val.val = NULL;
 
264
    }
 
265
 
 
266
    /*
 
267
     * if we have a saved loop ctx, clean it up
 
268
     */
 
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);
 
272
 
 
273
    /*
 
274
     * clean up loop ctx
 
275
     */
 
276
    if(ii->cleanup_loop_ctx)
 
277
        ii->cleanup_loop_ctx(ii->user_ctx,&loop_ctx);
 
278
 
 
279
    DEBUGMSGT(("container_iterator:results"," returning %p\n", best_val.val));
 
280
    return best_val.val;
 
281
}
 
282
 
 
283
/**********************************************************************
 
284
 *
 
285
 * container
 
286
 *
 
287
 **********************************************************************/
 
288
static void
 
289
_iterator_free(iterator_info *ii)
 
290
{
 
291
    DEBUGMSGT(("container_iterator",">%s\n", "_iterator_free"));
 
292
    
 
293
    if(NULL == ii)
 
294
        return;
 
295
    
 
296
    if(ii->user_ctx)
 
297
        ii->free_user_ctx(ii->user_ctx,ii->user_ctx);
 
298
    
 
299
    free(ii);
 
300
}
 
301
 
 
302
static void *
 
303
_iterator_find(iterator_info *ii, const void *data)
 
304
{
 
305
    DEBUGMSGT(("container_iterator",">%s\n", "_iterator_find"));
 
306
    
 
307
    if((NULL == ii) || (NULL == data))
 
308
        return NULL;
 
309
 
 
310
    return _iterator_get(ii, data);
 
311
}
 
312
 
 
313
static void *
 
314
_iterator_find_next(iterator_info *ii, const void *data)
 
315
{
 
316
    DEBUGMSGT(("container_iterator",">%s\n", "_iterator_find_next"));
 
317
    
 
318
    if(NULL == ii)
 
319
        return NULL;
 
320
 
 
321
    return _iterator_get_next(ii, data);
 
322
}
 
323
 
 
324
static int
 
325
_iterator_insert(iterator_info *ii, const void *data)
 
326
{
 
327
    DEBUGMSGT(("container_iterator",">%s\n", "_iterator_insert"));
 
328
    
 
329
    if(NULL == ii)
 
330
        return -1;
 
331
 
 
332
    if(NULL == ii->insert_data)
 
333
        return -1;
 
334
 
 
335
    return ii->insert_data(ii->user_ctx, data);
 
336
}
 
337
 
 
338
static int
 
339
_iterator_remove(iterator_info *ii, const void *data)
 
340
{
 
341
    DEBUGMSGT(("container_iterator",">%s\n", "_iterator_remove"));
 
342
    
 
343
    if(NULL == ii)
 
344
        return -1;
 
345
 
 
346
    if(NULL == ii->remove_data)
 
347
        return -1;
 
348
 
 
349
    return ii->remove_data(ii->user_ctx, data);
 
350
}
 
351
 
 
352
static int
 
353
_iterator_release(iterator_info *ii, const void *data)
 
354
{
 
355
    DEBUGMSGT(("container_iterator",">%s\n", "_iterator_release"));
 
356
    
 
357
    if(NULL == ii)
 
358
        return -1;
 
359
 
 
360
    if(NULL == ii->release_data)
 
361
        return -1;
 
362
 
 
363
    return ii->release_data(ii->user_ctx, data);
 
364
}
 
365
 
 
366
static size_t
 
367
_iterator_size(iterator_info *ii)
 
368
{
 
369
    size_t count = 0;
 
370
    int rc = SNMP_ERR_NOERROR;
 
371
    netsnmp_ref_void loop_ctx = { NULL };
 
372
    netsnmp_ref_void tmp = { NULL };
 
373
 
 
374
    DEBUGMSGT(("container_iterator",">%s\n", "_iterator_size"));
 
375
    
 
376
    if(NULL == ii)
 
377
        return -1;
 
378
 
 
379
    if(NULL != ii->get_size)
 
380
        return ii->get_size(ii->user_ctx);
 
381
 
 
382
    /*
 
383
     * no get_size. loop and count ourselves
 
384
     */
 
385
    if(ii->init_loop_ctx)
 
386
        ii->init_loop_ctx(ii->user_ctx, &loop_ctx);
 
387
    
 
388
    for( rc = ii->get_first(ii->user_ctx, &loop_ctx, &tmp);
 
389
         NULL != tmp.val;
 
390
         rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp) )
 
391
        ++count;
 
392
 
 
393
    if(ii->cleanup_loop_ctx)
 
394
        ii->cleanup_loop_ctx(ii->user_ctx,&loop_ctx);
 
395
 
 
396
    return count;
 
397
}
 
398
 
 
399
static void
 
400
_iterator_for_each(iterator_info *ii, netsnmp_container_obj_func *f,
 
401
                   void *ctx)
 
402
{
 
403
    int rc = SNMP_ERR_NOERROR;
 
404
    netsnmp_ref_void loop_ctx = { NULL };
 
405
    netsnmp_ref_void tmp = { NULL };
 
406
 
 
407
    DEBUGMSGT(("container_iterator",">%s\n", "_iterator_foreach"));
 
408
    
 
409
    if(NULL == ii)
 
410
        return;
 
411
 
 
412
    if(ii->init_loop_ctx)
 
413
        ii->init_loop_ctx(ii->user_ctx, &loop_ctx);
 
414
    
 
415
    for( rc = ii->get_first(ii->user_ctx, &loop_ctx, &tmp);
 
416
         NULL != tmp.val;
 
417
         rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp) )
 
418
        (*f) (tmp.val, ctx);
 
419
 
 
420
    if(ii->cleanup_loop_ctx)
 
421
        ii->cleanup_loop_ctx(ii->user_ctx,&loop_ctx);
 
422
}
 
423
 
 
424
/**********************************************************************
 
425
 *
 
426
 */
 
427
netsnmp_container*
 
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,
 
437
                               int sorted)
 
438
{
 
439
    iterator_info *ii;
 
440
 
 
441
    /*
 
442
     * sanity checks
 
443
     */
 
444
    if(get_data && ! save_pos) {
 
445
        snmp_log(LOG_ERR, "save_pos required with get_data\n");
 
446
        return NULL;
 
447
    }
 
448
 
 
449
    /*
 
450
     * allocate memory
 
451
     */
 
452
    ii = SNMP_MALLOC_TYPEDEF(iterator_info);
 
453
    if (NULL==ii) {
 
454
        snmp_log(LOG_ERR, "couldn't allocate memory\n");
 
455
        return NULL;
 
456
    }
 
457
 
 
458
    /*
 
459
     * init container structure with iterator functions
 
460
     */
 
461
    ii->c.cfree = (netsnmp_container_rc*)_iterator_free;
 
462
    ii->c.compare = compare;
 
463
    ii->c.get_size = (netsnmp_container_size*)_iterator_size;
 
464
    ii->c.init = NULL;
 
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;
 
473
 
 
474
    /*
 
475
     * init iterator structure with user functions
 
476
     */
 
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;
 
484
    ii->sorted = sorted;
 
485
 
 
486
    ii->user_ctx = iterator_user_ctx;
 
487
 
 
488
    return (netsnmp_container*)ii;
 
489
};
 
490
 
 
491
void
 
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)
 
496
{
 
497
    iterator_info *ii = (iterator_info *)c;
 
498
    if(NULL == ii)
 
499
        return;
 
500
    
 
501
    ii->insert_data = insert_data;
 
502
    ii->remove_data = remove_data;
 
503
    ii->get_size = get_size;
 
504
}