Coverage Report

Created: 2024-07-27 06:09

/src/net-snmp/snmplib/container_list_ssll.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * container_list_sl.c
3
 * $Id$
4
 *
5
 */
6
#include <net-snmp/net-snmp-config.h>
7
#include <net-snmp/net-snmp-features.h>
8
9
#include <stdio.h>
10
#ifdef HAVE_STDLIB_H
11
#include <stdlib.h>
12
#endif
13
#ifdef HAVE_MALLOC_H
14
#include <malloc.h>
15
#endif
16
#include <sys/types.h>
17
#ifdef HAVE_STRING_H
18
#include <string.h>
19
#else
20
#include <strings.h>
21
#endif
22
23
#include <net-snmp/net-snmp-includes.h>
24
#include <net-snmp/types.h>
25
#include <net-snmp/library/snmp_api.h>
26
#include <net-snmp/library/container.h>
27
#include <net-snmp/library/tools.h>
28
#include <net-snmp/library/snmp_assert.h>
29
30
#include <net-snmp/library/container_list_ssll.h>
31
#include "factory.h"
32
33
netsnmp_feature_child_of(container_linked_list, container_types);
34
netsnmp_feature_child_of(container_fifo, container_types);
35
netsnmp_feature_child_of(container_lifo, container_types);
36
37
/* this is a fancy way of cleaning up ifdefs */
38
#ifdef NETSNMP_FEATURE_REQUIRE_CONTAINER_FIFO
39
netsnmp_feature_require(container_linked_list);
40
#endif /* NETSNMP_FEATURE_REQUIRE_CONTAINER_FIFO */
41
#ifdef NETSNMP_FEATURE_REQUIRE_CONTAINER_LIFO
42
netsnmp_feature_require(container_linked_list);
43
#endif /* NETSNMP_FEATURE_REQUIRE_CONTAINER_LIFO */
44
45
#ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_LINKED_LIST
46
typedef struct sl_node {
47
   void           *data;
48
   struct sl_node *next;
49
} sl_node;
50
51
typedef struct sl_container_s {
52
   netsnmp_container          c;
53
   
54
   size_t                     count;      /* Index of the next free entry */
55
   sl_node                   *head;       /* head of list */
56
57
   int                        unsorted;   /* unsorted list? */
58
   int                        fifo;       /* lifo or fifo? */
59
60
} sl_container;
61
62
typedef struct ssll_iterator_s {
63
    netsnmp_iterator base;
64
 
65
    sl_node         *pos;
66
    sl_node         *last;
67
} ssll_iterator;
68
69
static netsnmp_iterator *_ssll_iterator_get(netsnmp_container *c);
70
71
72
static void *
73
_get(netsnmp_container *c, const void *key, int return_next)
74
0
{
75
0
    sl_container *sl = (sl_container *)c;
76
0
    sl_node *curr = sl->head;
77
0
    int rc = 0;
78
79
    /* If the key is NULL, return the first item in the container. */
80
0
    if (!key)
81
0
        return curr ? curr->data : NULL;
82
83
0
    for ( ; curr; curr = curr->next) {
84
0
        rc = sl->c.compare(curr->data, key);
85
0
        if (rc < 0)
86
0
            continue;
87
0
        if (rc == 0) {
88
0
            if (return_next)
89
0
                curr = curr->next;
90
0
            break;
91
0
        }
92
0
        if (!sl->unsorted) {
93
            /* If sorted, we can stop. */
94
0
            if (!return_next)
95
0
                curr = NULL;
96
0
            break;
97
0
        }
98
0
    }
99
100
0
    return curr ? curr->data : NULL;
101
0
}
102
103
/**********************************************************************
104
 *
105
 *
106
 *
107
 **********************************************************************/
