/*
 * 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 "mhd_options.h"
#include "tsearch.h"
#ifdef HAVE_STDDEF_H
#include <stddef.h>
#endif /* HAVE_STDDEF_H */
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif /* HAVE_STDLIB_H */


typedef struct node
{
  const void   *key;
  struct node  *llink;
  struct node  *rlink;
} node_t;


/*	$NetBSD: tsearch.c,v 1.5 2005/11/29 03:12:00 christos Exp $	*/
/* find or insert datum into search tree */
void *
tsearch (const void *vkey,  /* key to be located */
         void **vrootp,     /* address of tree root */
         int (*compar)(const void *, const void *))
{
  node_t *q;
  node_t **rootp = (node_t **) vrootp;

  if (NULL == rootp)
    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)
  {                            /* make new node */
    *rootp = q;                /* link new node to old */
    q->key = vkey;             /* initialize new node */
    q->llink = q->rlink = NULL;
  }
  return q;
}


/*	$NetBSD: tfind.c,v 1.5 2005/03/23 08:16:53 kleink Exp $	*/
/* find a node, or return NULL */
void *
tfind (const void *vkey,         /* key to be found */
       void *const *vrootp,      /* address of the tree root */
       int (*compar)(const void *, const void *))
{
  node_t *const *rootp = (node_t *const*) vrootp;

  if (NULL == rootp)
    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;
}


/*	$NetBSD: tdelete.c,v 1.2 1999/09/16 11:45:37 lukem Exp $	*/
/*
 * 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
 */
void *
tdelete (const void *__restrict vkey,
         void **__restrict vrootp,
         int (*compar)(const void *, const void *))
{
  node_t **rootp = (node_t **) vrootp;
  node_t *p;
  node_t *q;
  node_t *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;
}


/* end of tsearch.c */
