blob: 33ce594d5c8a74841122ef603c05846090555420 [file] [log] [blame]
/*
* util_funcs.c
* $Id$
*
* see comments in header file.
*
*/
#include <net-snmp/net-snmp-config.h>
#if HAVE_IO_H
#include <io.h>
#endif
#include <stdio.h>
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if HAVE_MALLOC_H
#include <malloc.h>
#endif
#include <sys/types.h>
#include <net-snmp/oid_array.h>
#include <net-snmp/snmp_api.h>
typedef struct oid_array_table_s {
int max_size; /* Size of the current data table */
int count; /* Index of the next free entry */
int dirty;
int data_size; /* Size of an individual entry */
void *data; /* The table itself */
} oid_array_table;
#define TABLE_ADD( x, y ) ((oid_array_header**)((char*)(x) + y))
#define TABLE_INDEX(t, i) (TABLE_ADD(t->data, i * t->data_size))
#define TABLE_START(t) (TABLE_INDEX(t, 0))
#define TABLE_NEXT(t) (TABLE_INDEX(t, t->count))
int
array_compare(const void *lhs, const void *rhs)
{
return snmp_oid_compare((*(const oid_array_header **) lhs)->idx,
(*(const oid_array_header **) lhs)->idx_len,
(*(const oid_array_header **) rhs)->idx,
(*(const oid_array_header **) rhs)->idx_len);
}
static int
Sort_Array(oid_array_table * table)
{
if (table->dirty) {
/*
* Sort the table
*/
if(table->count>1)
qsort(TABLE_START(table), table->count, table->data_size,
array_compare);
table->dirty = 0;
}
return 1;
}
static int
binary_search(oid_array_header * val, oid_array_table * t, int exact)
{
int len = t->count;
int half;
int middle;
int result = 0;
int first = 0;
if (!len)
return -1;
if (t->dirty)
Sort_Array(t);
while (len > 0) {
half = len >> 1;
middle = first;
middle += half;
if ((result = array_compare(TABLE_INDEX(t, middle), &val)) < 0) {
first = middle;
++first;
len = len - half - 1;
} else
len = half;
}
if (exact) {
if( (first == t->count) ||
array_compare(TABLE_INDEX(t, first), &val) != 0 )
return -1;
return first;
}
/*
* GETNEXT search - if result == 0, we want the next item
*/
if (result <= 0)
++first;
if (first >= t->count)
return -1;
return first;
}
oid_array
Initialise_oid_array(int size)
{
oid_array_table *t;
t = (oid_array_table *) malloc(sizeof(oid_array_table));
if (t == NULL)
return NULL;
t->max_size = 0;
t->count = 0;
t->dirty = 0;
t->data_size = size;
t->data = NULL;
return (oid_array) t;
}
void
Release_oid_array(oid_array a)
{
free(a);
}
int
Get_oid_data_count(oid_array a)
{
oid_array_table *t = (oid_array_table *) a;
/*
* return count
*/
return t ? t->count : 0;
}
void *
Get_oid_data(oid_array a, void *key, int exact)
{
oid_array_table *t = (oid_array_table *) a;
int index = 0;
/*
* if there is no data, return NULL;
*/
if (!t->count)
return 0;
/*
* if the table is dirty, sort it.
*/
if (t->dirty)
Sort_Array(t);
/*
* if there is a key, search. Otherwise default is 0;
*/
if (key) {
if ((index = binary_search(key, t, exact)) == -1)
return 0;
}
return *TABLE_INDEX(t, index);
}
int
Replace_oid_data(oid_array a, void *entry )
{
oid_array_table *t = (oid_array_table *) a;
void *new_data;
int index = 0;
/*
* if there is no data, return NULL;
*/
if (!t->count)
return 0;
/*
* if the table is dirty, sort it.
*/
if (t->dirty)
Sort_Array(t);
/*
* search
*/
if ((index = binary_search((oid_array_header*)&entry, t, 1)) == -1)
return 0;
new_data = TABLE_INDEX(t, index);
memcpy(new_data, &entry, t->data_size);
return 0;
}
int
Remove_oid_data(oid_array a, void *key, void *save )
{
oid_array_table *t = (oid_array_table *) a;
void *new_data, *old_data;
int index = 0;
/*
* if there is no data, return NULL;
*/
if (!t->count)
return 0;
/*
* if the table is dirty, sort it.
*/
if (t->dirty)
Sort_Array(t);
/*
* search
*/
if ((index = binary_search(key, t, 1)) == -1)
return -1;
/*
* find old data and save it, if ptr provided
*/
old_data = TABLE_INDEX(t, index);
if(save)
memcpy(save, old_data, t->data_size);
/*
* if entry was last item, just decrement count
*/
--t->count;
if(index != t->count) {
/*
* otherwise, shift array down
*/
new_data = TABLE_INDEX(t, index+1);
memcpy(old_data, new_data, t->data_size * (t->count - index) );
}
return 0;
}
void
For_each_oid_data(oid_array a, ForEach fe, void * context, int sort)
{
int i;
oid_array_table *t = (oid_array_table *) a;
if (sort && t->dirty)
Sort_Array(t);
for (i = 0; i < t->count; ++i)
(*fe) (*TABLE_INDEX(t, i), context);
}
int
Add_oid_data(oid_array a, void *entry)
{
oid_array_table *table = (oid_array_table *) a;
int new_max;
void *new_data; /* Used for * a) extending the data table
* * b) the next entry to use */
if (table->max_size <= table->count) {
/*
* Table is full, so extend it to double the size
*/
new_max = 2 * table->max_size;
if (new_max == 0)
new_max = 10; /* Start with 10 entries */
new_data = (void *) calloc(new_max, table->data_size);
if (new_data == NULL)
return -1;
if (table->data) {
memcpy(new_data, table->data,
table->max_size * table->data_size);
free(table->data);
}
table->data = new_data;
table->max_size = new_max;
}
/*
* Insert the new entry into the data array
*/
new_data = TABLE_NEXT(table);
memcpy(new_data, &entry, table->data_size);
table->count++;
table->dirty = 1;
return 0;
}
void *
Retrieve_oid_array(oid_array t, int *max_idx, int sort)
{
oid_array_table *table = (oid_array_table *) t;
if (sort && table->dirty)
Sort_Array(t);
*max_idx = table->count;
return table->data;
}
/**********************************************************************
*
* Special case support for subsets
*
*/
static int
array_ncompare(const void *lhs, const void *rhs)
{
return snmp_oid_ncompare((*(const oid_array_header **) lhs)->idx,
(*(const oid_array_header **) lhs)->idx_len,
(*(const oid_array_header **) rhs)->idx,
(*(const oid_array_header **) rhs)->idx_len,
(*(const oid_array_header **) rhs)->idx_len);
}
static int
binary_search_for_start(oid_array_header * val, oid_array_table * t)
{
int len = t->count;
int half;
int middle;
int result = 0;
int first = 0;
if (!len)
return -1;
if (t->dirty)
Sort_Array(t);
while (len > 0) {
half = len >> 1;
middle = first;
middle += half;
if ((result = array_ncompare(TABLE_INDEX(t, middle), &val)) < 0) {
first = middle;
++first;
len = len - half - 1;
} else
len = half;
}
if( (first >= t->count) ||
array_ncompare(TABLE_INDEX(t, first), &val) != 0 )
return -1;
return first;
}
void **
Get_oid_data_subset(oid_array a, void *key, int *len)
{
oid_array_table *t = (oid_array_table *) a;
void **subset;
int start, end, i;
/*
* if there is no data, return NULL;
*/
if (!t->count || !key)
return 0;
/*
* if the table is dirty, sort it.
*/
if (t->dirty)
Sort_Array(t);
/*
* find matching items
*/
start = end = binary_search_for_start(key, t);
if(start == -1)
return 0;
for( i = start + 1; i < t->count; ++i ) {
if( 0 != array_ncompare(TABLE_INDEX(t, i), &key) )
break;
++end;
}
*len = end - start;
subset = malloc( (*len) * t->data_size );
memcpy( subset, TABLE_INDEX(t, start), t->data_size * (*len));
return subset;
}