108
static int
109
_ssll_free(netsnmp_container *c)
110
2.81k
{
111
2.81k
    if(c) {
112
2.81k
        free(c);
113
2.81k
    }
114
2.81k
    return 0;
115
2.81k
}
116
117
static void *
118
_ssll_find(netsnmp_container *c, const void *data)
119
0
{
120
0
    if((NULL == c) || (NULL == data))
121
0
        return NULL;
122
123
0
    return _get(c, data, 0);
124
0
}
125
126
static void *
127
_ssll_find_next(netsnmp_container *c, const void *data)
128
0
{
129
0
    if(NULL == c)
130
0
        return NULL;
131
132
0
    return _get(c, data, 1);
133
0
}
134
135
static int
136
_ssll_insert(netsnmp_container *c, const void *data)
137
0
{
138
0
    sl_container *sl = (sl_container*)c;
139
0
    sl_node  *new_node, *curr;
140
    
141
0
    if (c == NULL)
142
0
        return -1;
143
144
0
    curr = sl->head;
145
146
0
    new_node = SNMP_MALLOC_TYPEDEF(sl_node);
147
0
    if (new_node == NULL)
148
0
        return -1;
149
0
    new_node->data = NETSNMP_REMOVE_CONST(void *, data);
150
0
    ++sl->count;
151
0
    ++c->sync;
152
153
    /*
154
     * first node?
155
     */
156
0
    if(NULL == sl->head) {
157
0
        sl->head = new_node;
158
0
        return 0;
159
0
    }
160
161
    /*
162
     * sorted or unsorted insert?
163
     */
164
0
    if (1 == sl->unsorted) {
165
        /*
166
         * unsorted: fifo, or lifo?
167
         */
168
0
        if (1 == sl->fifo) {
169
            /*
170
             * fifo: insert at tail
171
             */
172
0
            while(NULL != curr->next)
173
0
                curr = curr->next;
174
0
            curr->next = new_node;
175
0
        }
176
0
        else {
177
            /*
178
             * lifo: insert at head
179
             */
180
0
            new_node->next = sl->head;
181
0
            sl->head = new_node;
182
0
        }
183
0
    }
184
0
    else {
185
        /*
186
         * sorted
187
         */
188
0
        sl_node *last = NULL;
189
0
        for( ; curr; last = curr, curr = curr->next) {
190
0
            if(sl->c.compare(curr->data, data) > 0)
191
0
                break;
192
0
        }
193
0
        if(NULL == last) {
194
0
            new_node->next = sl->head;
195
0
            sl->head = new_node;
196
0
        }
197
0
        else {
198
0
            new_node->next = last->next;
199
0
            last->next = new_node;
200
0
        }
201
0
    }
202
    
203
0
    return 0;
204
0
}
205
206
static int
207
_ssll_remove(netsnmp_container *c, const void *data)
208
0
{
209
0
    sl_container *sl = (sl_container*)c;
210
0
    sl_node  *curr;
211
    
212
0
    if (c == NULL)
213
0
        return -1;
214
215
0
    curr = sl->head;
216
0
    if (curr == NULL)
217
0
        return -1;
218
219
    /*
220
     * special case for NULL data, act like stack
221
     */
222
0
    if ((NULL == data) ||
223
0
        (sl->c.compare(sl->head->data, data) == 0)) {
224
0
        curr = sl->head;
225
0
        sl->head = sl->head->next;
226
0
    }
227
0
    else {
228
0
        sl_node *last = sl->head;
229
0
        int rc;
230
0
        for(curr = sl->head->next ; curr; last = curr, curr = curr->next) {
231
0
            rc = sl->c.compare(curr->data, data);
232
0
            if (rc == 0) {
233
0
                last->next = curr->next;
234
0
                break;
235
0
            }
236
0
            else if ((rc > 0) && (0 == sl->unsorted)) {
237
                /*
238
                 * if sorted and rc > 0, didn't find entry
239
                 */
240
0
                curr = NULL;
241
0
                break;
242
0
            }
243
0
        }
244
0
    }
245
246
0
    if(NULL == curr)
247
0
        return -2;
248
    
249
    /*
250
     * free our node structure, but not the data
251
     */
252
0
    free(curr);
253
0
    --sl->count;
254
0
    ++c->sync;
255
    
256
0
    return 0;
257
0
}
258
259
static size_t
260
_ssll_size(netsnmp_container *c)
261
0
{
262
0
    sl_container *sl = (sl_container*)c;
263
    
264
0
    if(NULL == c)
265
0
        return 0;
266
267
0
    return sl->count;
268
0
}
269
270
static void
271
_ssll_for_each(netsnmp_container *c, netsnmp_container_obj_func *f,
272
             void *context)
273
0
{
274
0
    sl_container *sl = (sl_container*)c;
275
0
    sl_node  *curr;
276
    
277
0
    if(NULL == c)
278
0
        return;
279
    
280
0
    for(curr = sl->head; curr; curr = curr->next)
281
0
        (*f) ((void *)curr->data, context);
282
0
}
283
284
static void
285
_ssll_clear(netsnmp_container *c, netsnmp_container_obj_func *f,
286
             void *context)
