HEIMDAL: move code from source4/heimdal* to third_party/heimdal*
[samba.git] / third_party / heimdal / lib / roken / tsearch.c
1 /*
2  * Tree search generalized from Knuth (6.2.2) Algorithm T just like
3  * the AT&T man page says.
4  *
5  * The node_t structure is for internal use only, lint doesn't grok it.
6  *
7  * Written by reading the System V Interface Definition, not the code.
8  *
9  * Totally public domain.
10  *
11  * $NetBSD: tsearch.c,v 1.3 1999/09/16 11:45:37 lukem Exp $
12  * $NetBSD: twalk.c,v 1.1 1999/02/22 10:33:16 christos Exp $
13  * $NetBSD: tdelete.c,v 1.2 1999/09/16 11:45:37 lukem Exp $
14  * $NetBSD: tfind.c,v 1.2 1999/09/16 11:45:37 lukem Exp $
15  */
16
17 #include <config.h>
18 #include "roken.h"
19 #include "search.h"
20 #include <stdlib.h>
21
22 typedef struct node {
23   char         *key;
24   struct node  *llink, *rlink;
25 } node_t;
26
27 /*
28  * find or insert datum into search tree
29  *
30  * Parameters:
31  *      vkey:   key to be located
32  *      vrootp: address of tree root
33  */
34
35 ROKEN_LIB_FUNCTION void *
36 rk_tsearch(const void *vkey, void **vrootp,
37         int (*compar)(const void *, const void *))
38 {
39         node_t *q;
40         node_t **rootp = (node_t **)vrootp;
41
42         if (rootp == NULL)
43                 return NULL;
44
45         while (*rootp != NULL) {        /* Knuth's T1: */
46                 int r;
47
48                 if ((r = (*compar)(vkey, (*rootp)->key)) == 0)  /* T2: */
49                         return *rootp;          /* we found it! */
50
51                 rootp = (r < 0) ?
52                     &(*rootp)->llink :          /* T3: follow left branch */
53                     &(*rootp)->rlink;           /* T4: follow right branch */
54         }
55
56         q = malloc(sizeof(node_t));             /* T5: key not found */
57         if (q != 0) {                           /* make new node */
58                 *rootp = q;                     /* link new node to old */
59                 /* LINTED const castaway ok */
60                 q->key = rk_UNCONST(vkey); /* initialize new node */
61                 q->llink = q->rlink = NULL;
62         }
63         return q;
64 }
65
66 /*
67  * Walk the nodes of a tree
68  *
69  * Parameters:
70  *      root:   Root of the tree to be walked
71  */
72 static void
73 trecurse(const node_t *root, void (*action)(const void *, VISIT, int),
74          int level)
75 {
76
77         if (root->llink == NULL && root->rlink == NULL)
78                 (*action)(root, leaf, level);
79         else {
80                 (*action)(root, preorder, level);
81                 if (root->llink != NULL)
82                         trecurse(root->llink, action, level + 1);
83                 (*action)(root, postorder, level);
84                 if (root->rlink != NULL)
85                         trecurse(root->rlink, action, level + 1);
86                 (*action)(root, endorder, level);
87         }
88 }
89
90 /*
91  * Walk the nodes of a tree
92  *
93  * Parameters:
94  *      vroot:  Root of the tree to be walked
95  */
96 ROKEN_LIB_FUNCTION void
97 rk_twalk(const void *vroot,
98       void (*action)(const void *, VISIT, int))
99 {
100         if (vroot != NULL && action != NULL)
101                 trecurse(vroot, action, 0);
102 }
103
104 /*
105  * delete node with given key
106  *
107  * vkey:   key to be deleted
108  * vrootp: address of the root of the tree
109  * compar: function to carry out node comparisons
110  */
111 ROKEN_LIB_FUNCTION void *
112 rk_tdelete(const void * vkey, void ** vrootp,
113         int (*compar)(const void *, const void *))
114 {
115         node_t **rootp = (node_t **)vrootp;
116         node_t *q, *r;
117         int cmp;
118
119         if (rootp == NULL || *rootp == NULL)
120                 return NULL;
121
122         while ((cmp = (*compar)(vkey, (*rootp)->key)) != 0) {
123                 rootp = (cmp < 0) ?
124                     &(*rootp)->llink :          /* follow llink branch */
125                     &(*rootp)->rlink;           /* follow rlink branch */
126                 if (*rootp == NULL)
127                         return NULL;            /* key not found */
128         }
129         r = (*rootp)->rlink;                    /* D1: */
130         if ((q = (*rootp)->llink) == NULL)      /* Left NULL? */
131                 q = r;
132         else if (r != NULL) {                   /* Right link is NULL? */
133                 if (r->llink == NULL) {         /* D2: Find successor */
134                         r->llink = q;
135                         q = r;
136                 } else {                        /* D3: Find NULL link */
137                         for (q = r->llink; q->llink != NULL; q = r->llink)
138                                 r = q;
139                         r->llink = q->rlink;
140                         q->llink = (*rootp)->llink;
141                         q->rlink = (*rootp)->rlink;
142                 }
143         }
144         free(*rootp);                           /* D4: Free node */
145         *rootp = q;                             /* link parent to new node */
146         return *rootp;
147 }
148
149 /*
150  * find a node, or return 0
151  *
152  * Parameters:
153  *      vkey:   key to be found
154  *      vrootp: address of the tree root
155  */
156 ROKEN_LIB_FUNCTION void *
157 rk_tfind(const void *vkey, void * const *vrootp,
158       int (*compar)(const void *, const void *))
159 {
160         node_t **rootp = (node_t **)vrootp;
161
162         if (rootp == NULL)
163                 return NULL;
164
165         while (*rootp != NULL) {                /* T1: */
166                 int r;
167
168                 if ((r = (*compar)(vkey, (*rootp)->key)) == 0)  /* T2: */
169                         return *rootp;          /* key found */
170                 rootp = (r < 0) ?
171                     &(*rootp)->llink :          /* T3: follow left branch */
172                     &(*rootp)->rlink;           /* T4: follow right branch */
173         }
174         return NULL;
175 }