Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*----------------------------------------------------------------------------*
Toshihiro Shimizu 890ddd
 |                                                                            |
Toshihiro Shimizu 890ddd
 |                                   avl.c                                    |
Toshihiro Shimizu 890ddd
 |                                                                            |
Toshihiro Shimizu 890ddd
 |                by W.T.  11-MAR-91, last revision 11-OCT-96                 |
Toshihiro Shimizu 890ddd
 |                                                                            |
Toshihiro Shimizu 890ddd
 *----------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 9f5a1b
#ifdef _WIN32
Toshihiro Shimizu 890ddd
#pragma warning(push)
Toshihiro Shimizu 890ddd
#pragma warning(disable : 4113)
Toshihiro Shimizu 890ddd
#pragma warning(disable : 4996)
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <stdio.h></stdio.h>
Toshihiro Shimizu 890ddd
#include <stdlib.h></stdlib.h>
Toshihiro Shimizu 890ddd
#include <string.h></string.h>
Toshihiro Shimizu 890ddd
#define AVL_C
Toshihiro Shimizu 890ddd
#include "avl.h"
Toshihiro Shimizu 890ddd
#include "tcm.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifndef TRUE
Toshihiro Shimizu 890ddd
#define TRUE 1
Toshihiro Shimizu 890ddd
#define FALSE 0
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//#define NIL ((void *)0)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
typedef unsigned long ulong;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifndef MACOSX
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
typedef unsigned int uint;
Toshihiro Shimizu 890ddd
typedef unsigned short ushort;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
typedef struct avl_node NODE;
Toshihiro Shimizu 890ddd
typedef struct avl_path PATH;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define MBR_KEY (AVL_NODUP_MBR >> 1)
Toshihiro Shimizu 890ddd
#define PTR_KEY (AVL_NODUP_PTR >> 1)
Toshihiro Shimizu 890ddd
#define STR_KEY (AVL_NODUP_STR >> 1)
Toshihiro Shimizu 890ddd
#define LNG_KEY (AVL_NODUP_LNG >> 1)
Toshihiro Shimizu 890ddd
#define INT_KEY (AVL_NODUP_INT >> 1)
Toshihiro Shimizu 890ddd
#define SHT_KEY (AVL_NODUP_SHT >> 1)
Toshihiro Shimizu 890ddd
#define ULN_KEY (AVL_NODUP_ULN >> 1)
Toshihiro Shimizu 890ddd
#define UIN_KEY (AVL_NODUP_UIN >> 1)
Toshihiro Shimizu 890ddd
#define USH_KEY (AVL_NODUP_USH >> 1)
Toshihiro Shimizu 890ddd
#define CHR_KEY (AVL_NODUP_CHR >> 1)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define USR_CMP 0
Toshihiro Shimizu 890ddd
#define STR_CMP 1
Toshihiro Shimizu 890ddd
#define VAL_CMP 2
Toshihiro Shimizu 890ddd
#define COR_CMP 3
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define NODUP 0
Toshihiro Shimizu 890ddd
#define DUP 1
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define USR_NODUP (USR_CMP | NODUP << 2)
Toshihiro Shimizu 890ddd
#define STR_NODUP (STR_CMP | NODUP << 2)
Toshihiro Shimizu 890ddd
#define VAL_NODUP (VAL_CMP | NODUP << 2)
Toshihiro Shimizu 890ddd
#define COR_NODUP (COR_CMP | NODUP << 2)
Toshihiro Shimizu 890ddd
#define USR_DUP (USR_CMP | DUP << 2)
Toshihiro Shimizu 890ddd
#define STR_DUP (STR_CMP | DUP << 2)
Toshihiro Shimizu 890ddd
#define VAL_DUP (VAL_CMP | DUP << 2)
Toshihiro Shimizu 890ddd
#define COR_DUP (COR_CMP | DUP << 2)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/* keyinfo: bits 6-3: KEYTYPE, bit 2: DUP, bits 1-0: CMPTYPE */
Toshihiro Shimizu 890ddd
/*                bits 6-2: TREETYPE, bits 2-0: LOCTYPE      */
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define KEYTYPE(keyinfo) ((keyinfo) >> 3)
Toshihiro Shimizu 890ddd
#define TREETYPE(keyinfo) ((keyinfo) >> 2)
Toshihiro Shimizu 890ddd
#define CMPTYPE(keyinfo) ((keyinfo)&0x3)
Toshihiro Shimizu 890ddd
#define LOCTYPE(keyinfo) ((keyinfo)&0x7)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define MAXUSHORT (((unsigned short)(~0)) >> 1)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define MINLONG ((long)~(((unsigned long)(~0L)) >> 1))
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define CORRECT(u) ((long)(u) + MINLONG)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef VAX
Shinya Kitaoka 120a6e
#define SET_STRCMP(cmp, str1, str2)                                            \
Shinya Kitaoka 120a6e
  {                                                                            \
Shinya Kitaoka 120a6e
    char *p1, *p2;                                                             \
Shinya Kitaoka 120a6e
    for (p1 = (str1), p2 = (str2); *p1 && *p1 == *p2; p1++, p2++)              \
Shinya Kitaoka 120a6e
      ;                                                                        \
Shinya Kitaoka 120a6e
    (cmp) = *(unsigned char *)p1 - *(unsigned char *)p2;                       \
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
#else
Shinya Kitaoka 120a6e
#define SET_STRCMP(cmp, str1, str2)                                            \
Shinya Kitaoka 120a6e
  { (cmp) = strcmp((str1), (str2)); }
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
#define SET_PTRCMP(cmp, usrcmp, ptr1, ptr2)                                    \
Shinya Kitaoka 120a6e
  {                                                                            \
Shinya Kitaoka 120a6e
    if (usrcmp)                                                                \
Shinya Kitaoka 120a6e
      (cmp) = (*(usrcmp))((ptr1), (ptr2));                                     \
Shinya Kitaoka 120a6e
    else                                                                       \
Shinya Kitaoka 120a6e
      SET_STRCMP((cmp), (char *)(ptr1), (char *)(ptr2))                        \
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define ERROR (-1)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define BAL 0
Toshihiro Shimizu 890ddd
#define LEFT 1
Toshihiro Shimizu 890ddd
#define RIGHT 2
Toshihiro Shimizu 890ddd
#define LEFTUNBAL 3
Toshihiro Shimizu 890ddd
#define RIGHTUNBAL 4
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define LESS 3
Toshihiro Shimizu 890ddd
#define SAME 4
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define NOTINS 0
Toshihiro Shimizu 890ddd
#define INS 1
Toshihiro Shimizu 890ddd
#define DEEPER 2
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define NODE_LIST 0
Toshihiro Shimizu 890ddd
#define TREE_LIST (NODE_LIST + (sizeof(NODE) != sizeof(TREE)))
Toshihiro Shimizu 890ddd
#define PATH_LIST (TREE_LIST + 1)
Toshihiro Shimizu 890ddd
#define FREE_LISTS (PATH_LIST + 1)
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
#define LONG_ALIGNED_SIZE(obj)                                                 \
Shinya Kitaoka 120a6e
  ((sizeof(obj) + sizeof(long) - 1) & ~(sizeof(long) - 1))
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define SIZEOF_NODE LONG_ALIGNED_SIZE(NODE)
Toshihiro Shimizu 890ddd
#define SIZEOF_TREE LONG_ALIGNED_SIZE(TREE)
Toshihiro Shimizu 890ddd
#define SIZEOF_PATH LONG_ALIGNED_SIZE(PATH)
Toshihiro Shimizu 890ddd
#define SIZEOF_LONG sizeof(long)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define PREALLOC_LONGS (0x7FF0 / SIZEOF_LONG)
Toshihiro Shimizu 890ddd
#define PREALLOC_SIZE (PREALLOC_LONGS * SIZEOF_LONG)
Toshihiro Shimizu 890ddd
#define MALLOC_LONGS (0x7FE0 / SIZEOF_LONG)
Toshihiro Shimizu 890ddd
#define MALLOC_SIZE (MALLOC_LONGS * SIZEOF_LONG)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
static long Prealloc[PREALLOC_LONGS];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
static void *Free_List[FREE_LISTS]; /* init to 0 by C */
Toshihiro Shimizu 890ddd
static char *Avail_Base = (char *)Prealloc;
Shinya Kitaoka 120a6e
static uint Avail_Size  = PREALLOC_SIZE;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*===========================================================================*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
static void *new_memory(uint size) {
Shinya Kitaoka 120a6e
  char *base;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  while (Avail_Size >= SIZEOF_NODE) {
Shinya Kitaoka 120a6e
    base                 = Avail_Base + (Avail_Size -= SIZEOF_NODE);
Shinya Kitaoka 120a6e
    *(void **)base       = Free_List[NODE_LIST];
Shinya Kitaoka 120a6e
    Free_List[NODE_LIST] = (void *)base;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if ((Avail_Base = (char *)malloc(MALLOC_SIZE))) {
Shinya Kitaoka 120a6e
    Avail_Size = MALLOC_SIZE - size;
Shinya Kitaoka 120a6e
    return (void *)(Avail_Base + Avail_Size);
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    Avail_Size = 0;
Shinya Kitaoka 120a6e
    return NIL;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
#define ALLOC_OBJ(ptr, ptr_type, size, list)                                   \
Shinya Kitaoka 120a6e
  {                                                                            \
Shinya Kitaoka 120a6e
    if (Free_List[list]) {                                                     \
Shinya Kitaoka 120a6e
      (ptr)           = (ptr_type)Free_List[list];                             \
Shinya Kitaoka 120a6e
      Free_List[list] = *(void **)(ptr);                                       \
Shinya Kitaoka 120a6e
    } else if (Avail_Size >= size)                                             \
Shinya Kitaoka 120a6e
      (ptr) = (ptr_type)(Avail_Base + (Avail_Size -= size));                   \
Shinya Kitaoka 120a6e
    else                                                                       \
Shinya Kitaoka 120a6e
      (ptr) = (ptr_type)new_memory(size);                                      \
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
#define FREE_OBJ(ptr, list)                                                    \
Shinya Kitaoka 120a6e
  {                                                                            \
Shinya Kitaoka 120a6e
    *(void **)(ptr) = Free_List[list];                                         \
Shinya Kitaoka 120a6e
    Free_List[list] = (void *)(ptr);                                           \
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define ALLOC_NODE(node) ALLOC_OBJ(node, NODE *, SIZEOF_NODE, NODE_LIST)
Toshihiro Shimizu 890ddd
#define ALLOC_TREE(tree) ALLOC_OBJ(tree, TREE *, SIZEOF_TREE, TREE_LIST)
Toshihiro Shimizu 890ddd
#define ALLOC_PATH(path) ALLOC_OBJ(path, PATH *, SIZEOF_PATH, PATH_LIST)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define FREE_NODE(node) FREE_OBJ(node, NODE_LIST)
Toshihiro Shimizu 890ddd
#define FREE_TREE(tree) FREE_OBJ(tree, TREE_LIST)
Toshihiro Shimizu 890ddd
#define FREE_PATH(path) FREE_OBJ(path, PATH_LIST)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*===========================================================================*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TREE *avl__tree(int treetype, uint keyoffs, int (*usrcmp)(void *, void *)) {
Shinya Kitaoka 120a6e
  TREE *tree;
Shinya Kitaoka 120a6e
  int keyinfo;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  keyinfo = treetype << 2;
Shinya Kitaoka 120a6e
  switch (treetype) {
Shinya Kitaoka 120a6e
  case AVL_NODUP_MBR:
Shinya Kitaoka 120a6e
  case AVL_DUP_MBR:
Shinya Kitaoka 120a6e
    keyinfo |= USR_CMP;
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case AVL_NODUP_PTR:
Shinya Kitaoka 120a6e
  case AVL_DUP_PTR:
Shinya Kitaoka 120a6e
    keyinfo |= USR_CMP;
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case AVL_NODUP_STR:
Shinya Kitaoka 120a6e
  case AVL_DUP_STR:
Shinya Kitaoka 120a6e
    keyinfo |= STR_CMP;
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case AVL_NODUP_LNG:
Shinya Kitaoka 120a6e
  case AVL_DUP_LNG:
Shinya Kitaoka 120a6e
    keyinfo |= VAL_CMP;
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case AVL_NODUP_INT:
Shinya Kitaoka 120a6e
  case AVL_DUP_INT:
Shinya Kitaoka 120a6e
    keyinfo |= VAL_CMP;
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case AVL_NODUP_SHT:
Shinya Kitaoka 120a6e
  case AVL_DUP_SHT:
Shinya Kitaoka 120a6e
    keyinfo |= VAL_CMP;
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case AVL_NODUP_ULN:
Shinya Kitaoka 120a6e
  case AVL_DUP_ULN:
Shinya Kitaoka 120a6e
    keyinfo |= COR_CMP;
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case AVL_NODUP_UIN:
Shinya Kitaoka 120a6e
  case AVL_DUP_UIN:
Shinya Kitaoka 120a6e
    keyinfo |= COR_CMP;
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case AVL_NODUP_USH:
Shinya Kitaoka 120a6e
  case AVL_DUP_USH:
Shinya Kitaoka 120a6e
    keyinfo |= VAL_CMP;
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case AVL_NODUP_CHR:
Shinya Kitaoka 120a6e
  case AVL_DUP_CHR:
Shinya Kitaoka 120a6e
    keyinfo |= VAL_CMP;
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  default:
Shinya Kitaoka 120a6e
    return NIL;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  ALLOC_TREE(tree)
Shinya Kitaoka 120a6e
  if (!tree) return NIL;
Shinya Kitaoka 120a6e
  tree->root    = NIL;
Shinya Kitaoka 120a6e
  tree->keyinfo = (ushort)keyinfo;
Shinya Kitaoka 120a6e
  tree->keyoffs = (ushort)keyoffs;
Shinya Kitaoka 120a6e
  tree->usrcmp  = usrcmp;
Shinya Kitaoka 120a6e
  tree->nodes   = 0L;
Shinya Kitaoka 120a6e
  tree->path    = NIL;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return tree;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*===========================================================================*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
static int rebalance(NODE **rootaddr) {
Shinya Kitaoka 120a6e
  NODE *root = *rootaddr;
Shinya Kitaoka 120a6e
  NODE *newroot;
Shinya Kitaoka 120a6e
  NODE *half;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  switch (root->bal) {
Shinya Kitaoka 120a6e
  case LEFTUNBAL:
Shinya Kitaoka 120a6e
    switch (root->left->bal) {
Shinya Kitaoka 120a6e
    case LEFT: /* simple rotation, tree depth decreased */
Shinya Kitaoka 120a6e
      newroot        = root->left;
Shinya Kitaoka 120a6e
      root->left     = newroot->right;
Shinya Kitaoka 120a6e
      root->bal      = BAL;
Shinya Kitaoka 120a6e
      newroot->right = root;
Shinya Kitaoka 120a6e
      newroot->bal   = BAL;
Shinya Kitaoka 120a6e
      *rootaddr      = newroot;
Shinya Kitaoka 120a6e
      return LESS;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    case BAL: /* simple rotation, tree depth unchanged */
Shinya Kitaoka 120a6e
      newroot        = root->left;
Shinya Kitaoka 120a6e
      root->left     = newroot->right;
Shinya Kitaoka 120a6e
      root->bal      = LEFT;
Shinya Kitaoka 120a6e
      newroot->right = root;
Shinya Kitaoka 120a6e
      newroot->bal   = RIGHT;
Shinya Kitaoka 120a6e
      *rootaddr      = newroot;
Shinya Kitaoka 120a6e
      return SAME;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    case RIGHT: /* double rotation */
Shinya Kitaoka 120a6e
      half        = root->left;
Shinya Kitaoka 120a6e
      newroot     = half->right;
Shinya Kitaoka 120a6e
      root->left  = newroot->right;
Shinya Kitaoka 120a6e
      half->right = newroot->left;
Shinya Kitaoka 120a6e
      switch (newroot->bal) {
Shinya Kitaoka 120a6e
      case BAL:
Shinya Kitaoka 120a6e
        root->bal = BAL;
Shinya Kitaoka 120a6e
        half->bal = BAL;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      case LEFT:
Shinya Kitaoka 120a6e
        root->bal = RIGHT;
Shinya Kitaoka 120a6e
        half->bal = BAL;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      case RIGHT:
Shinya Kitaoka 120a6e
        root->bal = BAL;
Shinya Kitaoka 120a6e
        half->bal = LEFT;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      newroot->left  = half;
Shinya Kitaoka 120a6e
      newroot->right = root;
Shinya Kitaoka 120a6e
      newroot->bal   = BAL;
Shinya Kitaoka 120a6e
      *rootaddr      = newroot;
Shinya Kitaoka 120a6e
      return LESS;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case RIGHTUNBAL:
Shinya Kitaoka 120a6e
    switch (root->right->bal) {
Shinya Kitaoka 120a6e
    case RIGHT: /* simple rotation, tree depth decreased */
Shinya Kitaoka 120a6e
      newroot       = root->right;
Shinya Kitaoka 120a6e
      root->right   = newroot->left;
Shinya Kitaoka 120a6e
      root->bal     = BAL;
Shinya Kitaoka 120a6e
      newroot->left = root;
Shinya Kitaoka 120a6e
      newroot->bal  = BAL;
Shinya Kitaoka 120a6e
      *rootaddr     = newroot;
Shinya Kitaoka 120a6e
      return LESS;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    case BAL: /* simple rotation, tree depth unchanged */
Shinya Kitaoka 120a6e
      newroot       = root->right;
Shinya Kitaoka 120a6e
      root->right   = newroot->left;
Shinya Kitaoka 120a6e
      root->bal     = RIGHT;
Shinya Kitaoka 120a6e
      newroot->left = root;
Shinya Kitaoka 120a6e
      newroot->bal  = LEFT;
Shinya Kitaoka 120a6e
      *rootaddr     = newroot;
Shinya Kitaoka 120a6e
      return SAME;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    case LEFT: /* double rotation */
Shinya Kitaoka 120a6e
      half        = root->right;
Shinya Kitaoka 120a6e
      newroot     = half->left;
Shinya Kitaoka 120a6e
      root->right = newroot->left;
Shinya Kitaoka 120a6e
      half->left  = newroot->right;
Shinya Kitaoka 120a6e
      switch (newroot->bal) {
Shinya Kitaoka 120a6e
      case BAL:
Shinya Kitaoka 120a6e
        root->bal = BAL;
Shinya Kitaoka 120a6e
        half->bal = BAL;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      case RIGHT:
Shinya Kitaoka 120a6e
        root->bal = LEFT;
Shinya Kitaoka 120a6e
        half->bal = BAL;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      case LEFT:
Shinya Kitaoka 120a6e
        root->bal = BAL;
Shinya Kitaoka 120a6e
        half->bal = RIGHT;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      newroot->right = half;
Shinya Kitaoka 120a6e
      newroot->left  = root;
Shinya Kitaoka 120a6e
      newroot->bal   = BAL;
Shinya Kitaoka 120a6e
      *rootaddr      = newroot;
Shinya Kitaoka 120a6e
      return LESS;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  default:
Shinya Kitaoka 120a6e
    return SAME;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return ERROR;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*===========================================================================*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
static int insert_ptr(NODE **rootaddr, NODE *node,
Shinya Kitaoka 120a6e
                      int (*usrcmp)(void *, void *), int dup) {
Shinya Kitaoka 120a6e
  NODE *root = *rootaddr;
Shinya Kitaoka 120a6e
  int cmp;
Shinya Kitaoka 120a6e
  int ins;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  SET_PTRCMP(cmp, usrcmp, node->key.ptr, root->key.ptr)
Shinya Kitaoka 120a6e
  if (cmp < 0) {
Shinya Kitaoka 120a6e
    if (root->left)
Shinya Kitaoka 120a6e
      ins = insert_ptr(&root->left, node, usrcmp, dup);
Shinya Kitaoka 120a6e
    else {
Shinya Kitaoka 120a6e
      root->left = node;
Shinya Kitaoka 120a6e
      ins        = DEEPER;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    switch (ins) {
Shinya Kitaoka 120a6e
    case DEEPER:
Shinya Kitaoka 120a6e
      switch (root->bal) {
Shinya Kitaoka 120a6e
      case RIGHT:
Shinya Kitaoka 120a6e
        root->bal = BAL;
Shinya Kitaoka 120a6e
        return INS;
Shinya Kitaoka 120a6e
      case BAL:
Shinya Kitaoka 120a6e
        root->bal = LEFT;
Shinya Kitaoka 120a6e
        return DEEPER;
Shinya Kitaoka 120a6e
      case LEFT:
Shinya Kitaoka 120a6e
        root->bal = LEFTUNBAL;
Shinya Kitaoka 120a6e
        return rebalance(rootaddr) == LESS ? INS : DEEPER;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    case INS:
Shinya Kitaoka 120a6e
      return INS;
Shinya Kitaoka 120a6e
    case NOTINS:
Shinya Kitaoka 120a6e
      return NOTINS;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else if (cmp > 0 || dup) {
Shinya Kitaoka 120a6e
    if (root->right)
Shinya Kitaoka 120a6e
      ins = insert_ptr(&root->right, node, usrcmp, dup);
Shinya Kitaoka 120a6e
    else {
Shinya Kitaoka 120a6e
      root->right = node;
Shinya Kitaoka 120a6e
      ins         = DEEPER;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    switch (ins) {
Shinya Kitaoka 120a6e
    case DEEPER:
Shinya Kitaoka 120a6e
      switch (root->bal) {
Shinya Kitaoka 120a6e
      case LEFT:
Shinya Kitaoka 120a6e
        root->bal = BAL;
Shinya Kitaoka 120a6e
        return INS;
Shinya Kitaoka 120a6e
      case BAL:
Shinya Kitaoka 120a6e
        root->bal = RIGHT;
Shinya Kitaoka 120a6e
        return DEEPER;
Shinya Kitaoka 120a6e
      case RIGHT:
Shinya Kitaoka 120a6e
        root->bal = RIGHTUNBAL;
Shinya Kitaoka 120a6e
        return rebalance(rootaddr) == LESS ? INS : DEEPER;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    case INS:
Shinya Kitaoka 120a6e
      return INS;
Shinya Kitaoka 120a6e
    case NOTINS:
Shinya Kitaoka 120a6e
      return NOTINS;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return NOTINS;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
static int insert_val(NODE **rootaddr, NODE *node, int dup) {
Shinya Kitaoka 120a6e
  NODE *root = *rootaddr;
Shinya Kitaoka 120a6e
  int ins;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (node->key.val < root->key.val) {
Shinya Kitaoka 120a6e
    if (root->left)
Shinya Kitaoka 120a6e
      ins = insert_val(&root->left, node, dup);
Shinya Kitaoka 120a6e
    else {
Shinya Kitaoka 120a6e
      root->left = node;
Shinya Kitaoka 120a6e
      ins        = DEEPER;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    switch (ins) {
Shinya Kitaoka 120a6e
    case DEEPER:
Shinya Kitaoka 120a6e
      switch (root->bal) {
Shinya Kitaoka 120a6e
      case RIGHT:
Shinya Kitaoka 120a6e
        root->bal = BAL;
Shinya Kitaoka 120a6e
        return INS;
Shinya Kitaoka 120a6e
      case BAL:
Shinya Kitaoka 120a6e
        root->bal = LEFT;
Shinya Kitaoka 120a6e
        return DEEPER;
Shinya Kitaoka 120a6e
      case LEFT:
Shinya Kitaoka 120a6e
        root->bal = LEFTUNBAL;
Shinya Kitaoka 120a6e
        return rebalance(rootaddr) == LESS ? INS : DEEPER;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    case INS:
Shinya Kitaoka 120a6e
      return INS;
Shinya Kitaoka 120a6e
    case NOTINS:
Shinya Kitaoka 120a6e
      return NOTINS;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else if (node->key.val > root->key.val || dup) {
Shinya Kitaoka 120a6e
    if (root->right) {
Shinya Kitaoka 120a6e
      ins = insert_val(&root->right, node, dup);
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      root->right = node;
Shinya Kitaoka 120a6e
      ins         = DEEPER;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    switch (ins) {
Shinya Kitaoka 120a6e
    case DEEPER:
Shinya Kitaoka 120a6e
      switch (root->bal) {
Shinya Kitaoka 120a6e
      case LEFT:
Shinya Kitaoka 120a6e
        root->bal = BAL;
Shinya Kitaoka 120a6e
        return INS;
Shinya Kitaoka 120a6e
      case BAL:
Shinya Kitaoka 120a6e
        root->bal = RIGHT;
Shinya Kitaoka 120a6e
        return DEEPER;
Shinya Kitaoka 120a6e
      case RIGHT:
Shinya Kitaoka 120a6e
        root->bal = RIGHTUNBAL;
Shinya Kitaoka 120a6e
        return rebalance(rootaddr) == LESS ? INS : DEEPER;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    case INS:
Shinya Kitaoka 120a6e
      return INS;
Shinya Kitaoka 120a6e
    case NOTINS:
Shinya Kitaoka 120a6e
      return NOTINS;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return NOTINS;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int avl_insert(TREE *tree, void *data) {
Shinya Kitaoka 120a6e
  NODE *node;
Shinya Kitaoka 120a6e
  int keyinfo;
Shinya Kitaoka 120a6e
  int ins;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ALLOC_NODE(node)
Shinya Kitaoka 120a6e
  if (!node) return FALSE;
Shinya Kitaoka 120a6e
  node->data  = data;
Shinya Kitaoka 120a6e
  node->left  = NIL;
Shinya Kitaoka 120a6e
  node->right = NIL;
Shinya Kitaoka 120a6e
  node->bal   = BAL;
Shinya Kitaoka 120a6e
  keyinfo     = tree->keyinfo;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  switch (KEYTYPE(keyinfo)) {
Shinya Kitaoka 120a6e
  case MBR_KEY:
Shinya Kitaoka 120a6e
    node->key.ptr = (void *)((char *)data + tree->keyoffs);
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case PTR_KEY:
Shinya Kitaoka 120a6e
    node->key.ptr = *(void **)((char *)data + tree->keyoffs);
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case STR_KEY:
Shinya Kitaoka 120a6e
    node->key.ptr = *(void **)((char *)data + tree->keyoffs);
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case LNG_KEY:
Shinya Kitaoka 120a6e
    node->key.val = *(long *)((char *)data + tree->keyoffs);
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case INT_KEY:
Shinya Kitaoka 120a6e
    node->key.val = *(int *)((char *)data + tree->keyoffs);
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case SHT_KEY:
Shinya Kitaoka 120a6e
    node->key.val = *(short *)((char *)data + tree->keyoffs);
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case ULN_KEY:
Shinya Kitaoka 120a6e
    node->key.val = CORRECT(*(ulong *)((char *)data + tree->keyoffs));
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case UIN_KEY:
Shinya Kitaoka 120a6e
    node->key.val = CORRECT(*(uint *)((char *)data + tree->keyoffs));
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case USH_KEY:
Shinya Kitaoka 120a6e
    node->key.val = *(ushort *)((char *)data + tree->keyoffs);
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case CHR_KEY:
Shinya Kitaoka 120a6e
    node->key.val = *((char *)data + tree->keyoffs);
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  default:
Shinya Kitaoka 120a6e
    FREE_NODE(node)
Shinya Kitaoka 120a6e
    return FALSE;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (tree->root) {
Shinya Kitaoka 120a6e
    switch (LOCTYPE(keyinfo)) {
Shinya Kitaoka 120a6e
    case USR_NODUP:
Shinya Kitaoka 120a6e
      ins = insert_ptr(&tree->root, node, tree->usrcmp, NODUP);
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    case STR_NODUP:
Shinya Kitaoka 120a6e
      ins = insert_ptr(&tree->root, node, AVL_AVLCMP, NODUP);
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    case COR_NODUP:
Shinya Kitaoka 120a6e
    case VAL_NODUP:
Shinya Kitaoka 120a6e
      ins = insert_val(&tree->root, node, NODUP);
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    case USR_DUP:
Shinya Kitaoka 120a6e
      ins = insert_ptr(&tree->root, node, tree->usrcmp, DUP);
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    case STR_DUP:
Shinya Kitaoka 120a6e
      ins = insert_ptr(&tree->root, node, AVL_AVLCMP, DUP);
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    case COR_DUP:
Shinya Kitaoka 120a6e
    case VAL_DUP:
Shinya Kitaoka 120a6e
      ins = insert_val(&tree->root, node, DUP);
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (ins == NOTINS) {
Shinya Kitaoka 120a6e
      FREE_NODE(node)
Shinya Kitaoka 120a6e
      return FALSE;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    tree->root = node;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  tree->nodes++;
Shinya Kitaoka 120a6e
  if (tree->path) {
Shinya Kitaoka 120a6e
    FREE_PATH(tree->path)
Shinya Kitaoka 120a6e
    tree->path = NIL;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return TRUE;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*===========================================================================*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
#define SELECT_EQ_NODUP(node, val, this)                                       \
Shinya Kitaoka 120a6e
  {                                                                            \
Shinya Kitaoka 120a6e
    if (this < val)                                                            \
Shinya Kitaoka 120a6e
      node = node->right;                                                      \
Shinya Kitaoka 120a6e
    else if (val < this)                                                       \
Shinya Kitaoka 120a6e
      node = node->left;                                                       \
Shinya Kitaoka 120a6e
    else                                                                       \
Shinya Kitaoka 120a6e
      return node->data;                                                       \
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
#define SELECT_EQ_DUP(node, val, this, save)                                   \
Shinya Kitaoka 120a6e
  {                                                                            \
Shinya Kitaoka 120a6e
    if (this < val)                                                            \
Shinya Kitaoka 120a6e
      node = node->right;                                                      \
Shinya Kitaoka 120a6e
    else if (val < this)                                                       \
Shinya Kitaoka 120a6e
      node = node->left;                                                       \
Shinya Kitaoka 120a6e
    else {                                                                     \
Shinya Kitaoka 120a6e
      save = node;                                                             \
Shinya Kitaoka 120a6e
      node = node->left;                                                       \
Shinya Kitaoka 120a6e
    }                                                                          \
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
#define SELECT_GE_NODUP(node, val, this, save)                                 \
Shinya Kitaoka 120a6e
  {                                                                            \
Shinya Kitaoka 120a6e
    if (val < this) {                                                          \
Shinya Kitaoka 120a6e
      save = node;                                                             \
Shinya Kitaoka 120a6e
      node = node->left;                                                       \
Shinya Kitaoka 120a6e
    } else if (this < val)                                                     \
Shinya Kitaoka 120a6e
      node = node->right;                                                      \
Shinya Kitaoka 120a6e
    else                                                                       \
Shinya Kitaoka 120a6e
      return node->data;                                                       \
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
#define SELECT_GE_DUP(node, val, this, save)                                   \
Shinya Kitaoka 120a6e
  {                                                                            \
Shinya Kitaoka 120a6e
    if (this < val)                                                            \
Shinya Kitaoka 120a6e
      node = node->right;                                                      \
Shinya Kitaoka 120a6e
    else {                                                                     \
Shinya Kitaoka 120a6e
      save = node;                                                             \
Shinya Kitaoka 120a6e
      node = node->left;                                                       \
Shinya Kitaoka 120a6e
    }                                                                          \
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
#define SELECT_GT(node, val, this, save)                                       \
Shinya Kitaoka 120a6e
  {                                                                            \
Shinya Kitaoka 120a6e
    if (val < this) {                                                          \
Shinya Kitaoka 120a6e
      save = node;                                                             \
Shinya Kitaoka 120a6e
      node = node->left;                                                       \
Shinya Kitaoka 120a6e
    } else                                                                     \
Shinya Kitaoka 120a6e
      node = node->right;                                                      \
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
#define SELECT_LE_NODUP(node, val, this, save)                                 \
Shinya Kitaoka 120a6e
  {                                                                            \
Shinya Kitaoka 120a6e
    if (this < val) {                                                          \
Shinya Kitaoka 120a6e
      save = node;                                                             \
Shinya Kitaoka 120a6e
      node = node->right;                                                      \
Shinya Kitaoka 120a6e
    } else if (val < this)                                                     \
Shinya Kitaoka 120a6e
      node = node->left;                                                       \
Shinya Kitaoka 120a6e
    else                                                                       \
Shinya Kitaoka 120a6e
      return node->data;                                                       \
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
#define SELECT_LE_DUP(node, val, this, save)                                   \
Shinya Kitaoka 120a6e
  {                                                                            \
Shinya Kitaoka 120a6e
    if (val < this)                                                            \
Shinya Kitaoka 120a6e
      node = node->left;                                                       \
Shinya Kitaoka 120a6e
    else {                                                                     \
Shinya Kitaoka 120a6e
      save = node;                                                             \
Shinya Kitaoka 120a6e
      node = node->right;                                                      \
Shinya Kitaoka 120a6e
    }                                                                          \
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
#define SELECT_LT(node, val, this, save)                                       \
Shinya Kitaoka 120a6e
  {                                                                            \
Shinya Kitaoka 120a6e
    if (this < val) {                                                          \
Shinya Kitaoka 120a6e
      save = node;                                                             \
Shinya Kitaoka 120a6e
      node = node->right;                                                      \
Shinya Kitaoka 120a6e
    } else                                                                     \
Shinya Kitaoka 120a6e
      node = node->left;                                                       \
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void *avl__locate(TREE *tree, long keyval) {
Shinya Kitaoka 120a6e
  NODE *node;
Shinya Kitaoka 120a6e
  NODE *save;
Shinya Kitaoka 120a6e
  int (*usrcmp)(void *, void *);
Shinya Kitaoka 120a6e
  int cmp;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  node = tree->root;
Shinya Kitaoka 120a6e
  switch (LOCTYPE(tree->keyinfo)) {
Shinya Kitaoka 120a6e
  case USR_NODUP:
Shinya Kitaoka 120a6e
    usrcmp = tree->usrcmp;
Shinya Kitaoka 120a6e
    while (node) {
Shinya Kitaoka 120a6e
      cmp = (*usrcmp)((void *)keyval, node->key.ptr);
Shinya Kitaoka 120a6e
      SELECT_EQ_NODUP(node, cmp, 0);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case STR_NODUP:
Shinya Kitaoka 120a6e
    while (node) {
Shinya Kitaoka 120a6e
      SET_STRCMP(cmp, (char *)keyval, (char *)node->key.ptr);
Shinya Kitaoka 120a6e
      SELECT_EQ_NODUP(node, cmp, 0);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case COR_NODUP:
Shinya Kitaoka 120a6e
    keyval = CORRECT(keyval);
Shinya Kitaoka 120a6e
  // fallthrough
Shinya Kitaoka 120a6e
  case VAL_NODUP:
Shinya Kitaoka 120a6e
    while (node) {
Shinya Kitaoka 120a6e
      SELECT_EQ_NODUP(node, keyval, node->key.val);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case USR_DUP:
Shinya Kitaoka 120a6e
    save   = NIL;
Shinya Kitaoka 120a6e
    usrcmp = tree->usrcmp;
Shinya Kitaoka 120a6e
    while (node) {
Shinya Kitaoka 120a6e
      cmp = (*usrcmp)((void *)keyval, node->key.ptr);
Shinya Kitaoka 120a6e
      SELECT_EQ_DUP(node, cmp, 0, save);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (save) {
Shinya Kitaoka 120a6e
      return save->data;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case STR_DUP:
Shinya Kitaoka 120a6e
    save = NIL;
Shinya Kitaoka 120a6e
    while (node) {
Shinya Kitaoka 120a6e
      SET_STRCMP(cmp, (char *)keyval, (char *)node->key.ptr);
Shinya Kitaoka 120a6e
      SELECT_EQ_DUP(node, cmp, 0, save);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (save) {
Shinya Kitaoka 120a6e
      return save->data;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case COR_DUP:
Shinya Kitaoka 120a6e
    keyval = CORRECT(keyval);
Shinya Kitaoka 120a6e
  // fallthrough
Shinya Kitaoka 120a6e
  case VAL_DUP:
Shinya Kitaoka 120a6e
    save = NIL;
Shinya Kitaoka 120a6e
    while (node) {
Shinya Kitaoka 120a6e
      SELECT_EQ_DUP(node, keyval, node->key.val, save);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (save) {
Shinya Kitaoka 120a6e
      return save->data;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return NIL;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void *avl__locate_ge(TREE *tree, long keyval) {
Shinya Kitaoka 120a6e
  NODE *node;
Shinya Kitaoka 120a6e
  NODE *save;
Shinya Kitaoka 120a6e
  int (*usrcmp)(void *, void *);
Shinya Kitaoka 120a6e
  int cmp;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  node = tree->root;
Shinya Kitaoka 120a6e
  save = NIL;
Shinya Kitaoka 120a6e
  switch (LOCTYPE(tree->keyinfo)) {
Shinya Kitaoka 120a6e
  case USR_NODUP:
Shinya Kitaoka 120a6e
    usrcmp = tree->usrcmp;
Shinya Kitaoka 120a6e
    while (node) {
Shinya Kitaoka 120a6e
      cmp = (*usrcmp)((void *)keyval, node->key.ptr);
Shinya Kitaoka 120a6e
      SELECT_GE_NODUP(node, cmp, 0, save);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case STR_NODUP:
Shinya Kitaoka 120a6e
    while (node) {
Shinya Kitaoka 120a6e
      SET_STRCMP(cmp, (char *)keyval, (char *)node->key.ptr);
Shinya Kitaoka 120a6e
      SELECT_GE_NODUP(node, cmp, 0, save);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case COR_NODUP:
Shinya Kitaoka 120a6e
    keyval = CORRECT(keyval);
Shinya Kitaoka 120a6e
  // fallthrough
Shinya Kitaoka 120a6e
  case VAL_NODUP:
Shinya Kitaoka 120a6e
    while (node) {
Shinya Kitaoka 120a6e
      SELECT_GE_NODUP(node, keyval, node->key.val, save);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case USR_DUP:
Shinya Kitaoka 120a6e
    usrcmp = tree->usrcmp;
Shinya Kitaoka 120a6e
    while (node) {
Shinya Kitaoka 120a6e
      cmp = (*usrcmp)((void *)keyval, node->key.ptr);
Shinya Kitaoka 120a6e
      SELECT_GE_DUP(node, cmp, 0, save);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case STR_DUP:
Shinya Kitaoka 120a6e
    while (node) {
Shinya Kitaoka 120a6e
      SET_STRCMP(cmp, (char *)keyval, (char *)node->key.ptr);
Shinya Kitaoka 120a6e
      SELECT_GE_DUP(node, cmp, 0, save);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case COR_DUP:
Shinya Kitaoka 120a6e
    keyval = CORRECT(keyval);
Shinya Kitaoka 120a6e
  // fallthrough
Shinya Kitaoka 120a6e
  case VAL_DUP:
Shinya Kitaoka 120a6e
    while (node) {
Shinya Kitaoka 120a6e
      SELECT_GE_DUP(node, keyval, node->key.val, save);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return save ? save->data : NIL;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void *avl__locate_gt(TREE *tree, long keyval) {
Shinya Kitaoka 120a6e
  NODE *node;
Shinya Kitaoka 120a6e
  NODE *save;
Shinya Kitaoka 120a6e
  int (*usrcmp)(void *, void *);
Shinya Kitaoka 120a6e
  int cmp;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  node = tree->root;
Shinya Kitaoka 120a6e
  save = NIL;
Shinya Kitaoka 120a6e
  switch (CMPTYPE(tree->keyinfo)) {
Shinya Kitaoka 120a6e
  case USR_CMP:
Shinya Kitaoka 120a6e
    usrcmp = tree->usrcmp;
Shinya Kitaoka 120a6e
    while (node) {
Shinya Kitaoka 120a6e
      cmp = (*usrcmp)((void *)keyval, node->key.ptr);
Shinya Kitaoka 120a6e
      SELECT_GT(node, cmp, 0, save);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case STR_CMP:
Shinya Kitaoka 120a6e
    while (node) {
Shinya Kitaoka 120a6e
      SET_STRCMP(cmp, (char *)keyval, (char *)node->key.ptr);
Shinya Kitaoka 120a6e
      SELECT_GT(node, cmp, 0, save);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case COR_CMP:
Shinya Kitaoka 120a6e
    keyval = CORRECT(keyval);
Shinya Kitaoka 120a6e
  // fallthrough
Shinya Kitaoka 120a6e
  case VAL_CMP:
Shinya Kitaoka 120a6e
    while (node) {
Shinya Kitaoka 120a6e
      SELECT_GT(node, keyval, node->key.val, save);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return save ? save->data : NIL;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void *avl__locate_le(TREE *tree, long keyval) {
Shinya Kitaoka 120a6e
  NODE *node;
Shinya Kitaoka 120a6e
  NODE *save;
Shinya Kitaoka 120a6e
  int (*usrcmp)(void *, void *);
Shinya Kitaoka 120a6e
  int cmp;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  node = tree->root;
Shinya Kitaoka 120a6e
  save = NIL;
Shinya Kitaoka 120a6e
  switch (LOCTYPE(tree->keyinfo)) {
Shinya Kitaoka 120a6e
  case USR_NODUP:
Shinya Kitaoka 120a6e
    usrcmp = tree->usrcmp;
Shinya Kitaoka 120a6e
    while (node) {
Shinya Kitaoka 120a6e
      cmp = (*usrcmp)((void *)keyval, node->key.ptr);
Shinya Kitaoka 120a6e
      SELECT_LE_NODUP(node, cmp, 0, save);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case STR_NODUP:
Shinya Kitaoka 120a6e
    while (node) {
Shinya Kitaoka 120a6e
      SET_STRCMP(cmp, (char *)keyval, (char *)node->key.ptr);
Shinya Kitaoka 120a6e
      SELECT_LE_NODUP(node, cmp, 0, save);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case COR_NODUP:
Shinya Kitaoka 120a6e
    keyval = CORRECT(keyval);
Shinya Kitaoka 120a6e
  // fallthrough
Shinya Kitaoka 120a6e
  case VAL_NODUP:
Shinya Kitaoka 120a6e
    while (node) {
Shinya Kitaoka 120a6e
      SELECT_LE_NODUP(node, keyval, node->key.val, save);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case USR_DUP:
Shinya Kitaoka 120a6e
    usrcmp = tree->usrcmp;
Shinya Kitaoka 120a6e
    while (node) {
Shinya Kitaoka 120a6e
      cmp = (*usrcmp)((void *)keyval, node->key.ptr);
Shinya Kitaoka 120a6e
      SELECT_LE_DUP(node, cmp, 0, save);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case STR_DUP:
Shinya Kitaoka 120a6e
    while (node) {
Shinya Kitaoka 120a6e
      SET_STRCMP(cmp, (char *)keyval, (char *)node->key.ptr);
Shinya Kitaoka 120a6e
      SELECT_LE_DUP(node, cmp, 0, save);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case COR_DUP:
Shinya Kitaoka 120a6e
    keyval = CORRECT(keyval);
Shinya Kitaoka 120a6e
  // fallthrough
Shinya Kitaoka 120a6e
  case VAL_DUP:
Shinya Kitaoka 120a6e
    while (node) {
Shinya Kitaoka 120a6e
      SELECT_LE_DUP(node, keyval, node->key.val, save);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return save ? save->data : NIL;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void *avl__locate_lt(TREE *tree, long keyval) {
Shinya Kitaoka 120a6e
  NODE *node;
Shinya Kitaoka 120a6e
  NODE *save;
Shinya Kitaoka 120a6e
  int (*usrcmp)(void *, void *);
Shinya Kitaoka 120a6e
  int cmp;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  node = tree->root;
Shinya Kitaoka 120a6e
  save = NIL;
Shinya Kitaoka 120a6e
  switch (CMPTYPE(tree->keyinfo)) {
Shinya Kitaoka 120a6e
  case USR_CMP:
Shinya Kitaoka 120a6e
    usrcmp = tree->usrcmp;
Shinya Kitaoka 120a6e
    while (node) {
Shinya Kitaoka 120a6e
      cmp = (*usrcmp)((void *)keyval, node->key.ptr);
Shinya Kitaoka 120a6e
      SELECT_LT(node, cmp, 0, save);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case STR_CMP:
Shinya Kitaoka 120a6e
    while (node) {
Shinya Kitaoka 120a6e
      SET_STRCMP(cmp, (char *)keyval, (char *)node->key.ptr);
Shinya Kitaoka 120a6e
      SELECT_LT(node, cmp, 0, save);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case COR_CMP:
Shinya Kitaoka 120a6e
    keyval = CORRECT(keyval);
Shinya Kitaoka 120a6e
  // fallthrough
Shinya Kitaoka 120a6e
  case VAL_CMP:
Shinya Kitaoka 120a6e
    while (node) {
Shinya Kitaoka 120a6e
      SELECT_LT(node, keyval, node->key.val, save);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return save ? save->data : NIL;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void *avl_locate_first(TREE *tree) {
Shinya Kitaoka 120a6e
  NODE *node, *leftnode;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  node = tree->root;
Shinya Kitaoka 120a6e
  if (!node) return NIL;
Shinya Kitaoka 120a6e
  while ((leftnode = node->left)) node = leftnode;
Shinya Kitaoka 120a6e
  return node->data;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void *avl_locate_last(TREE *tree) {
Shinya Kitaoka 120a6e
  NODE *node, *rightnode;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  node = tree->root;
Shinya Kitaoka 120a6e
  if (!node) return NIL;
Shinya Kitaoka 120a6e
  while ((rightnode = node->right)) node = rightnode;
Shinya Kitaoka 120a6e
  return node->data;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*===========================================================================*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
static NODE *leftmost(NODE **rootaddr) {
Shinya Kitaoka 120a6e
  NODE *root = *rootaddr;
Shinya Kitaoka 120a6e
  NODE *node;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (root) {
Shinya Kitaoka 120a6e
    if (root->left) {
Shinya Kitaoka 120a6e
      node = leftmost(&root->left);
Shinya Kitaoka 120a6e
      if (node->bal == LESS) {
Shinya Kitaoka 120a6e
        /* left subtree depth decreased */
Shinya Kitaoka 120a6e
        switch (root->bal) {
Shinya Kitaoka 120a6e
        case LEFT:
Shinya Kitaoka 120a6e
          root->bal = BAL;
Shinya Kitaoka 120a6e
          break;
Shinya Kitaoka 120a6e
        case BAL:
Shinya Kitaoka 120a6e
          root->bal = RIGHT;
Shinya Kitaoka 120a6e
          node->bal = SAME;
Shinya Kitaoka 120a6e
          break;
Shinya Kitaoka 120a6e
        case RIGHT:
Shinya Kitaoka 120a6e
          root->bal = RIGHTUNBAL;
Shinya Kitaoka 120a6e
          node->bal = rebalance(rootaddr);
Shinya Kitaoka 120a6e
          break;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      return node;
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      *rootaddr = root->right;
Shinya Kitaoka 120a6e
      root->bal = LESS;
Shinya Kitaoka 120a6e
      return root;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    return NIL;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
static NODE *remove_ptr(NODE **rootaddr, void *keyptr,
Shinya Kitaoka 120a6e
                        int (*usrcmp)(void *, void *), int dup) {
Shinya Kitaoka 120a6e
  NODE *root = *rootaddr;
Shinya Kitaoka 120a6e
  NODE *node;
Shinya Kitaoka 120a6e
  int cmp;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  SET_PTRCMP(cmp, usrcmp, keyptr, root->key.ptr)
Shinya Kitaoka 120a6e
  if (cmp < 0) {
Shinya Kitaoka 120a6e
    if (!root->left) return NIL;
Shinya Kitaoka 120a6e
    node = remove_ptr(&root->left, keyptr, usrcmp, dup);
Shinya Kitaoka 120a6e
    if (node && node->bal == LESS) {
Shinya Kitaoka 120a6e
      /* left subtree depth decreased */
Shinya Kitaoka 120a6e
      switch (root->bal) {
Shinya Kitaoka 120a6e
      case LEFT:
Shinya Kitaoka 120a6e
        root->bal = BAL;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      case BAL:
Shinya Kitaoka 120a6e
        root->bal = RIGHT;
Shinya Kitaoka 120a6e
        node->bal = SAME;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      case RIGHT:
Shinya Kitaoka 120a6e
        root->bal = RIGHTUNBAL;
Shinya Kitaoka 120a6e
        node->bal = rebalance(rootaddr);
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else if (cmp > 0) {
Shinya Kitaoka 120a6e
    if (!root->right) return NIL;
Shinya Kitaoka 120a6e
    node = remove_ptr(&root->right, keyptr, usrcmp, dup);
Shinya Kitaoka 120a6e
    if (node && node->bal == LESS) {
Shinya Kitaoka 120a6e
      /* right subtree depth decreased */
Shinya Kitaoka 120a6e
      switch (root->bal) {
Shinya Kitaoka 120a6e
      case RIGHT:
Shinya Kitaoka 120a6e
        root->bal = BAL;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      case BAL:
Shinya Kitaoka 120a6e
        root->bal = LEFT;
Shinya Kitaoka 120a6e
        node->bal = SAME;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      case LEFT:
Shinya Kitaoka 120a6e
        root->bal = LEFTUNBAL;
Shinya Kitaoka 120a6e
        node->bal = rebalance(rootaddr);
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    if (dup && root->left &&
Shinya Kitaoka 120a6e
        (node = remove_ptr(&root->left, keyptr, usrcmp, dup))) {
Shinya Kitaoka 120a6e
      if (node->bal == LESS) {
Shinya Kitaoka 120a6e
        /* left subtree depth decreased */
Shinya Kitaoka 120a6e
        switch (root->bal) {
Shinya Kitaoka 120a6e
        case LEFT:
Shinya Kitaoka 120a6e
          root->bal = BAL;
Shinya Kitaoka 120a6e
          break;
Shinya Kitaoka 120a6e
        case BAL:
Shinya Kitaoka 120a6e
          root->bal = RIGHT;
Shinya Kitaoka 120a6e
          node->bal = SAME;
Shinya Kitaoka 120a6e
          break;
Shinya Kitaoka 120a6e
        case RIGHT:
Shinya Kitaoka 120a6e
          root->bal = RIGHTUNBAL;
Shinya Kitaoka 120a6e
          node->bal = rebalance(rootaddr);
Shinya Kitaoka 120a6e
          break;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      node = root;
Shinya Kitaoka 120a6e
      if (!node->right) {
Shinya Kitaoka 120a6e
        *rootaddr = node->left;
Shinya Kitaoka 120a6e
        node->bal = LESS;
Shinya Kitaoka 120a6e
      } else if (!node->left) {
Shinya Kitaoka 120a6e
        *rootaddr = node->right;
Shinya Kitaoka 120a6e
        node->bal = LESS;
Shinya Kitaoka 120a6e
      } else /* replace by the leftmost node of the right subtree */
Shinya Kitaoka 120a6e
      {
Shinya Kitaoka 120a6e
        root        = leftmost(&node->right);
Shinya Kitaoka 120a6e
        root->left  = node->left;
Shinya Kitaoka 120a6e
        root->right = node->right;
Shinya Kitaoka 120a6e
        if (root->bal == LESS) {
Shinya Kitaoka 120a6e
          /* right subtree depth decreased */
Shinya Kitaoka 120a6e
          switch (node->bal) {
Shinya Kitaoka 120a6e
          case RIGHT:
Shinya Kitaoka 120a6e
            root->bal = BAL;
Shinya Kitaoka 120a6e
            node->bal = LESS;
Shinya Kitaoka 120a6e
            break;
Shinya Kitaoka 120a6e
          case BAL:
Shinya Kitaoka 120a6e
            root->bal = LEFT;
Shinya Kitaoka 120a6e
            node->bal = SAME;
Shinya Kitaoka 120a6e
            break;
Shinya Kitaoka 120a6e
          case LEFT:
Shinya Kitaoka 120a6e
            root->bal = LEFTUNBAL;
Shinya Kitaoka 120a6e
            node->bal = rebalance(&root);
Shinya Kitaoka 120a6e
            break;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        } else {
Shinya Kitaoka 120a6e
          root->bal = node->bal;
Shinya Kitaoka 120a6e
          node->bal = SAME;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
        *rootaddr = root;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return node;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
static NODE *remove_val(NODE **rootaddr, long keyval, int dup) {
Shinya Kitaoka 120a6e
  NODE *root = *rootaddr;
Shinya Kitaoka 120a6e
  NODE *node;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (keyval < root->key.val) {
Shinya Kitaoka 120a6e
    if (!root->left) return NIL;
Shinya Kitaoka 120a6e
    node = remove_val(&root->left, keyval, dup);
Shinya Kitaoka 120a6e
    if (node && node->bal == LESS) {
Shinya Kitaoka 120a6e
      /* left subtree depth decreased */
Shinya Kitaoka 120a6e
      switch (root->bal) {
Shinya Kitaoka 120a6e
      case LEFT:
Shinya Kitaoka 120a6e
        root->bal = BAL;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      case BAL:
Shinya Kitaoka 120a6e
        root->bal = RIGHT;
Shinya Kitaoka 120a6e
        node->bal = SAME;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      case RIGHT:
Shinya Kitaoka 120a6e
        root->bal = RIGHTUNBAL;
Shinya Kitaoka 120a6e
        node->bal = rebalance(rootaddr);
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else if (keyval > root->key.val) {
Shinya Kitaoka 120a6e
    if (!root->right) return NIL;
Shinya Kitaoka 120a6e
    node = remove_val(&root->right, keyval, dup);
Shinya Kitaoka 120a6e
    if (node && node->bal == LESS) {
Shinya Kitaoka 120a6e
      /* right subtree depth decreased */
Shinya Kitaoka 120a6e
      switch (root->bal) {
Shinya Kitaoka 120a6e
      case RIGHT:
Shinya Kitaoka 120a6e
        root->bal = BAL;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      case BAL:
Shinya Kitaoka 120a6e
        root->bal = LEFT;
Shinya Kitaoka 120a6e
        node->bal = SAME;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      case LEFT:
Shinya Kitaoka 120a6e
        root->bal = LEFTUNBAL;
Shinya Kitaoka 120a6e
        node->bal = rebalance(rootaddr);
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    if (dup && root->left && (node = remove_val(&root->left, keyval, dup))) {
Shinya Kitaoka 120a6e
      if (node->bal == LESS) {
Shinya Kitaoka 120a6e
        /* left subtree depth decreased */
Shinya Kitaoka 120a6e
        switch (root->bal) {
Shinya Kitaoka 120a6e
        case LEFT:
Shinya Kitaoka 120a6e
          root->bal = BAL;
Shinya Kitaoka 120a6e
          break;
Shinya Kitaoka 120a6e
        case BAL:
Shinya Kitaoka 120a6e
          root->bal = RIGHT;
Shinya Kitaoka 120a6e
          node->bal = SAME;
Shinya Kitaoka 120a6e
          break;
Shinya Kitaoka 120a6e
        case RIGHT:
Shinya Kitaoka 120a6e
          root->bal = RIGHTUNBAL;
Shinya Kitaoka 120a6e
          node->bal = rebalance(rootaddr);
Shinya Kitaoka 120a6e
          break;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      node = root;
Shinya Kitaoka 120a6e
      if (!node->right) {
Shinya Kitaoka 120a6e
        *rootaddr = node->left;
Shinya Kitaoka 120a6e
        node->bal = LESS;
Shinya Kitaoka 120a6e
      } else if (!node->left) {
Shinya Kitaoka 120a6e
        *rootaddr = node->right;
Shinya Kitaoka 120a6e
        node->bal = LESS;
Shinya Kitaoka 120a6e
      } else /* replace by the leftmost node of the right subtree */
Shinya Kitaoka 120a6e
      {
Shinya Kitaoka 120a6e
        root        = leftmost(&node->right);
Shinya Kitaoka 120a6e
        root->left  = node->left;
Shinya Kitaoka 120a6e
        root->right = node->right;
Shinya Kitaoka 120a6e
        if (root->bal == LESS) {
Shinya Kitaoka 120a6e
          /* right subtree depth decreased */
Shinya Kitaoka 120a6e
          switch (node->bal) {
Shinya Kitaoka 120a6e
          case RIGHT:
Shinya Kitaoka 120a6e
            root->bal = BAL;
Shinya Kitaoka 120a6e
            node->bal = LESS;
Shinya Kitaoka 120a6e
            break;
Shinya Kitaoka 120a6e
          case BAL:
Shinya Kitaoka 120a6e
            root->bal = LEFT;
Shinya Kitaoka 120a6e
            node->bal = SAME;
Shinya Kitaoka 120a6e
            break;
Shinya Kitaoka 120a6e
          case LEFT:
Shinya Kitaoka 120a6e
            root->bal = LEFTUNBAL;
Shinya Kitaoka 120a6e
            node->bal = rebalance(&root);
Shinya Kitaoka 120a6e
            break;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        } else {
Shinya Kitaoka 120a6e
          root->bal = node->bal;
Shinya Kitaoka 120a6e
          node->bal = SAME;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
        *rootaddr = root;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return node;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void *avl__remove(TREE *tree, long keyval) {
Shinya Kitaoka 120a6e
  NODE *node;
Shinya Kitaoka 120a6e
  void *data;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (tree->root) {
Shinya Kitaoka 120a6e
    switch (LOCTYPE(tree->keyinfo)) {
Shinya Kitaoka 120a6e
    case USR_NODUP:
Shinya Kitaoka 120a6e
      node = remove_ptr(&tree->root, (void *)keyval, tree->usrcmp, NODUP);
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    case STR_NODUP:
Shinya Kitaoka 120a6e
      node = remove_ptr(&tree->root, (void *)keyval, AVL_AVLCMP, NODUP);
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    case COR_NODUP:
Shinya Kitaoka 120a6e
      keyval = CORRECT(keyval);
Shinya Kitaoka 120a6e
    // fallthrough
Shinya Kitaoka 120a6e
    case VAL_NODUP:
Shinya Kitaoka 120a6e
      node = remove_val(&tree->root, keyval, NODUP);
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    case USR_DUP:
Shinya Kitaoka 120a6e
      node = remove_ptr(&tree->root, (void *)keyval, tree->usrcmp, DUP);
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    case STR_DUP:
Shinya Kitaoka 120a6e
      node = remove_ptr(&tree->root, (void *)keyval, AVL_AVLCMP, DUP);
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    case COR_DUP:
Shinya Kitaoka 120a6e
      keyval = CORRECT(keyval);
Shinya Kitaoka 120a6e
    // fallthrough
Shinya Kitaoka 120a6e
    case VAL_DUP:
Shinya Kitaoka 120a6e
      node = remove_val(&tree->root, keyval, DUP);
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (node) {
Shinya Kitaoka 120a6e
      tree->nodes--;
Shinya Kitaoka 120a6e
      if (tree->path) {
Shinya Kitaoka 120a6e
        FREE_PATH(tree->path)
Shinya Kitaoka 120a6e
        tree->path = NIL;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      data = node->data;
Shinya Kitaoka 120a6e
      FREE_NODE(node)
Shinya Kitaoka 120a6e
      return data;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return NIL;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*===========================================================================*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
static void scan_subtree(NODE *root, void (*usrfun)(void *)) {
Shinya Kitaoka 120a6e
  if (root->left) scan_subtree(root->left, usrfun);
Shinya Kitaoka 120a6e
  (*usrfun)(root->data);
Shinya Kitaoka 120a6e
  if (root->right) scan_subtree(root->right, usrfun);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
static void backscan_subtree(NODE *root, void (*usrfun)(void *)) {
Shinya Kitaoka 120a6e
  if (root->right) backscan_subtree(root->right, usrfun);
Shinya Kitaoka 120a6e
  (*usrfun)(root->data);
Shinya Kitaoka 120a6e
  if (root->left) backscan_subtree(root->left, usrfun);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void avl__scan(TREE *tree, void (*usrfun)(void *), int back) {
Shinya Kitaoka 120a6e
  if (tree->root) {
Shinya Kitaoka 120a6e
    if (back)
Shinya Kitaoka 120a6e
      backscan_subtree(tree->root, usrfun);
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      scan_subtree(tree->root, usrfun);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*===========================================================================*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void *avl_first(TREE *tree) {
Shinya Kitaoka 120a6e
  PATH *path;
Shinya Kitaoka 120a6e
  char *pathright;
Shinya Kitaoka 120a6e
  NODE **pathnode;
Shinya Kitaoka 120a6e
  NODE *node;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!tree->root) return NIL;
Shinya Kitaoka 120a6e
  if (!tree->path) {
Shinya Kitaoka 120a6e
    ALLOC_PATH(path)
Shinya Kitaoka 120a6e
    if (!path) return NIL;
Shinya Kitaoka 120a6e
    tree->path = path;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    path = tree->path;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  pathnode     = &path->node[0];
Shinya Kitaoka 120a6e
  pathright    = &path->right[1];
Shinya Kitaoka 120a6e
  *pathnode    = NIL; /* sentinels */
Shinya Kitaoka 120a6e
  *pathright   = TRUE;
Shinya Kitaoka 120a6e
  *++pathnode  = NIL;
Shinya Kitaoka 120a6e
  *++pathright = FALSE;
Shinya Kitaoka 120a6e
  *++pathnode = node = tree->root;
Shinya Kitaoka 120a6e
  while ((node = node->left)) {
Shinya Kitaoka 120a6e
    *++pathright = FALSE;
Shinya Kitaoka 120a6e
    *++pathnode  = node;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  path->pathright = pathright;
Shinya Kitaoka 120a6e
  path->pathnode  = pathnode;
Shinya Kitaoka 120a6e
  return (*pathnode)->data;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void *avl_last(TREE *tree) {
Shinya Kitaoka 120a6e
  PATH *path;
Shinya Kitaoka 120a6e
  char *pathright;
Shinya Kitaoka 120a6e
  NODE **pathnode;
Shinya Kitaoka 120a6e
  NODE *node;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!tree->root) return NIL;
Shinya Kitaoka 120a6e
  if (!tree->path) {
Shinya Kitaoka 120a6e
    ALLOC_PATH(path)
Shinya Kitaoka 120a6e
    if (!path) return NIL;
Shinya Kitaoka 120a6e
    tree->path = path;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    path = tree->path;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  pathnode     = &path->node[0];
Shinya Kitaoka 120a6e
  pathright    = &path->right[1];
Shinya Kitaoka 120a6e
  *pathnode    = NIL; /* sentinels */
Shinya Kitaoka 120a6e
  *pathright   = FALSE;
Shinya Kitaoka 120a6e
  *++pathnode  = NIL;
Shinya Kitaoka 120a6e
  *++pathright = TRUE;
Shinya Kitaoka 120a6e
  *++pathnode = node = tree->root;
Shinya Kitaoka 120a6e
  while ((node = node->right)) {
Shinya Kitaoka 120a6e
    *++pathright = TRUE;
Shinya Kitaoka 120a6e
    *++pathnode  = node;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  path->pathright = pathright;
Shinya Kitaoka 120a6e
  path->pathnode  = pathnode;
Shinya Kitaoka 120a6e
  return (*pathnode)->data;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
#define DOWN_RIGHT_OR_BREAK(node, pathright, pathnode)                         \
Shinya Kitaoka 120a6e
  {                                                                            \
Shinya Kitaoka 120a6e
    if ((node = node->right)) {                                                \
Shinya Kitaoka 120a6e
      *++pathright = TRUE;                                                     \
Shinya Kitaoka 120a6e
      *++pathnode  = node;                                                     \
Shinya Kitaoka 120a6e
    } else                                                                     \
Shinya Kitaoka 120a6e
      break;                                                                   \
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
#define DOWN_LEFT_OR_BREAK(node, pathright, pathnode)                          \
Shinya Kitaoka 120a6e
  {                                                                            \
Shinya Kitaoka 120a6e
    if ((node = node->left)) {                                                 \
Shinya Kitaoka 120a6e
      *++pathright = FALSE;                                                    \
Shinya Kitaoka 120a6e
      *++pathnode  = node;                                                     \
Shinya Kitaoka 120a6e
    } else                                                                     \
Shinya Kitaoka 120a6e
      break;                                                                   \
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
#define START_OK_AND_RETURN(path, _pathright, _pathnode)                       \
Shinya Kitaoka 120a6e
  {                                                                            \
Shinya Kitaoka 120a6e
    path->pathright = _pathright;                                              \
Shinya Kitaoka 120a6e
    path->pathnode  = _pathnode;                                               \
Shinya Kitaoka 120a6e
    return (*_pathnode)->data;                                                 \
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void *avl__start(TREE *tree, long keyval, int back) {
Shinya Kitaoka 120a6e
  PATH *path;
Shinya Kitaoka 120a6e
  char *pathright;
Shinya Kitaoka 120a6e
  NODE **pathnode;
Shinya Kitaoka 120a6e
  NODE *node;
Shinya Kitaoka 120a6e
  char *saveright;
Shinya Kitaoka 120a6e
  NODE **savenode;
Shinya Kitaoka 120a6e
  int (*usrcmp)(void *, void *);
Shinya Kitaoka 120a6e
  int cmp;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!tree->root) return NIL;
Shinya Kitaoka 120a6e
  if (!tree->path) {
Shinya Kitaoka 120a6e
    ALLOC_PATH(path)
Shinya Kitaoka 120a6e
    if (!path) return NIL;
Shinya Kitaoka 120a6e
    tree->path = path;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    path = tree->path;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  pathnode     = &path->node[0];
Shinya Kitaoka 120a6e
  pathright    = &path->right[1];
Shinya Kitaoka 120a6e
  saveright    = NIL;
Shinya Kitaoka 120a6e
  savenode     = NIL;
Shinya Kitaoka 120a6e
  *pathnode    = NIL; /* sentinels */
Shinya Kitaoka 120a6e
  *pathright   = !back;
Shinya Kitaoka 120a6e
  *++pathnode  = NIL;
Shinya Kitaoka 120a6e
  *++pathright = back;
Shinya Kitaoka 120a6e
  *++pathnode = node = tree->root;
Shinya Kitaoka 120a6e
  switch (LOCTYPE(tree->keyinfo)) {
Shinya Kitaoka 120a6e
  case USR_NODUP:
Shinya Kitaoka 120a6e
  case STR_NODUP:
Shinya Kitaoka 120a6e
    usrcmp = tree->usrcmp;
Shinya Kitaoka 120a6e
    if (back) {
Shinya Kitaoka 120a6e
      for (;;) {
Shinya Kitaoka 120a6e
        SET_PTRCMP(cmp, usrcmp, (void *)keyval, node->key.ptr);
Shinya Kitaoka 120a6e
        if (cmp > 0) {
Shinya Kitaoka 120a6e
          saveright = pathright;
Shinya Kitaoka 120a6e
          savenode  = pathnode;
Shinya Kitaoka 120a6e
          DOWN_RIGHT_OR_BREAK(node, pathright, pathnode);
Shinya Kitaoka 120a6e
        } else if (cmp < 0) {
Shinya Kitaoka 120a6e
          DOWN_LEFT_OR_BREAK(node, pathright, pathnode);
Shinya Kitaoka 120a6e
        } else {
Shinya Kitaoka 120a6e
          START_OK_AND_RETURN(path, pathright, pathnode);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      for (;;) {
Shinya Kitaoka 120a6e
        SET_PTRCMP(cmp, usrcmp, (void *)keyval, node->key.ptr);
Shinya Kitaoka 120a6e
        if (cmp < 0) {
Shinya Kitaoka 120a6e
          saveright = pathright;
Shinya Kitaoka 120a6e
          savenode  = pathnode;
Shinya Kitaoka 120a6e
          DOWN_LEFT_OR_BREAK(node, pathright, pathnode);
Shinya Kitaoka 120a6e
        } else if (cmp > 0) {
Shinya Kitaoka 120a6e
          DOWN_RIGHT_OR_BREAK(node, pathright, pathnode);
Shinya Kitaoka 120a6e
        } else {
Shinya Kitaoka 120a6e
          START_OK_AND_RETURN(path, pathright, pathnode);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case COR_NODUP:
Shinya Kitaoka 120a6e
    keyval = CORRECT(keyval);
Shinya Kitaoka 120a6e
  // fallthrough
Shinya Kitaoka 120a6e
  case VAL_NODUP:
Shinya Kitaoka 120a6e
    if (back) {
Shinya Kitaoka 120a6e
      for (;;) {
Shinya Kitaoka 120a6e
        if (keyval > node->key.val) {
Shinya Kitaoka 120a6e
          saveright = pathright;
Shinya Kitaoka 120a6e
          savenode  = pathnode;
Shinya Kitaoka 120a6e
          DOWN_RIGHT_OR_BREAK(node, pathright, pathnode);
Shinya Kitaoka 120a6e
        } else if (keyval < node->key.val) {
Shinya Kitaoka 120a6e
          DOWN_LEFT_OR_BREAK(node, pathright, pathnode);
Shinya Kitaoka 120a6e
        } else {
Shinya Kitaoka 120a6e
          START_OK_AND_RETURN(path, pathright, pathnode);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      for (;;) {
Shinya Kitaoka 120a6e
        if (keyval < node->key.val) {
Shinya Kitaoka 120a6e
          saveright = pathright;
Shinya Kitaoka 120a6e
          savenode  = pathnode;
Shinya Kitaoka 120a6e
          DOWN_LEFT_OR_BREAK(node, pathright, pathnode);
Shinya Kitaoka 120a6e
        } else if (keyval > node->key.val) {
Shinya Kitaoka 120a6e
          DOWN_RIGHT_OR_BREAK(node, pathright, pathnode);
Shinya Kitaoka 120a6e
        } else {
Shinya Kitaoka 120a6e
          START_OK_AND_RETURN(path, pathright, pathnode);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case USR_DUP:
Shinya Kitaoka 120a6e
  case STR_DUP:
Shinya Kitaoka 120a6e
    usrcmp = tree->usrcmp;
Shinya Kitaoka 120a6e
    if (back) {
Shinya Kitaoka 120a6e
      for (;;) {
Shinya Kitaoka 120a6e
        SET_PTRCMP(cmp, usrcmp, (void *)keyval, node->key.ptr);
Shinya Kitaoka 120a6e
        if (cmp >= 0) {
Shinya Kitaoka 120a6e
          saveright = pathright;
Shinya Kitaoka 120a6e
          savenode  = pathnode;
Shinya Kitaoka 120a6e
          DOWN_RIGHT_OR_BREAK(node, pathright, pathnode);
Shinya Kitaoka 120a6e
        } else {
Shinya Kitaoka 120a6e
          DOWN_LEFT_OR_BREAK(node, pathright, pathnode);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      for (;;) {
Shinya Kitaoka 120a6e
        SET_PTRCMP(cmp, usrcmp, (void *)keyval, node->key.ptr);
Shinya Kitaoka 120a6e
        if (cmp <= 0) {
Shinya Kitaoka 120a6e
          saveright = pathright;
Shinya Kitaoka 120a6e
          savenode  = pathnode;
Shinya Kitaoka 120a6e
          DOWN_LEFT_OR_BREAK(node, pathright, pathnode);
Shinya Kitaoka 120a6e
        } else {
Shinya Kitaoka 120a6e
          DOWN_RIGHT_OR_BREAK(node, pathright, pathnode);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case COR_DUP:
Shinya Kitaoka 120a6e
    keyval = CORRECT(keyval);
Shinya Kitaoka 120a6e
  // fallthrough
Shinya Kitaoka 120a6e
  case VAL_DUP:
Shinya Kitaoka 120a6e
    if (back) {
Shinya Kitaoka 120a6e
      for (;;) {
Shinya Kitaoka 120a6e
        if (keyval >= node->key.val) {
Shinya Kitaoka 120a6e
          saveright = pathright;
Shinya Kitaoka 120a6e
          savenode  = pathnode;
Shinya Kitaoka 120a6e
          DOWN_RIGHT_OR_BREAK(node, pathright, pathnode);
Shinya Kitaoka 120a6e
        } else {
Shinya Kitaoka 120a6e
          DOWN_LEFT_OR_BREAK(node, pathright, pathnode);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      for (;;) {
Shinya Kitaoka 120a6e
        if (keyval <= node->key.val) {
Shinya Kitaoka 120a6e
          saveright = pathright;
Shinya Kitaoka 120a6e
          savenode  = pathnode;
Shinya Kitaoka 120a6e
          DOWN_LEFT_OR_BREAK(node, pathright, pathnode);
Shinya Kitaoka 120a6e
        } else {
Shinya Kitaoka 120a6e
          DOWN_RIGHT_OR_BREAK(node, pathright, pathnode);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (savenode) {
Shinya Kitaoka 120a6e
    path->pathright = saveright;
Shinya Kitaoka 120a6e
    path->pathnode  = savenode;
Shinya Kitaoka 120a6e
    return (*savenode)->data;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    FREE_PATH(path)
Shinya Kitaoka 120a6e
    tree->path = NIL;
Shinya Kitaoka 120a6e
    return NIL;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void *avl_next(TREE *tree) {
Shinya Kitaoka 120a6e
  PATH *path;
Shinya Kitaoka 120a6e
  char *pathright;
Shinya Kitaoka 120a6e
  NODE **pathnode;
Shinya Kitaoka 120a6e
  NODE *node;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  path = tree->path;
Shinya Kitaoka 120a6e
  if (!path) return NIL;
Shinya Kitaoka 120a6e
  pathright = path->pathright;
Shinya Kitaoka 120a6e
  pathnode  = path->pathnode;
Shinya Kitaoka 120a6e
  if ((node = (*pathnode)->right)) {
Shinya Kitaoka 120a6e
    *++pathright = TRUE;
Shinya Kitaoka 120a6e
    *++pathnode  = node;
Shinya Kitaoka 120a6e
    while ((node = node->left)) {
Shinya Kitaoka 120a6e
      *++pathright = FALSE;
Shinya Kitaoka 120a6e
      *++pathnode  = node;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    while (*pathright) {
Shinya Kitaoka 120a6e
      --pathright;
Shinya Kitaoka 120a6e
      --pathnode;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    --pathright;
Shinya Kitaoka 120a6e
    --pathnode;
Shinya Kitaoka 120a6e
    if (!*pathnode) {
Shinya Kitaoka 120a6e
      FREE_PATH(path)
Shinya Kitaoka 120a6e
      tree->path = NIL;
Shinya Kitaoka 120a6e
      return NIL;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  path->pathright = pathright;
Shinya Kitaoka 120a6e
  path->pathnode  = pathnode;
Shinya Kitaoka 120a6e
  return (*pathnode)->data;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void *avl_prev(TREE *tree) {
Shinya Kitaoka 120a6e
  PATH *path;
Shinya Kitaoka 120a6e
  char *pathright;
Shinya Kitaoka 120a6e
  NODE **pathnode;
Shinya Kitaoka 120a6e
  NODE *node;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  path = tree->path;
Shinya Kitaoka 120a6e
  if (!path) return NIL;
Shinya Kitaoka 120a6e
  pathright = path->pathright;
Shinya Kitaoka 120a6e
  pathnode  = path->pathnode;
Shinya Kitaoka 120a6e
  if ((node = (*pathnode)->left)) {
Shinya Kitaoka 120a6e
    *++pathright = FALSE;
Shinya Kitaoka 120a6e
    *++pathnode  = node;
Shinya Kitaoka 120a6e
    while ((node = node->right)) {
Shinya Kitaoka 120a6e
      *++pathright = TRUE;
Shinya Kitaoka 120a6e
      *++pathnode  = node;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    while (!*pathright) {
Shinya Kitaoka 120a6e
      --pathright;
Shinya Kitaoka 120a6e
      --pathnode;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    --pathright;
Shinya Kitaoka 120a6e
    --pathnode;
Shinya Kitaoka 120a6e
    if (!*pathnode) {
Shinya Kitaoka 120a6e
      FREE_PATH(path)
Shinya Kitaoka 120a6e
      tree->path = NIL;
Shinya Kitaoka 120a6e
      return NIL;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  path->pathright = pathright;
Shinya Kitaoka 120a6e
  path->pathnode  = pathnode;
Shinya Kitaoka 120a6e
  return (*pathnode)->data;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void avl_stop(TREE *tree) {
Shinya Kitaoka 120a6e
  if (tree->path) {
Shinya Kitaoka 120a6e
    FREE_PATH(tree->path)
Shinya Kitaoka 120a6e
    tree->path = NIL;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*===========================================================================*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
static uint Offset;
Toshihiro Shimizu 890ddd
static void *Save;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
static void link_subtree(NODE *node) {
Shinya Kitaoka 120a6e
  if (node->right) link_subtree(node->right);
Shinya Kitaoka 120a6e
  *(void **)((char *)node->data + Offset) = Save;
Shinya Kitaoka 120a6e
  Save                                    = node->data;
Shinya Kitaoka 120a6e
  if (node->left) link_subtree(node->left);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
static void backlink_subtree(NODE *node) {
Shinya Kitaoka 120a6e
  if (node->left) backlink_subtree(node->left);
Shinya Kitaoka 120a6e
  *(void **)((char *)node->data + Offset) = Save;
Shinya Kitaoka 120a6e
  Save                                    = node->data;
Shinya Kitaoka 120a6e
  if (node->right) backlink_subtree(node->right);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void *avl__link(TREE *tree, uint ptroffs, int back) {
Shinya Kitaoka 120a6e
  Offset = ptroffs;
Shinya Kitaoka 120a6e
  Save   = NIL;
Shinya Kitaoka 120a6e
  if (tree->root) {
Shinya Kitaoka 120a6e
    if (back)
Shinya Kitaoka 120a6e
      backlink_subtree(tree->root);
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      link_subtree(tree->root);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return Save;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*===========================================================================*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
static void release_subtree(NODE *root, void (*usrfun)(void *)) {
Shinya Kitaoka 120a6e
  if (root->left) release_subtree(root->left, usrfun);
Shinya Kitaoka 120a6e
  if (root->right) release_subtree(root->right, usrfun);
Shinya Kitaoka 120a6e
  (*usrfun)(root->data);
Shinya Kitaoka 120a6e
  FREE_NODE(root)
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
static void reset_subtree(NODE *root) {
Shinya Kitaoka 120a6e
  if (root->left) reset_subtree(root->left);
Shinya Kitaoka 120a6e
  if (root->right) reset_subtree(root->right);
Shinya Kitaoka 120a6e
  FREE_NODE(root)
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void avl_release(TREE *tree, void (*usrfun)(void *)) {
Shinya Kitaoka 120a6e
  if (tree->root) release_subtree(tree->root, usrfun);
Shinya Kitaoka 120a6e
  tree->root  = NIL;
Shinya Kitaoka 120a6e
  tree->nodes = 0;
Shinya Kitaoka 120a6e
  if (tree->path) {
Shinya Kitaoka 120a6e
    FREE_PATH(tree->path)
Shinya Kitaoka 120a6e
    tree->path = NIL;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void avl_reset(TREE *tree) {
Shinya Kitaoka 120a6e
  if (tree->root) reset_subtree(tree->root);
Shinya Kitaoka 120a6e
  tree->root  = NIL;
Shinya Kitaoka 120a6e
  tree->nodes = 0;
Shinya Kitaoka 120a6e
  if (tree->path) {
Shinya Kitaoka 120a6e
    FREE_PATH(tree->path)
Shinya Kitaoka 120a6e
    tree->path = NIL;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void avl_close(TREE *tree) {
Shinya Kitaoka 120a6e
  if (tree->root) reset_subtree(tree->root);
Shinya Kitaoka 120a6e
  if (tree->path) FREE_PATH(tree->path)
Shinya Kitaoka 120a6e
  tree->keyinfo = (ushort)ERROR;
Shinya Kitaoka 120a6e
  FREE_TREE(tree)
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*===========================================================================*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
static int copy_subtree(NODE *newroot, NODE *root) {
Shinya Kitaoka 120a6e
  newroot->key  = root->key;
Shinya Kitaoka 120a6e
  newroot->data = root->data;
Shinya Kitaoka 120a6e
  newroot->bal  = root->bal;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (root->left) {
Shinya Kitaoka 120a6e
    ALLOC_NODE(newroot->left)
Shinya Kitaoka 120a6e
    if (!newroot->left) return FALSE;
Shinya Kitaoka 120a6e
    if (!copy_subtree(newroot->left, root->left)) {
Shinya Kitaoka 120a6e
      FREE_NODE(newroot->left);
Shinya Kitaoka 120a6e
      return FALSE;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    newroot->left = NIL;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (root->right) {
Shinya Kitaoka 120a6e
    ALLOC_NODE(newroot->right)
Shinya Kitaoka 120a6e
    if (!newroot->right) return FALSE;
Shinya Kitaoka 120a6e
    if (!copy_subtree(newroot->right, root->right)) {
Shinya Kitaoka 120a6e
      FREE_NODE(newroot->right);
Shinya Kitaoka 120a6e
      return FALSE;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    newroot->right = NIL;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return TRUE;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TREE *avl_copy(TREE *tree) {
Shinya Kitaoka 120a6e
  TREE *newtree;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ALLOC_TREE(newtree)
Shinya Kitaoka 120a6e
  if (!newtree) return NIL;
Shinya Kitaoka 120a6e
  newtree->keyinfo = tree->keyinfo;
Shinya Kitaoka 120a6e
  newtree->keyoffs = tree->keyoffs;
Shinya Kitaoka 120a6e
  newtree->usrcmp  = tree->usrcmp;
Shinya Kitaoka 120a6e
  newtree->nodes   = tree->nodes;
Shinya Kitaoka 120a6e
  newtree->path    = NIL;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (tree->root) {
Shinya Kitaoka 120a6e
    ALLOC_NODE(newtree->root)
Shinya Kitaoka 120a6e
    if (!copy_subtree(newtree->root, tree->root)) {
Shinya Kitaoka 120a6e
      FREE_NODE(newtree->root)
Shinya Kitaoka 120a6e
      avl_close(newtree);
Shinya Kitaoka 120a6e
      return NIL;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    newtree->root = NIL;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return newtree;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*===========================================================================*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
static void **Dat;
Toshihiro Shimizu 890ddd
static int *Lev;
Toshihiro Shimizu 890ddd
static int *Pos;
Toshihiro Shimizu 890ddd
static int Nod;
Toshihiro Shimizu 890ddd
static int Max_Lev;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
static void dump_subtree(struct avl_node *root, int lev, int pos) {
Shinya Kitaoka 120a6e
  if (root->left) dump_subtree(root->left, lev + 1, pos * 2);
Shinya Kitaoka 120a6e
  Dat[Nod]                   = root->data;
Shinya Kitaoka 120a6e
  Lev[Nod]                   = lev;
Shinya Kitaoka 120a6e
  Pos[Nod]                   = pos;
Shinya Kitaoka 120a6e
  if (lev > Max_Lev) Max_Lev = lev;
Shinya Kitaoka 120a6e
  Nod++;
Shinya Kitaoka 120a6e
  if (root->right) dump_subtree(root->right, lev + 1, pos * 2 + 1);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int avl_dump(TREE *tree, void **dat_vect, int *lev_vect, int *pos_vect) {
Shinya Kitaoka 120a6e
  Dat     = dat_vect;
Shinya Kitaoka 120a6e
  Lev     = lev_vect;
Shinya Kitaoka 120a6e
  Pos     = pos_vect;
Shinya Kitaoka 120a6e
  Nod     = 0;
Shinya Kitaoka 120a6e
  Max_Lev = -1;
Shinya Kitaoka 120a6e
  if (tree->root) dump_subtree(tree->root, 0, 0);
Shinya Kitaoka 120a6e
  return Max_Lev + 1;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*===========================================================================*/
Toshihiro Shimizu 890ddd
#ifdef LEVO
Shinya Kitaoka 120a6e
int avl_porting_problems(void) {
Shinya Kitaoka 120a6e
  long lng1, lng2;
Shinya Kitaoka 120a6e
  ushort ush1, ush2;
Shinya Kitaoka 120a6e
  char chr1, chr2;
Shinya Kitaoka 120a6e
  void *ptr1, *ptr2;
Shinya Kitaoka 120a6e
  struct s {
Shinya Kitaoka 120a6e
    char c[4];
Shinya Kitaoka 120a6e
  } * ps;
Shinya Kitaoka 120a6e
  int problems;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define PROBLEM(n) (problems |= 1 | (1 << (n)))
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  problems = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  Avl_Dummy[0]           = 0.0;
Shinya Kitaoka 120a6e
  Avl_Dummy[1]           = 0.0;
Shinya Kitaoka 120a6e
  ((char *)Avl_Dummy)[1] = 0x15;
Shinya Kitaoka 120a6e
  ptr1                   = (void *)((char *)Avl_Dummy + 1);
Shinya Kitaoka 120a6e
  lng1                   = (long)ptr1;
Shinya Kitaoka 120a6e
  ptr2                   = (void *)lng1;
Shinya Kitaoka 120a6e
  if (*(char *)ptr2 != (char)0x15) PROBLEM(1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ps       = (struct s *)malloc(sizeof(struct s));
Shinya Kitaoka 120a6e
  ps->c[0] = 0;
Shinya Kitaoka 120a6e
  ps->c[1] = 0x15;
Shinya Kitaoka 120a6e
  ps->c[2] = 0;
Shinya Kitaoka 120a6e
  ps->c[3] = 0;
Shinya Kitaoka 120a6e
  ptr1     = (void *)&ps->c[1];
Shinya Kitaoka 120a6e
  lng1     = (long)ptr1;
Shinya Kitaoka 120a6e
  ptr2     = (void *)lng1;
Shinya Kitaoka 120a6e
  if (*(char *)ptr2 != (char)0x15) PROBLEM(2);
Shinya Kitaoka 120a6e
  free(ps);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  chr1 = 1;
Shinya Kitaoka 120a6e
  chr2 = 250;
Shinya Kitaoka 120a6e
  lng1 = chr1;
Shinya Kitaoka 120a6e
  lng2 = chr2;
Shinya Kitaoka 120a6e
  if ((chr1 > chr2) && (lng1 < lng2) || (chr1 < chr2) && (lng1 > lng2))
Shinya Kitaoka 120a6e
    PROBLEM(3);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (sizeof(long) == sizeof(short)) PROBLEM(4);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (sizeof(char) != 1) PROBLEM(5);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ush1 = (ushort)-1;
Shinya Kitaoka 120a6e
  ush2 = (ushort)-2;
Shinya Kitaoka 120a6e
  lng1 = CORRECT(ush1);
Shinya Kitaoka 120a6e
  lng2 = CORRECT(ush2);
Shinya Kitaoka 120a6e
  if (!(lng1 > lng2)) PROBLEM(6);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  lng1 = CORRECT(0L);
Shinya Kitaoka 120a6e
  lng2 = lng1 - 1;
Shinya Kitaoka 120a6e
  if (!((lng1 < 0) && (lng2 > 0))) PROBLEM(7);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return problems;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
#define CDB_TCALLOC(ptr, elem)                                                 \
Shinya Kitaoka 120a6e
  { (ptr) = (void *)calloc((elem), sizeof(*(ptr))); }
Shinya Kitaoka 120a6e
#define CDB_TMALLOC(ptr, elem)                                                 \
Shinya Kitaoka 120a6e
  { (ptr) = (void *)malloc((elem) * sizeof(*(ptr))); }
Shinya Kitaoka 120a6e
#define CDB_TREALLOC(ptr, elem)                                                \
Shinya Kitaoka 120a6e
  { (ptr) = (void *)realloc((ptr), (elem) * sizeof(*(ptr))); }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
#define GET_STRING_FIELD(P, FIELD) (P ? (P->FIELD ? P->FIELD : "") : "")
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define AVL_FOR(tree, p) for ((p) = avl_first(tree); (p); (p) = avl_next(tree))
Shinya Kitaoka 120a6e
typedef struct {
Shinya Kitaoka 120a6e
  int index;
Shinya Kitaoka 120a6e
  char *name;
Toshihiro Shimizu 890ddd
} COLOR_NAME;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
typedef struct {
Shinya Kitaoka 120a6e
  char *name;
Shinya Kitaoka 120a6e
  char *value;
Toshihiro Shimizu 890ddd
} CDB_PARAM;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
typedef struct {
Shinya Kitaoka 120a6e
  char *name;
Shinya Kitaoka 120a6e
  int num_params;
Shinya Kitaoka 120a6e
  CDB_PARAM *param;
Toshihiro Shimizu 890ddd
} CDB_EFFECT;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
char *strsave(const char *str) {
Shinya Kitaoka 120a6e
  char *neww;
Shinya Kitaoka 120a6e
  if (!str) return 0;
Shinya Kitaoka 120a6e
  neww = malloc(strlen(str) + 1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  strcpy(neww, str);
Shinya Kitaoka 120a6e
  return neww;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
char *strnsave(const char *str, int n) {
Shinya Kitaoka 120a6e
  char *neww;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  neww = malloc(n + 1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  strncpy(neww, str, n);
Shinya Kitaoka 120a6e
  neww[n] = '\0';
Shinya Kitaoka 120a6e
  return neww;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TREE *cdb_decode_all(char *names_in_plt_file, TCM_INFO tcm) {
Shinya Kitaoka 120a6e
  TREE *tree;
Shinya Kitaoka 120a6e
  char *c1, *c2, *endcol, *endstr, *ct;
Shinya Kitaoka 120a6e
  char tmp[100];
Shinya Kitaoka 120a6e
  int i, p;
Shinya Kitaoka 120a6e
  CDB_TREE_ITEM *item;
Shinya Kitaoka 120a6e
  CDB_EFFECT *effect;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  tree = avl_tree_nodup_int(CDB_TREE_ITEM, index);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  item   = NIL;
Shinya Kitaoka 120a6e
  endstr = strchr(names_in_plt_file, '\0');
Shinya Kitaoka 120a6e
  c1     = names_in_plt_file;
Shinya Kitaoka 120a6e
  c2     = NIL;
Shinya Kitaoka 120a6e
  for (i = 0; i < tcm.n_colors + tcm.n_pencils; i++) {
Shinya Kitaoka 120a6e
    CDB_TCALLOC(item, 1)
Shinya Kitaoka 120a6e
    item->index = i;
Shinya Kitaoka 120a6e
    // if (i < tcm.n_colors)
Shinya Kitaoka 120a6e
    //  item->index = TCM_COLOR_INDEX (tcm, i);
Shinya Kitaoka 120a6e
    // else
Shinya Kitaoka 120a6e
    //  item->index = TCM_PENCIL_INDEX (tcm, i - tcm.n_colors);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    endcol              = strchr(c1, '|');
Shinya Kitaoka 120a6e
    if (!endcol) endcol = endstr;
Shinya Kitaoka 120a6e
    c2                  = strchr(c1, '\t');
Shinya Kitaoka 120a6e
    if (!c2) c2         = endcol;
Shinya Kitaoka 120a6e
    if (*c2 == '\t') {
Shinya Kitaoka 120a6e
      if (c2 - c1 == 1 && *c1 == '*')
Shinya Kitaoka 120a6e
        item->group = strsave("");
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        item->group = strnsave(c1, c2 - c1);
Shinya Kitaoka 120a6e
      c1            = c2 + 1;
Shinya Kitaoka 120a6e
      c2            = strchr(c1, '\t');
Shinya Kitaoka 120a6e
      if (!c2) c2   = endcol;
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      item->group = strsave("");
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    while (*c1 == '<' && c1[1] == '!') {
Shinya Kitaoka 120a6e
      c1 += 2;
Shinya Kitaoka 120a6e
      ct = strstr(c1, "!>");
Shinya Kitaoka 120a6e
      if (!ct) goto error;
Shinya Kitaoka 120a6e
      if (*c1 == 'A') {
Shinya Kitaoka 120a6e
        c1++;
Shinya Kitaoka 120a6e
        item->accelerator = strnsave(c1, ct - c1);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      /* else if (*c1 == 'to be defined')... */
Shinya Kitaoka 120a6e
      c1 = ct + 2;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (c2 - c1 == 1 && *c1 == '*')
Shinya Kitaoka 120a6e
      item->name = strsave("");
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      item->name = strnsave(c1, c2 - c1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (*c2 == '\t')
Shinya Kitaoka 120a6e
      c1 = c2 + 1;
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      c1 = c2;
Shinya Kitaoka 120a6e
    if (!*c1) {
Shinya Kitaoka 120a6e
    } else if (*c1 == '|')
Shinya Kitaoka 120a6e
      c1++;
Shinya Kitaoka 120a6e
    else {
Shinya Kitaoka 120a6e
      item->effects = avl_tree_nodup_str(CDB_EFFECT, name);
Shinya Kitaoka 120a6e
      for (;;) {
Shinya Kitaoka 120a6e
        ct = strstr(c1, " ! ");
Shinya Kitaoka 120a6e
        if (ct) NOT_MORE_THAN(ct, endcol)
Shinya Kitaoka 120a6e
        ct = strstr(c1, "#! ");
Shinya Kitaoka 120a6e
        if (ct) NOT_MORE_THAN(ct, endcol)
Shinya Kitaoka 120a6e
        c2 = strchr(c1, '#');
Shinya Kitaoka 120a6e
        if (!c2 || c2 >= endcol) break;
Shinya Kitaoka 120a6e
        CDB_TCALLOC(effect, 1)
Shinya Kitaoka 120a6e
        effect->name = strnsave(c1, c2 - c1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        c1 = c2 + 1;
Shinya Kitaoka 120a6e
        c2 = strchr(c1, '#');
Shinya Kitaoka 120a6e
        if (!c2) goto error;
Shinya Kitaoka 120a6e
        strncpy(tmp, c1, c2 - c1);
Shinya Kitaoka 120a6e
        tmp[c2 - c1]       = '\0';
Shinya Kitaoka 120a6e
        effect->num_params = atoi(tmp);
Shinya Kitaoka 120a6e
        if (effect->num_params) CDB_TCALLOC(effect->param, effect->num_params)
Shinya Kitaoka 120a6e
        c1 = c2 + 1;
Shinya Kitaoka 120a6e
        for (p = 0; p < effect->num_params; p++) {
Shinya Kitaoka 120a6e
          c2 = strchr(c1, '#');
Shinya Kitaoka 120a6e
          if (!c2) goto error;
Shinya Kitaoka 120a6e
          effect->param[p].name = strnsave(c1, c2 - c1);
Shinya Kitaoka 120a6e
          c1                    = c2 + 1;
Shinya Kitaoka 120a6e
          c2 = (p == effect->num_params - 1) ? endcol : strstr(c1, " : ");
Shinya Kitaoka 120a6e
          if (!c2) goto error;
Shinya Kitaoka 120a6e
          effect->param[p].value = strnsave(c1, c2 - c1);
Shinya Kitaoka 120a6e
          ct = effect->param[p].value + strlen(effect->param[p].value) - 1;
Shinya Kitaoka 120a6e
          while (ct >= effect->param[p].value && (*ct == ' ' || *ct == '\t'))
Shinya Kitaoka 120a6e
            *ct-- = '\0';
Shinya Kitaoka 120a6e
          c1      = c2 + 3;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
        avl_insert(item->effects, effect);
Shinya Kitaoka 120a6e
        item->num_effects++;
Shinya Kitaoka 120a6e
        if (*endcol != '|')
Shinya Kitaoka 120a6e
          c1 = endcol + 3;
Shinya Kitaoka 120a6e
        else {
Shinya Kitaoka 120a6e
          c1 = endcol + 1;
Shinya Kitaoka 120a6e
          break;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    avl_insert(tree, item);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return tree;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
error:
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  printf("error parsing color names and fx\n");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return tree;
Toshihiro Shimizu 890ddd
}