1 /*                      _             _
2 **  _ __ ___   ___   __| |    ___ ___| |  mod_ssl
3 ** | '_ ` _ \ / _ \ / _` |   / __/ __| |  Apache Interface to OpenSSL
4 ** | | | | | | (_) | (_| |   \__ \__ \ |  www.modssl.org
5 ** |_| |_| |_|\___/ \__,_|___|___/___/_|  ftp.modssl.org
6 **                      |_____|
7 **  ssl_util_table.c
8 **  High Performance Hash Table Functions
9 */
10 
11 /* ====================================================================
12  * Copyright (c) 1999-2003 Ralf S. Engelschall. All rights reserved.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  *
18  * 1. Redistributions of source code must retain the above copyright
19  *    notice, this list of conditions and the following disclaimer.
20  *
21  * 2. Redistributions in binary form must reproduce the above copyright
22  *    notice, this list of conditions and the following
23  *    disclaimer in the documentation and/or other materials
24  *    provided with the distribution.
25  *
26  * 3. All advertising materials mentioning features or use of this
27  *    software must display the following acknowledgment:
28  *    "This product includes software developed by
29  *     Ralf S. Engelschall <rse@engelschall.com> for use in the
30  *     mod_ssl project (http://www.modssl.org/)."
31  *
32  * 4. The names "mod_ssl" must not be used to endorse or promote
33  *    products derived from this software without prior written
34  *    permission. For written permission, please contact
35  *    rse@engelschall.com.
36  *
37  * 5. Products derived from this software may not be called "mod_ssl"
38  *    nor may "mod_ssl" appear in their names without prior
39  *    written permission of Ralf S. Engelschall.
40  *
41  * 6. Redistributions of any form whatsoever must retain the following
42  *    acknowledgment:
43  *    "This product includes software developed by
44  *     Ralf S. Engelschall <rse@engelschall.com> for use in the
45  *     mod_ssl project (http://www.modssl.org/)."
46  *
47  * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
48  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
50  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL RALF S. ENGELSCHALL OR
51  * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
52  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
53  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
54  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
56  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
57  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
58  * OF THE POSSIBILITY OF SUCH DAMAGE.
59  * ====================================================================
60  */
61 
62 /*
63  * Generic hash table handler
64  * Table 4.1.0 July-28-1998
65  *
66  * This library is a generic open hash table with buckets and
67  * linked lists.  It is pretty high performance.  Each element
68  * has a key and a data.  The user indexes on the key to find the
69  * data.
70  *
71  * Copyright 1998 by Gray Watson <gray@letters.com>
72  *
73  * Permission to use, copy, modify, and distribute this software for any
74  * purpose and without fee is hereby granted, provided that the above
75  * copyright notice and this permission notice appear in all copies,
76  * and that the name of Gray Watson not be used in advertising or
77  * publicity pertaining to distribution of the document or software
78  * without specific, written prior permission.
79  *
80  * Gray Watson makes no representations about the suitability of the
81  * software described herein for any purpose.  It is provided "as is"
82  * without express or implied warranty.
83  *
84  * Modified in March 1999 by Ralf S. Engelschall <rse@engelschall.com>
85  * for use in the mod_ssl project:
86  *   o merged table_loc.h header into table.c
87  *   o removed fillproto-comments from table.h
88  *   o removed mmap() support because it's too unportable
89  *   o added support for MM library via ta_{malloc,calloc,realloc,free}
90  */
91 
92 #include <fcntl.h>
93 #include <stdio.h>
94 #include <stdlib.h>
95 #include <string.h>
96 #include <unistd.h>
97 
98 /* forward definitions for table.h */
99 typedef struct table_st table_t;
100 typedef struct table_entry_st table_entry_t;
101 
102 #define TABLE_PRIVATE
103 #include "ssl_util_table.h"
104 
105 /****************************** local defines ******************************/
106 
107 #ifndef BITSPERBYTE
108 #define BITSPERBYTE     8
109 #endif
110 #ifndef BITS
111 #define BITS(type)      (BITSPERBYTE * (int)sizeof(type))
112 #endif
113 
114 #define TABLE_MAGIC     0xBADF00D       /* very magic magicness */
115 #define LINEAR_MAGIC    0xAD00D00       /* magic value for linear struct */
116 #define DEFAULT_SIZE    1024    /* default table size */
117 #define MAX_ALIGNMENT   128     /* max alignment value */
118 #define MAX_SORT_SPLITS 128     /* qsort can handle 2^128 entries */
119 
120 /* returns 1 when we should grow or shrink the table */
121 #define SHOULD_TABLE_GROW(tab)  ((tab)->ta_entry_n > (tab)->ta_bucket_n * 2)
122 #define SHOULD_TABLE_SHRINK(tab) ((tab)->ta_entry_n < (tab)->ta_bucket_n / 2)
123 
124 /*
125  * void HASH_MIX
126  *
127  * DESCRIPTION:
128  *
129  * Mix 3 32-bit values reversibly.  For every delta with one or two bits
130  * set, and the deltas of all three high bits or all three low bits,
131  * whether the original value of a,b,c is almost all zero or is
132  * uniformly distributed.
133  *
134  * If HASH_MIX() is run forward or backward, at least 32 bits in a,b,c
135  * have at least 1/4 probability of changing.  If mix() is run
136  * forward, every bit of c will change between 1/3 and 2/3 of the
137  * time.  (Well, 22/100 and 78/100 for some 2-bit deltas.)
138  *
139  * HASH_MIX() takes 36 machine instructions, but only 18 cycles on a
140  * superscalar machine (like a Pentium or a Sparc).  No faster mixer
141  * seems to work, that's the result of my brute-force search.  There
142  * were about 2^68 hashes to choose from.  I only tested about a
143  * billion of those.
144  */
145 #define HASH_MIX(a, b, c) \
146  do { \
147    a -= b; a -= c; a ^= (c >> 13); \
148    b -= c; b -= a; b ^= (a << 8); \
149    c -= a; c -= b; c ^= (b >> 13); \
150    a -= b; a -= c; a ^= (c >> 12); \
151    b -= c; b -= a; b ^= (a << 16); \
152    c -= a; c -= b; c ^= (b >> 5); \
153    a -= b; a -= c; a ^= (c >> 3); \
154    b -= c; b -= a; b ^= (a << 10); \
155    c -= a; c -= b; c ^= (b >> 15); \
156  } while(0)
157 
158 #define TABLE_POINTER(table, type, pnt)         (pnt)
159 
160 /*
161  * Macros to get at the key and the data pointers
162  */
163 #define ENTRY_KEY_BUF(entry_p)          ((entry_p)->te_key_buf)
164 #define ENTRY_DATA_BUF(tab_p, entry_p)  \
165      (ENTRY_KEY_BUF(entry_p) + (entry_p)->te_key_size)
166 
167 /*
168  * Table structures...
169  */
170 
171 /*
172  * HACK: this should be equiv as the table_entry_t without the key_buf
173  * char.  We use this with the ENTRY_SIZE() macro above which solves
174  * the problem with the lack of the [0] GNU hack.  We use the
175  * table_entry_t structure to better map the memory and make things
176  * faster.
177  */
178 typedef struct table_shell_st {
179     unsigned int te_key_size;   /* size of data */
180     unsigned int te_data_size;  /* size of data */
181     struct table_shell_st *te_next_p;   /* pointer to next in the list */
182     /* NOTE: this does not have the te_key_buf field here */
183 } table_shell_t;
184 
185 /*
186  * Elements in the bucket linked-lists.  The key[1] is the start of
187  * the key with the rest of the key and all of the data information
188  * packed in memory directly after the end of this structure.
189  *
190  * NOTE: if this structure is changed, the table_shell_t must be changed
191  * to match.
192  */
193 struct table_entry_st {
194     unsigned int te_key_size;   /* size of data */
195     unsigned int te_data_size;  /* size of data */
196     struct table_entry_st *te_next_p;   /* pointer to next in the list */
197     unsigned char te_key_buf[1];        /* 1st byte of key buf */
198 };
199 
200 /* external structure for debuggers be able to see void */
201 typedef table_entry_t table_entry_ext_t;
202 
203 /* main table structure */
204 struct table_st {
205     unsigned int ta_magic;      /* magic number */
206     unsigned int ta_flags;      /* table's flags defined in table.h */
207     unsigned int ta_bucket_n;   /* num of buckets, should be 2^X */
208     unsigned int ta_entry_n;    /* num of entries in all buckets */
209     unsigned int ta_data_align; /* data alignment value */
210     table_entry_t **ta_buckets; /* array of linked lists */
211     table_linear_t ta_linear;   /* linear tracking */
212     unsigned long ta_file_size; /* size of on-disk space */
213     void *(*ta_malloc)(size_t size);
214     void *(*ta_calloc)(size_t number, size_t size);
215     void *(*ta_realloc)(void *ptr, size_t size);
216     void (*ta_free)(void *ptr);
217 };
218 
219 /* external table structure for debuggers */
220 typedef table_t table_ext_t;
221 
222 /* local comparison functions */
223 typedef int (*compare_t) (const void *element1_p, const void *element2_p,
224                           table_compare_t user_compare,
225                           const table_t * table_p);
226 
227 /*
228  * to map error to string
229  */
230 typedef struct {
231     int es_error;               /* error number */
232     char *es_string;            /* assocaited string */
233 } error_str_t;
234 
235 static error_str_t errors[] =
236 {
237     {TABLE_ERROR_NONE, "no error"},
238     {TABLE_ERROR_PNT, "invalid table pointer"},
239     {TABLE_ERROR_ARG_NULL, "buffer argument is null"},
240     {TABLE_ERROR_SIZE, "incorrect size argument"},
241     {TABLE_ERROR_OVERWRITE, "key exists and no overwrite"},
242     {TABLE_ERROR_NOT_FOUND, "key does not exist"},
243     {TABLE_ERROR_ALLOC, "error allocating memory"},
244     {TABLE_ERROR_LINEAR, "linear access not in progress"},
245     {TABLE_ERROR_OPEN, "could not open file"},
246     {TABLE_ERROR_SEEK, "could not seek to position in file"},
247     {TABLE_ERROR_READ, "could not read from file"},
248     {TABLE_ERROR_WRITE, "could not write to file"},
249     {TABLE_ERROR_EMPTY, "table is empty"},
250     {TABLE_ERROR_NOT_EMPTY, "table contains data"},
251     {TABLE_ERROR_ALIGNMENT, "invalid alignment value"},
252     {0}
253 };
254 
255 #define INVALID_ERROR   "invalid error code"
256 
257 /****************************** local functions ******************************/
258 
259 /*
260  * static table_entry_t *first_entry
261  *
262  * DESCRIPTION:
263  *
264  * Return the first entry in the table.  It will set the linear
265  * structure counter to the position of the first entry.
266  *
267  * RETURNS:
268  *
269  * Success: A pointer to the first entry in the table.
270  *
271  * Failure: NULL if there is no first entry.
272  *
273  * ARGUMENTS:
274  *
275  * table_p - Table whose next entry we are finding.
276  *
277  * linear_p - Pointer to a linear structure which we will advance and
278  * then find the corresponding entry.
279  */
first_entry(table_t * table_p,table_linear_t * linear_p)280 static table_entry_t *first_entry(table_t * table_p,
281                                   table_linear_t * linear_p)
282 {
283     table_entry_t *entry_p;
284     unsigned int bucket_c = 0;
285 
286     /* look for the first non-empty bucket */
287     for (bucket_c = 0; bucket_c < table_p->ta_bucket_n; bucket_c++) {
288         entry_p = table_p->ta_buckets[bucket_c];
289         if (entry_p != NULL) {
290             if (linear_p != NULL) {
291                 linear_p->tl_bucket_c = bucket_c;
292                 linear_p->tl_entry_c = 0;
293             }
294             return TABLE_POINTER(table_p, table_entry_t *, entry_p);
295         }
296     }
297 
298     return NULL;
299 }
300 
301 /*
302  * static table_entry_t *next_entry
303  *
304  * DESCRIPTION:
305  *
306  * Return the next entry in the table which is past the position in
307  * our linear pointer.  It will advance the linear structure counters.
308  *
309  * RETURNS:
310  *
311  * Success: A pointer to the next entry in the table.
312  *
313  * Failure: NULL.
314  *
315  * ARGUMENTS:
316  *
317  * table_p - Table whose next entry we are finding.
318  *
319  * linear_p - Pointer to a linear structure which we will advance and
320  * then find the corresponding entry.
321  *
322  * error_p - Pointer to an integer which when the routine returns will
323  * contain a table error code.
324  */
next_entry(table_t * table_p,table_linear_t * linear_p,int * error_p)325 static table_entry_t *next_entry(table_t * table_p, table_linear_t * linear_p,
326                                  int *error_p)
327 {
328     table_entry_t *entry_p;
329     int entry_c;
330 
331     /* can't next if we haven't first-ed */
332     if (linear_p == NULL) {
333         if (error_p != NULL)
334             *error_p = TABLE_ERROR_LINEAR;
335         return NULL;
336     }
337 
338     if (linear_p->tl_bucket_c >= table_p->ta_bucket_n) {
339         /*
340          * NOTE: this might happen if we delete an item which shortens the
341          * table bucket numbers.
342          */
343         if (error_p != NULL)
344             *error_p = TABLE_ERROR_NOT_FOUND;
345         return NULL;
346     }
347 
348     linear_p->tl_entry_c++;
349 
350     /* find the entry which is the nth in the list */
351     entry_p = table_p->ta_buckets[linear_p->tl_bucket_c];
352     /* NOTE: we swap the order here to be more efficient */
353     for (entry_c = linear_p->tl_entry_c; entry_c > 0; entry_c--) {
354         /* did we reach the end of the list? */
355         if (entry_p == NULL)
356             break;
357         entry_p = TABLE_POINTER(table_p, table_entry_t *, entry_p)->te_next_p;
358     }
359 
360     /* did we find an entry in the current bucket? */
361     if (entry_p != NULL) {
362         if (error_p != NULL)
363             *error_p = TABLE_ERROR_NONE;
364         return TABLE_POINTER(table_p, table_entry_t *, entry_p);
365     }
366 
367     /* find the first entry in the next non-empty bucket */
368 
369     linear_p->tl_entry_c = 0;
370     for (linear_p->tl_bucket_c++; linear_p->tl_bucket_c < table_p->ta_bucket_n;
371          linear_p->tl_bucket_c++) {
372         entry_p = table_p->ta_buckets[linear_p->tl_bucket_c];
373         if (entry_p != NULL) {
374             if (error_p != NULL)
375                 *error_p = TABLE_ERROR_NONE;
376             return TABLE_POINTER(table_p, table_entry_t *, entry_p);
377         }
378     }
379 
380     if (error_p != NULL)
381         *error_p = TABLE_ERROR_NOT_FOUND;
382     return NULL;
383 }
384 
385 /*
386  * static unsigned int hash
387  *
388  * DESCRIPTION:
389  *
390  * Hash a variable-length key into a 32-bit value.  Every bit of the
391  * key affects every bit of the return value.  Every 1-bit and 2-bit
392  * delta achieves avalanche.  About (6 * len + 35) instructions.  The
393  * best hash table sizes are powers of 2.  There is no need to use mod
394  * (sooo slow!).  If you need less than 32 bits, use a bitmask.  For
395  * example, if you need only 10 bits, do h = (h & hashmask(10)); In
396  * which case, the hash table should have hashsize(10) elements.
397  *
398  * By Bob Jenkins, 1996.  bob_jenkins@compuserve.com.  You may use
399  * this code any way you wish, private, educational, or commercial.
400  * It's free.  See
401  * http://ourworld.compuserve.com/homepages/bob_jenkins/evahash.htm
402  * Use for hash table lookup, or anything where one collision in 2^^32
403  * is acceptable.  Do NOT use for cryptographic purposes.
404  *
405  * RETURNS:
406  *
407  * Returns a 32-bit hash value.
408  *
409  * ARGUMENTS:
410  *
411  * key - Key (the unaligned variable-length array of bytes) that we
412  * are hashing.
413  *
414  * length - Length of the key in bytes.
415  *
416  * init_val - Initialization value of the hash if you need to hash a
417  * number of strings together.  For instance, if you are hashing N
418  * strings (unsigned char **)keys, do it like this:
419  *
420  * for (i=0, h=0; i<N; ++i) h = hash( keys[i], len[i], h);
421  */
hash(const unsigned char * key,const unsigned int length,const unsigned int init_val)422 static unsigned int hash(const unsigned char *key,
423                          const unsigned int length,
424                          const unsigned int init_val)
425 {
426     const unsigned char *key_p = key;
427     unsigned int a, b, c, len;
428 
429     /* set up the internal state */
430     a = 0x9e3779b9;             /* the golden ratio; an arbitrary value */
431     b = 0x9e3779b9;
432     c = init_val;               /* the previous hash value */
433 
434     /* handle most of the key */
435     for (len = length; len >= 12; len -= 12) {
436         a += (key_p[0]
437               + ((unsigned long) key_p[1] << 8)
438               + ((unsigned long) key_p[2] << 16)
439               + ((unsigned long) key_p[3] << 24));
440         b += (key_p[4]
441               + ((unsigned long) key_p[5] << 8)
442               + ((unsigned long) key_p[6] << 16)
443               + ((unsigned long) key_p[7] << 24));
444         c += (key_p[8]
445               + ((unsigned long) key_p[9] << 8)
446               + ((unsigned long) key_p[10] << 16)
447               + ((unsigned long) key_p[11] << 24));
448         HASH_MIX(a, b, c);
449         key_p += 12;
450     }
451 
452     c += length;
453 
454     /* all the case statements fall through to the next */
455     switch (len) {
456     case 11:
457         c += ((unsigned long) key_p[10] << 24);
458     case 10:
459         c += ((unsigned long) key_p[9] << 16);
460     case 9:
461         c += ((unsigned long) key_p[8] << 8);
462         /* the first byte of c is reserved for the length */
463     case 8:
464         b += ((unsigned long) key_p[7] << 24);
465     case 7:
466         b += ((unsigned long) key_p[6] << 16);
467     case 6:
468         b += ((unsigned long) key_p[5] << 8);
469     case 5:
470         b += key_p[4];
471     case 4:
472         a += ((unsigned long) key_p[3] << 24);
473     case 3:
474         a += ((unsigned long) key_p[2] << 16);
475     case 2:
476         a += ((unsigned long) key_p[1] << 8);
477     case 1:
478         a += key_p[0];
479         /* case 0: nothing left to add */
480     }
481     HASH_MIX(a, b, c);
482 
483     return c;
484 }
485 
486 /*
487  * static int entry_size
488  *
489  * DESCRIPTION:
490  *
491  * Calculates the appropriate size of an entry to include the key and
492  * data sizes as well as any associated alignment to the data.
493  *
494  * RETURNS:
495  *
496  * The associated size of the entry.
497  *
498  * ARGUMENTS:
499  *
500  * table_p - Table associated with the entries whose size we are
501  * determining.
502  *
503  * key_size - Size of the entry key.
504  *
505  * data - Size of the entry data.
506  */
entry_size(const table_t * table_p,const unsigned int key_size,const unsigned int data_size)507 static int entry_size(const table_t * table_p, const unsigned int key_size,
508                       const unsigned int data_size)
509 {
510     int size, left;
511 
512     /* initial size -- key is already aligned if right after struct */
513     size = sizeof(struct table_shell_st) + key_size;
514 
515     /* if there is no alignment then it is easy */
516     if (table_p->ta_data_align == 0)
517         return size + data_size;
518     /* add in our alignement */
519     left = size & (table_p->ta_data_align - 1);
520     if (left > 0)
521         size += table_p->ta_data_align - left;
522     /* we add the data size here after the alignment */
523     size += data_size;
524 
525     return size;
526 }
527 
528 /*
529  * static unsigned char *entry_data_buf
530  *
531  * DESCRIPTION:
532  *
533  * Companion to the ENTRY_DATA_BUF macro but this handles any
534  * associated alignment to the data in the entry.
535  *
536  * RETURNS:
537  *
538  * Pointer to the data segment of the entry.
539  *
540  * ARGUMENTS:
541  *
542  * table_p - Table associated with the entry.
543  *
544  * entry_p - Entry whose data pointer we are determining.
545  */
entry_data_buf(const table_t * table_p,const table_entry_t * entry_p)546 static unsigned char *entry_data_buf(const table_t * table_p,
547                                      const table_entry_t * entry_p)
548 {
549     const unsigned char *buf_p;
550     int size, pad;
551 
552     buf_p = entry_p->te_key_buf + entry_p->te_key_size;
553 
554     /* if there is no alignment then it is easy */
555     if (table_p->ta_data_align == 0)
556         return (unsigned char *) buf_p;
557     /* we need the size of the space before the data */
558     size = sizeof(struct table_shell_st) + entry_p->te_key_size;
559 
560     /* add in our alignment */
561     pad = size & (table_p->ta_data_align - 1);
562     if (pad > 0)
563         pad = table_p->ta_data_align - pad;
564     return (unsigned char *) buf_p + pad;
565 }
566 
567 /******************************* sort routines *******************************/
568 
569 /*
570  * static int our_compare
571  *
572  * DESCRIPTION:
573  *
574  * Compare two entries by calling user's compare program or by using
575  * memcmp.
576  *
577  * RETURNS:
578  *
579  * < 0, == 0, or > 0 depending on whether p1 is > p2, == p2, < p2.
580  *
581  * ARGUMENTS:
582  *
583  * p1 - First entry pointer to compare.
584  *
585  * p2 - Second entry pointer to compare.
586  *
587  * compare - User comparison function.  Ignored.
588  *
589  * table_p - Associated table being ordered.  Ignored.
590  */
local_compare(const void * p1,const void * p2,table_compare_t compare,const table_t * table_p)591 static int local_compare(const void *p1, const void *p2,
592                          table_compare_t compare, const table_t * table_p)
593 {
594     const table_entry_t *const *ent1_p = p1, *const *ent2_p = p2;
595     int cmp;
596     unsigned int size;
597 
598     /* compare as many bytes as we can */
599     size = (*ent1_p)->te_key_size;
600     if ((*ent2_p)->te_key_size < size)
601         size = (*ent2_p)->te_key_size;
602     cmp = memcmp(ENTRY_KEY_BUF(*ent1_p), ENTRY_KEY_BUF(*ent2_p), size);
603     /* if common-size equal, then if next more bytes, it is larger */
604     if (cmp == 0)
605         cmp = (*ent1_p)->te_key_size - (*ent2_p)->te_key_size;
606     return cmp;
607 }
608 
609 /*
610  * static int external_compare
611  *
612  * DESCRIPTION:
613  *
614  * Compare two entries by calling user's compare program or by using
615  * memcmp.
616  *
617  * RETURNS:
618  *
619  * < 0, == 0, or > 0 depending on whether p1 is > p2, == p2, < p2.
620  *
621  * ARGUMENTS:
622  *
623  * p1 - First entry pointer to compare.
624  *
625  * p2 - Second entry pointer to compare.
626  *
627  * user_compare - User comparison function.
628  *
629  * table_p - Associated table being ordered.
630  */
external_compare(const void * p1,const void * p2,table_compare_t user_compare,const table_t * table_p)631 static int external_compare(const void *p1, const void *p2,
632                             table_compare_t user_compare,
633                             const table_t * table_p)
634 {
635     const table_entry_t *const *ent1_p = p1, *const *ent2_p = p2;
636     /* since we know we are not aligned we can use the EXTRY_DATA_BUF macro */
637     return user_compare(ENTRY_KEY_BUF(*ent1_p), (*ent1_p)->te_key_size,
638                         ENTRY_DATA_BUF(table_p, *ent1_p),
639                         (*ent1_p)->te_data_size,
640                         ENTRY_KEY_BUF(*ent2_p), (*ent2_p)->te_key_size,
641                         ENTRY_DATA_BUF(table_p, *ent2_p),
642                         (*ent2_p)->te_data_size);
643 }
644 
645 /*
646  * static int external_compare_align
647  *
648  * DESCRIPTION:
649  *
650  * Compare two entries by calling user's compare program or by using
651  * memcmp.  Alignment information is necessary.
652  *
653  * RETURNS:
654  *
655  * < 0, == 0, or > 0 depending on whether p1 is > p2, == p2, < p2.
656  *
657  * ARGUMENTS:
658  *
659  * p1 - First entry pointer to compare.
660  *
661  * p2 - Second entry pointer to compare.
662  *
663  * user_compare - User comparison function.
664  *
665  * table_p - Associated table being ordered.
666  */
external_compare_align(const void * p1,const void * p2,table_compare_t user_compare,const table_t * table_p)667 static int external_compare_align(const void *p1, const void *p2,
668                                   table_compare_t user_compare,
669                                   const table_t * table_p)
670 {
671     const table_entry_t *const *ent1_p = p1, *const *ent2_p = p2;
672     /* since we are aligned we have to use the entry_data_buf function */
673     return user_compare(ENTRY_KEY_BUF(*ent1_p), (*ent1_p)->te_key_size,
674                         entry_data_buf(table_p, *ent1_p),
675                         (*ent1_p)->te_data_size,
676                         ENTRY_KEY_BUF(*ent2_p), (*ent2_p)->te_key_size,
677                         entry_data_buf(table_p, *ent2_p),
678                         (*ent2_p)->te_data_size);
679 }
680 
681 /*
682  * static void split
683  *
684  * DESCRIPTION:
685  *
686  * This sorts an array of longs via the quick sort algorithm (it's
687  * pretty quick)
688  *
689  * RETURNS:
690  *
691  * None.
692  *
693  * ARGUMENTS:
694  *
695  * first_p - Start of the list that we are splitting.
696  *
697  * last_p - Last entry in the list that we are splitting.
698  *
699  * compare - Comparison function which is handling the actual
700  * elements.  This is either a local function or a function to setup
701  * the problem element key and data pointers which then hands off to
702  * the user function.
703  *
704  * user_compare - User comparison function.  Could be NULL if we are
705  * just using a local comparison function.
706  *
707  * table_p - Associated table being sorted.
708  */
split(void * first_p,void * last_p,compare_t compare,table_compare_t user_compare,table_t * table_p)709 static void split(void *first_p, void *last_p, compare_t compare,
710                   table_compare_t user_compare, table_t * table_p)
711 {
712     void *pivot_p, *left_p, *right_p, *left_last_p, *right_first_p;
713     void *firsts[MAX_SORT_SPLITS], *lasts[MAX_SORT_SPLITS];
714     int split_c = 0;
715 
716     for (;;) {
717 
718         /* no need to split the list if it is < 2 elements */
719         while (first_p >= last_p) {
720             if (split_c == 0) {
721                 /* we are done */
722                 return;
723             }
724             split_c--;
725             first_p = firsts[split_c];
726             last_p = lasts[split_c];
727         }
728 
729         left_p = first_p;
730         right_p = last_p;
731         pivot_p = first_p;
732 
733         do {
734             /* scan from right hand side */
735             while (right_p > left_p
736                    && compare(right_p, pivot_p, user_compare, table_p) > 0)
737                 right_p = (char *) right_p - sizeof(table_entry_t *);
738             /* scan from left hand side */
739             while (right_p > left_p
740                    && compare(pivot_p, left_p, user_compare, table_p) >= 0)
741                 left_p = (char *) left_p + sizeof(table_entry_t *);
742             /* if the pointers haven't met then swap values */
743             if (right_p > left_p) {
744                 /* swap_bytes(left_p, right_p) */
745                 table_entry_t *temp;
746 
747                 temp = *(table_entry_t **) left_p;
748                 *(table_entry_t **) left_p = *(table_entry_t **) right_p;
749                 *(table_entry_t **) right_p = temp;
750             }
751         } while (right_p > left_p);
752 
753         /* now we swap the pivot with the right-hand side */
754         {
755             /* swap_bytes(pivot_p, right_p); */
756             table_entry_t *temp;
757 
758             temp = *(table_entry_t **) pivot_p;
759             *(table_entry_t **) pivot_p = *(table_entry_t **) right_p;
760             *(table_entry_t **) right_p = temp;
761         }
762         pivot_p = right_p;
763 
764         /* save the section to the right of the pivot in our stack */
765         right_first_p = (char *) pivot_p + sizeof(table_entry_t *);
766         left_last_p = (char *) pivot_p - sizeof(table_entry_t *);
767 
768         /* do we need to save the righthand side? */
769         if (right_first_p < last_p) {
770             if (split_c >= MAX_SORT_SPLITS) {
771                 /* sanity check here -- we should never get here */
772                 abort();
773             }
774             firsts[split_c] = right_first_p;
775             lasts[split_c] = last_p;
776             split_c++;
777         }
778 
779         /* do the left hand side of the pivot */
780         /* first_p = first_p */
781         last_p = left_last_p;
782     }
783 }
784 
785 /*************************** exported routines *******************************/
786 
787 /*
788  * table_t *table_alloc
789  *
790  * DESCRIPTION:
791  *
792  * Allocate a new table structure.
793  *
794  * RETURNS:
795  *
796  * A pointer to the new table structure which must be passed to
797  * table_free to be deallocated.  On error a NULL is returned.
798  *
799  * ARGUMENTS:
800  *
801  * bucket_n - Number of buckets for the hash table.  Our current hash
802  * value works best with base two numbers.  Set to 0 to take the
803  * library default of 1024.
804  *
805  * error_p - Pointer to an integer which, if not NULL, will contain a
806  * table error code.
807  *
808  * malloc_f, realloc_f, free_f - Pointers to malloc(3)-, realloc(3)-
809  * and free(3)-style functions.
810  */
table_alloc(const unsigned int bucket_n,int * error_p,void * (* malloc_f)(size_t size),void * (* calloc_f)(size_t number,size_t size),void * (* realloc_f)(void * ptr,size_t size),void (* free_f)(void * ptr))811 table_t *table_alloc(const unsigned int bucket_n, int *error_p,
812                      void *(*malloc_f)(size_t size),
813                      void *(*calloc_f)(size_t number, size_t size),
814                      void *(*realloc_f)(void *ptr, size_t size),
815                      void (*free_f)(void *ptr))
816 {
817     table_t *table_p = NULL;
818     unsigned int buck_n;
819 
820     /* allocate a table structure */
821     if (malloc_f != NULL)
822         table_p = malloc_f(sizeof(table_t));
823     else
824         table_p = malloc(sizeof(table_t));
825     if (table_p == NULL) {
826         if (error_p != NULL)
827             *error_p = TABLE_ERROR_ALLOC;
828         return NULL;
829     }
830 
831     if (bucket_n > 0)
832         buck_n = bucket_n;
833     else
834         buck_n = DEFAULT_SIZE;
835     /* allocate the buckets which are NULLed */
836     if (calloc_f != NULL)
837         table_p->ta_buckets = (table_entry_t **)calloc_f(buck_n, sizeof(table_entry_t *));
838     else
839         table_p->ta_buckets = (table_entry_t **)calloc(buck_n, sizeof(table_entry_t *));
840     if (table_p->ta_buckets == NULL) {
841         if (error_p != NULL)
842             *error_p = TABLE_ERROR_ALLOC;
843         if (free_f != NULL)
844             free_f(table_p);
845         else
846             free(table_p);
847         return NULL;
848     }
849 
850     /* initialize structure */
851     table_p->ta_magic = TABLE_MAGIC;
852     table_p->ta_flags = 0;
853     table_p->ta_bucket_n = buck_n;
854     table_p->ta_entry_n = 0;
855     table_p->ta_data_align = 0;
856     table_p->ta_linear.tl_magic = 0;
857     table_p->ta_linear.tl_bucket_c = 0;
858     table_p->ta_linear.tl_entry_c = 0;
859     table_p->ta_file_size = 0;
860     table_p->ta_malloc  = malloc_f  != NULL ? malloc_f  : malloc;
861     table_p->ta_calloc  = calloc_f  != NULL ? calloc_f  : calloc;
862     table_p->ta_realloc = realloc_f != NULL ? realloc_f : realloc;
863     table_p->ta_free    = free_f    != NULL ? free_f    : free;
864 
865     if (error_p != NULL)
866         *error_p = TABLE_ERROR_NONE;
867     return table_p;
868 }
869 
870 /*
871  * int table_attr
872  *
873  * DESCRIPTION:
874  *
875  * Set the attributes for the table.  The available attributes are
876  * specified at the top of table.h.
877  *
878  * RETURNS:
879  *
880  * Success - TABLE_ERROR_NONE
881  *
882  * Failure - Table error code.
883  *
884  * ARGUMENTS:
885  *
886  * table_p - Pointer to a table structure which we will be altering.
887  *
888  * attr - Attribute(s) that we will be applying to the table.
889  */
table_attr(table_t * table_p,const int attr)890 int table_attr(table_t * table_p, const int attr)
891 {
892     if (table_p == NULL)
893         return TABLE_ERROR_ARG_NULL;
894     if (table_p->ta_magic != TABLE_MAGIC)
895         return TABLE_ERROR_PNT;
896     table_p->ta_flags = attr;
897 
898     return TABLE_ERROR_NONE;
899 }
900 
901 /*
902  * int table_set_data_alignment
903  *
904  * DESCRIPTION:
905  *
906  * Set the alignment for the data in the table.  For data elements
907  * sizeof(long) is recommended unless you use smaller data types
908  * exclusively.
909  *
910  * WARNING: This must be done before any data gets put into the table.
911  *
912  * RETURNS:
913  *
914  * Success - TABLE_ERROR_NONE
915  *
916  * Failure - Table error code.
917  *
918  * ARGUMENTS:
919  *
920  * table_p - Pointer to a table structure which we will be altering.
921  *
922  * alignment - Alignment requested for the data.  Must be a power of
923  * 2.  Set to 0 for none.
924  */
table_set_data_alignment(table_t * table_p,const int alignment)925 int table_set_data_alignment(table_t * table_p, const int alignment)
926 {
927     int val;
928 
929     if (table_p == NULL)
930         return TABLE_ERROR_ARG_NULL;
931     if (table_p->ta_magic != TABLE_MAGIC)
932         return TABLE_ERROR_PNT;
933     if (table_p->ta_entry_n > 0)
934         return TABLE_ERROR_NOT_EMPTY;
935     /* defaults */
936     if (alignment < 2)
937         table_p->ta_data_align = 0;
938     else {
939         /* verify we have a base 2 number */
940         for (val = 2; val < MAX_ALIGNMENT; val *= 2) {
941             if (val == alignment)
942                 break;
943         }
944         if (val >= MAX_ALIGNMENT)
945             return TABLE_ERROR_ALIGNMENT;
946         table_p->ta_data_align = alignment;
947     }
948 
949     return TABLE_ERROR_NONE;
950 }
951 
952 /*
953  * int table_clear
954  *
955  * DESCRIPTION:
956  *
957  * Clear out and free all elements in a table structure.
958  *
959  * RETURNS:
960  *
961  * Success - TABLE_ERROR_NONE
962  *
963  * Failure - Table error code.
964  *
965  * ARGUMENTS:
966  *
967  * table_p - Table structure pointer that we will be clearing.
968  */
table_clear(table_t * table_p)969 int table_clear(table_t * table_p)
970 {
971     table_entry_t *entry_p, *next_p;
972     table_entry_t **bucket_p, **bounds_p;
973 
974     if (table_p == NULL)
975         return TABLE_ERROR_ARG_NULL;
976     if (table_p->ta_magic != TABLE_MAGIC)
977         return TABLE_ERROR_PNT;
978     /* free the table allocation and table structure */
979     bounds_p = table_p->ta_buckets + table_p->ta_bucket_n;
980     for (bucket_p = table_p->ta_buckets; bucket_p < bounds_p; bucket_p++) {
981         for (entry_p = *bucket_p; entry_p != NULL; entry_p = next_p) {
982             /* record the next pointer before we free */
983             next_p = entry_p->te_next_p;
984             table_p->ta_free(entry_p);
985         }
986 
987         /* clear the bucket entry after we free its entries */
988         *bucket_p = NULL;
989     }
990 
991     /* reset table state info */
992     table_p->ta_entry_n = 0;
993     table_p->ta_linear.tl_magic = 0;
994     table_p->ta_linear.tl_bucket_c = 0;
995     table_p->ta_linear.tl_entry_c = 0;
996 
997     return TABLE_ERROR_NONE;
998 }
999 
1000 /*
1001  * int table_free
1002  *
1003  * DESCRIPTION:
1004  *
1005  * Deallocates a table structure.
1006  *
1007  * RETURNS:
1008  *
1009  * Success - TABLE_ERROR_NONE
1010  *
1011  * Failure - Table error code.
1012  *
1013  * ARGUMENTS:
1014  *
1015  * table_p - Table structure pointer that we will be freeing.
1016  */
table_free(table_t * table_p)1017 int table_free(table_t * table_p)
1018 {
1019     int ret;
1020 
1021     if (table_p == NULL)
1022         return TABLE_ERROR_ARG_NULL;
1023     if (table_p->ta_magic != TABLE_MAGIC)
1024         return TABLE_ERROR_PNT;
1025     ret = table_clear(table_p);
1026 
1027     if (table_p->ta_buckets != NULL)
1028         table_p->ta_free(table_p->ta_buckets);
1029     table_p->ta_magic = 0;
1030     table_p->ta_free(table_p);
1031 
1032     return ret;
1033 }
1034 
1035 /*
1036  * int table_insert_kd
1037  *
1038  * DESCRIPTION:
1039  *
1040  * Like table_insert except it passes back a pointer to the key and
1041  * the data buffers after they have been inserted into the table
1042  * structure.
1043  *
1044  * This routine adds a key/data pair both of which are made up of a
1045  * buffer of bytes and an associated size.  Both the key and the data
1046  * will be copied into buffers allocated inside the table.  If the key
1047  * exists already, the associated data will be replaced if the
1048  * overwrite flag is set, otherwise an error is returned.
1049  *
1050  * NOTE: be very careful changing the values since the table library
1051  * provides the pointers to its memory.  The key can _never_ be
1052  * changed otherwise you will not find it again.  The data can be
1053  * changed but its length can never be altered unless you delete and
1054  * re-insert it into the table.
1055  *
1056  * WARNING: The pointers to the key and data are not in any specific
1057  * alignment.  Accessing the key and/or data as an short, integer, or
1058  * long pointer directly can cause problems.
1059  *
1060  * WARNING: Replacing a data cell (not inserting) will cause the table
1061  * linked list to be temporarily invalid.  Care must be taken with
1062  * multiple threaded programs which are relying on the first/next
1063  * linked list to be always valid.
1064  *
1065  * RETURNS:
1066  *
1067  * Success - TABLE_ERROR_NONE
1068  *
1069  * Failure - Table error code.
1070  *
1071  * ARGUMENTS:
1072  *
1073  * table_p - Table structure pointer into which we will be inserting a
1074  * new key/data pair.
1075  *
1076  * key_buf - Buffer of bytes of the key that we are inserting.  If you
1077  * are storing an (int) as the key (for example) then key_buf should
1078  * be a (int *).
1079  *
1080  * key_size - Size of the key_buf buffer.  If set to < 0 then the
1081  * library will do a strlen of key_buf and add 1 for the '\0'.  If you
1082  * are storing an (int) as the key (for example) then key_size should
1083  * be sizeof(int).
1084  *
1085  * data_buf - Buffer of bytes of the data that we are inserting.  If
1086  * it is NULL then the library will allocate space for the data in the
1087  * table without copying in any information.  If data_buf is NULL and
1088  * data_size is 0 then the library will associate a NULL data pointer
1089  * with the key.  If you are storing a (long) as the data (for
1090  * example) then data_buf should be a (long *).
1091  *
1092  * data_size - Size of the data_buf buffer.  If set to < 0 then the
1093  * library will do a strlen of data_buf and add 1 for the '\0'.  If
1094  * you are storing an (long) as the key (for example) then key_size
1095  * should be sizeof(long).
1096  *
1097  * key_buf_p - Pointer which, if not NULL, will be set to the address
1098  * of the key storage that was allocated in the table.  If you are
1099  * storing an (int) as the key (for example) then key_buf_p should be
1100  * (int **) i.e. the address of a (int *).
1101  *
1102  * data_buf_p - Pointer which, if not NULL, will be set to the address
1103  * of the data storage that was allocated in the table.  If you are
1104  * storing an (long) as the data (for example) then data_buf_p should
1105  * be (long **) i.e. the address of a (long *).
1106  *
1107  * overwrite - Flag which, if set to 1, will allow the overwriting of
1108  * the data in the table with the new data if the key already exists
1109  * in the table.
1110  */
table_insert_kd(table_t * table_p,const void * key_buf,const int key_size,const void * data_buf,const int data_size,void ** key_buf_p,void ** data_buf_p,const char overwrite_b)1111 int table_insert_kd(table_t * table_p,
1112                     const void *key_buf, const int key_size,
1113                     const void *data_buf, const int data_size,
1114                     void **key_buf_p, void **data_buf_p,
1115                     const char overwrite_b)
1116 {
1117     int bucket;
1118     unsigned int ksize, dsize;
1119     table_entry_t *entry_p, *last_p;
1120     void *key_copy_p, *data_copy_p;
1121 
1122     /* check the arguments */
1123     if (table_p == NULL)
1124         return TABLE_ERROR_ARG_NULL;
1125     if (table_p->ta_magic != TABLE_MAGIC)
1126         return TABLE_ERROR_PNT;
1127     if (key_buf == NULL)
1128         return TABLE_ERROR_ARG_NULL;
1129     /* data_buf can be null but size must be >= 0, if it isn't null size != 0 */
1130     if ((data_buf == NULL && data_size < 0)
1131         || (data_buf != NULL && data_size == 0))
1132         return TABLE_ERROR_SIZE;
1133     /* determine sizes of key and data */
1134     if (key_size < 0)
1135         ksize = strlen((char *) key_buf) + sizeof(char);
1136     else
1137         ksize = key_size;
1138     if (data_size < 0)
1139         dsize = strlen((char *) data_buf) + sizeof(char);
1140     else
1141         dsize = data_size;
1142     /* get the bucket number via a hash function */
1143     bucket = hash(key_buf, ksize, 0) % table_p->ta_bucket_n;
1144 
1145     /* look for the entry in this bucket, only check keys of the same size */
1146     last_p = NULL;
1147     for (entry_p = table_p->ta_buckets[bucket];
1148          entry_p != NULL;
1149          last_p = entry_p, entry_p = entry_p->te_next_p) {
1150         if (entry_p->te_key_size == ksize
1151             && memcmp(ENTRY_KEY_BUF(entry_p), key_buf, ksize) == 0)
1152             break;
1153     }
1154 
1155     /* did we find it?  then we are in replace mode. */
1156     if (entry_p != NULL) {
1157 
1158         /* can we not overwrite existing data? */
1159         if (!overwrite_b) {
1160             if (key_buf_p != NULL)
1161                 *key_buf_p = ENTRY_KEY_BUF(entry_p);
1162             if (data_buf_p != NULL) {
1163                 if (entry_p->te_data_size == 0)
1164                     *data_buf_p = NULL;
1165                 else {
1166                     if (table_p->ta_data_align == 0)
1167                         *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p);
1168                     else
1169                         *data_buf_p = entry_data_buf(table_p, entry_p);
1170                 }
1171             }
1172             return TABLE_ERROR_OVERWRITE;
1173         }
1174 
1175         /* re-alloc entry's data if the new size != the old */
1176         if (dsize != entry_p->te_data_size) {
1177 
1178             /*
1179              * First we delete it from the list to keep the list whole.
1180              * This properly preserves the linked list in case we have a
1181              * thread marching through the linked list while we are
1182              * inserting.  Maybe this is an unnecessary protection but it
1183              * should not harm that much.
1184              */
1185             if (last_p == NULL)
1186                 table_p->ta_buckets[bucket] = entry_p->te_next_p;
1187             else
1188                 last_p->te_next_p = entry_p->te_next_p;
1189             /*
1190              * Realloc the structure which may change its pointer. NOTE:
1191              * this may change any previous data_key_p and data_copy_p
1192              * pointers.
1193              */
1194             entry_p = (table_entry_t *) table_p->ta_realloc(entry_p,
1195                                                 entry_size(table_p,
1196                                                        entry_p->te_key_size,
1197                                                            dsize));
1198             if (entry_p == NULL)
1199                 return TABLE_ERROR_ALLOC;
1200             /* add it back to the front of the list */
1201             entry_p->te_data_size = dsize;
1202             entry_p->te_next_p = table_p->ta_buckets[bucket];
1203             table_p->ta_buckets[bucket] = entry_p;
1204         }
1205 
1206         /* copy or replace data in storage */
1207         if (dsize > 0) {
1208             if (table_p->ta_data_align == 0)
1209                 data_copy_p = ENTRY_DATA_BUF(table_p, entry_p);
1210             else
1211                 data_copy_p = entry_data_buf(table_p, entry_p);
1212             if (data_buf != NULL)
1213                 memcpy(data_copy_p, data_buf, dsize);
1214         }
1215         else
1216             data_copy_p = NULL;
1217         if (key_buf_p != NULL)
1218             *key_buf_p = ENTRY_KEY_BUF(entry_p);
1219         if (data_buf_p != NULL)
1220             *data_buf_p = data_copy_p;
1221         /* returning from the section where we were overwriting table data */
1222         return TABLE_ERROR_NONE;
1223     }
1224 
1225     /*
1226      * It is a new entry.
1227      */
1228 
1229     /* allocate a new entry */
1230     entry_p = (table_entry_t *) table_p->ta_malloc(entry_size(table_p, ksize, dsize));
1231     if (entry_p == NULL)
1232         return TABLE_ERROR_ALLOC;
1233     /* copy key into storage */
1234     entry_p->te_key_size = ksize;
1235     key_copy_p = ENTRY_KEY_BUF(entry_p);
1236     memcpy(key_copy_p, key_buf, ksize);
1237 
1238     /* copy data in */
1239     entry_p->te_data_size = dsize;
1240     if (dsize > 0) {
1241         if (table_p->ta_data_align == 0)
1242             data_copy_p = ENTRY_DATA_BUF(table_p, entry_p);
1243         else
1244             data_copy_p = entry_data_buf(table_p, entry_p);
1245         if (data_buf != NULL)
1246             memcpy(data_copy_p, data_buf, dsize);
1247     }
1248     else
1249         data_copy_p = NULL;
1250     if (key_buf_p != NULL)
1251         *key_buf_p = key_copy_p;
1252     if (data_buf_p != NULL)
1253         *data_buf_p = data_copy_p;
1254     /* insert into list, no need to append */
1255     entry_p->te_next_p = table_p->ta_buckets[bucket];
1256     table_p->ta_buckets[bucket] = entry_p;
1257 
1258     table_p->ta_entry_n++;
1259 
1260     /* do we need auto-adjust? */
1261     if (table_p->ta_flags & TABLE_FLAG_AUTO_ADJUST
1262         && SHOULD_TABLE_GROW(table_p))
1263         return table_adjust(table_p, table_p->ta_entry_n);
1264     return TABLE_ERROR_NONE;
1265 }
1266 
1267 /*
1268  * int table_insert
1269  *
1270  * DESCRIPTION:
1271  *
1272  * Exactly the same as table_insert_kd except it does not pass back a
1273  * pointer to the key after they have been inserted into the table
1274  * structure.  This is still here for backwards compatibility.
1275  *
1276  * See table_insert_kd for more information.
1277  *
1278  * RETURNS:
1279  *
1280  * Success - TABLE_ERROR_NONE
1281  *
1282  * Failure - Table error code.
1283  *
1284  * ARGUMENTS:
1285  *
1286  * table_p - Table structure pointer into which we will be inserting a
1287  * new key/data pair.
1288  *
1289  * key_buf - Buffer of bytes of the key that we are inserting.  If you
1290  * are storing an (int) as the key (for example) then key_buf should
1291  * be a (int *).
1292  *
1293  * key_size - Size of the key_buf buffer.  If set to < 0 then the
1294  * library will do a strlen of key_buf and add 1 for the '\0'.  If you
1295  * are storing an (int) as the key (for example) then key_size should
1296  * be sizeof(int).
1297  *
1298  * data_buf - Buffer of bytes of the data that we are inserting.  If
1299  * it is NULL then the library will allocate space for the data in the
1300  * table without copying in any information.  If data_buf is NULL and
1301  * data_size is 0 then the library will associate a NULL data pointer
1302  * with the key.  If you are storing a (long) as the data (for
1303  * example) then data_buf should be a (long *).
1304  *
1305  * data_size - Size of the data_buf buffer.  If set to < 0 then the
1306  * library will do a strlen of data_buf and add 1 for the '\0'.  If
1307  * you are storing an (long) as the key (for example) then key_size
1308  * should be sizeof(long).
1309  *
1310  * data_buf_p - Pointer which, if not NULL, will be set to the address
1311  * of the data storage that was allocated in the table.  If you are
1312  * storing an (long) as the data (for example) then data_buf_p should
1313  * be (long **) i.e. the address of a (long *).
1314  *
1315  * overwrite - Flag which, if set to 1, will allow the overwriting of
1316  * the data in the table with the new data if the key already exists
1317  * in the table.
1318  */
table_insert(table_t * table_p,const void * key_buf,const int key_size,const void * data_buf,const int data_size,void ** data_buf_p,const char overwrite_b)1319 int table_insert(table_t * table_p,
1320                  const void *key_buf, const int key_size,
1321                  const void *data_buf, const int data_size,
1322                  void **data_buf_p, const char overwrite_b)
1323 {
1324     return table_insert_kd(table_p, key_buf, key_size, data_buf, data_size,
1325                            NULL, data_buf_p, overwrite_b);
1326 }
1327 
1328 /*
1329  * int table_retrieve
1330  *
1331  * DESCRIPTION:
1332  *
1333  * This routine looks up a key made up of a buffer of bytes and an
1334  * associated size in the table.  If found then it returns the
1335  * associated data information.
1336  *
1337  * RETURNS:
1338  *
1339  * Success - TABLE_ERROR_NONE
1340  *
1341  * Failure - Table error code.
1342  *
1343  * ARGUMENTS:
1344  *
1345  * table_p - Table structure pointer into which we will be searching
1346  * for the key.
1347  *
1348  * key_buf - Buffer of bytes of the key that we are searching for.  If
1349  * you are looking for an (int) as the key (for example) then key_buf
1350  * should be a (int *).
1351  *
1352  * key_size - Size of the key_buf buffer.  If set to < 0 then the
1353  * library will do a strlen of key_buf and add 1 for the '\0'.  If you
1354  * are looking for an (int) as the key (for example) then key_size
1355  * should be sizeof(int).
1356  *
1357  * data_buf_p - Pointer which, if not NULL, will be set to the address
1358  * of the data storage that was allocated in the table and that is
1359  * associated with the key.  If a (long) was stored as the data (for
1360  * example) then data_buf_p should be (long **) i.e. the address of a
1361  * (long *).
1362  *
1363  * data_size_p - Pointer to an integer which, if not NULL, will be set
1364  * to the size of the data stored in the table that is associated with
1365  * the key.
1366  */
table_retrieve(table_t * table_p,const void * key_buf,const int key_size,void ** data_buf_p,int * data_size_p)1367 int table_retrieve(table_t * table_p,
1368                    const void *key_buf, const int key_size,
1369                    void **data_buf_p, int *data_size_p)
1370 {
1371     int bucket;
1372     unsigned int ksize;
1373     table_entry_t *entry_p, **buckets;
1374 
1375     if (table_p == NULL)
1376         return TABLE_ERROR_ARG_NULL;
1377     if (table_p->ta_magic != TABLE_MAGIC)
1378         return TABLE_ERROR_PNT;
1379     if (key_buf == NULL)
1380         return TABLE_ERROR_ARG_NULL;
1381     /* find key size */
1382     if (key_size < 0)
1383         ksize = strlen((char *) key_buf) + sizeof(char);
1384     else
1385         ksize = key_size;
1386     /* get the bucket number via a has function */
1387     bucket = hash(key_buf, ksize, 0) % table_p->ta_bucket_n;
1388 
1389     /* look for the entry in this bucket, only check keys of the same size */
1390     buckets = table_p->ta_buckets;
1391     for (entry_p = buckets[bucket];
1392          entry_p != NULL;
1393          entry_p = entry_p->te_next_p) {
1394         entry_p = TABLE_POINTER(table_p, table_entry_t *, entry_p);
1395         if (entry_p->te_key_size == ksize
1396             && memcmp(ENTRY_KEY_BUF(entry_p), key_buf, ksize) == 0)
1397             break;
1398     }
1399 
1400     /* not found? */
1401     if (entry_p == NULL)
1402         return TABLE_ERROR_NOT_FOUND;
1403     if (data_buf_p != NULL) {
1404         if (entry_p->te_data_size == 0)
1405             *data_buf_p = NULL;
1406         else {
1407             if (table_p->ta_data_align == 0)
1408                 *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p);
1409             else
1410                 *data_buf_p = entry_data_buf(table_p, entry_p);
1411         }
1412     }
1413     if (data_size_p != NULL)
1414         *data_size_p = entry_p->te_data_size;
1415     return TABLE_ERROR_NONE;
1416 }
1417 
1418 /*
1419  * int table_delete
1420  *
1421  * DESCRIPTION:
1422  *
1423  * This routine looks up a key made up of a buffer of bytes and an
1424  * associated size in the table.  If found then it will be removed
1425  * from the table.  The associated data can be passed back to the user
1426  * if requested.
1427  *
1428  * RETURNS:
1429  *
1430  * Success - TABLE_ERROR_NONE
1431  *
1432  * Failure - Table error code.
1433  *
1434  * NOTE: this could be an allocation error if the library is to return
1435  * the data to the user.
1436  *
1437  * ARGUMENTS:
1438  *
1439  * table_p - Table structure pointer from which we will be deleteing
1440  * the key.
1441  *
1442  * key_buf - Buffer of bytes of the key that we are searching for to
1443  * delete.  If you are deleting an (int) key (for example) then
1444  * key_buf should be a (int *).
1445  *
1446  * key_size - Size of the key_buf buffer.  If set to < 0 then the
1447  * library will do a strlen of key_buf and add 1 for the '\0'.  If you
1448  * are deleting an (int) key (for example) then key_size should be
1449  * sizeof(int).
1450  *
1451  * data_buf_p - Pointer which, if not NULL, will be set to the address
1452  * of the data storage that was allocated in the table and that was
1453  * associated with the key.  If a (long) was stored as the data (for
1454  * example) then data_buf_p should be (long **) i.e. the address of a
1455  * (long *).  If a pointer is passed in, the caller is responsible for
1456  * freeing it after use.  If data_buf_p is NULL then the library will
1457  * free up the data allocation itself.
1458  *
1459  * data_size_p - Pointer to an integer which, if not NULL, will be set
1460  * to the size of the data that was stored in the table and that was
1461  * associated with the key.
1462  */
table_delete(table_t * table_p,const void * key_buf,const int key_size,void ** data_buf_p,int * data_size_p)1463 int table_delete(table_t * table_p,
1464                  const void *key_buf, const int key_size,
1465                  void **data_buf_p, int *data_size_p)
1466 {
1467     int bucket;
1468     unsigned int ksize;
1469     unsigned char *data_copy_p;
1470     table_entry_t *entry_p, *last_p;
1471 
1472     if (table_p == NULL)
1473         return TABLE_ERROR_ARG_NULL;
1474     if (table_p->ta_magic != TABLE_MAGIC)
1475         return TABLE_ERROR_PNT;
1476     if (key_buf == NULL)
1477         return TABLE_ERROR_ARG_NULL;
1478     /* get the key size */
1479     if (key_size < 0)
1480         ksize = strlen((char *) key_buf) + sizeof(char);
1481     else
1482         ksize = key_size;
1483     /* find our bucket */
1484     bucket = hash(key_buf, ksize, 0) % table_p->ta_bucket_n;
1485 
1486     /* look for the entry in this bucket, only check keys of the same size */
1487     for (last_p = NULL, entry_p = table_p->ta_buckets[bucket]; entry_p != NULL;
1488          last_p = entry_p, entry_p = entry_p->te_next_p) {
1489         if (entry_p->te_key_size == ksize
1490             && memcmp(ENTRY_KEY_BUF(entry_p), key_buf, ksize) == 0)
1491             break;
1492     }
1493 
1494     /* did we find it? */
1495     if (entry_p == NULL)
1496         return TABLE_ERROR_NOT_FOUND;
1497     /*
1498      * NOTE: we may want to adjust the linear counters here if the entry
1499      * we are deleting is the one we are pointing on or is ahead of the
1500      * one in the bucket list
1501      */
1502 
1503     /* remove entry from the linked list */
1504     if (last_p == NULL)
1505         table_p->ta_buckets[bucket] = entry_p->te_next_p;
1506     else
1507         last_p->te_next_p = entry_p->te_next_p;
1508     /* free entry */
1509     if (data_buf_p != NULL) {
1510         if (entry_p->te_data_size == 0)
1511             *data_buf_p = NULL;
1512         else {
1513             /*
1514              * if we were storing it compacted, we now need to malloc some
1515              * space if the user wants the value after the delete.
1516              */
1517             *data_buf_p = table_p->ta_malloc(entry_p->te_data_size);
1518             if (*data_buf_p == NULL)
1519                 return TABLE_ERROR_ALLOC;
1520             if (table_p->ta_data_align == 0)
1521                 data_copy_p = ENTRY_DATA_BUF(table_p, entry_p);
1522             else
1523                 data_copy_p = entry_data_buf(table_p, entry_p);
1524             memcpy(*data_buf_p, data_copy_p, entry_p->te_data_size);
1525         }
1526     }
1527     if (data_size_p != NULL)
1528         *data_size_p = entry_p->te_data_size;
1529     table_p->ta_free(entry_p);
1530 
1531     table_p->ta_entry_n--;
1532 
1533     /* do we need auto-adjust down? */
1534     if ((table_p->ta_flags & TABLE_FLAG_AUTO_ADJUST)
1535         && (table_p->ta_flags & TABLE_FLAG_ADJUST_DOWN)
1536         && SHOULD_TABLE_SHRINK(table_p))
1537         return table_adjust(table_p, table_p->ta_entry_n);
1538     return TABLE_ERROR_NONE;
1539 }
1540 
1541 /*
1542  * int table_delete_first
1543  *
1544  * DESCRIPTION:
1545  *
1546  * This is like the table_delete routines except it deletes the first
1547  * key/data pair in the table instead of an entry corresponding to a
1548  * particular key.  The associated key and data information can be
1549  * passed back to the user if requested.  This routines is handy to
1550  * clear out a table.
1551  *
1552  * RETURNS:
1553  *
1554  * Success - TABLE_ERROR_NONE
1555  *
1556  * Failure - Table error code.
1557  *
1558  * NOTE: this could be an allocation error if the library is to return
1559  * the data to the user.
1560  *
1561  * ARGUMENTS:
1562  *
1563  * table_p - Table structure pointer from which we will be deleteing
1564  * the first key.
1565  *
1566  * key_buf_p - Pointer which, if not NULL, will be set to the address
1567  * of the storage of the first key that was allocated in the table.
1568  * If an (int) was stored as the first key (for example) then
1569  * key_buf_p should be (int **) i.e. the address of a (int *).  If a
1570  * pointer is passed in, the caller is responsible for freeing it
1571  * after use.  If key_buf_p is NULL then the library will free up the
1572  * key allocation itself.
1573  *
1574  * key_size_p - Pointer to an integer which, if not NULL, will be set
1575  * to the size of the key that was stored in the table and that was
1576  * associated with the key.
1577  *
1578  * data_buf_p - Pointer which, if not NULL, will be set to the address
1579  * of the data storage that was allocated in the table and that was
1580  * associated with the key.  If a (long) was stored as the data (for
1581  * example) then data_buf_p should be (long **) i.e. the address of a
1582  * (long *).  If a pointer is passed in, the caller is responsible for
1583  * freeing it after use.  If data_buf_p is NULL then the library will
1584  * free up the data allocation itself.
1585  *
1586  * data_size_p - Pointer to an integer which, if not NULL, will be set
1587  * to the size of the data that was stored in the table and that was
1588  * associated with the key.
1589  */
table_delete_first(table_t * table_p,void ** key_buf_p,int * key_size_p,void ** data_buf_p,int * data_size_p)1590 int table_delete_first(table_t * table_p,
1591                        void **key_buf_p, int *key_size_p,
1592                        void **data_buf_p, int *data_size_p)
1593 {
1594     unsigned char *data_copy_p;
1595     table_entry_t *entry_p;
1596     table_linear_t linear;
1597 
1598     if (table_p == NULL)
1599         return TABLE_ERROR_ARG_NULL;
1600     if (table_p->ta_magic != TABLE_MAGIC)
1601         return TABLE_ERROR_PNT;
1602     /* take the first entry */
1603     entry_p = first_entry(table_p, &linear);
1604     if (entry_p == NULL)
1605         return TABLE_ERROR_NOT_FOUND;
1606     /*
1607      * NOTE: we may want to adjust the linear counters here if the entry
1608      * we are deleting is the one we are pointing on or is ahead of the
1609      * one in the bucket list
1610      */
1611 
1612     /* remove entry from the linked list */
1613     table_p->ta_buckets[linear.tl_bucket_c] = entry_p->te_next_p;
1614 
1615     /* free entry */
1616     if (key_buf_p != NULL) {
1617         if (entry_p->te_key_size == 0)
1618             *key_buf_p = NULL;
1619         else {
1620             /*
1621              * if we were storing it compacted, we now need to malloc some
1622              * space if the user wants the value after the delete.
1623              */
1624             *key_buf_p = table_p->ta_malloc(entry_p->te_key_size);
1625             if (*key_buf_p == NULL)
1626                 return TABLE_ERROR_ALLOC;
1627             memcpy(*key_buf_p, ENTRY_KEY_BUF(entry_p), entry_p->te_key_size);
1628         }
1629     }
1630     if (key_size_p != NULL)
1631         *key_size_p = entry_p->te_key_size;
1632     if (data_buf_p != NULL) {
1633         if (entry_p->te_data_size == 0)
1634             *data_buf_p = NULL;
1635         else {
1636             /*
1637              * if we were storing it compacted, we now need to malloc some
1638              * space if the user wants the value after the delete.
1639              */
1640             *data_buf_p = table_p->ta_malloc(entry_p->te_data_size);
1641             if (*data_buf_p == NULL)
1642                 return TABLE_ERROR_ALLOC;
1643             if (table_p->ta_data_align == 0)
1644                 data_copy_p = ENTRY_DATA_BUF(table_p, entry_p);
1645             else
1646                 data_copy_p = entry_data_buf(table_p, entry_p);
1647             memcpy(*data_buf_p, data_copy_p, entry_p->te_data_size);
1648         }
1649     }
1650     if (data_size_p != NULL)
1651         *data_size_p = entry_p->te_data_size;
1652     table_p->ta_free(entry_p);
1653 
1654     table_p->ta_entry_n--;
1655 
1656     /* do we need auto-adjust down? */
1657     if ((table_p->ta_flags & TABLE_FLAG_AUTO_ADJUST)
1658         && (table_p->ta_flags & TABLE_FLAG_ADJUST_DOWN)
1659         && SHOULD_TABLE_SHRINK(table_p))
1660         return table_adjust(table_p, table_p->ta_entry_n);
1661     return TABLE_ERROR_NONE;
1662 }
1663 
1664 /*
1665  * int table_info
1666  *
1667  * DESCRIPTION:
1668  *
1669  * Get some information about a table_p structure.
1670  *
1671  * RETURNS:
1672  *
1673  * Success - TABLE_ERROR_NONE
1674  *
1675  * Failure - Table error code.
1676  *
1677  * ARGUMENTS:
1678  *
1679  * table_p - Table structure pointer from which we are getting
1680  * information.
1681  *
1682  * num_buckets_p - Pointer to an integer which, if not NULL, will
1683  * contain the number of buckets in the table.
1684  *
1685  * num_entries_p - Pointer to an integer which, if not NULL, will
1686  * contain the number of entries stored in the table.
1687  */
table_info(table_t * table_p,int * num_buckets_p,int * num_entries_p)1688 int table_info(table_t * table_p, int *num_buckets_p, int *num_entries_p)
1689 {
1690     if (table_p == NULL)
1691         return TABLE_ERROR_ARG_NULL;
1692     if (table_p->ta_magic != TABLE_MAGIC)
1693         return TABLE_ERROR_PNT;
1694     if (num_buckets_p != NULL)
1695         *num_buckets_p = table_p->ta_bucket_n;
1696     if (num_entries_p != NULL)
1697         *num_entries_p = table_p->ta_entry_n;
1698     return TABLE_ERROR_NONE;
1699 }
1700 
1701 /*
1702  * int table_adjust
1703  *
1704  * DESCRIPTION:
1705  *
1706  * Set the number of buckets in a table to a certain value.
1707  *
1708  * RETURNS:
1709  *
1710  * Success - TABLE_ERROR_NONE
1711  *
1712  * Failure - Table error code.
1713  *
1714  * ARGUMENTS:
1715  *
1716  * table_p - Table structure pointer of which we are adjusting.
1717  *
1718  * bucket_n - Number buckets to adjust the table to.  Set to 0 to
1719  * adjust the table to its number of entries.
1720  */
table_adjust(table_t * table_p,const int bucket_n)1721 int table_adjust(table_t * table_p, const int bucket_n)
1722 {
1723     table_entry_t *entry_p, *next_p;
1724     table_entry_t **buckets, **bucket_p, **bounds_p;
1725     int bucket;
1726     unsigned int buck_n;
1727 
1728     if (table_p == NULL)
1729         return TABLE_ERROR_ARG_NULL;
1730     if (table_p->ta_magic != TABLE_MAGIC)
1731         return TABLE_ERROR_PNT;
1732     /*
1733      * NOTE: we walk through the entries and rehash them.  If we stored
1734      * the hash value as a full int in the table-entry, all we would
1735      * have to do is remod it.
1736      */
1737 
1738     /* normalize to the number of entries */
1739     if (bucket_n == 0)
1740         buck_n = table_p->ta_entry_n;
1741     else
1742         buck_n = bucket_n;
1743     /* we must have at least 1 bucket */
1744     if (buck_n == 0)
1745         buck_n = 1;
1746     /* make sure we have somethign to do */
1747     if (buck_n == table_p->ta_bucket_n)
1748         return TABLE_ERROR_NONE;
1749     /* allocate a new bucket list */
1750     if ((buckets = (table_entry_t **) table_p->ta_calloc(buck_n, sizeof(table_entry_t *))) == NULL)
1751         return TABLE_ERROR_ALLOC;
1752     if (table_p->ta_buckets == NULL)
1753         return TABLE_ERROR_ALLOC;
1754     /*
1755      * run through each of the items in the current table and rehash
1756      * them into the newest bucket sizes
1757      */
1758     bounds_p = table_p->ta_buckets + table_p->ta_bucket_n;
1759     for (bucket_p = table_p->ta_buckets; bucket_p < bounds_p; bucket_p++) {
1760         for (entry_p = *bucket_p; entry_p != NULL; entry_p = next_p) {
1761 
1762             /* hash the old data into the new table size */
1763             bucket = hash(ENTRY_KEY_BUF(entry_p), entry_p->te_key_size, 0) % buck_n;
1764 
1765             /* record the next one now since we overwrite next below */
1766             next_p = entry_p->te_next_p;
1767 
1768             /* insert into new list, no need to append */
1769             entry_p->te_next_p = buckets[bucket];
1770             buckets[bucket] = entry_p;
1771 
1772             /*
1773              * NOTE: we may want to adjust the bucket_c linear entry here to
1774              * keep it current
1775              */
1776         }
1777         /* remove the old table pointers as we go by */
1778         *bucket_p = NULL;
1779     }
1780 
1781     /* replace the table buckets with the new ones */
1782     table_p->ta_free(table_p->ta_buckets);
1783     table_p->ta_buckets = buckets;
1784     table_p->ta_bucket_n = buck_n;
1785 
1786     return TABLE_ERROR_NONE;
1787 }
1788 
1789 /*
1790  * const char *table_strerror
1791  *
1792  * DESCRIPTION:
1793  *
1794  * Return the corresponding string for the error number.
1795  *
1796  * RETURNS:
1797  *
1798  * Success - String equivalient of the error.
1799  *
1800  * Failure - String "invalid error code"
1801  *
1802  * ARGUMENTS:
1803  *
1804  * error - Error number that we are converting.
1805  */
table_strerror(const int error)1806 const char *table_strerror(const int error)
1807 {
1808     error_str_t *err_p;
1809 
1810     for (err_p = errors; err_p->es_error != 0; err_p++) {
1811         if (err_p->es_error == error)
1812             return err_p->es_string;
1813     }
1814 
1815     return INVALID_ERROR;
1816 }
1817 
1818 /*
1819  * int table_type_size
1820  *
1821  * DESCRIPTION:
1822  *
1823  * Return the size of the internal table type.
1824  *
1825  * RETURNS:
1826  *
1827  * The size of the table_t type.
1828  *
1829  * ARGUMENTS:
1830  *
1831  * None.
1832  */
table_type_size(void)1833 int table_type_size(void)
1834 {
1835     return sizeof(table_t);
1836 }
1837 
1838 /************************* linear access routines ****************************/
1839 
1840 /*
1841  * int table_first
1842  *
1843  * DESCRIPTION:
1844  *
1845  * Find first element in a table and pass back information about the
1846  * key/data pair.  If any of the key/data pointers are NULL then they
1847  * are ignored.
1848  *
1849  * NOTE: This function is not reentrant.  More than one thread cannot
1850  * be doing a first and next on the same table at the same time.  Use
1851  * the table_first_r version below for this.
1852  *
1853  * RETURNS:
1854  *
1855  * Success - TABLE_ERROR_NONE
1856  *
1857  * Failure - Table error code.
1858  *
1859  * ARGUMENTS:
1860  *
1861  * table_p - Table structure pointer from which we are getting the
1862  * first element.
1863  *
1864  * key_buf_p - Pointer which, if not NULL, will be set to the address
1865  * of the storage of the first key that is allocated in the table.  If
1866  * an (int) is stored as the first key (for example) then key_buf_p
1867  * should be (int **) i.e. the address of a (int *).
1868  *
1869  * key_size_p - Pointer to an integer which, if not NULL, will be set
1870  * to the size of the key that is stored in the table and that is
1871  * associated with the first key.
1872  *
1873  * data_buf_p - Pointer which, if not NULL, will be set to the address
1874  * of the data storage that is allocated in the table and that is
1875  * associated with the first key.  If a (long) is stored as the data
1876  * (for example) then data_buf_p should be (long **) i.e. the address
1877  * of a (long *).
1878  *
1879  * data_size_p - Pointer to an integer which, if not NULL, will be set
1880  * to the size of the data that is stored in the table and that is
1881  * associated with the first key.
1882  */
table_first(table_t * table_p,void ** key_buf_p,int * key_size_p,void ** data_buf_p,int * data_size_p)1883 int table_first(table_t * table_p,
1884                 void **key_buf_p, int *key_size_p,
1885                 void **data_buf_p, int *data_size_p)
1886 {
1887     table_entry_t *entry_p;
1888 
1889     if (table_p == NULL)
1890         return TABLE_ERROR_ARG_NULL;
1891     if (table_p->ta_magic != TABLE_MAGIC)
1892         return TABLE_ERROR_PNT;
1893     /* initialize our linear magic number */
1894     table_p->ta_linear.tl_magic = LINEAR_MAGIC;
1895 
1896     entry_p = first_entry(table_p, &table_p->ta_linear);
1897     if (entry_p == NULL)
1898         return TABLE_ERROR_NOT_FOUND;
1899     if (key_buf_p != NULL)
1900         *key_buf_p = ENTRY_KEY_BUF(entry_p);
1901     if (key_size_p != NULL)
1902         *key_size_p = entry_p->te_key_size;
1903     if (data_buf_p != NULL) {
1904         if (entry_p->te_data_size == 0)
1905             *data_buf_p = NULL;
1906         else {
1907             if (table_p->ta_data_align == 0)
1908                 *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p);
1909             else
1910                 *data_buf_p = entry_data_buf(table_p, entry_p);
1911         }
1912     }
1913     if (data_size_p != NULL)
1914         *data_size_p = entry_p->te_data_size;
1915     return TABLE_ERROR_NONE;
1916 }
1917 
1918 /*
1919  * int table_next
1920  *
1921  * DESCRIPTION:
1922  *
1923  * Find the next element in a table and pass back information about
1924  * the key/data pair.  If any of the key/data pointers are NULL then
1925  * they are ignored.
1926  *
1927  * NOTE: This function is not reentrant.  More than one thread cannot
1928  * be doing a first and next on the same table at the same time.  Use
1929  * the table_next_r version below for this.
1930  *
1931  * RETURNS:
1932  *
1933  * Success - TABLE_ERROR_NONE
1934  *
1935  * Failure - Table error code.
1936  *
1937  * ARGUMENTS:
1938  *
1939  * table_p - Table structure pointer from which we are getting the
1940  * next element.
1941  *
1942  * key_buf_p - Pointer which, if not NULL, will be set to the address
1943  * of the storage of the next key that is allocated in the table.  If
1944  * an (int) is stored as the next key (for example) then key_buf_p
1945  * should be (int **) i.e. the address of a (int *).
1946  *
1947  * key_size_p - Pointer to an integer which, if not NULL, will be set
1948  * to the size of the key that is stored in the table and that is
1949  * associated with the next key.
1950  *
1951  * data_buf_p - Pointer which, if not NULL, will be set to the address
1952  * of the data storage that is allocated in the table and that is
1953  * associated with the next key.  If a (long) is stored as the data
1954  * (for example) then data_buf_p should be (long **) i.e. the address
1955  * of a (long *).
1956  *
1957  * data_size_p - Pointer to an integer which, if not NULL, will be set
1958  * to the size of the data that is stored in the table and that is
1959  * associated with the next key.
1960  */
table_next(table_t * table_p,void ** key_buf_p,int * key_size_p,void ** data_buf_p,int * data_size_p)1961 int table_next(table_t * table_p,
1962                void **key_buf_p, int *key_size_p,
1963                void **data_buf_p, int *data_size_p)
1964 {
1965     table_entry_t *entry_p;
1966     int error;
1967 
1968     if (table_p == NULL)
1969         return TABLE_ERROR_ARG_NULL;
1970     if (table_p->ta_magic != TABLE_MAGIC)
1971         return TABLE_ERROR_PNT;
1972     if (table_p->ta_linear.tl_magic != LINEAR_MAGIC)
1973         return TABLE_ERROR_LINEAR;
1974     /* move to the next entry */
1975     entry_p = next_entry(table_p, &table_p->ta_linear, &error);
1976     if (entry_p == NULL)
1977         return error;
1978     if (key_buf_p != NULL)
1979         *key_buf_p = ENTRY_KEY_BUF(entry_p);
1980     if (key_size_p != NULL)
1981         *key_size_p = entry_p->te_key_size;
1982     if (data_buf_p != NULL) {
1983         if (entry_p->te_data_size == 0)
1984             *data_buf_p = NULL;
1985         else {
1986             if (table_p->ta_data_align == 0)
1987                 *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p);
1988             else
1989                 *data_buf_p = entry_data_buf(table_p, entry_p);
1990         }
1991     }
1992     if (data_size_p != NULL)
1993         *data_size_p = entry_p->te_data_size;
1994     return TABLE_ERROR_NONE;
1995 }
1996 
1997 /*
1998  * int table_this
1999  *
2000  * DESCRIPTION:
2001  *
2002  * Find the current element in a table and pass back information about
2003  * the key/data pair.  If any of the key/data pointers are NULL then
2004  * they are ignored.
2005  *
2006  * NOTE: This function is not reentrant.  Use the table_current_r
2007  * version below.
2008  *
2009  * RETURNS:
2010  *
2011  * Success - TABLE_ERROR_NONE
2012  *
2013  * Failure - Table error code.
2014  *
2015  * ARGUMENTS:
2016  *
2017  * table_p - Table structure pointer from which we are getting the
2018  * current element.
2019  *
2020  * key_buf_p - Pointer which, if not NULL, will be set to the address
2021  * of the storage of the current key that is allocated in the table.
2022  * If an (int) is stored as the current key (for example) then
2023  * key_buf_p should be (int **) i.e. the address of a (int *).
2024  *
2025  * key_size_p - Pointer to an integer which, if not NULL, will be set
2026  * to the size of the key that is stored in the table and that is
2027  * associated with the current key.
2028  *
2029  * data_buf_p - Pointer which, if not NULL, will be set to the address
2030  * of the data storage that is allocated in the table and that is
2031  * associated with the current key.  If a (long) is stored as the data
2032  * (for example) then data_buf_p should be (long **) i.e. the address
2033  * of a (long *).
2034  *
2035  * data_size_p - Pointer to an integer which, if not NULL, will be set
2036  * to the size of the data that is stored in the table and that is
2037  * associated with the current key.
2038  */
table_this(table_t * table_p,void ** key_buf_p,int * key_size_p,void ** data_buf_p,int * data_size_p)2039 int table_this(table_t * table_p,
2040                void **key_buf_p, int *key_size_p,
2041                void **data_buf_p, int *data_size_p)
2042 {
2043     table_entry_t *entry_p = NULL;
2044     int entry_c;
2045 
2046     if (table_p == NULL)
2047         return TABLE_ERROR_ARG_NULL;
2048     if (table_p->ta_magic != TABLE_MAGIC)
2049         return TABLE_ERROR_PNT;
2050     if (table_p->ta_linear.tl_magic != LINEAR_MAGIC)
2051         return TABLE_ERROR_LINEAR;
2052     /* if we removed an item that shorted the bucket list, we may get this */
2053     if (table_p->ta_linear.tl_bucket_c >= table_p->ta_bucket_n) {
2054         /*
2055          * NOTE: this might happen if we delete an item which shortens the
2056          * table bucket numbers.
2057          */
2058         return TABLE_ERROR_NOT_FOUND;
2059     }
2060 
2061     /* find the entry which is the nth in the list */
2062     entry_p = table_p->ta_buckets[table_p->ta_linear.tl_bucket_c];
2063     /* NOTE: we swap the order here to be more efficient */
2064     for (entry_c = table_p->ta_linear.tl_entry_c; entry_c > 0; entry_c--) {
2065         /* did we reach the end of the list? */
2066         if (entry_p == NULL)
2067             break;
2068         entry_p = TABLE_POINTER(table_p, table_entry_t *, entry_p)->te_next_p;
2069     }
2070 
2071     /* is this a NOT_FOUND or a LINEAR error */
2072     if (entry_p == NULL)
2073         return TABLE_ERROR_NOT_FOUND;
2074     if (key_buf_p != NULL)
2075         *key_buf_p = ENTRY_KEY_BUF(entry_p);
2076     if (key_size_p != NULL)
2077         *key_size_p = entry_p->te_key_size;
2078     if (data_buf_p != NULL) {
2079         if (entry_p->te_data_size == 0)
2080             *data_buf_p = NULL;
2081         else {
2082             if (table_p->ta_data_align == 0)
2083                 *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p);
2084             else
2085                 *data_buf_p = entry_data_buf(table_p, entry_p);
2086         }
2087     }
2088     if (data_size_p != NULL)
2089         *data_size_p = entry_p->te_data_size;
2090     return TABLE_ERROR_NONE;
2091 }
2092 
2093 /*
2094  * int table_first_r
2095  *
2096  * DESCRIPTION:
2097  *
2098  * Reetrant version of the table_first routine above.  Find first
2099  * element in a table and pass back information about the key/data
2100  * pair.  If any of the key/data pointers are NULL then they are
2101  * ignored.
2102  *
2103  * RETURNS:
2104  *
2105  * Success - TABLE_ERROR_NONE
2106  *
2107  * Failure - Table error code.
2108  *
2109  * ARGUMENTS:
2110  *
2111  * table_p - Table structure pointer from which we are getting the
2112  * first element.
2113  *
2114  * linear_p - Pointer to a table linear structure which is initialized
2115  * here.  The same pointer should then be passed to table_next_r
2116  * below.
2117  *
2118  * key_buf_p - Pointer which, if not NULL, will be set to the address
2119  * of the storage of the first key that is allocated in the table.  If
2120  * an (int) is stored as the first key (for example) then key_buf_p
2121  * should be (int **) i.e. the address of a (int *).
2122  *
2123  * key_size_p - Pointer to an integer which, if not NULL, will be set
2124  * to the size of the key that is stored in the table and that is
2125  * associated with the first key.
2126  *
2127  * data_buf_p - Pointer which, if not NULL, will be set to the address
2128  * of the data storage that is allocated in the table and that is
2129  * associated with the first key.  If a (long) is stored as the data
2130  * (for example) then data_buf_p should be (long **) i.e. the address
2131  * of a (long *).
2132  *
2133  * data_size_p - Pointer to an integer which, if not NULL, will be set
2134  * to the size of the data that is stored in the table and that is
2135  * associated with the first key.
2136  */
table_first_r(table_t * table_p,table_linear_t * linear_p,void ** key_buf_p,int * key_size_p,void ** data_buf_p,int * data_size_p)2137 int table_first_r(table_t * table_p, table_linear_t * linear_p,
2138                   void **key_buf_p, int *key_size_p,
2139                   void **data_buf_p, int *data_size_p)
2140 {
2141     table_entry_t *entry_p;
2142 
2143     if (table_p == NULL)
2144         return TABLE_ERROR_ARG_NULL;
2145     if (table_p->ta_magic != TABLE_MAGIC)
2146         return TABLE_ERROR_PNT;
2147     if (linear_p == NULL)
2148         return TABLE_ERROR_ARG_NULL;
2149     /* initialize our linear magic number */
2150     linear_p->tl_magic = LINEAR_MAGIC;
2151 
2152     entry_p = first_entry(table_p, linear_p);
2153     if (entry_p == NULL)
2154         return TABLE_ERROR_NOT_FOUND;
2155     if (key_buf_p != NULL)
2156         *key_buf_p = ENTRY_KEY_BUF(entry_p);
2157     if (key_size_p != NULL)
2158         *key_size_p = entry_p->te_key_size;
2159     if (data_buf_p != NULL) {
2160         if (entry_p->te_data_size == 0)
2161             *data_buf_p = NULL;
2162         else {
2163             if (table_p->ta_data_align == 0)
2164                 *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p);
2165             else
2166                 *data_buf_p = entry_data_buf(table_p, entry_p);
2167         }
2168     }
2169     if (data_size_p != NULL)
2170         *data_size_p = entry_p->te_data_size;
2171     return TABLE_ERROR_NONE;
2172 }
2173 
2174 /*
2175  * int table_next_r
2176  *
2177  * DESCRIPTION:
2178  *
2179  * Reetrant version of the table_next routine above.  Find next
2180  * element in a table and pass back information about the key/data
2181  * pair.  If any of the key/data pointers are NULL then they are
2182  * ignored.
2183  *
2184  * RETURNS:
2185  *
2186  * Success - TABLE_ERROR_NONE
2187  *
2188  * Failure - Table error code.
2189  *
2190  * ARGUMENTS:
2191  *
2192  * table_p - Table structure pointer from which we are getting the
2193  * next element.
2194  *
2195  * linear_p - Pointer to a table linear structure which is incremented
2196  * here.  The same pointer must have been passed to table_first_r
2197  * first so that it can be initialized.
2198  *
2199  * key_buf_p - Pointer which, if not NULL, will be set to the address
2200  * of the storage of the next key that is allocated in the table.  If
2201  * an (int) is stored as the next key (for example) then key_buf_p
2202  * should be (int **) i.e. the address of a (int *).
2203  *
2204  * key_size_p - Pointer to an integer which, if not NULL will be set
2205  * to the size of the key that is stored in the table and that is
2206  * associated with the next key.
2207  *
2208  * data_buf_p - Pointer which, if not NULL, will be set to the address
2209  * of the data storage that is allocated in the table and that is
2210  * associated with the next key.  If a (long) is stored as the data
2211  * (for example) then data_buf_p should be (long **) i.e. the address
2212  * of a (long *).
2213  *
2214  * data_size_p - Pointer to an integer which, if not NULL, will be set
2215  * to the size of the data that is stored in the table and that is
2216  * associated with the next key.
2217  */
table_next_r(table_t * table_p,table_linear_t * linear_p,void ** key_buf_p,int * key_size_p,void ** data_buf_p,int * data_size_p)2218 int table_next_r(table_t * table_p, table_linear_t * linear_p,
2219                  void **key_buf_p, int *key_size_p,
2220                  void **data_buf_p, int *data_size_p)
2221 {
2222     table_entry_t *entry_p;
2223     int error;
2224 
2225     if (table_p == NULL)
2226         return TABLE_ERROR_ARG_NULL;
2227     if (table_p->ta_magic != TABLE_MAGIC)
2228         return TABLE_ERROR_PNT;
2229     if (linear_p == NULL)
2230         return TABLE_ERROR_ARG_NULL;
2231     if (linear_p->tl_magic != LINEAR_MAGIC)
2232         return TABLE_ERROR_LINEAR;
2233     /* move to the next entry */
2234     entry_p = next_entry(table_p, linear_p, &error);
2235     if (entry_p == NULL)
2236         return error;
2237     if (key_buf_p != NULL)
2238         *key_buf_p = ENTRY_KEY_BUF(entry_p);
2239     if (key_size_p != NULL)
2240         *key_size_p = entry_p->te_key_size;
2241     if (data_buf_p != NULL) {
2242         if (entry_p->te_data_size == 0)
2243             *data_buf_p = NULL;
2244         else {
2245             if (table_p->ta_data_align == 0)
2246                 *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p);
2247             else
2248                 *data_buf_p = entry_data_buf(table_p, entry_p);
2249         }
2250     }
2251     if (data_size_p != NULL)
2252         *data_size_p = entry_p->te_data_size;
2253     return TABLE_ERROR_NONE;
2254 }
2255 
2256 /*
2257  * int table_this_r
2258  *
2259  * DESCRIPTION:
2260  *
2261  * Reetrant version of the table_this routine above.  Find current
2262  * element in a table and pass back information about the key/data
2263  * pair.  If any of the key/data pointers are NULL then they are
2264  * ignored.
2265  *
2266  * RETURNS:
2267  *
2268  * Success - TABLE_ERROR_NONE
2269  *
2270  * Failure - Table error code.
2271  *
2272  * ARGUMENTS:
2273  *
2274  * table_p - Table structure pointer from which we are getting the
2275  * current element.
2276  *
2277  * linear_p - Pointer to a table linear structure which is accessed
2278  * here.  The same pointer must have been passed to table_first_r
2279  * first so that it can be initialized.
2280  *
2281  * key_buf_p - Pointer which, if not NULL, will be set to the address
2282  * of the storage of the current key that is allocated in the table.
2283  * If an (int) is stored as the current key (for example) then
2284  * key_buf_p should be (int **) i.e. the address of a (int *).
2285  *
2286  * key_size_p - Pointer to an integer which, if not NULL, will be set
2287  * to the size of the key that is stored in the table and that is
2288  * associated with the current key.
2289  *
2290  * data_buf_p - Pointer which, if not NULL, will be set to the address
2291  * of the data storage that is allocated in the table and that is
2292  * associated with the current key.  If a (long) is stored as the data
2293  * (for example) then data_buf_p should be (long **) i.e. the address
2294  * of a (long *).
2295  *
2296  * data_size_p - Pointer to an integer which, if not NULL, will be set
2297  * to the size of the data that is stored in the table and that is
2298  * associated with the current key.
2299  */
table_this_r(table_t * table_p,table_linear_t * linear_p,void ** key_buf_p,int * key_size_p,void ** data_buf_p,int * data_size_p)2300 int table_this_r(table_t * table_p, table_linear_t * linear_p,
2301                  void **key_buf_p, int *key_size_p,
2302                  void **data_buf_p, int *data_size_p)
2303 {
2304     table_entry_t *entry_p;
2305     int entry_c;
2306 
2307     if (table_p == NULL)
2308         return TABLE_ERROR_ARG_NULL;
2309     if (table_p->ta_magic != TABLE_MAGIC)
2310         return TABLE_ERROR_PNT;
2311     if (linear_p->tl_magic != LINEAR_MAGIC)
2312         return TABLE_ERROR_LINEAR;
2313     /* if we removed an item that shorted the bucket list, we may get this */
2314     if (linear_p->tl_bucket_c >= table_p->ta_bucket_n) {
2315         /*
2316          * NOTE: this might happen if we delete an item which shortens the
2317          * table bucket numbers.
2318          */
2319         return TABLE_ERROR_NOT_FOUND;
2320     }
2321 
2322     /* find the entry which is the nth in the list */
2323     for (entry_c = linear_p->tl_entry_c,
2324          entry_p = table_p->ta_buckets[linear_p->tl_bucket_c];
2325          entry_p != NULL && entry_c > 0;
2326          entry_c--, entry_p = TABLE_POINTER(table_p, table_entry_t *,
2327                                             entry_p)->te_next_p) {
2328     }
2329 
2330     if (entry_p == NULL)
2331         return TABLE_ERROR_NOT_FOUND;
2332     if (key_buf_p != NULL)
2333         *key_buf_p = ENTRY_KEY_BUF(entry_p);
2334     if (key_size_p != NULL)
2335         *key_size_p = entry_p->te_key_size;
2336     if (data_buf_p != NULL) {
2337         if (entry_p->te_data_size == 0)
2338             *data_buf_p = NULL;
2339         else {
2340             if (table_p->ta_data_align == 0)
2341                 *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p);
2342             else
2343                 *data_buf_p = entry_data_buf(table_p, entry_p);
2344         }
2345     }
2346     if (data_size_p != NULL)
2347         *data_size_p = entry_p->te_data_size;
2348     return TABLE_ERROR_NONE;
2349 }
2350 
2351 /******************************* file routines *******************************/
2352 
2353 /*
2354  * int table_read
2355  *
2356  * DESCRIPTION:
2357  *
2358  * Read in a table from a file that had been written to disk earlier
2359  * via table_write.
2360  *
2361  * RETURNS:
2362  *
2363  * Success - Pointer to the new table structure which must be passed
2364  * to table_free to be deallocated.
2365  *
2366  * Failure - NULL
2367  *
2368  * ARGUMENTS:
2369  *
2370  * path - Table file to read in.
2371  *
2372  * error_p - Pointer to an integer which, if not NULL, will contain a
2373  * table error code.
2374  */
table_read(const char * path,int * error_p,void * (* malloc_f)(size_t size),void * (* calloc_f)(size_t number,size_t size),void * (* realloc_f)(void * ptr,size_t size),void (* free_f)(void * ptr))2375 table_t *table_read(const char *path, int *error_p,
2376                     void *(*malloc_f)(size_t size),
2377                     void *(*calloc_f)(size_t number, size_t size),
2378                     void *(*realloc_f)(void *ptr, size_t size),
2379                     void (*free_f)(void *ptr))
2380 {
2381     unsigned int size;
2382     int fd, ent_size;
2383     FILE *infile;
2384     table_entry_t entry, **bucket_p, *entry_p = NULL, *last_p;
2385     unsigned long pos;
2386     table_t *table_p;
2387 
2388     /* open the file */
2389     fd = open(path, O_RDONLY, 0);
2390     if (fd < 0) {
2391         if (error_p != NULL)
2392             *error_p = TABLE_ERROR_OPEN;
2393         return NULL;
2394     }
2395 
2396     /* allocate a table structure */
2397     if (malloc_f != NULL)
2398         table_p = malloc_f(sizeof(table_t));
2399     else
2400         table_p = malloc(sizeof(table_t));
2401     if (table_p == NULL) {
2402         if (error_p != NULL)
2403             *error_p = TABLE_ERROR_ALLOC;
2404         return NULL;
2405     }
2406 
2407     /* now open the fd to get buffered i/o */
2408     infile = fdopen(fd, "r");
2409     if (infile == NULL) {
2410         if (error_p != NULL)
2411             *error_p = TABLE_ERROR_OPEN;
2412         return NULL;
2413     }
2414 
2415     /* read the main table struct */
2416     if (fread(table_p, sizeof(table_t), 1, infile) != 1) {
2417         if (error_p != NULL)
2418             *error_p = TABLE_ERROR_READ;
2419         if (free_f != NULL)
2420             free_f(table_p);
2421         else
2422             free(table_p);
2423         return NULL;
2424     }
2425     table_p->ta_file_size = 0;
2426 
2427     table_p->ta_malloc  = malloc_f  != NULL ? malloc_f  : malloc;
2428     table_p->ta_calloc  = calloc_f  != NULL ? calloc_f  : calloc;
2429     table_p->ta_realloc = realloc_f != NULL ? realloc_f : realloc;
2430     table_p->ta_free    = free_f    != NULL ? free_f    : free;
2431 
2432     /* is the file contain bad info or maybe another system type? */
2433     if (table_p->ta_magic != TABLE_MAGIC) {
2434         if (error_p != NULL)
2435             *error_p = TABLE_ERROR_PNT;
2436         return NULL;
2437     }
2438 
2439     /* allocate the buckets */
2440     table_p->ta_buckets = (table_entry_t **)table_p->ta_calloc(table_p->ta_bucket_n, sizeof(table_entry_t *));
2441     if (table_p->ta_buckets == NULL) {
2442         if (error_p != NULL)
2443             *error_p = TABLE_ERROR_ALLOC;
2444         table_p->ta_free(table_p);
2445         return NULL;
2446     }
2447 
2448     if (fread(table_p->ta_buckets, sizeof(table_entry_t *), table_p->ta_bucket_n,
2449               infile) != (size_t) table_p->ta_bucket_n) {
2450         if (error_p != NULL)
2451             *error_p = TABLE_ERROR_READ;
2452         table_p->ta_free(table_p->ta_buckets);
2453         table_p->ta_free(table_p);
2454         return NULL;
2455     }
2456 
2457     /* read in the entries */
2458     for (bucket_p = table_p->ta_buckets;
2459          bucket_p < table_p->ta_buckets + table_p->ta_bucket_n;
2460          bucket_p++) {
2461 
2462         /* skip null buckets */
2463         if (*bucket_p == NULL)
2464             continue;
2465         /* run through the entry list */
2466         last_p = NULL;
2467         for (pos = *(unsigned long *) bucket_p;;
2468              pos = (unsigned long) entry_p->te_next_p) {
2469 
2470             /* read in the entry */
2471             if (fseek(infile, pos, SEEK_SET) != 0) {
2472                 if (error_p != NULL)
2473                     *error_p = TABLE_ERROR_SEEK;
2474                 table_p->ta_free(table_p->ta_buckets);
2475                 if (entry_p != NULL)
2476                     table_p->ta_free(entry_p);
2477                 table_p->ta_free(table_p);
2478                 /* the other table elements will not be freed */
2479                 return NULL;
2480             }
2481             if (fread(&entry, sizeof(struct table_shell_st), 1, infile) != 1) {
2482                 if (error_p != NULL)
2483                     *error_p = TABLE_ERROR_READ;
2484                 table_p->ta_free(table_p->ta_buckets);
2485                 if (entry_p != NULL)
2486                     table_p->ta_free(entry_p);
2487                 table_p->ta_free(table_p);
2488                 /* the other table elements will not be freed */
2489                 return NULL;
2490             }
2491 
2492             /* make a new entry */
2493             ent_size = entry_size(table_p, entry.te_key_size, entry.te_data_size);
2494             entry_p = (table_entry_t *)table_p->ta_malloc(ent_size);
2495             if (entry_p == NULL) {
2496                 if (error_p != NULL)
2497                     *error_p = TABLE_ERROR_ALLOC;
2498                 table_p->ta_free(table_p->ta_buckets);
2499                 table_p->ta_free(table_p);
2500                 /* the other table elements will not be freed */
2501                 return NULL;
2502             }
2503             entry_p->te_key_size = entry.te_key_size;
2504             entry_p->te_data_size = entry.te_data_size;
2505             entry_p->te_next_p = entry.te_next_p;
2506 
2507             if (last_p == NULL)
2508                 *bucket_p = entry_p;
2509             else
2510                 last_p->te_next_p = entry_p;
2511             /* determine how much more we have to read */
2512             size = ent_size - sizeof(struct table_shell_st);
2513             if (fread(ENTRY_KEY_BUF(entry_p), sizeof(char), size, infile) != size) {
2514                 if (error_p != NULL)
2515                     *error_p = TABLE_ERROR_READ;
2516                 table_p->ta_free(table_p->ta_buckets);
2517                 table_p->ta_free(entry_p);
2518                 table_p->ta_free(table_p);
2519                 /* the other table elements will not be freed */
2520                 return NULL;
2521             }
2522 
2523             /* we are done if the next pointer is null */
2524             if (entry_p->te_next_p == (unsigned long) 0)
2525                 break;
2526             last_p = entry_p;
2527         }
2528     }
2529 
2530     (void) fclose(infile);
2531 
2532     if (error_p != NULL)
2533         *error_p = TABLE_ERROR_NONE;
2534     return table_p;
2535 }
2536 
2537 /*
2538  * int table_write
2539  *
2540  * DESCRIPTION:
2541  *
2542  * Write a table from memory to file.
2543  *
2544  * RETURNS:
2545  *
2546  * Success - TABLE_ERROR_NONE
2547  *
2548  * Failure - Table error code.
2549  *
2550  * ARGUMENTS:
2551  *
2552  * table_p - Pointer to the table that we are writing to the file.
2553  *
2554  * path - Table file to write out to.
2555  *
2556  * mode - Mode of the file.  This argument is passed on to open when
2557  * the file is created.
2558  */
table_write(const table_t * table_p,const char * path,const int mode)2559 int table_write(const table_t * table_p, const char *path, const int mode)
2560 {
2561     int fd, rem, ent_size;
2562     unsigned int bucket_c;
2563     unsigned long size;
2564     table_entry_t *entry_p, **buckets, **bucket_p, *next_p;
2565     table_t tmain;
2566     FILE *outfile;
2567 
2568     if (table_p == NULL)
2569         return TABLE_ERROR_ARG_NULL;
2570     if (table_p->ta_magic != TABLE_MAGIC)
2571         return TABLE_ERROR_PNT;
2572     fd = open(path, O_WRONLY | O_CREAT, mode);
2573     if (fd < 0)
2574         return TABLE_ERROR_OPEN;
2575     outfile = fdopen(fd, "w");
2576     if (outfile == NULL)
2577         return TABLE_ERROR_OPEN;
2578     /* allocate a block of sizes for each bucket */
2579     buckets = (table_entry_t **) table_p->ta_malloc(sizeof(table_entry_t *) *
2580                                         table_p->ta_bucket_n);
2581     if (buckets == NULL)
2582         return TABLE_ERROR_ALLOC;
2583     /* make a copy of the tmain struct */
2584     tmain = *table_p;
2585 
2586     /* start counting the bytes */
2587     size = 0;
2588     size += sizeof(table_t);
2589 
2590     /* buckets go right after tmain struct */
2591     tmain.ta_buckets = (table_entry_t **) size;
2592     size += sizeof(table_entry_t *) * table_p->ta_bucket_n;
2593 
2594     /* run through and count the buckets */
2595     for (bucket_c = 0; bucket_c < table_p->ta_bucket_n; bucket_c++) {
2596         bucket_p = table_p->ta_buckets + bucket_c;
2597         if (*bucket_p == NULL) {
2598             buckets[bucket_c] = NULL;
2599             continue;
2600         }
2601         buckets[bucket_c] = (table_entry_t *) size;
2602         for (entry_p = *bucket_p; entry_p != NULL; entry_p = entry_p->te_next_p) {
2603             size += entry_size(table_p, entry_p->te_key_size, entry_p->te_data_size);
2604             /*
2605              * We now have to round the file to the nearest long so the
2606              * mmaping of the longs in the entry structs will work.
2607              */
2608             rem = size & (sizeof(long) - 1);
2609             if (rem > 0)
2610                 size += sizeof(long) - rem;
2611         }
2612     }
2613     /* add a \0 at the end to fill the last section */
2614     size++;
2615 
2616     /* set the tmain fields */
2617     tmain.ta_linear.tl_magic = 0;
2618     tmain.ta_linear.tl_bucket_c = 0;
2619     tmain.ta_linear.tl_entry_c = 0;
2620     tmain.ta_file_size = size;
2621 
2622     /*
2623      * Now we can start the writing because we got the bucket offsets.
2624      */
2625 
2626     /* write the tmain table struct */
2627     size = 0;
2628     if (fwrite(&tmain, sizeof(table_t), 1, outfile) != 1) {
2629         table_p->ta_free(buckets);
2630         return TABLE_ERROR_WRITE;
2631     }
2632     size += sizeof(table_t);
2633     if (fwrite(buckets, sizeof(table_entry_t *), table_p->ta_bucket_n,
2634                outfile) != (size_t) table_p->ta_bucket_n) {
2635         table_p->ta_free(buckets);
2636         return TABLE_ERROR_WRITE;
2637     }
2638     size += sizeof(table_entry_t *) * table_p->ta_bucket_n;
2639 
2640     /* write out the entries */
2641     for (bucket_p = table_p->ta_buckets;
2642          bucket_p < table_p->ta_buckets + table_p->ta_bucket_n;
2643          bucket_p++) {
2644         for (entry_p = *bucket_p; entry_p != NULL; entry_p = entry_p->te_next_p) {
2645 
2646             ent_size = entry_size(table_p, entry_p->te_key_size,
2647                                   entry_p->te_data_size);
2648             size += ent_size;
2649             /* round to nearest long here so we can write copy */
2650             rem = size & (sizeof(long) - 1);
2651             if (rem > 0)
2652                 size += sizeof(long) - rem;
2653             next_p = entry_p->te_next_p;
2654             if (next_p != NULL)
2655                 entry_p->te_next_p = (table_entry_t *) size;
2656             /* now write to disk */
2657             if (fwrite(entry_p, ent_size, 1, outfile) != 1) {
2658                 table_p->ta_free(buckets);
2659                 return TABLE_ERROR_WRITE;
2660             }
2661 
2662             /* restore the next pointer */
2663             if (next_p != NULL)
2664                 entry_p->te_next_p = next_p;
2665             /* now write the padding information */
2666             if (rem > 0) {
2667                 rem = sizeof(long) - rem;
2668                 /*
2669                  * NOTE: this won't leave fseek'd space at the end but we
2670                  * don't care there because there is no accessed memory
2671                  * afterwards.  We write 1 \0 at the end to make sure.
2672                  */
2673                 if (fseek(outfile, rem, SEEK_CUR) != 0) {
2674                     table_p->ta_free(buckets);
2675                     return TABLE_ERROR_SEEK;
2676                 }
2677             }
2678         }
2679     }
2680     /*
2681      * Write a \0 at the end of the file to make sure that the last
2682      * fseek filled with nulls.
2683      */
2684     (void) fputc('\0', outfile);
2685 
2686     (void) fclose(outfile);
2687     table_p->ta_free(buckets);
2688 
2689     return TABLE_ERROR_NONE;
2690 }
2691 
2692 /******************************** table order ********************************/
2693 
2694 /*
2695  * table_entry_t *table_order
2696  *
2697  * DESCRIPTION:
2698  *
2699  * Order a table by building an array of table entry pointers and then
2700  * sorting this array using the qsort function.  To retrieve the
2701  * sorted entries, you can then use the table_entry routine to access
2702  * each entry in order.
2703  *
2704  * NOTE: This routine is now thread safe in that two table_order calls
2705  * can now happen at the same time, even on the same table.
2706  *
2707  * RETURNS:
2708  *
2709  * An allocated list of entry pointers which must be freed later.
2710  * Returns null on error.
2711  *
2712  * ARGUMENTS:
2713  *
2714  * table_p - Pointer to the table that we are ordering.
2715  *
2716  * compare - Comparison function defined by the user.  Its definition
2717  * is at the top of the table.h file.  If this is NULL then it will
2718  * order the table my memcmp-ing the keys.
2719  *
2720  * num_entries_p - Pointer to an integer which, if not NULL, will
2721  * contain the number of entries in the returned entry pointer array.
2722  *
2723  * error_p - Pointer to an integer which, if not NULL, will contain a
2724  * table error code.
2725  */
table_order(table_t * table_p,table_compare_t compare,int * num_entries_p,int * error_p)2726 table_entry_t **table_order(table_t * table_p, table_compare_t compare,
2727                             int *num_entries_p, int *error_p)
2728 {
2729     table_entry_t *entry_p, **entries, **entries_p;
2730     table_linear_t linear;
2731     compare_t comp_func;
2732     int error;
2733 
2734     if (table_p == NULL) {
2735         if (error_p != NULL)
2736             *error_p = TABLE_ERROR_ARG_NULL;
2737         return NULL;
2738     }
2739     if (table_p->ta_magic != TABLE_MAGIC) {
2740         if (error_p != NULL)
2741             *error_p = TABLE_ERROR_PNT;
2742         return NULL;
2743     }
2744 
2745     /* there must be at least 1 element in the table for this to work */
2746     if (table_p->ta_entry_n == 0) {
2747         if (error_p != NULL)
2748             *error_p = TABLE_ERROR_EMPTY;
2749         return NULL;
2750     }
2751 
2752     entries = (table_entry_t **) table_p->ta_malloc(table_p->ta_entry_n *
2753                                         sizeof(table_entry_t *));
2754     if (entries == NULL) {
2755         if (error_p != NULL)
2756             *error_p = TABLE_ERROR_ALLOC;
2757         return NULL;
2758     }
2759 
2760     /* get a pointer to all entries */
2761     entry_p = first_entry(table_p, &linear);
2762     if (entry_p == NULL) {
2763         if (error_p != NULL)
2764             *error_p = TABLE_ERROR_NOT_FOUND;
2765         return NULL;
2766     }
2767 
2768     /* add all of the entries to the array */
2769     for (entries_p = entries;
2770          entry_p != NULL;
2771          entry_p = next_entry(table_p, &linear, &error))
2772         *entries_p++ = entry_p;
2773     if (error != TABLE_ERROR_NOT_FOUND) {
2774         if (error_p != NULL)
2775             *error_p = error;
2776         return NULL;
2777     }
2778 
2779     if (compare == NULL) {
2780         /* this is regardless of the alignment */
2781         comp_func = local_compare;
2782     }
2783     else if (table_p->ta_data_align == 0)
2784         comp_func = external_compare;
2785     else
2786         comp_func = external_compare_align;
2787     /* now qsort the entire entries array from first to last element */
2788     split(entries, entries + table_p->ta_entry_n - 1, comp_func, compare,
2789           table_p);
2790 
2791     if (num_entries_p != NULL)
2792         *num_entries_p = table_p->ta_entry_n;
2793     if (error_p != NULL)
2794         *error_p = TABLE_ERROR_NONE;
2795     return entries;
2796 }
2797 
2798 /*
2799  * int table_entry
2800  *
2801  * DESCRIPTION:
2802  *
2803  * Get information about an element.  The element is one from the
2804  * array returned by the table_order function.  If any of the key/data
2805  * pointers are NULL then they are ignored.
2806  *
2807  * RETURNS:
2808  *
2809  * Success - TABLE_ERROR_NONE
2810  *
2811  * Failure - Table error code.
2812  *
2813  * ARGUMENTS:
2814  *
2815  * table_p - Table structure pointer from which we are getting the
2816  * element.
2817  *
2818  * entry_p - Pointer to a table entry from the array returned by the
2819  * table_order function.
2820  *
2821  * key_buf_p - Pointer which, if not NULL, will be set to the address
2822  * of the storage of this entry that is allocated in the table.  If an
2823  * (int) is stored as this entry (for example) then key_buf_p should
2824  * be (int **) i.e. the address of a (int *).
2825  *
2826  * key_size_p - Pointer to an integer which, if not NULL, will be set
2827  * to the size of the key that is stored in the table.
2828  *
2829  * data_buf_p - Pointer which, if not NULL, will be set to the address
2830  * of the data storage of this entry that is allocated in the table.
2831  * If a (long) is stored as this entry data (for example) then
2832  * data_buf_p should be (long **) i.e. the address of a (long *).
2833  *
2834  * data_size_p - Pointer to an integer which, if not NULL, will be set
2835  * to the size of the data that is stored in the table.
2836  */
table_entry_info(table_t * table_p,table_entry_t * entry_p,void ** key_buf_p,int * key_size_p,void ** data_buf_p,int * data_size_p)2837 int table_entry_info(table_t * table_p, table_entry_t * entry_p,
2838                 void **key_buf_p, int *key_size_p,
2839                 void **data_buf_p, int *data_size_p)
2840 {
2841     if (table_p == NULL)
2842         return TABLE_ERROR_ARG_NULL;
2843     if (table_p->ta_magic != TABLE_MAGIC)
2844         return TABLE_ERROR_PNT;
2845     if (entry_p == NULL)
2846         return TABLE_ERROR_ARG_NULL;
2847     if (key_buf_p != NULL)
2848         *key_buf_p = ENTRY_KEY_BUF(entry_p);
2849     if (key_size_p != NULL)
2850         *key_size_p = entry_p->te_key_size;
2851     if (data_buf_p != NULL) {
2852         if (entry_p->te_data_size == 0)
2853             *data_buf_p = NULL;
2854         else {
2855             if (table_p->ta_data_align == 0)
2856                 *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p);
2857             else
2858                 *data_buf_p = entry_data_buf(table_p, entry_p);
2859         }
2860     }
2861     if (data_size_p != NULL)
2862         *data_size_p = entry_p->te_data_size;
2863     return TABLE_ERROR_NONE;
2864 }
2865