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