Annotation of embedaddon/mpd/src/contrib/libpdel/util/ghash.c, revision 1.1
1.1 ! misho 1:
! 2: /*
! 3: * Copyright (c) 2001-2002 Packet Design, LLC.
! 4: * All rights reserved.
! 5: *
! 6: * Subject to the following obligations and disclaimer of warranty,
! 7: * use and redistribution of this software, in source or object code
! 8: * forms, with or without modifications are expressly permitted by
! 9: * Packet Design; provided, however, that:
! 10: *
! 11: * (i) Any and all reproductions of the source or object code
! 12: * must include the copyright notice above and the following
! 13: * disclaimer of warranties; and
! 14: * (ii) No rights are granted, in any manner or form, to use
! 15: * Packet Design trademarks, including the mark "PACKET DESIGN"
! 16: * on advertising, endorsements, or otherwise except as such
! 17: * appears in the above copyright notice or in the software.
! 18: *
! 19: * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
! 20: * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
! 21: * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
! 22: * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
! 23: * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
! 24: * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
! 25: * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
! 26: * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
! 27: * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
! 28: * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
! 29: * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
! 30: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
! 31: * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
! 32: * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
! 33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
! 35: * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
! 36: * THE POSSIBILITY OF SUCH DAMAGE.
! 37: *
! 38: * Author: Archie Cobbs <archie@freebsd.org>
! 39: */
! 40:
! 41: #include <sys/types.h>
! 42: #include <sys/param.h>
! 43: #include <netinet/in.h>
! 44:
! 45: #ifndef _KERNEL
! 46: #include <stdio.h>
! 47: #include <stdlib.h>
! 48: #include <stdarg.h>
! 49: #include <syslog.h>
! 50: #include <errno.h>
! 51: #include <assert.h>
! 52: #include <string.h>
! 53: #include <err.h>
! 54: #else
! 55: #include <sys/systm.h>
! 56: #include <sys/syslog.h>
! 57: #endif
! 58:
! 59: #include "structs/structs.h"
! 60: #include "structs/type/array.h"
! 61:
! 62: #include "util/ghash.h"
! 63: #include "util/typed_mem.h"
! 64:
! 65: #define MIN_BUCKETS 31
! 66: #define DEFAULT_MAX_LOAD 75 /* 75% full */
! 67: #define MIN_LOAD_FACTOR 20 /* 1/20 of current size */
! 68:
! 69: struct gent {
! 70: const void *item; /* this item */
! 71: struct gent *next; /* next item in bucket */
! 72: };
! 73:
! 74: struct ghash {
! 75: void *arg;
! 76: ghash_hash_t *hash;
! 77: ghash_equal_t *equal;
! 78: ghash_add_t *add;
! 79: ghash_del_t *del;
! 80: u_int maxload; /* maximum load factor in % */
! 81: u_int mods; /* modification counter */
! 82: u_int size; /* number of items in table */
! 83: u_int maxsize; /* when we need to increase */
! 84: u_int minsize; /* when we need to decrease */
! 85: u_int nbuckets; /* number of buckets in table */
! 86: u_int iter_count; /* number outstanding iter's */
! 87: struct gent **buckets; /* hash bucket array */
! 88: struct { /* typed memory alloc types */
! 89: const char *g;
! 90: char g_buf[TYPED_MEM_TYPELEN];
! 91: const char *gent;
! 92: char gent_buf[TYPED_MEM_TYPELEN];
! 93: const char *iter;
! 94: char iter_buf[TYPED_MEM_TYPELEN];
! 95: const char *buckets;
! 96: char buckets_buf[TYPED_MEM_TYPELEN];
! 97: } mtype;
! 98: u_char locked;
! 99: };
! 100:
! 101: /*
! 102: * Internal functions
! 103: */
! 104:
! 105: static ghash_equal_t ghash_default_equal;
! 106: static ghash_hash_t ghash_default_hash;
! 107: static ghash_add_t ghash_default_add;
! 108: static ghash_del_t ghash_default_del;
! 109:
! 110: static void ghash_rehash(struct ghash *g, u_int new_nbuckets);
! 111:
! 112: /* Update maxsize and minsize after nbuckets changes */
! 113: #define UPDATE_SIZES(g) \
! 114: do { \
! 115: (g)->maxsize = ((g)->nbuckets * (g)->maxload) / 100; \
! 116: if ((g)->maxsize == 0) \
! 117: (g)->maxsize = 1; \
! 118: (g)->minsize = (g)->nbuckets / MIN_LOAD_FACTOR; \
! 119: } while (0)
! 120:
! 121: /*
! 122: * Create a new hash table.
! 123: */
! 124: struct ghash *
! 125: ghash_create(void *arg, u_int isize, u_int maxload, const char *mtype,
! 126: ghash_hash_t *hash, ghash_equal_t *equal, ghash_add_t *add,
! 127: ghash_del_t *del)
! 128: {
! 129: struct ghash *g;
! 130:
! 131: /* Apply defaults and sanity check */
! 132: if (isize < MIN_BUCKETS)
! 133: isize = MIN_BUCKETS;
! 134: if (maxload == 0)
! 135: maxload = DEFAULT_MAX_LOAD;
! 136:
! 137: /* Create new hash table object */
! 138: if ((g = MALLOC(mtype, sizeof(*g))) == NULL)
! 139: return (NULL);
! 140: memset(g, 0, sizeof(*g));
! 141: g->arg = arg;
! 142: g->hash = hash != NULL ? hash : ghash_default_hash;
! 143: g->equal = equal != NULL ? equal : ghash_default_equal;
! 144: g->add = add != NULL ? add : ghash_default_add;
! 145: g->del = del != NULL ? del: ghash_default_del;
! 146: g->nbuckets = isize;
! 147: g->maxload = maxload;
! 148: UPDATE_SIZES(g);
! 149:
! 150: /* Create memory subtypes */
! 151: if (mtype != NULL) {
! 152: snprintf(g->mtype.g_buf, sizeof(g->mtype.g_buf), "%s", mtype);
! 153: g->mtype.g = g->mtype.g_buf;
! 154: snprintf(g->mtype.gent_buf, sizeof(g->mtype.gent_buf),
! 155: "%s.gent", mtype);
! 156: g->mtype.gent = g->mtype.gent_buf;
! 157: snprintf(g->mtype.iter_buf, sizeof(g->mtype.iter_buf),
! 158: "%s.iter", mtype);
! 159: g->mtype.iter = g->mtype.iter_buf;
! 160: snprintf(g->mtype.buckets_buf, sizeof(g->mtype.buckets_buf),
! 161: "%s.buckets", mtype);
! 162: g->mtype.buckets = g->mtype.buckets_buf;
! 163: }
! 164:
! 165: /* Allocate initial bucket array */
! 166: if ((g->buckets = MALLOC(g->mtype.buckets,
! 167: g->nbuckets * sizeof(*g->buckets))) == NULL) {
! 168: FREE(g->mtype.g, g);
! 169: return (NULL);
! 170: }
! 171: memset(g->buckets, 0, g->nbuckets * sizeof(*g->buckets));
! 172:
! 173: /* Done */
! 174: return (g);
! 175: }
! 176:
! 177: /*
! 178: * Destroy a hash table.
! 179: */
! 180: void
! 181: ghash_destroy(struct ghash **gp)
! 182: {
! 183: struct ghash *const g = *gp;
! 184: u_int i;
! 185:
! 186: if (g == NULL)
! 187: return;
! 188: assert(!g->locked);
! 189: assert(g->iter_count == 0);
! 190: g->locked = 1;
! 191: for (i = 0; i < g->nbuckets; i++) {
! 192: while (g->buckets[i] != NULL) {
! 193: struct gent *const e = g->buckets[i];
! 194: const void *const item = e->item;
! 195:
! 196: g->buckets[i] = e->next;
! 197: FREE(g->mtype.gent, e);
! 198: g->size--;
! 199: (*g->del)(g, (void *)item);
! 200: }
! 201: }
! 202: FREE(g->mtype.buckets, g->buckets);
! 203: FREE(g->mtype.g, g);
! 204: *gp = NULL;
! 205: }
! 206:
! 207: /*
! 208: * Get the argument supplied to ghash_create().
! 209: */
! 210: void *
! 211: ghash_arg(struct ghash *g)
! 212: {
! 213: return (g->arg);
! 214: }
! 215:
! 216: /*
! 217: * Return number of items in the table.
! 218: */
! 219: u_int
! 220: ghash_size(struct ghash *g)
! 221: {
! 222: return (g->size);
! 223: }
! 224:
! 225: /*
! 226: * Get an item.
! 227: *
! 228: * Returns the item, or NULL if the item does not exist.
! 229: */
! 230: void *
! 231: ghash_get(struct ghash *g, const void *item)
! 232: {
! 233: struct gent *e;
! 234:
! 235: if (item == NULL)
! 236: return (NULL);
! 237: for (e = g->buckets[(*g->hash)(g, item) % g->nbuckets];
! 238: e != NULL; e = e->next) {
! 239: if (item == e->item || (*g->equal)(g, item, e->item))
! 240: return ((void *)e->item);
! 241: }
! 242: return (NULL);
! 243: }
! 244:
! 245: /*
! 246: * Put an item.
! 247: *
! 248: * Returns 0 if the item is new, 1 if it replaces an existing
! 249: * item, and -1 if there was an error.
! 250: */
! 251: int
! 252: ghash_put(struct ghash *g, const void *item)
! 253: {
! 254: struct gent **start;
! 255: struct gent *e;
! 256:
! 257: /* Sanity check */
! 258: if (item == NULL) {
! 259: errno = EINVAL;
! 260: return (-1);
! 261: }
! 262:
! 263: /* Lock hash table */
! 264: if (g->locked) {
! 265: errno = EBUSY;
! 266: return (-1);
! 267: }
! 268: g->locked = 1;
! 269:
! 270: /* Find item's bucket */
! 271: start = &g->buckets[(*g->hash)(g, item) % g->nbuckets];
! 272:
! 273: /* See if item already exists, and replace it if so */
! 274: for (e = *start; e != NULL; e = e->next) {
! 275: if ((*g->equal)(g, item, e->item)) {
! 276: (*g->del)(g, (void *)e->item);
! 277: e->item = item;
! 278: (*g->add)(g, (void *)e->item);
! 279: g->mods++;
! 280: g->locked = 0;
! 281: return (1);
! 282: }
! 283: }
! 284:
! 285: /* Expand table if necessary */
! 286: if (g->size + 1 > g->maxsize) {
! 287: ghash_rehash(g, (g->nbuckets * 2) - 1);
! 288: start = &g->buckets[(*g->hash)(g, item) % g->nbuckets];
! 289: }
! 290: g->mods++;
! 291:
! 292: /* Add new item */
! 293: if ((e = MALLOC(g->mtype.gent, sizeof(*e))) == NULL) {
! 294: g->locked = 0;
! 295: return (-1);
! 296: }
! 297: (*g->add)(g, (void *)item);
! 298: e->item = item;
! 299: e->next = *start;
! 300: *start = e;
! 301: g->size++;
! 302:
! 303: /* Unlock tree and return */
! 304: g->locked = 0;
! 305: return (0);
! 306: }
! 307:
! 308: /*
! 309: * Remove an item.
! 310: *
! 311: * Returns 1 if the item was found and removed, 0 if not found.
! 312: */
! 313: int
! 314: ghash_remove(struct ghash *g, const void *item)
! 315: {
! 316: struct gent **ep;
! 317: int found = 0;
! 318:
! 319: /* Sanity check */
! 320: if (item == NULL)
! 321: return (0);
! 322:
! 323: /* Lock hash table */
! 324: if (g->locked) {
! 325: errno = EBUSY;
! 326: return (-1);
! 327: }
! 328: g->locked = 1;
! 329:
! 330: /* Find item */
! 331: for (ep = &g->buckets[(*g->hash)(g, item) % g->nbuckets];
! 332: *ep != NULL; ep = &(*ep)->next) {
! 333: struct gent *const e = *ep;
! 334:
! 335: if ((*g->equal)(g, item, e->item)) {
! 336: const void *const oitem = e->item;
! 337:
! 338: *ep = e->next;
! 339: FREE(g->mtype.gent, e);
! 340: g->size--;
! 341: (*g->del)(g, (void *)oitem);
! 342: found = 1;
! 343: break;
! 344: }
! 345: }
! 346: if (!found) {
! 347: g->locked = 0;
! 348: return (0);
! 349: }
! 350: g->mods++;
! 351:
! 352: /* Shrink table if desired */
! 353: if (g->size < g->minsize && g->size > MIN_BUCKETS) {
! 354: u_int new_size;
! 355:
! 356: new_size = (g->size * g->maxload) / 200;
! 357: if (new_size > MIN_BUCKETS)
! 358: new_size = MIN_BUCKETS;
! 359: ghash_rehash(g, new_size);
! 360: }
! 361:
! 362: /* Unlock tree and return */
! 363: g->locked = 0;
! 364: return (1);
! 365: }
! 366:
! 367: /**********************************************************************
! 368: ITERATOR METHODS
! 369: **********************************************************************/
! 370:
! 371: struct ghash_iter {
! 372: struct ghash *g; /* hash table we're iterating over */
! 373: u_int mods; /* guard against changes to table */
! 374: u_int bucket; /* current bucket we're traversing */
! 375: u_int count; /* number of items returned so far */
! 376: struct gent **ep; /* points to previous rtn'd by next() */
! 377: };
! 378:
! 379: struct ghash_iter *
! 380: ghash_iter_create(struct ghash *g)
! 381: {
! 382: struct ghash_iter *iter;
! 383:
! 384: if (g == NULL) {
! 385: errno = EINVAL;
! 386: return (NULL);
! 387: }
! 388: if ((iter = MALLOC(g->mtype.iter, sizeof(*iter))) == NULL)
! 389: return (NULL);
! 390: memset(iter, 0, sizeof(*iter));
! 391: iter->g = g;
! 392: iter->mods = g->mods;
! 393: g->iter_count++;
! 394: return (iter);
! 395: }
! 396:
! 397: void
! 398: ghash_iter_destroy(struct ghash_iter **iterp)
! 399: {
! 400: struct ghash_iter *const iter = *iterp;
! 401:
! 402: if (iter == NULL)
! 403: return;
! 404: iter->g->iter_count--;
! 405: FREE(iter->g->mtype.iter, iter);
! 406: *iterp = NULL;
! 407: }
! 408:
! 409: int
! 410: ghash_iter_has_next(struct ghash_iter *iter)
! 411: {
! 412: struct ghash *const g = iter->g;
! 413:
! 414: if (iter->mods != g->mods)
! 415: return (1); /* force a call to next() */
! 416: return (iter->count < g->size);
! 417: }
! 418:
! 419: /*
! 420: * Return next element in an iteration.
! 421: */
! 422: void *
! 423: ghash_iter_next(struct ghash_iter *iter)
! 424: {
! 425: struct ghash *const g = iter->g;
! 426:
! 427: /* Sanity checks */
! 428: if (iter->mods != g->mods || iter->count >= g->size) {
! 429: errno = EINVAL;
! 430: return (NULL);
! 431: }
! 432:
! 433: /* Advance pointer to next element */
! 434: if (iter->count++ == 0)
! 435: iter->ep = &g->buckets[0]; /* initialize pointer */
! 436: else {
! 437: assert(*iter->ep != NULL);
! 438: iter->ep = &(*iter->ep)->next;
! 439: }
! 440: while (*iter->ep == NULL) {
! 441: iter->ep = &g->buckets[++iter->bucket];
! 442: assert(iter->bucket < g->nbuckets);
! 443: }
! 444:
! 445: /* Update item count and return next item */
! 446: return ((void *)(*iter->ep)->item);
! 447: }
! 448:
! 449: /*
! 450: * Remove previously returned element in an iteration.
! 451: */
! 452: int
! 453: ghash_iter_remove(struct ghash_iter *iter)
! 454: {
! 455: struct ghash *const g = iter->g;
! 456: const void *item;
! 457: struct gent *e;
! 458:
! 459: /* Sanity checks */
! 460: if (iter->count == 0 || iter->mods != g->mods) {
! 461: errno = EINVAL;
! 462: return (-1);
! 463: }
! 464:
! 465: /* Lock hash table */
! 466: if (g->locked) {
! 467: errno = EBUSY;
! 468: return (-1);
! 469: }
! 470: g->locked = 1;
! 471:
! 472: /* Remove element */
! 473: e = *iter->ep;
! 474: item = e->item;
! 475: *iter->ep = e->next;
! 476: FREE(g->mtype.gent, e);
! 477: g->size--;
! 478: iter->count--;
! 479: g->mods++;
! 480: iter->mods++;
! 481: (*g->del)(g, (void *)item);
! 482:
! 483: /* Shrink table if desired */
! 484: if (g->size < g->minsize && g->size > MIN_BUCKETS) {
! 485: u_int new_size;
! 486:
! 487: new_size = (g->size * g->maxload) / 200;
! 488: if (new_size > MIN_BUCKETS)
! 489: new_size = MIN_BUCKETS;
! 490: ghash_rehash(g, new_size);
! 491: }
! 492: g->locked = 0;
! 493: return (0);
! 494: }
! 495:
! 496: /*
! 497: * Get an array of hash table contents, optionally sorted.
! 498: */
! 499: int
! 500: ghash_dump(struct ghash *g, void ***listp, const char *mtype)
! 501: {
! 502: struct gent *e;
! 503: void **list;
! 504: u_int num;
! 505: u_int i;
! 506:
! 507: /* Get items in a list */
! 508: if ((list = MALLOC(mtype, g->size * sizeof(*list))) == NULL)
! 509: return (-1);
! 510: for (num = i = 0; i < g->nbuckets; i++) {
! 511: for (e = g->buckets[i]; e != NULL; e = e->next)
! 512: list[num++] = (void *)e->item;
! 513: }
! 514: assert(num == g->size);
! 515:
! 516: /* Done */
! 517: *listp = list;
! 518: return (num);
! 519: }
! 520:
! 521: /*
! 522: * Start a hash table walk.
! 523: */
! 524: void
! 525: ghash_walk_init(struct ghash *g, struct ghash_walk *walk)
! 526: {
! 527: memset(walk, 0, sizeof(*walk));
! 528: walk->mods = g->mods;
! 529: }
! 530:
! 531: /*
! 532: * Get the next item in the hash table walk.
! 533: */
! 534: void *
! 535: ghash_walk_next(struct ghash *g, struct ghash_walk *walk)
! 536: {
! 537: void *item;
! 538:
! 539: /* Check for modifications */
! 540: if (g->mods != walk->mods) {
! 541: errno = EINVAL;
! 542: return (NULL);
! 543: }
! 544:
! 545: /* Go to next bucket if needed */
! 546: if (walk->e == NULL) {
! 547: while (walk->bucket < g->nbuckets
! 548: && g->buckets[walk->bucket] == NULL)
! 549: walk->bucket++;
! 550: if (walk->bucket == g->nbuckets) {
! 551: errno = ENOENT;
! 552: return (NULL);
! 553: }
! 554: walk->e = g->buckets[walk->bucket++];
! 555: }
! 556:
! 557: /* Get item to return */
! 558: item = (void *)walk->e->item;
! 559:
! 560: /* Point at next item for next time */
! 561: walk->e = walk->e->next;
! 562:
! 563: /* Return item */
! 564: return (item);
! 565: }
! 566:
! 567: /**********************************************************************
! 568: DEFAULT CALLBACKS
! 569: **********************************************************************/
! 570:
! 571: static int
! 572: ghash_default_equal(struct ghash *g, const void *item1, const void *item2)
! 573: {
! 574: return (item1 == item2);
! 575: }
! 576:
! 577: static u_int32_t
! 578: ghash_default_hash(struct ghash *g, const void *item)
! 579: {
! 580: return ((u_int32_t)(u_long)item);
! 581: }
! 582:
! 583: static void
! 584: ghash_default_add(struct ghash *g, void *item)
! 585: {
! 586: return;
! 587: }
! 588:
! 589: static void
! 590: ghash_default_del(struct ghash *g, void *item)
! 591: {
! 592: return;
! 593: }
! 594:
! 595: /**********************************************************************
! 596: HELPER METHODS
! 597: **********************************************************************/
! 598:
! 599: /*
! 600: * Resize the hash bucket array.
! 601: */
! 602: static void
! 603: ghash_rehash(struct ghash *g, u_int new_nbuckets)
! 604: {
! 605: struct gent **new_buckets;
! 606: u_int i;
! 607:
! 608: /* Get new bucket array */
! 609: assert(new_nbuckets > 0);
! 610: if ((new_buckets = MALLOC(g->mtype.buckets,
! 611: new_nbuckets * sizeof(*new_buckets))) == NULL)
! 612: return; /* can't do it */
! 613: memset(new_buckets, 0, new_nbuckets * sizeof(*new_buckets));
! 614:
! 615: /* Move all entries over to new array */
! 616: for (i = 0; i < g->nbuckets; i++) {
! 617: while (g->buckets[i] != NULL) {
! 618: struct gent *const e = g->buckets[i];
! 619: const u_int new_bucket
! 620: = (*g->hash)(g, e->item) % new_nbuckets;
! 621:
! 622: g->buckets[i] = e->next;
! 623: e->next = new_buckets[new_bucket];
! 624: new_buckets[new_bucket] = e;
! 625: }
! 626: }
! 627: g->nbuckets = new_nbuckets;
! 628: FREE(g->mtype.buckets, g->buckets);
! 629: g->buckets = new_buckets;
! 630:
! 631: /* Update new upper and lower size limits */
! 632: UPDATE_SIZES(g);
! 633: }
! 634:
! 635: #ifdef GHASH_TEST
! 636:
! 637: /**********************************************************************
! 638: TEST ROUTINE
! 639: **********************************************************************/
! 640:
! 641: #define MAX_ARGS 32
! 642: #define WS " \t\r\n\v\f"
! 643:
! 644: static ghash_equal_t ghash_test_equal;
! 645: static ghash_hash_t ghash_test_hash;
! 646: static ghash_add_t ghash_test_add;
! 647: static ghash_del_t ghash_test_del;
! 648:
! 649: static int ghash_test_sort(const void *p1, const void *p2);
! 650:
! 651: int
! 652: main(int ac, char **av)
! 653: {
! 654: char buf[1024];
! 655: struct ghash *g;
! 656:
! 657: if ((g = ghash_create(NULL, 3, 0, "ghash", ghash_test_hash,
! 658: ghash_test_equal, ghash_test_add, ghash_test_del)) == NULL)
! 659: err(1, "ghash_create");
! 660:
! 661: while (1) {
! 662: char *args[MAX_ARGS];
! 663: char *tokctx;
! 664: char *s;
! 665:
! 666: /* Prompt */
! 667: printf("Current size is %d items (%d buckets)\n",
! 668: ghash_size(g), g->nbuckets);
! 669: getline:
! 670: printf("> ");
! 671: if (fgets(buf, sizeof(buf), stdin) == NULL)
! 672: break;
! 673:
! 674: /* Parse line */
! 675: for (ac = 0, s = strtok_r(buf, WS, &tokctx);
! 676: ac < MAX_ARGS && s != NULL;
! 677: ac++, s = strtok_r(NULL, WS, &tokctx)) {
! 678: if ((args[ac] = STRDUP(NULL, s)) == NULL)
! 679: err(1, "strdup");
! 680: }
! 681: if (ac == 0)
! 682: goto getline;
! 683:
! 684: /* Do cmd */
! 685: if (strcmp(args[0], "put") == 0) {
! 686: if (ac != 2)
! 687: err(1, "usage: put <token>");
! 688: printf("Putting \"%s\"...\n", args[1]);
! 689: if (ghash_put(g, args[1]) == -1)
! 690: err(1, "ghash_put");
! 691: printf("Done\n");
! 692: } else if (strcmp(args[0], "get") == 0) {
! 693: const char *s;
! 694:
! 695: if (ac != 2)
! 696: err(1, "usage: get <token>");
! 697: if ((s = ghash_get(g, args[1])) == NULL)
! 698: printf("\"%s\" was not found\n", args[1]);
! 699: else
! 700: printf("Found \"%s\"\n", s);
! 701: } else if (strcmp(args[0], "del") == 0) {
! 702: int rtn;
! 703:
! 704: if (ac != 2)
! 705: err(1, "usage: del <token>");
! 706: if ((rtn = ghash_remove(g, args[1])) == -1)
! 707: err(1, "ghash_remove");
! 708: if (rtn)
! 709: printf("Removed \"%s\"\n", args[1]);
! 710: else
! 711: printf("\"%s\" was not found\n", args[1]);
! 712: } else if (strcmp(args[0], "dump") == 0) {
! 713: struct ghash_iter *iter;
! 714:
! 715: if ((iter = ghash_iter_create(g)) == NULL)
! 716: err(1, "ghash_iter_create");
! 717: printf("Iterating contents...\n");
! 718: while (ghash_iter_has_next(iter)) {
! 719: const char *s = ghash_iter_next(iter);
! 720:
! 721: if (s == NULL)
! 722: err(1, "ghash_iter_next");
! 723: printf("\t\"%s\"\n", s);
! 724: }
! 725: ghash_iter_destroy(&iter);
! 726: printf("Done\n");
! 727: } else if (strcmp(args[0], "sort") == 0) {
! 728: void **list;
! 729: int i, num;
! 730:
! 731: if ((num = ghash_dump(g, &list, TYPED_MEM_TEMP)) == -1)
! 732: err(1, "ghash_get_sorted");
! 733: printf("Sorting contents...\n");
! 734: qsort(list, num, sizeof(*list), ghash_test_sort);
! 735: for (i = 0; i < num; i++)
! 736: printf("\t\"%s\"\n", (const char *)list[i]);
! 737: FREE(TYPED_MEM_TEMP, list);
! 738: printf("Done\n");
! 739: } else {
! 740: printf("Commands:\n"
! 741: "\tget <token>\n"
! 742: "\tput <token>\n"
! 743: "\tdel <token>\n"
! 744: "\tdump\n"
! 745: "\tsort\n");
! 746: }
! 747: }
! 748: if (ferror(stdin))
! 749: err(1, "stdin");
! 750: printf("\n");
! 751: ghash_destroy(&g);
! 752: typed_mem_dump(stdout);
! 753: return (0);
! 754: }
! 755:
! 756: static int
! 757: ghash_test_equal(struct ghash *g, const void *item1, const void *item2)
! 758: {
! 759: return (strcmp((const char *)item1, (const char *)item2) == 0);
! 760: }
! 761:
! 762: static int
! 763: ghash_test_sort(const void *p1, const void *p2)
! 764: {
! 765: const char *s1 = *((const char **)p1);
! 766: const char *s2 = *((const char **)p2);
! 767:
! 768: return (strcmp(s1, s2));
! 769: }
! 770:
! 771: static u_int32_t
! 772: ghash_test_hash(struct ghash *g, const void *item)
! 773: {
! 774: const char *s = item;
! 775: u_int32_t hash;
! 776:
! 777: for (hash = 0; *s != '\0'; s++)
! 778: hash = (hash * 31) + (u_char)*s;
! 779: return (hash);
! 780: }
! 781:
! 782: static void
! 783: ghash_test_add(struct ghash *g, void *item)
! 784: {
! 785: printf("-> adding \"%s\"\n", (char *)item);
! 786: }
! 787:
! 788: static void
! 789: ghash_test_del(struct ghash *g, void *item)
! 790: {
! 791: printf("-> deleting \"%s\"\n", (char *)item);
! 792: }
! 793:
! 794: #endif /* GHASH_TEST */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>