ssl_util_table.c revision b27ea9ce4dbb169b987ecef743238971b8c97d44
/* _ _
** _ __ ___ ___ __| | ___ ___| | mod_ssl
** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
** |_____|
** High Performance Hash Table Functions
*/
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000-2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*/
/*
* Generic hash table handler
* Table 4.1.0 July-28-1998
*
* This library is a generic open hash table with buckets and
* linked lists. It is pretty high performance. Each element
* has a key and a data. The user indexes on the key to find the
* data.
*
* Copyright 1998 by Gray Watson <gray@letters.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose and without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies,
* and that the name of Gray Watson not be used in advertising or
* publicity pertaining to distribution of the document or software
* without specific, written prior permission.
*
* Gray Watson makes no representations about the suitability of the
* software described herein for any purpose. It is provided "as is"
* without express or implied warranty.
*
* Modified in March 1999 by Ralf S. Engelschall <rse@engelschall.com>
* for use in the mod_ssl project:
* o merged table_loc.h header into table.c
* o removed fillproto-comments from table.h
* o removed mmap() support because it's too unportable
* o added support for MM library via ta_{malloc,calloc,realloc,free}
*/
#include <stdlib.h>
#include <string.h>
/* forward definitions for table.h */
typedef struct table_entry_st table_entry_t;
#define TABLE_PRIVATE
#include "ssl_util_table.h"
/****************************** local defines ******************************/
#ifndef BITSPERBYTE
#define BITSPERBYTE 8
#endif
#ifndef BITS
#endif
/* returns 1 when we should grow or shrink the table */
/*
* void HASH_MIX
*
* DESCRIPTION:
*
* Mix 3 32-bit values reversibly. For every delta with one or two bits
* set, and the deltas of all three high bits or all three low bits,
* whether the original value of a,b,c is almost all zero or is
* uniformly distributed.
*
* If HASH_MIX() is run forward or backward, at least 32 bits in a,b,c
* have at least 1/4 probability of changing. If mix() is run
* forward, every bit of c will change between 1/3 and 2/3 of the
* time. (Well, 22/100 and 78/100 for some 2-bit deltas.)
*
* HASH_MIX() takes 36 machine instructions, but only 18 cycles on a
* superscalar machine (like a Pentium or a Sparc). No faster mixer
* seems to work, that's the result of my brute-force search. There
* were about 2^68 hashes to choose from. I only tested about a
* billion of those.
*/
#define HASH_MIX(a, b, c) \
do { \
a -= b; a -= c; a ^= (c >> 13); \
b -= c; b -= a; b ^= (a << 8); \
c -= a; c -= b; c ^= (b >> 13); \
a -= b; a -= c; a ^= (c >> 12); \
b -= c; b -= a; b ^= (a << 16); \
c -= a; c -= b; c ^= (b >> 5); \
a -= b; a -= c; a ^= (c >> 3); \
b -= c; b -= a; b ^= (a << 10); \
c -= a; c -= b; c ^= (b >> 15); \
} while(0)
/*
* Macros to get at the key and the data pointers
*/
/*
* Table structures...
*/
/*
* HACK: this should be equiv as the table_entry_t without the key_buf
* char. We use this with the ENTRY_SIZE() macro above which solves
* the problem with the lack of the [0] GNU hack. We use the
* table_entry_t structure to better map the memory and make things
* faster.
*/
typedef struct table_shell_st {
unsigned int te_key_size; /* size of data */
unsigned int te_data_size; /* size of data */
/* NOTE: this does not have the te_key_buf field here */
/*
* Elements in the bucket linked-lists. The key[1] is the start of
* the key with the rest of the key and all of the data information
* packed in memory directly after the end of this structure.
*
* NOTE: if this structure is changed, the table_shell_t must be changed
* to match.
*/
struct table_entry_st {
unsigned int te_key_size; /* size of data */
unsigned int te_data_size; /* size of data */
};
/* external structure for debuggers be able to see void */
typedef table_entry_t table_entry_ext_t;
/* main table structure */
struct table_st {
unsigned int ta_magic; /* magic number */
unsigned int ta_bucket_n; /* num of buckets, should be 2^X */
unsigned int ta_entry_n; /* num of entries in all buckets */
unsigned int ta_data_align; /* data alignment value */
unsigned long ta_file_size; /* size of on-disk space */
};
/* external table structure for debuggers */
typedef table_t table_ext_t;
/* local comparison functions */
/*
* to map error to string
*/
typedef struct {
int es_error; /* error number */
char *es_string; /* assocaited string */
} error_str_t;
static error_str_t errors[] =
{
{TABLE_ERROR_NONE, "no error"},
{TABLE_ERROR_PNT, "invalid table pointer"},
{TABLE_ERROR_ARG_NULL, "buffer argument is null"},
{TABLE_ERROR_SIZE, "incorrect size argument"},
{TABLE_ERROR_OVERWRITE, "key exists and no overwrite"},
{TABLE_ERROR_NOT_FOUND, "key does not exist"},
{TABLE_ERROR_ALLOC, "error allocating memory"},
{TABLE_ERROR_LINEAR, "linear access not in progress"},
{TABLE_ERROR_OPEN, "could not open file"},
{TABLE_ERROR_SEEK, "could not seek to position in file"},
{TABLE_ERROR_READ, "could not read from file"},
{TABLE_ERROR_WRITE, "could not write to file"},
{TABLE_ERROR_EMPTY, "table is empty"},
{TABLE_ERROR_NOT_EMPTY, "table contains data"},
{TABLE_ERROR_ALIGNMENT, "invalid alignment value"},
{0}
};
#define INVALID_ERROR "invalid error code"
/****************************** local functions ******************************/
/*
* static table_entry_t *first_entry
*
* DESCRIPTION:
*
* Return the first entry in the table. It will set the linear
* structure counter to the position of the first entry.
*
* RETURNS:
*
* Success: A pointer to the first entry in the table.
*
* Failure: NULL if there is no first entry.
*
* ARGUMENTS:
*
* table_p - Table whose next entry we are finding.
*
* linear_p - Pointer to a linear structure which we will advance and
* then find the corresponding entry.
*/
{
unsigned int bucket_c = 0;
/* look for the first non-empty bucket */
linear_p->tl_entry_c = 0;
}
}
}
return NULL;
}
/*
* static table_entry_t *next_entry
*
* DESCRIPTION:
*
* Return the next entry in the table which is past the position in
* our linear pointer. It will advance the linear structure counters.
*
* RETURNS:
*
* Success: A pointer to the next entry in the table.
*
* Failure: NULL.
*
* ARGUMENTS:
*
* table_p - Table whose next entry we are finding.
*
* linear_p - Pointer to a linear structure which we will advance and
* then find the corresponding entry.
*
* error_p - Pointer to an integer which when the routine returns will
* contain a table error code.
*/
int *error_p)
{
int entry_c;
/* can't next if we haven't first-ed */
return NULL;
}
/*
* NOTE: this might happen if we delete an item which shortens the
* table bucket numbers.
*/
return NULL;
}
linear_p->tl_entry_c++;
/* find the entry which is the nth in the list */
/* NOTE: we swap the order here to be more efficient */
/* did we reach the end of the list? */
break;
}
/* did we find an entry in the current bucket? */
}
/* find the first entry in the next non-empty bucket */
linear_p->tl_entry_c = 0;
linear_p->tl_bucket_c++) {
}
}
return NULL;
}
/*
* static unsigned int hash
*
* DESCRIPTION:
*
* Hash a variable-length key into a 32-bit value. Every bit of the
* key affects every bit of the return value. Every 1-bit and 2-bit
* delta achieves avalanche. About (6 * len + 35) instructions. The
* best hash table sizes are powers of 2. There is no need to use mod
* (sooo slow!). If you need less than 32 bits, use a bitmask. For
* example, if you need only 10 bits, do h = (h & hashmask(10)); In
* which case, the hash table should have hashsize(10) elements.
*
* By Bob Jenkins, 1996. bob_jenkins@compuserve.com. You may use
* this code any way you wish, private, educational, or commercial.
* It's free. See
* Use for hash table lookup, or anything where one collision in 2^^32
* is acceptable. Do NOT use for cryptographic purposes.
*
* RETURNS:
*
* Returns a 32-bit hash value.
*
* ARGUMENTS:
*
* key - Key (the unaligned variable-length array of bytes) that we
* are hashing.
*
* length - Length of the key in bytes.
*
* init_val - Initialization value of the hash if you need to hash a
* number of strings together. For instance, if you are hashing N
* strings (unsigned char **)keys, do it like this:
*
* for (i=0, h=0; i<N; ++i) h = hash( keys[i], len[i], h);
*/
const unsigned int length,
const unsigned int init_val)
{
unsigned int a, b, c, len;
/* set up the internal state */
a = 0x9e3779b9; /* the golden ratio; an arbitrary value */
b = 0x9e3779b9;
c = init_val; /* the previous hash value */
/* handle most of the key */
a += (key_p[0]
b += (key_p[4]
c += (key_p[8]
HASH_MIX(a, b, c);
key_p += 12;
}
c += length;
/* all the case statements fall through to the next */
switch (len) {
case 11:
case 10:
case 9:
/* the first byte of c is reserved for the length */
case 8:
case 7:
case 6:
case 5:
b += key_p[4];
case 4:
case 3:
case 2:
case 1:
a += key_p[0];
/* case 0: nothing left to add */
}
HASH_MIX(a, b, c);
return c;
}
/*
* static int entry_size
*
* DESCRIPTION:
*
* Calculates the appropriate size of an entry to include the key and
* data sizes as well as any associated alignment to the data.
*
* RETURNS:
*
* The associated size of the entry.
*
* ARGUMENTS:
*
* table_p - Table associated with the entries whose size we are
* determining.
*
* key_size - Size of the entry key.
*
* data - Size of the entry data.
*/
const unsigned int data_size)
{
/* initial size -- key is already aligned if right after struct */
/* if there is no alignment then it is easy */
if (table_p->ta_data_align == 0)
/* add in our alignement */
if (left > 0)
/* we add the data size here after the alignment */
return size;
}
/*
* static unsigned char *entry_data_buf
*
* DESCRIPTION:
*
* Companion to the ENTRY_DATA_BUF macro but this handles any
* associated alignment to the data in the entry.
*
* RETURNS:
*
* Pointer to the data segment of the entry.
*
* ARGUMENTS:
*
* table_p - Table associated with the entry.
*
* entry_p - Entry whose data pointer we are determining.
*/
const table_entry_t * entry_p)
{
const unsigned char *buf_p;
/* if there is no alignment then it is easy */
if (table_p->ta_data_align == 0)
return (unsigned char *) buf_p;
/* we need the size of the space before the data */
/* add in our alignment */
if (pad > 0)
}
/******************************* sort routines *******************************/
/*
* static int our_compare
*
* DESCRIPTION:
*
* Compare two entries by calling user's compare program or by using
* memcmp.
*
* RETURNS:
*
* < 0, == 0, or > 0 depending on whether p1 is > p2, == p2, < p2.
*
* ARGUMENTS:
*
* p1 - First entry pointer to compare.
*
* p2 - Second entry pointer to compare.
*
* compare - User comparison function. Ignored.
*
* table_p - Associated table being ordered. Ignored.
*/
{
int cmp;
unsigned int size;
/* compare as many bytes as we can */
/* if common-size equal, then if next more bytes, it is larger */
if (cmp == 0)
return cmp;
}
/*
* static int external_compare
*
* DESCRIPTION:
*
* Compare two entries by calling user's compare program or by using
* memcmp.
*
* RETURNS:
*
* < 0, == 0, or > 0 depending on whether p1 is > p2, == p2, < p2.
*
* ARGUMENTS:
*
* p1 - First entry pointer to compare.
*
* p2 - Second entry pointer to compare.
*
* user_compare - User comparison function.
*
* table_p - Associated table being ordered.
*/
{
/* since we know we are not aligned we can use the EXTRY_DATA_BUF macro */
(*ent1_p)->te_data_size,
(*ent2_p)->te_data_size);
}
/*
* static int external_compare_align
*
* DESCRIPTION:
*
* Compare two entries by calling user's compare program or by using
* memcmp. Alignment information is necessary.
*
* RETURNS:
*
* < 0, == 0, or > 0 depending on whether p1 is > p2, == p2, < p2.
*
* ARGUMENTS:
*
* p1 - First entry pointer to compare.
*
* p2 - Second entry pointer to compare.
*
* user_compare - User comparison function.
*
* table_p - Associated table being ordered.
*/
{
/* since we are aligned we have to use the entry_data_buf function */
(*ent1_p)->te_data_size,
(*ent2_p)->te_data_size);
}
/*
* static void split
*
* DESCRIPTION:
*
* This sorts an array of longs via the quick sort algorithm (it's
* pretty quick)
*
* RETURNS:
*
* None.
*
* ARGUMENTS:
*
* first_p - Start of the list that we are splitting.
*
* last_p - Last entry in the list that we are splitting.
*
* compare - Comparison function which is handling the actual
* elements. This is either a local function or a function to setup
* the problem element key and data pointers which then hands off to
* the user function.
*
* user_compare - User comparison function. Could be NULL if we are
* just using a local comparison function.
*
* table_p - Associated table being sorted.
*/
{
int split_c = 0;
for (;;) {
/* no need to split the list if it is < 2 elements */
if (split_c == 0) {
/* we are done */
return;
}
split_c--;
}
do {
/* scan from right hand side */
/* scan from left hand side */
/* if the pointers haven't met then swap values */
/* swap_bytes(left_p, right_p) */
}
/* now we swap the pivot with the right-hand side */
{
/* swap_bytes(pivot_p, right_p); */
}
/* save the section to the right of the pivot in our stack */
/* do we need to save the righthand side? */
if (right_first_p < last_p) {
if (split_c >= MAX_SORT_SPLITS) {
/* sanity check here -- we should never get here */
abort();
}
split_c++;
}
/* do the left hand side of the pivot */
/* first_p = first_p */
}
}
/*************************** exported routines *******************************/
/*
* table_t *table_alloc
*
* DESCRIPTION:
*
* Allocate a new table structure.
*
* RETURNS:
*
* A pointer to the new table structure which must be passed to
* table_free to be deallocated. On error a NULL is returned.
*
* ARGUMENTS:
*
* bucket_n - Number of buckets for the hash table. Our current hash
* value works best with base two numbers. Set to 0 to take the
* library default of 1024.
*
* error_p - Pointer to an integer which, if not NULL, will contain a
* table error code.
*
* malloc_f, realloc_f, free_f - Pointers to malloc(3)-, realloc(3)-
* and free(3)-style functions.
*/
{
unsigned int buck_n;
/* allocate a table structure */
else
return NULL;
}
if (bucket_n > 0)
else
/* allocate the buckets which are NULLed */
else
else
return NULL;
}
/* initialize structure */
table_p->ta_entry_n = 0;
table_p->ta_data_align = 0;
table_p->ta_file_size = 0;
return table_p;
}
/*
* int table_attr
*
* DESCRIPTION:
*
* Set the attributes for the table. The available attributes are
* specified at the top of table.h.
*
* RETURNS:
*
* Success - TABLE_ERROR_NONE
*
* Failure - Table error code.
*
* ARGUMENTS:
*
* table_p - Pointer to a table structure which we will be altering.
*
* attr - Attribute(s) that we will be applying to the table.
*/
{
return TABLE_ERROR_ARG_NULL;
return TABLE_ERROR_PNT;
return TABLE_ERROR_NONE;
}
/*
* int table_set_data_alignment
*
* DESCRIPTION:
*
* Set the alignment for the data in the table. For data elements
* sizeof(long) is recommended unless you use smaller data types
* exclusively.
*
* WARNING: This must be done before any data gets put into the table.
*
* RETURNS:
*
* Success - TABLE_ERROR_NONE
*
* Failure - Table error code.
*
* ARGUMENTS:
*
* table_p - Pointer to a table structure which we will be altering.
*
* alignment - Alignment requested for the data. Must be a power of
* 2. Set to 0 for none.
*/
{
int val;
return TABLE_ERROR_ARG_NULL;
return TABLE_ERROR_PNT;
if (table_p->ta_entry_n > 0)
return TABLE_ERROR_NOT_EMPTY;
/* defaults */
if (alignment < 2)
table_p->ta_data_align = 0;
else {
/* verify we have a base 2 number */
break;
}
if (val >= MAX_ALIGNMENT)
return TABLE_ERROR_ALIGNMENT;
}
return TABLE_ERROR_NONE;
}
/*
* int table_clear
*
* DESCRIPTION:
*
* Clear out and free all elements in a table structure.
*
* RETURNS:
*
* Success - TABLE_ERROR_NONE
*
* Failure - Table error code.
*
* ARGUMENTS:
*
* table_p - Table structure pointer that we will be clearing.
*/
{
return TABLE_ERROR_ARG_NULL;
return TABLE_ERROR_PNT;
/* free the table allocation and table structure */
/* record the next pointer before we free */
}
/* clear the bucket entry after we free its entries */
}
/* reset table state info */
table_p->ta_entry_n = 0;
return TABLE_ERROR_NONE;
}
/*
* int table_free
*
* DESCRIPTION:
*
* Deallocates a table structure.
*
* RETURNS:
*
* Success - TABLE_ERROR_NONE
*
* Failure - Table error code.
*
* ARGUMENTS:
*
* table_p - Table structure pointer that we will be freeing.
*/
{
int ret;
return TABLE_ERROR_ARG_NULL;
return TABLE_ERROR_PNT;
return ret;
}
/*
* int table_insert_kd
*
* DESCRIPTION:
*
* Like table_insert except it passes back a pointer to the key and
* the data buffers after they have been inserted into the table
* structure.
*
* buffer of bytes and an associated size. Both the key and the data
* will be copied into buffers allocated inside the table. If the key
* exists already, the associated data will be replaced if the
* overwrite flag is set, otherwise an error is returned.
*
* NOTE: be very careful changing the values since the table library
* provides the pointers to its memory. The key can _never_ be
* changed otherwise you will not find it again. The data can be
* changed but its length can never be altered unless you delete and
* re-insert it into the table.
*
* WARNING: The pointers to the key and data are not in any specific
* long pointer directly can cause problems.
*
* WARNING: Replacing a data cell (not inserting) will cause the table
* linked list to be temporarily invalid. Care must be taken with
* linked list to be always valid.
*
* RETURNS:
*
* Success - TABLE_ERROR_NONE
*
* Failure - Table error code.
*
* ARGUMENTS:
*
* table_p - Table structure pointer into which we will be inserting a
*
* key_buf - Buffer of bytes of the key that we are inserting. If you
* are storing an (int) as the key (for example) then key_buf should
* be a (int *).
*
* key_size - Size of the key_buf buffer. If set to < 0 then the
* library will do a strlen of key_buf and add 1 for the '\0'. If you
* are storing an (int) as the key (for example) then key_size should
* be sizeof(int).
*
* data_buf - Buffer of bytes of the data that we are inserting. If
* it is NULL then the library will allocate space for the data in the
* table without copying in any information. If data_buf is NULL and
* data_size is 0 then the library will associate a NULL data pointer
* with the key. If you are storing a (long) as the data (for
* example) then data_buf should be a (long *).
*
* data_size - Size of the data_buf buffer. If set to < 0 then the
* library will do a strlen of data_buf and add 1 for the '\0'. If
* you are storing an (long) as the key (for example) then key_size
* should be sizeof(long).
*
* key_buf_p - Pointer which, if not NULL, will be set to the address
* of the key storage that was allocated in the table. If you are
* storing an (int) as the key (for example) then key_buf_p should be
* (int **) i.e. the address of a (int *).
*
* data_buf_p - Pointer which, if not NULL, will be set to the address
* of the data storage that was allocated in the table. If you are
* storing an (long) as the data (for example) then data_buf_p should
* be (long **) i.e. the address of a (long *).
*
* overwrite - Flag which, if set to 1, will allow the overwriting of
* the data in the table with the new data if the key already exists
* in the table.
*/
void **key_buf_p, void **data_buf_p,
const char overwrite_b)
{
int bucket;
void *key_copy_p, *data_copy_p;
/* check the arguments */
return TABLE_ERROR_ARG_NULL;
return TABLE_ERROR_PNT;
return TABLE_ERROR_ARG_NULL;
/* data_buf can be null but size must be >= 0, if it isn't null size != 0 */
return TABLE_ERROR_SIZE;
/* determine sizes of key and data */
if (key_size < 0)
else
if (data_size < 0)
else
/* get the bucket number via a hash function */
/* look for the entry in this bucket, only check keys of the same size */
break;
}
/* did we find it? then we are in replace mode. */
/* can we not overwrite existing data? */
if (!overwrite_b) {
if (data_buf_p != NULL) {
if (entry_p->te_data_size == 0)
*data_buf_p = NULL;
else {
if (table_p->ta_data_align == 0)
else
}
}
return TABLE_ERROR_OVERWRITE;
}
/* re-alloc entry's data if the new size != the old */
/*
* First we delete it from the list to keep the list whole.
* This properly preserves the linked list in case we have a
* thread marching through the linked list while we are
* inserting. Maybe this is an unnecessary protection but it
* should not harm that much.
*/
else
/*
* Realloc the structure which may change its pointer. NOTE:
* this may change any previous data_key_p and data_copy_p
* pointers.
*/
dsize));
return TABLE_ERROR_ALLOC;
/* add it back to the front of the list */
}
/* copy or replace data in storage */
if (dsize > 0) {
if (table_p->ta_data_align == 0)
else
}
else
data_copy_p = NULL;
if (data_buf_p != NULL)
/* returning from the section where we were overwriting table data */
return TABLE_ERROR_NONE;
}
/*
* It is a new entry.
*/
/* allocate a new entry */
return TABLE_ERROR_ALLOC;
/* copy key into storage */
/* copy data in */
if (dsize > 0) {
if (table_p->ta_data_align == 0)
else
}
else
data_copy_p = NULL;
*key_buf_p = key_copy_p;
if (data_buf_p != NULL)
/* insert into list, no need to append */
table_p->ta_entry_n++;
/* do we need auto-adjust? */
&& SHOULD_TABLE_GROW(table_p))
return TABLE_ERROR_NONE;
}
/*
* int table_insert
*
* DESCRIPTION:
*
* Exactly the same as table_insert_kd except it does not pass back a
* pointer to the key after they have been inserted into the table
* structure. This is still here for backwards compatibility.
*
* See table_insert_kd for more information.
*
* RETURNS:
*
* Success - TABLE_ERROR_NONE
*
* Failure - Table error code.
*
* ARGUMENTS:
*
* table_p - Table structure pointer into which we will be inserting a
*
* key_buf - Buffer of bytes of the key that we are inserting. If you
* are storing an (int) as the key (for example) then key_buf should
* be a (int *).
*
* key_size - Size of the key_buf buffer. If set to < 0 then the
* library will do a strlen of key_buf and add 1 for the '\0'. If you
* are storing an (int) as the key (for example) then key_size should
* be sizeof(int).
*
* data_buf - Buffer of bytes of the data that we are inserting. If
* it is NULL then the library will allocate space for the data in the
* table without copying in any information. If data_buf is NULL and
* data_size is 0 then the library will associate a NULL data pointer
* with the key. If you are storing a (long) as the data (for
* example) then data_buf should be a (long *).
*
* data_size - Size of the data_buf buffer. If set to < 0 then the
* library will do a strlen of data_buf and add 1 for the '\0'. If
* you are storing an (long) as the key (for example) then key_size
* should be sizeof(long).
*
* data_buf_p - Pointer which, if not NULL, will be set to the address
* of the data storage that was allocated in the table. If you are
* storing an (long) as the data (for example) then data_buf_p should
* be (long **) i.e. the address of a (long *).
*
* overwrite - Flag which, if set to 1, will allow the overwriting of
* the data in the table with the new data if the key already exists
* in the table.
*/
void **data_buf_p, const char overwrite_b)
{
}
/*
* int table_retrieve
*
* DESCRIPTION:
*
* This routine looks up a key made up of a buffer of bytes and an
* associated size in the table. If found then it returns the
* associated data information.
*
* RETURNS:
*
* Success - TABLE_ERROR_NONE
*
* Failure - Table error code.
*
* ARGUMENTS:
*
* table_p - Table structure pointer into which we will be searching
* for the key.
*
* key_buf - Buffer of bytes of the key that we are searching for. If
* you are looking for an (int) as the key (for example) then key_buf
* should be a (int *).
*
* key_size - Size of the key_buf buffer. If set to < 0 then the
* library will do a strlen of key_buf and add 1 for the '\0'. If you
* are looking for an (int) as the key (for example) then key_size
* should be sizeof(int).
*
* data_buf_p - Pointer which, if not NULL, will be set to the address
* of the data storage that was allocated in the table and that is
* associated with the key. If a (long) was stored as the data (for
* example) then data_buf_p should be (long **) i.e. the address of a
* (long *).
*
* data_size_p - Pointer to an integer which, if not NULL, will be set
* to the size of the data stored in the table that is associated with
* the key.
*/
void **data_buf_p, int *data_size_p)
{
int bucket;
unsigned int ksize;
return TABLE_ERROR_ARG_NULL;
return TABLE_ERROR_PNT;
return TABLE_ERROR_ARG_NULL;
/* find key size */
if (key_size < 0)
else
/* get the bucket number via a has function */
/* look for the entry in this bucket, only check keys of the same size */
break;
}
/* not found? */
return TABLE_ERROR_NOT_FOUND;
if (data_buf_p != NULL) {
if (entry_p->te_data_size == 0)
*data_buf_p = NULL;
else {
if (table_p->ta_data_align == 0)
else
}
}
if (data_size_p != NULL)
return TABLE_ERROR_NONE;
}
/*
* int table_delete
*
* DESCRIPTION:
*
* This routine looks up a key made up of a buffer of bytes and an
* associated size in the table. If found then it will be removed
* from the table. The associated data can be passed back to the user
* if requested.
*
* RETURNS:
*
* Success - TABLE_ERROR_NONE
*
* Failure - Table error code.
*
* NOTE: this could be an allocation error if the library is to return
* the data to the user.
*
* ARGUMENTS:
*
* table_p - Table structure pointer from which we will be deleteing
* the key.
*
* key_buf - Buffer of bytes of the key that we are searching for to
* delete. If you are deleting an (int) key (for example) then
* key_buf should be a (int *).
*
* key_size - Size of the key_buf buffer. If set to < 0 then the
* library will do a strlen of key_buf and add 1 for the '\0'. If you
* are deleting an (int) key (for example) then key_size should be
* sizeof(int).
*
* data_buf_p - Pointer which, if not NULL, will be set to the address
* of the data storage that was allocated in the table and that was
* associated with the key. If a (long) was stored as the data (for
* example) then data_buf_p should be (long **) i.e. the address of a
* (long *). If a pointer is passed in, the caller is responsible for
* freeing it after use. If data_buf_p is NULL then the library will
* free up the data allocation itself.
*
* data_size_p - Pointer to an integer which, if not NULL, will be set
* to the size of the data that was stored in the table and that was
* associated with the key.
*/
void **data_buf_p, int *data_size_p)
{
int bucket;
unsigned int ksize;
unsigned char *data_copy_p;
return TABLE_ERROR_ARG_NULL;
return TABLE_ERROR_PNT;
return TABLE_ERROR_ARG_NULL;
/* get the key size */
if (key_size < 0)
else
/* find our bucket */
/* look for the entry in this bucket, only check keys of the same size */
break;
}
/* did we find it? */
return TABLE_ERROR_NOT_FOUND;
/*
* NOTE: we may want to adjust the linear counters here if the entry
* we are deleting is the one we are pointing on or is ahead of the
* one in the bucket list
*/
/* remove entry from the linked list */
else
/* free entry */
if (data_buf_p != NULL) {
if (entry_p->te_data_size == 0)
*data_buf_p = NULL;
else {
/*
* if we were storing it compacted, we now need to malloc some
* space if the user wants the value after the delete.
*/
if (*data_buf_p == NULL)
return TABLE_ERROR_ALLOC;
if (table_p->ta_data_align == 0)
else
}
}
if (data_size_p != NULL)
table_p->ta_entry_n--;
/* do we need auto-adjust down? */
return TABLE_ERROR_NONE;
}
/*
* int table_delete_first
*
* DESCRIPTION:
*
* This is like the table_delete routines except it deletes the first
* particular key. The associated key and data information can be
* passed back to the user if requested. This routines is handy to
* clear out a table.
*
* RETURNS:
*
* Success - TABLE_ERROR_NONE
*
* Failure - Table error code.
*
* NOTE: this could be an allocation error if the library is to return
* the data to the user.
*
* ARGUMENTS:
*
* table_p - Table structure pointer from which we will be deleteing
* the first key.
*
* key_buf_p - Pointer which, if not NULL, will be set to the address
* of the storage of the first key that was allocated in the table.
* If an (int) was stored as the first key (for example) then
* key_buf_p should be (int **) i.e. the address of a (int *). If a
* pointer is passed in, the caller is responsible for freeing it
* after use. If key_buf_p is NULL then the library will free up the
* key allocation itself.
*
* key_size_p - Pointer to an integer which, if not NULL, will be set
* to the size of the key that was stored in the table and that was
* associated with the key.
*
* data_buf_p - Pointer which, if not NULL, will be set to the address
* of the data storage that was allocated in the table and that was
* associated with the key. If a (long) was stored as the data (for
* example) then data_buf_p should be (long **) i.e. the address of a
* (long *). If a pointer is passed in, the caller is responsible for
* freeing it after use. If data_buf_p is NULL then the library will
* free up the data allocation itself.
*
* data_size_p - Pointer to an integer which, if not NULL, will be set
* to the size of the data that was stored in the table and that was
* associated with the key.
*/
void **key_buf_p, int *key_size_p,
void **data_buf_p, int *data_size_p)
{
unsigned char *data_copy_p;
return TABLE_ERROR_ARG_NULL;
return TABLE_ERROR_PNT;
/* take the first entry */
return TABLE_ERROR_NOT_FOUND;
/*
* NOTE: we may want to adjust the linear counters here if the entry
* we are deleting is the one we are pointing on or is ahead of the
* one in the bucket list
*/
/* remove entry from the linked list */
/* free entry */
if (entry_p->te_key_size == 0)
else {
/*
* if we were storing it compacted, we now need to malloc some
* space if the user wants the value after the delete.
*/
return TABLE_ERROR_ALLOC;
}
}
if (key_size_p != NULL)
if (data_buf_p != NULL) {
if (entry_p->te_data_size == 0)
*data_buf_p = NULL;
else {
/*
* if we were storing it compacted, we now need to malloc some
* space if the user wants the value after the delete.
*/
if (*data_buf_p == NULL)
return TABLE_ERROR_ALLOC;
if (table_p->ta_data_align == 0)
else
}
}
if (data_size_p != NULL)
table_p->ta_entry_n--;
/* do we need auto-adjust down? */
return TABLE_ERROR_NONE;
}
/*
* int table_info
*
* DESCRIPTION:
*
* Get some information about a table_p structure.
*
* RETURNS:
*
* Success - TABLE_ERROR_NONE
*
* Failure - Table error code.
*
* ARGUMENTS:
*
* table_p - Table structure pointer from which we are getting
* information.
*
* num_buckets_p - Pointer to an integer which, if not NULL, will
* contain the number of buckets in the table.
*
* num_entries_p - Pointer to an integer which, if not NULL, will
* contain the number of entries stored in the table.
*/
{
return TABLE_ERROR_ARG_NULL;
return TABLE_ERROR_PNT;
if (num_buckets_p != NULL)
if (num_entries_p != NULL)
return TABLE_ERROR_NONE;
}
/*
* int table_adjust
*
* DESCRIPTION:
*
* Set the number of buckets in a table to a certain value.
*
* RETURNS:
*
* Success - TABLE_ERROR_NONE
*
* Failure - Table error code.
*
* ARGUMENTS:
*
* table_p - Table structure pointer of which we are adjusting.
*
* bucket_n - Number buckets to adjust the table to. Set to 0 to
* adjust the table to its number of entries.
*/
{
int bucket;
unsigned int buck_n;
return TABLE_ERROR_ARG_NULL;
return TABLE_ERROR_PNT;
/*
* NOTE: we walk through the entries and rehash them. If we stored
* the hash value as a full int in the table-entry, all we would
* have to do is remod it.
*/
/* normalize to the number of entries */
if (bucket_n == 0)
else
/* we must have at least 1 bucket */
if (buck_n == 0)
buck_n = 1;
/* make sure we have somethign to do */
return TABLE_ERROR_NONE;
/* allocate a new bucket list */
return TABLE_ERROR_ALLOC;
/*
* run through each of the items in the current table and rehash
* them into the newest bucket sizes
*/
/* hash the old data into the new table size */
/* record the next one now since we overwrite next below */
/* insert into new list, no need to append */
/*
* NOTE: we may want to adjust the bucket_c linear entry here to
* keep it current
*/
}
/* remove the old table pointers as we go by */
}
/* replace the table buckets with the new ones */
return TABLE_ERROR_NONE;
}
/*
* const char *table_strerror
*
* DESCRIPTION:
*
* Return the corresponding string for the error number.
*
* RETURNS:
*
* Success - String equivalient of the error.
*
* Failure - String "invalid error code"
*
* ARGUMENTS:
*
* error - Error number that we are converting.
*/
const char *table_strerror(const int error)
{
}
return INVALID_ERROR;
}
/*
* int table_type_size
*
* DESCRIPTION:
*
* Return the size of the internal table type.
*
* RETURNS:
*
* The size of the table_t type.
*
* ARGUMENTS:
*
* None.
*/
int table_type_size(void)
{
return sizeof(table_t);
}
/************************* linear access routines ****************************/
/*
* int table_first
*
* DESCRIPTION:
*
* Find first element in a table and pass back information about the
* are ignored.
*
* NOTE: This function is not reentrant. More than one thread cannot
* be doing a first and next on the same table at the same time. Use
* the table_first_r version below for this.
*
* RETURNS:
*
* Success - TABLE_ERROR_NONE
*
* Failure - Table error code.
*
* ARGUMENTS:
*
* table_p - Table structure pointer from which we are getting the
* first element.
*
* key_buf_p - Pointer which, if not NULL, will be set to the address
* of the storage of the first key that is allocated in the table. If
* an (int) is stored as the first key (for example) then key_buf_p
* should be (int **) i.e. the address of a (int *).
*
* key_size_p - Pointer to an integer which, if not NULL, will be set
* to the size of the key that is stored in the table and that is
* associated with the first key.
*
* data_buf_p - Pointer which, if not NULL, will be set to the address
* of the data storage that is allocated in the table and that is
* associated with the first key. If a (long) is stored as the data
* (for example) then data_buf_p should be (long **) i.e. the address
* of a (long *).
*
* data_size_p - Pointer to an integer which, if not NULL, will be set
* to the size of the data that is stored in the table and that is
* associated with the first key.
*/
void **key_buf_p, int *key_size_p,
void **data_buf_p, int *data_size_p)
{
return TABLE_ERROR_ARG_NULL;
return TABLE_ERROR_PNT;
/* initialize our linear magic number */
return TABLE_ERROR_NOT_FOUND;
if (key_size_p != NULL)
if (data_buf_p != NULL) {
if (entry_p->te_data_size == 0)
*data_buf_p = NULL;
else {
if (table_p->ta_data_align == 0)
else
}
}
if (data_size_p != NULL)
return TABLE_ERROR_NONE;
}
/*
* int table_next
*
* DESCRIPTION:
*
* Find the next element in a table and pass back information about
* they are ignored.
*
* NOTE: This function is not reentrant. More than one thread cannot
* be doing a first and next on the same table at the same time. Use
* the table_next_r version below for this.
*
* RETURNS:
*
* Success - TABLE_ERROR_NONE
*
* Failure - Table error code.
*
* ARGUMENTS:
*
* table_p - Table structure pointer from which we are getting the
* next element.
*
* key_buf_p - Pointer which, if not NULL, will be set to the address
* of the storage of the next key that is allocated in the table. If
* an (int) is stored as the next key (for example) then key_buf_p
* should be (int **) i.e. the address of a (int *).
*
* key_size_p - Pointer to an integer which, if not NULL, will be set
* to the size of the key that is stored in the table and that is
* associated with the next key.
*
* data_buf_p - Pointer which, if not NULL, will be set to the address
* of the data storage that is allocated in the table and that is
* associated with the next key. If a (long) is stored as the data
* (for example) then data_buf_p should be (long **) i.e. the address
* of a (long *).
*
* data_size_p - Pointer to an integer which, if not NULL, will be set
* to the size of the data that is stored in the table and that is
* associated with the next key.
*/
void **key_buf_p, int *key_size_p,
void **data_buf_p, int *data_size_p)
{
int error;
return TABLE_ERROR_ARG_NULL;
return TABLE_ERROR_PNT;
return TABLE_ERROR_LINEAR;
/* move to the next entry */
return error;
if (key_size_p != NULL)
if (data_buf_p != NULL) {
if (entry_p->te_data_size == 0)
*data_buf_p = NULL;
else {
if (table_p->ta_data_align == 0)
else
}
}
if (data_size_p != NULL)
return TABLE_ERROR_NONE;
}
/*
* int table_this
*
* DESCRIPTION:
*
* Find the current element in a table and pass back information about
* they are ignored.
*
* NOTE: This function is not reentrant. Use the table_current_r
* version below.
*
* RETURNS:
*
* Success - TABLE_ERROR_NONE
*
* Failure - Table error code.
*
* ARGUMENTS:
*
* table_p - Table structure pointer from which we are getting the
* current element.
*
* key_buf_p - Pointer which, if not NULL, will be set to the address
* of the storage of the current key that is allocated in the table.
* If an (int) is stored as the current key (for example) then
* key_buf_p should be (int **) i.e. the address of a (int *).
*
* key_size_p - Pointer to an integer which, if not NULL, will be set
* to the size of the key that is stored in the table and that is
* associated with the current key.
*
* data_buf_p - Pointer which, if not NULL, will be set to the address
* of the data storage that is allocated in the table and that is
* associated with the current key. If a (long) is stored as the data
* (for example) then data_buf_p should be (long **) i.e. the address
* of a (long *).
*
* data_size_p - Pointer to an integer which, if not NULL, will be set
* to the size of the data that is stored in the table and that is
* associated with the current key.
*/
void **key_buf_p, int *key_size_p,
void **data_buf_p, int *data_size_p)
{
int entry_c;
return TABLE_ERROR_ARG_NULL;
return TABLE_ERROR_PNT;
return TABLE_ERROR_LINEAR;
/* if we removed an item that shorted the bucket list, we may get this */
/*
* NOTE: this might happen if we delete an item which shortens the
* table bucket numbers.
*/
return TABLE_ERROR_NOT_FOUND;
}
/* find the entry which is the nth in the list */
/* NOTE: we swap the order here to be more efficient */
/* did we reach the end of the list? */
break;
}
/* is this a NOT_FOUND or a LINEAR error */
return TABLE_ERROR_NOT_FOUND;
if (key_size_p != NULL)
if (data_buf_p != NULL) {
if (entry_p->te_data_size == 0)
*data_buf_p = NULL;
else {
if (table_p->ta_data_align == 0)
else
}
}
if (data_size_p != NULL)
return TABLE_ERROR_NONE;
}
/*
* int table_first_r
*
* DESCRIPTION:
*
* Reetrant version of the table_first routine above. Find first
* ignored.
*
* RETURNS:
*
* Success - TABLE_ERROR_NONE
*
* Failure - Table error code.
*
* ARGUMENTS:
*
* table_p - Table structure pointer from which we are getting the
* first element.
*
* linear_p - Pointer to a table linear structure which is initialized
* here. The same pointer should then be passed to table_next_r
* below.
*
* key_buf_p - Pointer which, if not NULL, will be set to the address
* of the storage of the first key that is allocated in the table. If
* an (int) is stored as the first key (for example) then key_buf_p
* should be (int **) i.e. the address of a (int *).
*
* key_size_p - Pointer to an integer which, if not NULL, will be set
* to the size of the key that is stored in the table and that is
* associated with the first key.
*
* data_buf_p - Pointer which, if not NULL, will be set to the address
* of the data storage that is allocated in the table and that is
* associated with the first key. If a (long) is stored as the data
* (for example) then data_buf_p should be (long **) i.e. the address
* of a (long *).
*
* data_size_p - Pointer to an integer which, if not NULL, will be set
* to the size of the data that is stored in the table and that is
* associated with the first key.
*/
void **key_buf_p, int *key_size_p,
void **data_buf_p, int *data_size_p)
{
return TABLE_ERROR_ARG_NULL;
return TABLE_ERROR_PNT;
return TABLE_ERROR_ARG_NULL;
/* initialize our linear magic number */
return TABLE_ERROR_NOT_FOUND;
if (key_size_p != NULL)
if (data_buf_p != NULL) {
if (entry_p->te_data_size == 0)
*data_buf_p = NULL;
else {
if (table_p->ta_data_align == 0)
else
}
}
if (data_size_p != NULL)
return TABLE_ERROR_NONE;
}
/*
* int table_next_r
*
* DESCRIPTION:
*
* Reetrant version of the table_next routine above. Find next
* ignored.
*
* RETURNS:
*
* Success - TABLE_ERROR_NONE
*
* Failure - Table error code.
*
* ARGUMENTS:
*
* table_p - Table structure pointer from which we are getting the
* next element.
*
* linear_p - Pointer to a table linear structure which is incremented
* here. The same pointer must have been passed to table_first_r
* first so that it can be initialized.
*
* key_buf_p - Pointer which, if not NULL, will be set to the address
* of the storage of the next key that is allocated in the table. If
* an (int) is stored as the next key (for example) then key_buf_p
* should be (int **) i.e. the address of a (int *).
*
* key_size_p - Pointer to an integer which, if not NULL will be set
* to the size of the key that is stored in the table and that is
* associated with the next key.
*
* data_buf_p - Pointer which, if not NULL, will be set to the address
* of the data storage that is allocated in the table and that is
* associated with the next key. If a (long) is stored as the data
* (for example) then data_buf_p should be (long **) i.e. the address
* of a (long *).
*
* data_size_p - Pointer to an integer which, if not NULL, will be set
* to the size of the data that is stored in the table and that is
* associated with the next key.
*/
void **key_buf_p, int *key_size_p,
void **data_buf_p, int *data_size_p)
{
int error;
return TABLE_ERROR_ARG_NULL;
return TABLE_ERROR_PNT;
return TABLE_ERROR_ARG_NULL;
return TABLE_ERROR_LINEAR;
/* move to the next entry */
return error;
if (key_size_p != NULL)
if (data_buf_p != NULL) {
if (entry_p->te_data_size == 0)
*data_buf_p = NULL;
else {
if (table_p->ta_data_align == 0)
else
}
}
if (data_size_p != NULL)
return TABLE_ERROR_NONE;
}
/*
* int table_this_r
*
* DESCRIPTION:
*
* Reetrant version of the table_this routine above. Find current
* ignored.
*
* RETURNS:
*
* Success - TABLE_ERROR_NONE
*
* Failure - Table error code.
*
* ARGUMENTS:
*
* table_p - Table structure pointer from which we are getting the
* current element.
*
* linear_p - Pointer to a table linear structure which is accessed
* here. The same pointer must have been passed to table_first_r
* first so that it can be initialized.
*
* key_buf_p - Pointer which, if not NULL, will be set to the address
* of the storage of the current key that is allocated in the table.
* If an (int) is stored as the current key (for example) then
* key_buf_p should be (int **) i.e. the address of a (int *).
*
* key_size_p - Pointer to an integer which, if not NULL, will be set
* to the size of the key that is stored in the table and that is
* associated with the current key.
*
* data_buf_p - Pointer which, if not NULL, will be set to the address
* of the data storage that is allocated in the table and that is
* associated with the current key. If a (long) is stored as the data
* (for example) then data_buf_p should be (long **) i.e. the address
* of a (long *).
*
* data_size_p - Pointer to an integer which, if not NULL, will be set
* to the size of the data that is stored in the table and that is
* associated with the current key.
*/
void **key_buf_p, int *key_size_p,
void **data_buf_p, int *data_size_p)
{
int entry_c;
return TABLE_ERROR_ARG_NULL;
return TABLE_ERROR_PNT;
return TABLE_ERROR_LINEAR;
/* if we removed an item that shorted the bucket list, we may get this */
/*
* NOTE: this might happen if we delete an item which shortens the
* table bucket numbers.
*/
return TABLE_ERROR_NOT_FOUND;
}
/* find the entry which is the nth in the list */
}
return TABLE_ERROR_NOT_FOUND;
if (key_size_p != NULL)
if (data_buf_p != NULL) {
if (entry_p->te_data_size == 0)
*data_buf_p = NULL;
else {
if (table_p->ta_data_align == 0)
else
}
}
if (data_size_p != NULL)
return TABLE_ERROR_NONE;
}
/******************************** table order ********************************/
/*
* table_entry_t *table_order
*
* DESCRIPTION:
*
* Order a table by building an array of table entry pointers and then
* sorting this array using the qsort function. To retrieve the
* sorted entries, you can then use the table_entry routine to access
* each entry in order.
*
* NOTE: This routine is now thread safe in that two table_order calls
* can now happen at the same time, even on the same table.
*
* RETURNS:
*
* An allocated list of entry pointers which must be freed later.
* Returns null on error.
*
* ARGUMENTS:
*
* table_p - Pointer to the table that we are ordering.
*
* compare - Comparison function defined by the user. Its definition
* is at the top of the table.h file. If this is NULL then it will
* order the table my memcmp-ing the keys.
*
* num_entries_p - Pointer to an integer which, if not NULL, will
* contain the number of entries in the returned entry pointer array.
*
* error_p - Pointer to an integer which, if not NULL, will contain a
* table error code.
*/
int *num_entries_p, int *error_p)
{
int error;
return NULL;
}
return NULL;
}
/* there must be at least 1 element in the table for this to work */
if (table_p->ta_entry_n == 0) {
return NULL;
}
sizeof(table_entry_t *));
return NULL;
}
/* get a pointer to all entries */
return NULL;
}
/* add all of the entries to the array */
if (error != TABLE_ERROR_NOT_FOUND) {
return NULL;
}
/* this is regardless of the alignment */
}
else if (table_p->ta_data_align == 0)
else
/* now qsort the entire entries array from first to last element */
table_p);
if (num_entries_p != NULL)
return entries;
}
/*
* int table_entry
*
* DESCRIPTION:
*
* Get information about an element. The element is one from the
* pointers are NULL then they are ignored.
*
* RETURNS:
*
* Success - TABLE_ERROR_NONE
*
* Failure - Table error code.
*
* ARGUMENTS:
*
* table_p - Table structure pointer from which we are getting the
* element.
*
* entry_p - Pointer to a table entry from the array returned by the
* table_order function.
*
* key_buf_p - Pointer which, if not NULL, will be set to the address
* of the storage of this entry that is allocated in the table. If an
* (int) is stored as this entry (for example) then key_buf_p should
* be (int **) i.e. the address of a (int *).
*
* key_size_p - Pointer to an integer which, if not NULL, will be set
* to the size of the key that is stored in the table.
*
* data_buf_p - Pointer which, if not NULL, will be set to the address
* of the data storage of this entry that is allocated in the table.
* If a (long) is stored as this entry data (for example) then
* data_buf_p should be (long **) i.e. the address of a (long *).
*
* data_size_p - Pointer to an integer which, if not NULL, will be set
* to the size of the data that is stored in the table.
*/
void **key_buf_p, int *key_size_p,
void **data_buf_p, int *data_size_p)
{
return TABLE_ERROR_ARG_NULL;
return TABLE_ERROR_PNT;
return TABLE_ERROR_ARG_NULL;
if (key_size_p != NULL)
if (data_buf_p != NULL) {
if (entry_p->te_data_size == 0)
*data_buf_p = NULL;
else {
if (table_p->ta_data_align == 0)
else
}
}
if (data_size_p != NULL)
return TABLE_ERROR_NONE;
}