287
2.81k
{
288
2.81k
    sl_container *sl = (sl_container*)c;
289
2.81k
    sl_node  *curr, *next;
290
    
291
2.81k
    if(NULL == c)
292
0
        return;
293
    
294
2.81k
    for(curr = sl->head; curr; curr = next) {
295
296
0
        next = curr->next;
297
298
0
        if( NULL != f ) {
299
0
            curr->next = NULL;
300
0
            (*f) ((void *)curr->data, context);
301
0
        }
302
303
        /*
304
         * free our node structure, but not the data
305
         */
306
0
        free(curr);
307
0
    }
308
2.81k
    sl->head = NULL;
309
2.81k
    sl->count = 0;
310
2.81k
    ++c->sync;
311
2.81k
}
312
313
/**********************************************************************
314
 *
315
 *
316
 *
317
 **********************************************************************/
318
netsnmp_container *
319
netsnmp_container_get_ssll(void)
320
2.81k
{
321
    /*
322
     * allocate memory
323
     */
324
2.81k
    sl_container *sl = SNMP_MALLOC_TYPEDEF(sl_container);
325
2.81k
    if (NULL==sl) {
326
0
        snmp_log(LOG_ERR, "couldn't allocate memory\n");
327
0
        return NULL;
328
0
    }
329
330
2.81k
    netsnmp_init_container((netsnmp_container *)sl, NULL, _ssll_free,
331
2.81k
                           _ssll_size, NULL, _ssll_insert, _ssll_remove,
332
2.81k
                           _ssll_find);
333
2.81k
    sl->c.find_next = _ssll_find_next;
334
2.81k
    sl->c.get_subset = NULL;
335
2.81k
    sl->c.get_iterator =_ssll_iterator_get;
336
2.81k
    sl->c.for_each = _ssll_for_each;
337
2.81k
    sl->c.clear = _ssll_clear;
338
339
2.81k
    return &sl->c;
340
2.81k
}
341
342
netsnmp_container *
343
netsnmp_container_get_usll(void)
344
2.81k
{
345
    /*
346
     * allocate memory
347
     */
348
2.81k
    sl_container *sl = (sl_container *)netsnmp_container_get_ssll();
349
2.81k
    if (NULL==sl)
350
0
        return NULL; /* msg already logged */
351
352
2.81k
    sl->unsorted = 1;
353
354
2.81k
    return (netsnmp_container*)sl;
355
2.81k
}
356
357
netsnmp_container *
358
netsnmp_container_get_singly_linked_list(int fifo)
359
2.81k
{
360
2.81k
    sl_container *sl = (sl_container *)netsnmp_container_get_usll();
361
2.81k
    if (NULL == sl)
362
0
        return NULL; /* error already logged */
363
364
2.81k
    sl->fifo = fifo;
365
366
2.81k
    return (netsnmp_container *)sl;
367
2.81k
}
368
369
netsnmp_container *
370
netsnmp_container_get_fifo(void)
371
2.81k
{
372
2.81k
    return netsnmp_container_get_singly_linked_list(1);
373
2.81k
}
374
375
void
376
netsnmp_container_ssll_init(void)
377
2.81k
{
378
2.81k
    static netsnmp_factory ssll = {
379
2.81k
        "sorted_singly_linked_list",
380
2.81k
        netsnmp_container_get_ssll
381
2.81k
    };
382
2.81k
    static netsnmp_factory usll = {
383
2.81k
        "unsorted_singly_linked_list-lifo",
384
2.81k
        netsnmp_container_get_usll
385
2.81k
    };
386
2.81k
    static netsnmp_factory fifo = {
387
2.81k
        "unsorted_singly_linked_list-fifo",
388
2.81k
        netsnmp_container_get_fifo
389
2.81k
    };
390
391
2.81k
    netsnmp_container_register("sorted_singly_linked_list", &ssll);
392
2.81k
    netsnmp_container_register("unsorted_singly_linked_list", &usll);
393
2.81k
    netsnmp_container_register("lifo", &usll);
394
2.81k
    netsnmp_container_register("fifo", &fifo);
395
2.81k
}
396
397
398
/**********************************************************************
399
 *
400
 * iterator
401
 *
402
 */
