.github
.zed
admin
appl
cf
doc
etc
include
kadmin
kcm
kdc
kpasswd
kuser
lib
asn1
base
com_err
gss_preauth
gssapi
hcrypto
hdb
heimdal
hx509
ipc
kadm5
kafs
kdfs
krb5
libedit
ntlm
otp
roken
ChangeLog
Makefile.am
NTMakefile
base32-test.c
base32.c
base32.h
base64-test.c
base64.c
base64.h
bswap.c
chown.c
cloexec.c
closefrom.c
clz.c
concat.c
copyhostent.c
ct.c
daemon.c
detach.c
dirent-test.c
dirent.c
dirent.hin
dlfcn.hin
dlfcn_w32.c
doxygen.c
dumpdata.c
ecalloc.3
ecalloc.c
emalloc.c
environment.c
eread.c
erealloc.c
err.c
err.hin
errx.c
esetenv.c
estrdup.c
ewrite.c
fchown.c
flock.c
fnmatch.c
fnmatch.hin
freeaddrinfo.c
freehostent.c
fseeko.c
ftello.c
gai_strerror.c
get_window_size.c
getaddrinfo-test.c
getaddrinfo.c
getaddrinfo_hostspec.c
getarg.3
getarg.c
getarg.h
getauxval.c
getauxval.h
getcwd.c
getdtablesize.c
getegid.c
geteuid.c
getgid.c
gethostname.c
getifaddrs-test.c
getifaddrs.c
getifaddrs_w32.c
getipnodebyaddr.c
getipnodebyname.c
getnameinfo.c
getnameinfo_verified.c
getopt.c
getprogname.c
gettimeofday.c
getuid.c
getuserinfo.c
getusershell.c
h_errno.c
hex-test.c
hex.c
hex.h
hostent_find_fqdn.c
hstrerror.c
ifaddrs.hin
inet_aton.c
inet_ntop.c
inet_pton.c
initgroups.c
innetgr.c
install-sh
issuid.c
localtime_r.c
lstat.c
memmem.c
memmove.c
memset_s.c
mergesort.c
mergesort_r.c
mini_inetd.c
missing
mkdir.c
mkdtemp.c
mkinstalldirs
mkostemp.c
mkstemp.c
ndbm_wrap.c
ndbm_wrap.h
net_read.c
net_write.c
parse_bytes-test.c
parse_bytes.c
parse_bytes.h
parse_reply-test.c
parse_time-test.c
parse_time.3
parse_time.c
parse_time.h
parse_units.c
parse_units.h
putenv.c
qsort.c
rand.c
rcmd.c
readv.c
realloc.c
recvmsg.c
rename.c
resolve-test.c
resolve.c
resolve.h
rkpty.c
roken-common.h
roken.awk
roken.h.in
roken_gethostby.c
rtbl.3
rtbl.c
rtbl.h
search.hin
secure_getenv.c
secure_getenv.h
sendmsg.c
setegid.c
setenv.c
seteuid.c
setprogname.c
signal.c
simple_exec.c
simple_exec_w32.c
sleep.c
snprintf-test.c
snprintf.c
socket.c
socket_wrapper.c
socket_wrapper.h
sockstartup_w32.c
stdbool.hin
stdint.hin
strcasecmp.c
strcollect.c
strdup.c
strerror.c
strerror_r.c
strftime.c
strlcat.c
strlcpy.c
strlwr.c
strncasecmp.c
strndup.c
strnlen.c
strpftime-test.c
strpftime-test.h
strpool.c
strptime.c
strsep.c
strsep_copy.c
strtok_r.c
strtoll.c
strtoull.c
strupr.c
swab.c
syslog.hin
syslogc.c
test-auxval.c
test-detach.c
test-getuserinfo.c
test-mem.c
test-mem.h
test-mini_inetd.c
test-readenv.c
timegm.c
timeval.c
tm2time.c
tsearch-test.c
tsearch.c
unsetenv.c
unvis.c
verr.c
verrx.c
version-script.map
versionsupport.h
vis-extras.h
vis.c
vis.hin
vsyslog.c
vwarn.c
vwarnx.c
warn.c
warnerr.c
warnx.c
win32_alloc.c
win32_version.c
write_pid.c
writev.c
xdbm.h
xfree.c
sl
sqlite
vers
wind
Makefile.am
NTMakefile
nix
packages
po
tests
tools
windows
.gitignore
.travis.yml
CODE_OF_CONDUCT.md
ChangeLog
ChangeLog.1998
ChangeLog.1999
ChangeLog.2000
ChangeLog.2001
ChangeLog.2002
ChangeLog.2003
ChangeLog.2004
ChangeLog.2005
ChangeLog.2006
ChangeLog.2007
LICENSE
Makefile.am
Makefile.am.common
NEWS
NTMakefile
README
README.fast
README.md
SECURITY.md
TODO
acinclude.m4
appveyor.yml
autogen.sh
configure.ac
flake.lock
flake.nix
krb5.conf

The rk_UNCONST macro exists because neither __DECONST nor uintptr_t are available on all platforms (for example, AIX). Change-Id: Ie36f0dd7a9ce454d411761ee4dbd6fc1f7c6692c
176 lines
4.0 KiB
C
176 lines
4.0 KiB
C
/*
|
|
* 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;
|
|
|
|
/*
|
|
* 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 = rk_UNCONST(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 * vkey, void ** vrootp,
|
|
int (*compar)(const void *, const void *))
|
|
{
|
|
node_t **rootp = (node_t **)vrootp;
|
|
node_t *q, *r;
|
|
int cmp;
|
|
|
|
if (rootp == NULL || *rootp == NULL)
|
|
return NULL;
|
|
|
|
while ((cmp = (*compar)(vkey, (*rootp)->key)) != 0) {
|
|
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 *rootp;
|
|
}
|
|
|
|
/*
|
|
* 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;
|
|
}
|