diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc index dab369f5f47c..2e18e204d0bd 100644 --- a/lib/libc/stdlib/Makefile.inc +++ b/lib/libc/stdlib/Makefile.inc @@ -1,4 +1,4 @@ -# $NetBSD: Makefile.inc,v 1.77 2011/04/13 07:12:52 jruoho Exp $ +# $NetBSD: Makefile.inc,v 1.78 2011/09/14 23:33:51 christos Exp $ # from: @(#)Makefile.inc 8.3 (Berkeley) 2/4/95 # stdlib sources @@ -65,6 +65,7 @@ MLINKS+=div.3 ldiv.3 \ MLINKS+=getenv.3 setenv.3 getenv.3 unsetenv.3 getenv.3 putenv.3 MLINKS+=getenv.3 getenv_r.3 MLINKS+=hcreate.3 hdestroy.3 hcreate.3 hsearch.3 +MLINKS+=hcreate.3 hcreate_r.3 hcreate.3 hdestroy_r.3 hcreate.3 hsearch_r.3 MLINKS+=insque.3 remque.3 MLINKS+=lsearch.3 lfind.3 MLINKS+=malloc.3 calloc.3 malloc.3 realloc.3 malloc.3 free.3 diff --git a/lib/libc/stdlib/hcreate.3 b/lib/libc/stdlib/hcreate.3 index 0bc844fee2e1..752379edbbe6 100644 --- a/lib/libc/stdlib/hcreate.3 +++ b/lib/libc/stdlib/hcreate.3 @@ -1,4 +1,4 @@ -.\" $NetBSD: hcreate.3,v 1.8 2010/05/01 06:18:03 jruoho Exp $ +.\" $NetBSD: hcreate.3,v 1.9 2011/09/14 23:33:51 christos Exp $ .\" .\" Copyright (c) 1999 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -27,13 +27,16 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd May 1, 2010 +.Dd September 14, 2011 .Dt HCREATE 3 .Os .Sh NAME .Nm hcreate , +.Nm hcreate_r , .Nm hdestroy , -.Nm hsearch +.Nm hdestroy_r , +.Nm hsearch , +.Nm hsearch_r .Nd manage hash search table .Sh LIBRARY .Lb libc @@ -41,16 +44,25 @@ .In search.h .Ft int .Fn hcreate "size_t nel" +.Ft int +.Fn hcreate_r "size_t nel" "struct hsearch_data *table" .Ft void .Fn hdestroy "void" +.Ft void +.Fn hdestroy_r "struct hsearch_data *table" .Ft ENTRY * .Fn hsearch "ENTRY item" "ACTION action" +.Ft int +.Fn hsearch_r "ENTRY item" "ACTION action" "ENTRY ** itemp" "struct hsearch_data *table" .Sh DESCRIPTION The .Fn hcreate , -.Fn hdestroy +.Fn hcreate_r , +.Fn hdestroy , +.Fn hdestroy_r and -.Fn hsearch +.Fn hsearch , +.Fn hsearch_r functions manage hash search tables. .Pp The @@ -152,18 +164,46 @@ Typically the comparison .Fa key is allocated by using .Xr strdup 3 . +.Pp +The +.Fn hcreate_r , +.Fn hdestroy_r , +and +.Fn hsearch_r +are re-entrant versions of the above functions that can operate on a table +supplied by the user. +The +.Fn hsearch_r +function returns +.Dv 0 +if the action is +.Dv ENTER +and the element cannot be created, +.Dv 1 +otherwise. +If the element exists or can be created, it will be placed in +.Fa itemp , +otherwise +.Fa itemp +will be set to +.Dv NULL . .Sh RETURN VALUES If successful, the .Fn hcreate -function returns a non-zero value. -Otherwise, a value of 0 is returned and +and +.Fn hcreate_r +function return a non-zero value. +Otherwise, a value of +.Dv 0 +is returned and .Va errno is set to indicate the error. .Pp The .Fn hdestroy -functions -returns no value. +and +.Fn hdestroy_r +functions return no value. .Pp If successful, the .Fn hsearch @@ -182,16 +222,45 @@ If the action is .Dv ENTER and an entry already existed in the table matching the given key, the existing entry is returned and is not replaced. +.Pp +The +.Fn hsearch_r +function returns +.Dv 1 +unless the table is full, when it returns +.Dv 0 . +If the +.Fn hsearch +returns +.Dv 0 +or the element is not found, +.Va errno +is set to indicate the error. .Sh ERRORS The -.Fn hcreate -and +.Fn hcreate , +.Fn hcreate_r , .Fn hsearch +and +.Fn hsearch_r functions will fail if: .Bl -tag -width Er .It Bq Er ENOMEM Insufficient memory is available. .El +.Pp +The +.Fn hsearch +and +.Fn hsearch_r +functions will also fail if the action is +.Dv SEARCH and the element is not found: +.Bl -tag -width Er +.It Bq Er ESRCH +The +.Fa item +given is not found. +.El .Sh SEE ALSO .Xr bsearch 3 , .Xr lsearch 3 , @@ -213,11 +282,21 @@ and .Fn hsearch functions first appeared in .At V . +The +.Fn hcreate_r , +.Fn hdestroy_r +and +.Fn hsearch_r +are +.Tn GNU +extensions. .Sh CAVEATS At least the following limitations can be mentioned: .Bl -bullet .It -The interface permits the use of only one hash table at a time. +The original, non- +.Tn GNU +interface permits the use of only one hash table at a time. .It Individual hash table entries can be added, but not deleted. .It diff --git a/lib/libc/stdlib/hcreate.c b/lib/libc/stdlib/hcreate.c index 8f06fdf5d943..97006f00fccf 100644 --- a/lib/libc/stdlib/hcreate.c +++ b/lib/libc/stdlib/hcreate.c @@ -1,4 +1,4 @@ -/* $NetBSD: hcreate.c,v 1.6 2008/07/21 12:05:43 lukem Exp $ */ +/* $NetBSD: hcreate.c,v 1.7 2011/09/14 23:33:51 christos Exp $ */ /* * Copyright (c) 2001 Christopher G. Demetriou @@ -48,7 +48,7 @@ #include #if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: hcreate.c,v 1.6 2008/07/21 12:05:43 lukem Exp $"); +__RCSID("$NetBSD: hcreate.c,v 1.7 2011/09/14 23:33:51 christos Exp $"); #endif /* LIBC_SCCS and not lint */ #if !defined(lint) @@ -88,21 +88,28 @@ SLIST_HEAD(internal_head, internal_entry); /* Default hash function, from db/hash/hash_func.c */ extern u_int32_t (*__default_hash)(const void *, size_t); -static struct internal_head *htable; -static size_t htablesize; +static struct hsearch_data htable; int hcreate(size_t nel) { - size_t idx; - unsigned int p2; + _DIAGASSERT(htable.table == NULL); /* Make sure this isn't called when a table already exists. */ - _DIAGASSERT(htable == NULL); - if (htable != NULL) { + if (htable.table != NULL) { errno = EINVAL; return 0; } + return hcreate_r(nel, &htable); +} + +int +hcreate_r(size_t nel, struct hsearch_data *head) +{ + struct internal_head *table; + size_t idx; + unsigned int p2; + void *p; /* If nel is too small, make it min sized. */ if (nel < MIN_BUCKETS) @@ -121,76 +128,108 @@ hcreate(size_t nel) } /* Allocate the table. */ - htablesize = nel; - htable = malloc(htablesize * sizeof htable[0]); - if (htable == NULL) { + head->size = nel; + head->filled = 0; + p = malloc(nel * sizeof table[0]); + if (p == NULL) { errno = ENOMEM; return 0; } + head->table = p; + table = p; /* Initialize it. */ - for (idx = 0; idx < htablesize; idx++) - SLIST_INIT(&htable[idx]); + for (idx = 0; idx < nel; idx++) + SLIST_INIT(&table[idx]); return 1; } void hdestroy(void) +{ + _DIAGASSERT(htable.table != NULL); + hdestroy_r(&htable); +} + +void +hdestroy_r(struct hsearch_data *head) { struct internal_entry *ie; size_t idx; + void *p; + struct internal_head *table; - _DIAGASSERT(htable != NULL); - if (htable == NULL) + if (head == NULL) return; - for (idx = 0; idx < htablesize; idx++) { - while (!SLIST_EMPTY(&htable[idx])) { - ie = SLIST_FIRST(&htable[idx]); - SLIST_REMOVE_HEAD(&htable[idx], link); + p = head->table; + head->table = NULL; + table = p; + + for (idx = 0; idx < head->size; idx++) { + while (!SLIST_EMPTY(&table[idx])) { + ie = SLIST_FIRST(&table[idx]); + SLIST_REMOVE_HEAD(&table[idx], link); free(ie->ent.key); free(ie); } } - free(htable); - htable = NULL; + free(table); } ENTRY * hsearch(ENTRY item, ACTION action) { - struct internal_head *head; + ENTRY *ep; + _DIAGASSERT(htable.table != NULL); + (void)hsearch_r(item, action, &ep, &htable); + return ep; +} + +int +hsearch_r(ENTRY item, ACTION action, ENTRY **itemp, struct hsearch_data *head) +{ + struct internal_head *table, *chain; struct internal_entry *ie; uint32_t hashval; size_t len; + void *p; - _DIAGASSERT(htable != NULL); _DIAGASSERT(item.key != NULL); _DIAGASSERT(action == ENTER || action == FIND); + p = head->table; + table = p; + len = strlen(item.key); hashval = (*__default_hash)(item.key, len); - head = &htable[hashval & (htablesize - 1)]; - ie = SLIST_FIRST(head); + chain = &table[hashval & (head->size - 1)]; + ie = SLIST_FIRST(chain); while (ie != NULL) { if (strcmp(ie->ent.key, item.key) == 0) break; ie = SLIST_NEXT(ie, link); } - if (ie != NULL) - return &ie->ent; - else if (action == FIND) - return NULL; + if (ie != NULL) { + *itemp = &ie->ent; + return 1; + } else if (action == FIND) { + *itemp = NULL; + errno = ESRCH; + return 1; + } ie = malloc(sizeof *ie); if (ie == NULL) - return NULL; + return 0; ie->ent.key = item.key; ie->ent.data = item.data; - SLIST_INSERT_HEAD(head, ie, link); - return &ie->ent; + SLIST_INSERT_HEAD(chain, ie, link); + *itemp = &ie->ent; + head->filled++; + return 1; }