403
NETSNMP_STATIC_INLINE sl_container *
404
_ssll_it2cont(ssll_iterator *it)
405
0
{
406
0
    if(NULL == it) {
407
0
        netsnmp_assert(NULL != it);
408
0
        return NULL;
409
0
    }
410
411
0
    if(NULL == it->base.container) {
412
0
        netsnmp_assert(NULL != it->base.container);
413
0
        return NULL;
414
0
    }
415
416
0
    if(it->base.container->sync != it->base.sync) {
417
0
        DEBUGMSGTL(("container:iterator", "out of sync\n"));
418
0
        return NULL;
419
0
    }
420
421
0
    return (sl_container *)it->base.container;
422
0
}
423
424
static void *
425
_ssll_iterator_curr(netsnmp_iterator *p)
426
0
{
427
0
    ssll_iterator *it = (void *)p;
428
0
    sl_container *t = _ssll_it2cont(it);
429
0
    if ((NULL == t) || (NULL == it->pos))
430
0
        return NULL;
431
432
0
    return it->pos->data;
433
0
}
434
435
static void *
436
_ssll_iterator_first(netsnmp_iterator *p)
437
0
{
438
0
    ssll_iterator *it = (void *)p;
439
0
    sl_container *t = _ssll_it2cont(it);
440
0
    if ((NULL == t) || (NULL == t->head))
441
0
        return NULL;
442
443
0
    return t->head->data;
444
0
}
445
446
static void *
447
_ssll_iterator_next(netsnmp_iterator *p)
448
0
{
449
0
    ssll_iterator *it = (void *)p;
450
0
    sl_container *t = _ssll_it2cont(it);
451
0
    if ((NULL == t) || (NULL == it->pos))
452
0
        return NULL;
453
454
0
    it->pos = it->pos->next;
455
0
    if (NULL == it->pos)
456
0
        return NULL;
457
458
0
    return it->pos->data;
459
0
}
460
461
static void *
462
_ssll_iterator_last(netsnmp_iterator *p)
463
0
{
464
0
    ssll_iterator *it = (void *)p;
465
0
    sl_node      *n;
466
0
    sl_container *t = _ssll_it2cont(it);
467
0
    if(NULL == t)
468
0
        return NULL;
469
    
470
0
    if (it->last)
471
0
        return it->last;
472
473
0
    n = it->pos ? it->pos : t->head;
474
0
    if (NULL == n)
475
0
        return NULL;
476
477
0
    while (n->next)
478
0
        n = n->next;
479
480
0
    it->last = n;
481
482
0
    return it->last->data;
483
0
}
484
485
static int
486
_ssll_iterator_reset(netsnmp_iterator *p)
487
0
{
488
0
    ssll_iterator *it = (void *)p;
489
0
    sl_container *t;
490
491
    /** can't use it2conf cuz we might be out of sync */
492
0
    if(NULL == it) {
493
0
        netsnmp_assert(NULL != it);
494
0
        return 0;
495
0
    }
496
497
0
    if(NULL == it->base.container) {
498
0
        netsnmp_assert(NULL != it->base.container);
499
0
        return 0;
500
0
    }
501
0
    t = (sl_container *)it->base.container;
502
0
    if(NULL == t)
503
0
        return -1;
504
505
0
    it->last = NULL;
506
0
    it->pos = t->head;
507
508
    /*
509
     * save sync count, to make sure container doesn't change while
510
     * iterator is in use.
511
     */
512
0
    it->base.sync = it->base.container->sync;
513
514
0
    return 0;
515
0
}
516
517
static int
518
_ssll_iterator_release(netsnmp_iterator *it)
519
0
{
520
0
    free(it);
521
522
0
    return 0;
523
0
}
524
525
static netsnmp_iterator *
526
_ssll_iterator_get(netsnmp_container *c)
527
0
{
528
0
    ssll_iterator* it;
529
530
0
    if(NULL == c)
531
0
        return NULL;
532
533
0
    it = SNMP_MALLOC_TYPEDEF(ssll_iterator);
534
0
    if(NULL == it)
535
0
        return NULL;
536
537
0
    it->base.container = c;
538
    
539
0
    it->base.first = _ssll_iterator_first;
540
0
    it->base.next = _ssll_iterator_next;
541
0
    it->base.curr = _ssll_iterator_curr;
542
0
    it->base.last = _ssll_iterator_last;
543
0
    it->base.reset = _ssll_iterator_reset;
544
0
    it->base.release = _ssll_iterator_release;
545
546
0
    (void)_ssll_iterator_reset(&it->base);
547
548
0
    return &it->base;
549
0
}
550
#else /* NETSNMP_FEATURE_REMOVE_CONTAINER_LINKED_LIST */
551
netsnmp_feature_unused(container_linked_list);
552
#endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_LINKED_LIST */