Add tsearch and friends, and a test program
tsearch is missing from windows. use the netbsd version as it's license-compatible.
This commit is contained in:

committed by
Simon Wilkinson

parent
3d36172090
commit
2a32bf67f0
@@ -65,6 +65,7 @@ AC_CHECK_HEADERS([\
|
||||
poll.h \
|
||||
pwd.h \
|
||||
rpcsvc/ypclnt.h \
|
||||
search.h \
|
||||
shadow.h \
|
||||
stdint.h \
|
||||
sys/bswap.h \
|
||||
@@ -149,6 +150,7 @@ AC_REQUIRE([CHECK_NETINET_IP_AND_TCP])
|
||||
|
||||
AM_CONDITIONAL(have_err_h, test "$ac_cv_header_err_h" = yes)
|
||||
AM_CONDITIONAL(have_ifaddrs_h, test "$ac_cv_header_ifaddrs_h" = yes)
|
||||
AM_CONDITIONAL(have_search_h, test "$ac_cv_header_search_h" = yes)
|
||||
AM_CONDITIONAL(have_vis_h, test "$ac_cv_header_vis_h" = yes)
|
||||
|
||||
dnl Check for functions and libraries
|
||||
@@ -197,6 +199,10 @@ AC_CHECK_FUNCS([ \
|
||||
svis \
|
||||
sysconf \
|
||||
sysctl \
|
||||
tdelete \
|
||||
tfind \
|
||||
tsearch \
|
||||
twalk \
|
||||
uname \
|
||||
unvis \
|
||||
vasnprintf \
|
||||
|
@@ -32,7 +32,8 @@ check_PROGRAMS = \
|
||||
parse_reply-test \
|
||||
parse_time-test \
|
||||
snprintf-test \
|
||||
strpftime-test
|
||||
strpftime-test \
|
||||
tsearch-test
|
||||
|
||||
TESTS = $(check_PROGRAMS)
|
||||
|
||||
@@ -58,6 +59,9 @@ strpftime_test_CFLAGS = -DTEST_STRPFTIME
|
||||
snprintf_test_SOURCES = snprintf-test.c
|
||||
snprintf_test_LDADD = libtest.la $(LDADD)
|
||||
snprintf_test_CFLAGS = -DTEST_SNPRINTF
|
||||
tsearch_test_SOURCES = tsearch-test.c
|
||||
tsearch_test_LDADD = libtest.la $(LDADD)
|
||||
tsearch_test_CFLAGS = -DTEST_TSEARCH
|
||||
|
||||
resolve_test_SOURCES = resolve-test.c
|
||||
|
||||
@@ -107,6 +111,7 @@ libroken_la_SOURCES = \
|
||||
strerror_r.c \
|
||||
strpool.c \
|
||||
timeval.c \
|
||||
tsearch.c \
|
||||
tm2time.c \
|
||||
unvis.c \
|
||||
verify.c \
|
||||
@@ -121,6 +126,7 @@ EXTRA_libroken_la_SOURCES = \
|
||||
glob.hin \
|
||||
fnmatch.hin \
|
||||
ifaddrs.hin \
|
||||
search.hin \
|
||||
vis.hin
|
||||
|
||||
libroken_la_LIBADD = @LTLIBOBJS@ $(LIB_crypt)
|
||||
@@ -153,6 +159,12 @@ else
|
||||
ifaddrs_h = ifaddrs.h
|
||||
endif
|
||||
|
||||
if have_search_h
|
||||
search_h =
|
||||
else
|
||||
search_h = search.h
|
||||
endif
|
||||
|
||||
if have_vis_h
|
||||
vis_h =
|
||||
else
|
||||
@@ -160,8 +172,8 @@ vis_h = vis.h
|
||||
endif
|
||||
|
||||
## these are controlled by configure
|
||||
XHEADERS = $(err_h) $(fnmatch_h) $(glob_h) $(ifaddrs_h) $(vis_h)
|
||||
CLEANFILES += err.h fnmatch.h glob.h ifaddrs.h vis.h
|
||||
XHEADERS = $(err_h) $(fnmatch_h) $(glob_h) $(ifaddrs_h) $(search_h) $(vis_h)
|
||||
CLEANFILES += err.h fnmatch.h glob.h ifaddrs.h search.h vis.h
|
||||
|
||||
dist_include_HEADERS = \
|
||||
base64.h \
|
||||
@@ -186,7 +198,7 @@ nodist_include_HEADERS = roken.h
|
||||
rokenincludedir = $(includedir)/roken
|
||||
nodist_rokeninclude_HEADERS = $(XHEADERS)
|
||||
|
||||
man_MANS = getarg.3 parse_time.3 rtbl.3 ecalloc.3
|
||||
man_MANS = getarg.3 parse_time.3 rtbl.3 ecalloc.3 tsearch.3
|
||||
|
||||
SUFFIXES += .hin
|
||||
.hin.h:
|
||||
|
@@ -103,6 +103,7 @@ libroken_la_OBJS = \
|
||||
$(OBJ)\timegm.obj \
|
||||
$(OBJ)\timeval.obj \
|
||||
$(OBJ)\tm2time.obj \
|
||||
$(OBJ)\tsearch.obj \
|
||||
$(OBJ)\unvis.obj \
|
||||
$(OBJ)\verr.obj \
|
||||
$(OBJ)\verrx.obj \
|
||||
@@ -155,6 +156,7 @@ INCFILES = \
|
||||
$(INCDIR)\roken.h \
|
||||
$(INCDIR)\roken-common.h \
|
||||
$(INCDIR)\rtbl.h \
|
||||
$(INCDIR)\search.h \
|
||||
$(INCDIR)\stdbool.h \
|
||||
$(INCDIR)\syslog.h \
|
||||
$(INCDIR)\vis.h \
|
||||
|
@@ -1099,6 +1099,18 @@ rk_qsort(void *, size_t, size_t, int (*)(const void *, const void *));
|
||||
#define rk_random() rand()
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_TDELETE
|
||||
#define tdelete(a,b,c) rk_tdelete(a,b,c)
|
||||
#endif
|
||||
#ifndef HAVE_TFIND
|
||||
#define tfind(a,b,c) rk_tfind(a,b,c)
|
||||
#endif
|
||||
#ifndef HAVE_TSEARCH
|
||||
#define tsearch(a,b,c) rk_tsearch(a,b,c)
|
||||
#endif
|
||||
#ifndef HAVE_TWALK
|
||||
#define twalk(a,b) rk_twalk(a,b)
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) && defined(SOCK_CLOEXEC) && !defined(SOCKET_WRAPPER_REPLACE) && !defined(__SOCKET_WRAPPER_H__)
|
||||
#undef socket
|
||||
|
42
lib/roken/search.hin
Normal file
42
lib/roken/search.hin
Normal file
@@ -0,0 +1,42 @@
|
||||
/*-
|
||||
* Written by J.T. Conklin <jtc@netbsd.org>
|
||||
* Public domain.
|
||||
*
|
||||
* $NetBSD: search.h,v 1.12 1999/02/22 10:34:28 christos Exp $
|
||||
*/
|
||||
|
||||
#ifndef _rk_SEARCH_H_
|
||||
#define _rk_SEARCH_H_ 1
|
||||
|
||||
#ifndef ROKEN_LIB_FUNCTION
|
||||
#ifdef _WIN32
|
||||
#define ROKEN_LIB_FUNCTION
|
||||
#define ROKEN_LIB_CALL __cdecl
|
||||
#else
|
||||
#define ROKEN_LIB_FUNCTION
|
||||
#define ROKEN_LIB_CALL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef enum {
|
||||
preorder,
|
||||
postorder,
|
||||
endorder,
|
||||
leaf
|
||||
} VISIT;
|
||||
|
||||
ROKEN_CPP_START
|
||||
|
||||
ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL rk_tdelete(const void * __restrict, void ** __restrict,
|
||||
int (*)(const void *, const void *));
|
||||
ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL rk_tfind(const void *, void * const *,
|
||||
int (*)(const void *, const void *));
|
||||
ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL rk_tsearch(const void *, void **, int (*)(const void *, const void *));
|
||||
ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL rk_twalk(const void *, void (*)(const void *, VISIT, int));
|
||||
|
||||
ROKEN_CPP_END
|
||||
|
||||
#endif /* !_rk_SEARCH_H_ */
|
125
lib/roken/tsearch-test.c
Normal file
125
lib/roken/tsearch-test.c
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Tree search generalized from Knuth (6.2.2) Algorithm T just like
|
||||
* the AT&T man page says.
|
||||
*
|
||||
* The node_t structure is for internal use only, lint doesn't grok it.
|
||||
*
|
||||
* Written by reading the System V Interface Definition, not the code.
|
||||
*
|
||||
* Totally public domain.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "roken.h"
|
||||
#include "search.h"
|
||||
|
||||
struct node {
|
||||
char *string;
|
||||
int order;
|
||||
};
|
||||
|
||||
extern void *rk_tdelete(const void * __restrict, void ** __restrict,
|
||||
int (*)(const void *, const void *));
|
||||
extern void *rk_tfind(const void *, void * const *,
|
||||
int (*)(const void *, const void *));
|
||||
extern void *rk_tsearch(const void *, void **, int (*)(const void *, const void *));
|
||||
extern void rk_twalk(const void *, void (*)(const void *, VISIT, int));
|
||||
|
||||
void *rootnode = NULL;
|
||||
int numerr = 0;
|
||||
|
||||
/*
|
||||
* This routine compares two nodes, based on an
|
||||
* alphabetical ordering of the string field.
|
||||
*/
|
||||
int
|
||||
node_compare(const void *node1, const void *node2)
|
||||
{
|
||||
return strcmp(((const struct node *) node1)->string,
|
||||
((const struct node *) node2)->string);
|
||||
}
|
||||
|
||||
static int walkorder = -1;
|
||||
|
||||
void
|
||||
list_node(const void *ptr, VISIT order, int level)
|
||||
{
|
||||
const struct node *p = *(const struct node **) ptr;
|
||||
|
||||
if (order == postorder || order == leaf) {
|
||||
walkorder++;
|
||||
if (p->order != walkorder) {
|
||||
warnx("sort failed: expected %d next, got %d\n", walkorder,
|
||||
p->order);
|
||||
numerr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int numtest = 1;
|
||||
struct node *t, *p, tests[] = {
|
||||
{ "", 0 },
|
||||
{ "ab", 3 },
|
||||
{ "abc", 4 },
|
||||
{ "abcdefg", 8 },
|
||||
{ "abcd", 5 },
|
||||
{ "a", 2 },
|
||||
{ "abcdef", 7 },
|
||||
{ "abcde", 6 },
|
||||
{ "=", 1 },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
for(t = tests; t->string; t++) {
|
||||
/* Better not be there */
|
||||
p = (struct node *)rk_tfind((void *)t, (void **)&rootnode,
|
||||
node_compare);
|
||||
|
||||
if (p) {
|
||||
warnx("erroneous list: found %d\n", p->order);
|
||||
numerr++;
|
||||
}
|
||||
|
||||
/* Put node into the tree. */
|
||||
p = (struct node *) rk_tsearch((void *)t, (void **)&rootnode,
|
||||
node_compare);
|
||||
|
||||
if (!p) {
|
||||
warnx("erroneous list: missing %d\n", t->order);
|
||||
numerr++;
|
||||
}
|
||||
}
|
||||
|
||||
rk_twalk(rootnode, list_node);
|
||||
|
||||
for(t = tests; t->string; t++) {
|
||||
/* Better be there */
|
||||
p = (struct node *) rk_tfind((void *)t, (void **)&rootnode,
|
||||
node_compare);
|
||||
|
||||
if (!p) {
|
||||
warnx("erroneous list: missing %d\n", t->order);
|
||||
numerr++;
|
||||
}
|
||||
|
||||
/* pull out node */
|
||||
(void) rk_tdelete((void *)t, (void **)&rootnode,
|
||||
node_compare);
|
||||
|
||||
/* Better not be there */
|
||||
p = (struct node *) rk_tfind((void *)t, (void **)&rootnode,
|
||||
node_compare);
|
||||
|
||||
if (p) {
|
||||
warnx("erroneous list: found %d\n", p->order);
|
||||
numerr++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return numerr;
|
||||
}
|
138
lib/roken/tsearch.3
Normal file
138
lib/roken/tsearch.3
Normal file
@@ -0,0 +1,138 @@
|
||||
.\" $NetBSD$
|
||||
.\" Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. The name of the author may not be used to endorse or promote products
|
||||
.\" derived from this software without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
.\" AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
.\" THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
.\" EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
.\" PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
.\" OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" OpenBSD: tsearch.3,v 1.2 1998/06/21 22:13:49 millert Exp
|
||||
.\" $FreeBSD: src/lib/libc/stdlib/tsearch.3,v 1.15 2006/06/23 13:36:33 keramida Exp $
|
||||
.\" $DragonFly: src/lib/libc/stdlib/tsearch.c,v 1.6 2005/11/24 17:18:30 swildner Exp $
|
||||
.\"
|
||||
.Dd June 15, 1997
|
||||
.Dt TSEARCH 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm tsearch ,
|
||||
.Nm tfind ,
|
||||
.Nm tdelete ,
|
||||
.Nm twalk
|
||||
.Nd manipulate binary search trees
|
||||
.Sh LIBRARY
|
||||
.Lb libc
|
||||
.Sh SYNOPSIS
|
||||
.In search.h
|
||||
.Ft void *
|
||||
.Fn tdelete "const void * restrict key" "void ** restrict rootp" "int (*compar) (const void *, const void *)"
|
||||
.Ft void *
|
||||
.Fn tfind "const void *key" "void * const *rootp" "int (*compar) (const void *, const void *)"
|
||||
.Ft void *
|
||||
.Fn tsearch "const void *key" "void **rootp" "int (*compar) (const void *, const void *)"
|
||||
.Ft void
|
||||
.Fn twalk "const void *root" "void (*action) (const void *, VISIT, int)"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Fn tdelete ,
|
||||
.Fn tfind ,
|
||||
.Fn tsearch ,
|
||||
and
|
||||
.Fn twalk
|
||||
functions manage binary search trees based on algorithms T and D
|
||||
from Knuth (6.2.2).
|
||||
The comparison function passed in by
|
||||
the user has the same style of return values as
|
||||
.Xr strcmp 3 .
|
||||
.Pp
|
||||
The
|
||||
.Fn tfind
|
||||
function
|
||||
searches for the datum matched by the argument
|
||||
.Fa key
|
||||
in the binary tree rooted at
|
||||
.Fa rootp ,
|
||||
returning a pointer to the datum if it is found and NULL
|
||||
if it is not.
|
||||
.Pp
|
||||
The
|
||||
.Fn tsearch
|
||||
function
|
||||
is identical to
|
||||
.Fn tfind
|
||||
except that if no match is found,
|
||||
.Fa key
|
||||
is inserted into the tree and a pointer to it is returned.
|
||||
If
|
||||
.Fa rootp
|
||||
points to a NULL value a new binary search tree is created.
|
||||
.Pp
|
||||
The
|
||||
.Fn tdelete
|
||||
function
|
||||
deletes a node from the specified binary search tree and returns
|
||||
a pointer to the parent of the node to be deleted.
|
||||
It takes the same arguments as
|
||||
.Fn tfind
|
||||
and
|
||||
.Fn tsearch .
|
||||
If the node to be deleted is the root of the binary search tree,
|
||||
.Fa rootp
|
||||
will be adjusted.
|
||||
.Pp
|
||||
The
|
||||
.Fn twalk
|
||||
function
|
||||
walks the binary search tree rooted in
|
||||
.Fa root
|
||||
and calls the function
|
||||
.Fa action
|
||||
on each node.
|
||||
The
|
||||
.Fa action
|
||||
function
|
||||
is called with three arguments: a pointer to the current node,
|
||||
a value from the enum
|
||||
.Sy "typedef enum { preorder, postorder, endorder, leaf } VISIT;"
|
||||
specifying the traversal type, and a node level (where level
|
||||
zero is the root of the tree).
|
||||
.Sh RETURN VALUES
|
||||
The
|
||||
.Fn tsearch
|
||||
function returns NULL if allocation of a new node fails (usually
|
||||
due to a lack of free memory).
|
||||
.Pp
|
||||
The
|
||||
.Fn tfind ,
|
||||
.Fn tsearch ,
|
||||
and
|
||||
.Fn tdelete
|
||||
functions
|
||||
return NULL if
|
||||
.Fa rootp
|
||||
is NULL or the datum cannot be found.
|
||||
.Pp
|
||||
The
|
||||
.Fn twalk
|
||||
function returns no value.
|
||||
.Sh SEE ALSO
|
||||
.Xr bsearch 3 ,
|
||||
.Xr hsearch 3 ,
|
||||
.Xr lsearch 3
|
180
lib/roken/tsearch.c
Normal file
180
lib/roken/tsearch.c
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Tree search generalized from Knuth (6.2.2) Algorithm T just like
|
||||
* the AT&T man page says.
|
||||
*
|
||||
* The node_t structure is for internal use only, lint doesn't grok it.
|
||||
*
|
||||
* Written by reading the System V Interface Definition, not the code.
|
||||
*
|
||||
* Totally public domain.
|
||||
*
|
||||
* $NetBSD: tsearch.c,v 1.3 1999/09/16 11:45:37 lukem Exp $
|
||||
* $NetBSD: twalk.c,v 1.1 1999/02/22 10:33:16 christos Exp $
|
||||
* $NetBSD: tdelete.c,v 1.2 1999/09/16 11:45:37 lukem Exp $
|
||||
* $NetBSD: tfind.c,v 1.2 1999/09/16 11:45:37 lukem Exp $
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include "roken.h"
|
||||
#include "search.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct node {
|
||||
char *key;
|
||||
struct node *llink, *rlink;
|
||||
} node_t;
|
||||
|
||||
#ifndef __DECONST
|
||||
#define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* find or insert datum into search tree
|
||||
*
|
||||
* Parameters:
|
||||
* vkey: key to be located
|
||||
* vrootp: address of tree root
|
||||
*/
|
||||
|
||||
ROKEN_LIB_FUNCTION void *
|
||||
rk_tsearch(const void *vkey, void **vrootp,
|
||||
int (*compar)(const void *, const void *))
|
||||
{
|
||||
node_t *q;
|
||||
node_t **rootp = (node_t **)vrootp;
|
||||
|
||||
if (rootp == NULL)
|
||||
return NULL;
|
||||
|
||||
while (*rootp != NULL) { /* Knuth's T1: */
|
||||
int r;
|
||||
|
||||
if ((r = (*compar)(vkey, (*rootp)->key)) == 0) /* T2: */
|
||||
return *rootp; /* we found it! */
|
||||
|
||||
rootp = (r < 0) ?
|
||||
&(*rootp)->llink : /* T3: follow left branch */
|
||||
&(*rootp)->rlink; /* T4: follow right branch */
|
||||
}
|
||||
|
||||
q = malloc(sizeof(node_t)); /* T5: key not found */
|
||||
if (q != 0) { /* make new node */
|
||||
*rootp = q; /* link new node to old */
|
||||
/* LINTED const castaway ok */
|
||||
q->key = __DECONST(void *, vkey); /* initialize new node */
|
||||
q->llink = q->rlink = NULL;
|
||||
}
|
||||
return q;
|
||||
}
|
||||
|
||||
/*
|
||||
* Walk the nodes of a tree
|
||||
*
|
||||
* Parameters:
|
||||
* root: Root of the tree to be walked
|
||||
*/
|
||||
static void
|
||||
trecurse(const node_t *root, void (*action)(const void *, VISIT, int),
|
||||
int level)
|
||||
{
|
||||
|
||||
if (root->llink == NULL && root->rlink == NULL)
|
||||
(*action)(root, leaf, level);
|
||||
else {
|
||||
(*action)(root, preorder, level);
|
||||
if (root->llink != NULL)
|
||||
trecurse(root->llink, action, level + 1);
|
||||
(*action)(root, postorder, level);
|
||||
if (root->rlink != NULL)
|
||||
trecurse(root->rlink, action, level + 1);
|
||||
(*action)(root, endorder, level);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Walk the nodes of a tree
|
||||
*
|
||||
* Parameters:
|
||||
* vroot: Root of the tree to be walked
|
||||
*/
|
||||
ROKEN_LIB_FUNCTION void
|
||||
rk_twalk(const void *vroot,
|
||||
void (*action)(const void *, VISIT, int))
|
||||
{
|
||||
if (vroot != NULL && action != NULL)
|
||||
trecurse(vroot, action, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* delete node with given key
|
||||
*
|
||||
* vkey: key to be deleted
|
||||
* vrootp: address of the root of the tree
|
||||
* compar: function to carry out node comparisons
|
||||
*/
|
||||
ROKEN_LIB_FUNCTION void *
|
||||
rk_tdelete(const void * __restrict vkey, void ** __restrict vrootp,
|
||||
int (*compar)(const void *, const void *))
|
||||
{
|
||||
node_t **rootp = (node_t **)vrootp;
|
||||
node_t *p, *q, *r;
|
||||
int cmp;
|
||||
|
||||
if (rootp == NULL || (p = *rootp) == NULL)
|
||||
return NULL;
|
||||
|
||||
while ((cmp = (*compar)(vkey, (*rootp)->key)) != 0) {
|
||||
p = *rootp;
|
||||
rootp = (cmp < 0) ?
|
||||
&(*rootp)->llink : /* follow llink branch */
|
||||
&(*rootp)->rlink; /* follow rlink branch */
|
||||
if (*rootp == NULL)
|
||||
return NULL; /* key not found */
|
||||
}
|
||||
r = (*rootp)->rlink; /* D1: */
|
||||
if ((q = (*rootp)->llink) == NULL) /* Left NULL? */
|
||||
q = r;
|
||||
else if (r != NULL) { /* Right link is NULL? */
|
||||
if (r->llink == NULL) { /* D2: Find successor */
|
||||
r->llink = q;
|
||||
q = r;
|
||||
} else { /* D3: Find NULL link */
|
||||
for (q = r->llink; q->llink != NULL; q = r->llink)
|
||||
r = q;
|
||||
r->llink = q->rlink;
|
||||
q->llink = (*rootp)->llink;
|
||||
q->rlink = (*rootp)->rlink;
|
||||
}
|
||||
}
|
||||
free(*rootp); /* D4: Free node */
|
||||
*rootp = q; /* link parent to new node */
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* find a node, or return 0
|
||||
*
|
||||
* Parameters:
|
||||
* vkey: key to be found
|
||||
* vrootp: address of the tree root
|
||||
*/
|
||||
ROKEN_LIB_FUNCTION void *
|
||||
rk_tfind(const void *vkey, void * const *vrootp,
|
||||
int (*compar)(const void *, const void *))
|
||||
{
|
||||
node_t **rootp = (node_t **)vrootp;
|
||||
|
||||
if (rootp == NULL)
|
||||
return NULL;
|
||||
|
||||
while (*rootp != NULL) { /* T1: */
|
||||
int r;
|
||||
|
||||
if ((r = (*compar)(vkey, (*rootp)->key)) == 0) /* T2: */
|
||||
return *rootp; /* key found */
|
||||
rootp = (r < 0) ?
|
||||
&(*rootp)->llink : /* T3: follow left branch */
|
||||
&(*rootp)->rlink; /* T4: follow right branch */
|
||||
}
|
||||
return NULL;
|
||||
}
|
@@ -139,6 +139,10 @@ HEIMDAL_ROKEN_1.0 {
|
||||
rk_timevaladd;
|
||||
rk_timevalfix;
|
||||
rk_timevalsub;
|
||||
rk_tdelete;
|
||||
rx_tfind;
|
||||
rk_tsearch;
|
||||
rk_twalk;
|
||||
rk_undumpdata;
|
||||
rk_unvis;
|
||||
rk_vasnprintf;
|
||||
|
Reference in New Issue
Block a user