/* This file was generated by scm2c from source file "blink.scm" */
/*  "blink.scm" WB-tree File Based Associative String Data Base System. */
/*  Copyright (C) 1991, 1992, 1993, 2000, 2003, 2010 Free Software Foundation, Inc. */
/*  */
/*  This program is free software: you can redistribute it and/or modify */
/*  it under the terms of the GNU Lesser General Public License as */
/*  published by the Free Software Foundation, either version 3 of the */
/*  License, or (at your option) any later version. */
/*  */
/*  This program is distributed in the hope that it will be useful, but */
/*  WITHOUT ANY WARRANTY; without even the implied warranty of */
/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU */
/*  Lesser General Public License for more details. */
/*  */
/*  You should have received a copy of the GNU Lesser General Public */
/*  License along with this program.  If not, see */
/*  <http://www.gnu.org/licenses/>. */

/*  TBD: */
/*  allow different size blks for index and leaves. */
/*  add multi-record operations */

/*  uncomment for newlines at end of blocks: */

/*  uncomment for extra check in REROOT! and path tracing in BLK:FIND-POS. */
/* (provide 'DEBUG) */


#include "wbsys.h"

/*  BLK ACCESS AND MODIFICATION ROUTINES */


void short2str(str, pos, cint)
     unsigned char *str;
     int pos;
     int cint;
{
  str[(pos)+1] = (cint)&0xff;
  str[(pos)+0] = (cint)>>8;
  return;
}

short str2short(str, pos)
     unsigned char *str;
     int pos;
{
  return ((((unsigned char*)(str))[(pos)+1]))|(((((unsigned char*)(str))[pos]))<<8);
}


void long2str(str, pos, clong)
     unsigned char *str;
     int pos;
     long clong;
{
  str[(pos)+3] = (clong)&0xff;
  str[(pos)+2] = ((clong)>>8)&0xff;
  str[(pos)+1] = ((clong)>>0x10)&0xff;
  str[(pos)+0] = (clong)>>0x18;
  return;
}

long str2long(str, pos)
     unsigned char *str;
     int pos;
{
  return ((((unsigned char*)(str))[(pos)+3]))|((((((unsigned char*)(str))[(pos)+2]))|((((((unsigned char*)(str))[(pos)+1]))|(((((unsigned char*)(str))[pos]))<<0x8L))<<0x8L))<<0x8L);
}


int set_field(blk, b_pos, val_str, f_pos, f_len)
     unsigned char *blk;
     int b_pos;
     unsigned char *val_str;
     int f_pos;
     int f_len;
{
  set_field_len(blk, b_pos, f_len);
  subbytes_move(val_str, f_pos, (f_pos)+(f_len), blk, 1+(b_pos));
  return (f_len)+1+(b_pos);
}


unsigned char leaf_split_key_str[] = {0xff,(leaf)};


void init_leaf_blk(nblk, bnum, typ)
     unsigned char *nblk;
     long bnum;
     int typ;
{
  nblk[(blk_size)-1] = 0xa;
  blk_set_id(nblk, bnum);
  blk_set_nxt_id(nblk, 0);
  blk_set_top_id(nblk, bnum);
  blk_set_time(nblk, 0);
  blk_set_level(nblk, leaf);
  blk_set_typ(nblk, typ);
  set_field_len(nblk, blk_data_start, 0);
  set_field(nblk, (blk_data_start)+1, leaf_split_key_str, 0, 2);
  blk_set_end(nblk, (blk_data_start)+(
     ((typ)==(seq_typ)
       ?0
       :4)));
  return;
}

/* RBLK= the root block, NBLK= new block to hold root's data, BNUM= its ID */


void reroot(rblk, nblk, bnum, bsiz)
     unsigned char *rblk;
     unsigned char *nblk;
     long bnum;
     int bsiz;
{
  int rpos = blk_data_start;
  subbytes_move(rblk, 4, bsiz, nblk, 4);
  blk_set_nxt_id(rblk, 0);
  blk_set_level(rblk, (blk_level(rblk))+1);
  set_field_len(rblk, rpos, 0);
  rpos = set_field(rblk, (rpos)+1, leaf_split_key_str, 0, 2);
  rblk[(rpos)-1] = (blk_level(rblk))-1;
  rpos = set_field(rblk, rpos, nblk, 0, 4);
  set_field_len(rblk, rpos, 1);
  rpos = set_field(rblk, (rpos)+1, leaf_split_key_str, 0, 1);
  rblk[(rpos)-1] = blk_level(rblk);
  blk_set_end(rblk, rpos);
  return;
}


void init_next_blk(blk, nblk)
     unsigned char *blk;
     unsigned char *nblk;
{
  nblk[(blk_size)-1] = 0xa;
  blk_set_nxt_id(nblk, blk_nxt_id(blk));
  blk_set_top_id(nblk, blk_top_id(blk));
  blk_set_level(nblk, blk_level(blk));
  blk_set_typ(nblk, blk_typ(blk));
  blk_set_nxt_id(blk, blk_id(nblk));
  set_field_len(nblk, blk_data_start, 0);
  set_field(nblk, (blk_data_start)+1, no_byts, 0, 0);
  blk_set_end(nblk, (blk_data_start)+2);
  return;
}


int split_key_pos(blk)
     unsigned char *blk;
{
  int b_end = blk_end(blk);
  {
    int b_pos = blk_data_start;
L_lp:
    {
      int s_pos = next_field(blk, 1+(b_pos));
      if ((s_pos)==(b_end))
	return b_pos;
      else if ((s_pos)<(b_end))
	{
	  b_pos = next_cnvpair(blk, b_pos);
	  goto L_lp;
	}
      else {
	dprintf((diagout, ">>>>ERROR<<<< %s: blk past end %ld %d\n", "split_key_pos", blk_id(blk), s_pos));
	return 0;
      }
    }
  }
}


/*  Pass in len; -1 to seek END-OF-CHAIN; -2 for START-OF-CHAIN. */
/*  If key-str = END-OF-CHAIN, then return PASTEND @ split-pos. */
/*  If key-str = START-OF-CHAIN, then return QPASTP @ blk-data-start. */
/*  Otherwise, can return any of 5 match conditions. */

/*  As we go through blk looking for key, KEY-POS (k-pos) is the */
/*  number of characters matching between key and blk. */


int blk_find_pos(blk, key_str, k_len, pkt)
     unsigned char *blk;
     unsigned char *key_str;
     int k_len;
     int *pkt;
{
  if ((k_len)<0)
    {
      if ((k_len)==(end_of_chain))
	{
	  int skpos = split_key_pos(blk);
	  pkt_pack(pkt, 
	    (end_of_chain_P(blk)
	      ?qpastp
	      :pastend), skpos, 0, blk_prev_key(blk, skpos));
	}
      else pkt_pack(pkt, qpastp, blk_data_start, 0, 0);
      return !0;
    }
  else {
    int k_pos = 0;
    int b_end = blk_end(blk);
    {
      int b_pos = blk_data_start;
      int p_pos = 0;
L_chknxt:
      if ((field_len(blk, b_pos))<(k_pos))
	{
	  pkt_pack(pkt, qpastp, b_pos, k_pos, p_pos);
	  return !0;
	}
      else if ((field_len(blk, b_pos))>(k_pos))
	{
	  int s_pos = next_field(blk, (b_pos)+1);
	  if ((s_pos)<(b_end))
	    {
	      int T_b_pos = next_cnvpair(blk, b_pos);
	      p_pos = b_pos;
	      b_pos = T_b_pos;
	      goto L_chknxt;
	    }
	  else if ((s_pos)==(b_end))
	    {
	      pkt_pack(pkt, pastend, b_pos, k_pos, p_pos);
	      return !0;
	    }
	  else {
	    dprintf((diagout, ">>>>ERROR<<<< %s1: blk past end %ld %d\n", "blk_find_pos", blk_id(blk), s_pos));
	    return 0;
	  }
	}
      else {
	int i = (b_pos)+2;
	int f_len = field_len(blk, (b_pos)+1);
L_mchlp:
	if ((k_pos)>=(k_len))
	  if ((f_len)>0)
	    {
	      pkt_pack(pkt, pastp, b_pos, k_pos, p_pos);
	      return !0;
	    }
	  else {
	    int s_pos = next_field(blk, (b_pos)+1);
	    if ((s_pos)<(b_end))
	      {
		pkt_pack(pkt, match, b_pos, k_len, p_pos);
		return !0;
	      }
	    else if ((s_pos)==(b_end))
	      {
		pkt_pack(pkt, matchend, b_pos, k_pos, p_pos);
		return !0;
	      }
	    else {
	      dprintf((diagout, ">>>>ERROR<<<< %s2: blk past end %ld %d\n", "blk_find_pos", blk_id(blk), s_pos));
	      return 0;
	    }
	  }
	else if (((f_len)<=0)
	    || (((((unsigned char*)(blk))[i]))<((((unsigned char*)(key_str))[k_pos]))))
	  {
	    int s_pos = next_field(blk, (b_pos)+1);
	    if ((s_pos)<(b_end))
	      {
		int T_b_pos = next_cnvpair(blk, b_pos);
		p_pos = b_pos;
		b_pos = T_b_pos;
		goto L_chknxt;
	      }
	    else if ((s_pos)==(b_end))
	      {
		pkt_pack(pkt, pastend, b_pos, k_pos, p_pos);
		return !0;
	      }
	    else {
	      dprintf((diagout, ">>>>ERROR<<<< %s3: blk past end %ld %d\n", "blk_find_pos", blk_id(blk), s_pos));
	      return 0;
	    }
	  }
	else if (((((unsigned char*)(blk))[i]))>((((unsigned char*)(key_str))[k_pos])))
	  {
	    pkt_pack(pkt, 
	      ((k_pos)>(field_len(blk, b_pos))
		?pastp
		:qpastp), b_pos, k_pos, p_pos);
	    return !0;
	  }
	else {
	  k_pos = (k_pos)+1;
	  {
	    i = 1+(i);
	    f_len = (f_len)-1;
	    goto L_mchlp;
	  }
	}
      }
    }
  }
}

/*  Can return QPASTP or PASTP @ any key or MATCH at non-split key. */


ENTRY *chain_find(ent, accmode, key_str, k_len, pkt)
     ENTRY *ent;
     int accmode;
     unsigned char *key_str;
     int k_len;
     int *pkt;
{
L_chain_find:
  {
    unsigned char *blk = ent_blk(ent);
    if (!(blk_find_pos(blk, key_str, k_len, pkt)))
      {
	release_ent(ent, accmode);
	return 0;
      }
    else if (!(((pkt_match_type(pkt))==(matchend))
	  || ((pkt_match_type(pkt))==(pastend))))
      return ent;
    else if (end_of_chain_P(blk))
      {
	dprintf((diagout,
	 ">>>>ERROR<<<< %s: matched or past end of chain %ld:%ld\n",
	 "chain_find",
	 seg_id(ent_seg(ent)),
	 ent_id(ent)));
	pkt_set_match_type(pkt, qpastp);
	return ent;
      }
    else {
      chains_to_next = 1+(chains_to_next);
      ent = switch_ent(ent, accmode, blk_nxt_id(blk), accmode);
      if (ent)
	goto L_chain_find;
      else return 0;
    }
  }
}

/*  find-ent is always called with ent = (get-ent <seg> <blk-num> ACCNONE). */
/*  TBD - These calls could be colapsed. */
/*  should be called with LAST-LEVEL=-1 */


ENTRY *find_ent(ent, desired_level, last_level, key_str, k_len)
     ENTRY *ent;
     int desired_level;
     int last_level;
     unsigned char *key_str;
     int k_len;
{
L_find_ent:
  if (ent)
    if (ents_ent_update_access_P(ent, accnone, accread))
      {
	unsigned char *blk = ent_blk(ent);
	int blvl = blk_level(blk);
	if ((blvl)==(desired_level))
	  return ent;
	else if ((blvl)<(desired_level))
	  {
	    dprintf((diagout,
	 ">>>>ERROR<<<< bad blk level %d (des=%d) in %ld:%ld\n",
	 blvl,
	 desired_level,
	 seg_id(ent_seg(ent)),
	 ent_id(ent)));
	    return 0;
	  }
	else if (((last_level)>=0)
	    && ((blvl)!=((last_level)-1)))
	  {
	    dprintf((diagout,
	 ">>>>ERROR<<<< bad blk level %d last=%d in %ld:%ld\n",
	 blvl,
	 last_level,
	 seg_id(ent_seg(ent)),
	 ent_id(ent)));
	    return 0;
	  }
	else {
	  int pkt[pkt_size];
	  ent = chain_find(ent, accread, key_str, k_len, pkt);
	  if (ent)
	    {
	      int pos = next_field(blk, 1+(pkt_match_pos(pkt)));
	      blk = ent_blk(ent);
	      switch (pkt_match_type(pkt)) {
	      case qpastp:
	      case pastp:
		;
		break;
	      case match:
		if ((blk_end(blk))==(pos))
		  {
		    pos = pkt_match_pos(pkt);
		  }
		else pos = next_field(blk, pos);
		break;
	      default:
		pos = 0;
		break;
	      }
	      if (!(pos))
		{
		  dprintf((diagout,
	 ">>>>ERROR<<<< %s: bad-MATCH-TYPE %d blk %ld:%ld\n",
	 "find_ent",
	 pkt_match_pos(pkt),
	 seg_id(ent_seg(ent)),
	 ent_id(ent)));
		  return 0;
		}
	      else {
		pos = next_field(blk, 1+(pkt_match_pos(pkt)));
		{
		  ent = switch_ent(ent, accread, 
		    ((blk_end(blk))==(pos)
		      ?
		      (end_of_chain_P(blk)
			?str2long(blk,  -6+(pos))
			:blk_nxt_id(blk))
		      :str2long(blk, 1+(pos))), accnone);
		  last_level = ((blk_end(blk))==(pos))
		      && (!(end_of_chain_P(blk)))
		    ?(blk_level(blk))+1
		    :blk_level(blk);
		  goto L_find_ent;
		}
	      }
	    }
	  else return 0;
	}
      }
    else return 0;
  else return 0;
}


int blk_prev_key(blk, pos)
     unsigned char *blk;
     int pos;
{
  {
    int b_pos = blk_data_start;
    int p_pos = 0;
    while (!((b_pos)>=(pos))) {
      {
	int T_b_pos = next_cnvpair(blk, b_pos);
	p_pos = b_pos;
	b_pos = T_b_pos;
      }
    }
    if ((b_pos)>(pos))
      {
	dprintf((diagout, ">>>>ERROR<<<< %s: blk past end %ld %d\n", "blk_prev_key", blk_id(blk), p_pos));
	return 0;
      }
    else return p_pos;
  }
}

/*  DATA BASE OPERATIONS */


int get_this_val(blk, b_pos, ans_str)
     unsigned char *blk;
     int b_pos;
     unsigned char *ans_str;
{
  b_pos = next_field(blk, (b_pos)+1);
  {
    int alen = field_len(blk, b_pos);
    subbytes_move(blk, (b_pos)+1, (b_pos)+1+(alen), ans_str, 0);
    return alen;
  }
}


int get_this_key(blk, b_pos, key_str, ans_str, ent, k_len, pkt)
     unsigned char *blk;
     int b_pos;
     unsigned char *key_str;
     unsigned char *ans_str;
     ENTRY *ent;
     int k_len;
     int *pkt;
{
  {
    int b_end = blk_end(blk);
    int s_pos = next_field(blk, (b_pos)+1);
    if ((s_pos)<(b_end))
      {
	int f_pos = field_len(blk, b_pos);
	int f_siz = field_len(blk, (b_pos)+1);
	int alen = (f_pos)+(f_siz);
	if ((key_str)!=(ans_str))
	  subbytes_move(key_str, 0, f_pos, ans_str, 0);
	subbytes_move(blk, (b_pos)+2, (b_pos)+2+(f_siz), ans_str, f_pos);
	release_ent(ent, accread);
	return alen;
      }
    else if ((s_pos)!=(b_end))
      {
	dprintf((diagout, ">>>>ERROR<<<< %s: blk past end %ld %d\n", "chain_next", blk_id(blk), s_pos));
	release_ent(ent, accread);
	return strangerr;
      }
    else if (end_of_chain_P(blk))
      {
	release_ent(ent, accread);
	return notpres;
      }
    else {
      ent = switch_ent(ent, accread, blk_nxt_id(blk), accread);
      if (ent)
	ent = chain_find(ent, accread, key_str, k_len, pkt);
      if (ent)
	return chain_next(ent, key_str, k_len, ans_str, pkt);
      else return unkerr;
    }
  }
}


int chain_next(ent, key_str, k_len, ans_str, pkt)
     ENTRY *ent;
     unsigned char *key_str;
     int k_len;
     unsigned char *ans_str;
     int *pkt;
{
  pkt_set_blk_to_cache(pkt, ent_id(ent));
  switch (pkt_match_type(pkt)) {
  case pastp:
  case qpastp:
    return get_this_key(ent_blk(ent), pkt_match_pos(pkt), key_str, ans_str, ent, k_len, pkt);
  case match:
    return get_this_key(ent_blk(ent), next_cnvpair(ent_blk(ent), pkt_match_pos(pkt)), key_str, ans_str, ent, k_len, pkt);
  default:
    release_ent(ent, accread);
    return notpres;
  }
}

/*  To shrink a block give growth less than 0 and location equals */
/*  position after deleted. */
/*  blk-change-size returns #f if not enough room */

int blk_change_size(blk, loc, growth, bsiz)
     unsigned char *blk;
     int loc;
     int growth;
     int bsiz;
{
  int b_end = blk_end(blk);
  if (!(growth))
    return !0;
  else if (((b_end)+(growth))>(bsiz))
    return 0;
  else if (0 > (growth))
    {
      subbytes_move_left(blk, loc, b_end, blk, (loc)+(growth));
      blk_set_end(blk, (b_end)+(growth));
      return !0;
    }
  else {
    subbytes_move_right(blk, loc, b_end, blk, (loc)+(growth));
    blk_set_end(blk, (b_end)+(growth));
    return !0;
  }
}


int blk_remove_key_and_val(blk, b_pos, bsiz)
     unsigned char *blk;
     int b_pos;
     int bsiz;
{
  int nb_pos = next_cnvpair(blk, b_pos);
  if ((field_len(blk, nb_pos))>(field_len(blk, b_pos)))
    {
      int delk_pos = (field_len(blk, nb_pos))-(field_len(blk, b_pos));
      set_field_len(blk, 1+(b_pos), (field_len(blk, 1+(nb_pos)))+(delk_pos));
      return blk_change_size(blk, 2+(nb_pos), ((b_pos)-(nb_pos))+(delk_pos), bsiz);
    }
  else return blk_change_size(blk, nb_pos, (b_pos)-(nb_pos), bsiz);
}

/*  return #t if operation was succsessful; #f if not */
/*  */
/*  Note the splitting of OBLK into OBLK+NBLK by inserting the split */
/*  key of each block into parent. */
/*  */
/*  Note this routine does not check if the key(s) have already been */
/*  (perhaps by another process) inserted into parent. */
/*  */
/*  unfortunately, the right way to do this requires that the update */
/*  look just like a PUT of the NKEY-STR with value N-ID, albeit one */
/*  that then swaps the values of the new entry and the one */
/*  following... */
/*  */
/*  The SCREW-CASE occurs when the key is inserted at the endof the */
/*  block, so that we have to get access to the next (NON-EMPTY!) */
/*  block to make the swap... */


int defer_insert_updates_P = 0;


int parent_insert_update(seg, top_id, level, nkey_str, nk_len, n_id)
     SEGD *seg;
     long top_id;
     int level;
     unsigned char *nkey_str;
     int nk_len;
     long n_id;
{
  int pkt[pkt_size];
  {
    ENTRY *ent = find_ent(get_ent(seg, top_id, accnone), 1+(level),  -1, nkey_str, nk_len);
    ENTRY *xent = 0;
    int screw_case_P = 0;
    unsigned char blkidstr[4];
    unsigned char *blk = 0;
    if (ent)
      {
	long2str(blkidstr, 0, n_id);
	if (ents_ent_update_access_P(ent, accread, accwrite))
	  {
	    ent = chain_find(ent, accwrite, nkey_str, nk_len, pkt);
	    blk = ent_blk(ent);
	  }
	else {
	  release_ent(ent, accread);
	  ent = 0;
	}
	if ((ent)
	    && (at_split_key_pos_P(blk, pkt_match_pos(pkt))))
	  {
	    screw_case_P = !0;
	    xent = next_nonempty_ent(ent_seg(ent), blk_nxt_id(blk));
	    if (!(xent))
	      dprintf((diagout,
	 ">>>>ERROR<<<< No next key found for index insert %ld:%ld\n",
	 seg_id(ent_seg(ent)),
	 blk_id(blk)));
	  }
	if ((!(defer_insert_updates_P))
	    && (ent)
	    && ((!(screw_case_P))
	        || (xent))
	    && (chain_put(ent, nkey_str, nk_len, blkidstr, 4, pkt, xent, wcb_sar)))
	  return !0;
	else {
	  dprintf((diagout,
	 "WARNING: %s: couldn't update parent n-id=%ld nk-len=%d\n",
	 "parent_insert_update",
	 n_id,
	 nk_len));
	  deferred_inserts = 1+(deferred_inserts);
	  if (ent)
	    release_ent(ent, accwrite);
	  return 0;
	}
      }
    else return 0;
  }
}

/*  only valid if called with POS=position of some KEY */

int at_split_key_pos_P(blk, pos)
     unsigned char *blk;
     int pos;
{
  return (blk_end(blk))==(next_field(blk, 1+(pos)));
}


ENTRY *next_nonempty_ent(seg, blknum)
     SEGD *seg;
     long blknum;
{
  if ((blknum)<=0)
    return 0;
  else {
    ENTRY *xent = get_ent(seg, blknum, accread);
L_loop:
    if (xent)
      ents_ent_update_access_P(xent, accread, accwrite);
    if (!(xent))
      return 0;
    else if (!(blk_empty_P(ent_blk(xent))))
      return xent;
    else if (!(blk_nxt_id(ent_blk(xent))))
      {
	release_ent(xent, accwrite);
	return 0;
      }
    else {
      xent = switch_ent(xent, accwrite, blk_nxt_id(ent_blk(xent)), accwrite);
      goto L_loop;
    }
  }
}

/*  Note: CFP must NOT return the split key position IFF at a LEAF */
/*  RECON-THIS-KEY returns the data in KEY and its length as its return value. */
/*  END-OF-CHAIN (-1) is returned if the key reconstructed is the end-of-file mark */
/*  k-len is now used correctly to signal a potential overflow */


int recon_this_key(blk, pos, key_str, k_pos, k_len)
     unsigned char *blk;
     int pos;
     unsigned char *key_str;
     int k_pos;
     int k_len;
{
  {
    int b_pos = blk_data_start;
    int k_size = 0;
    while (!((b_pos)>(pos))) {
      if (((k_size)>(field_len(blk, b_pos)))
	  && (((((unsigned char*)(blk))[(b_pos)+2]))<=((((unsigned char*)(key_str))[(k_pos)+(field_len(blk, b_pos))]))))
	dprintf((diagout, ">>>>ERROR<<<< bad key sequence %ld @ %d\n", blk_id(blk), b_pos));
      k_size = (field_len(blk, b_pos))+(field_len(blk, 1+(b_pos)));
      if ((k_size)>=(k_len))
	dprintf((diagout, ">>>>ERROR<<<< not-enough-room %d\n", k_len));
      subbytes_move(blk, (b_pos)+2, (b_pos)+2+(field_len(blk, 1+(b_pos))), key_str, (k_pos)+(field_len(blk, b_pos)));
      b_pos = next_field(blk, 1+(b_pos));
      if ((b_pos)<(blk_end(blk)))
	b_pos = next_field(blk, b_pos);
      {
      }
    }
    return k_size;
  }
}


int blk_insert_and_adjust(blk, b_pos, k_pos, key_str, k_len, val_str, v_len, bsiz)
     unsigned char *blk;
     int b_pos;
     int k_pos;
     unsigned char *key_str;
     int k_len;
     unsigned char *val_str;
     int v_len;
     int bsiz;
{
  {
    int oldk_pos = field_len(blk, b_pos);
    int oldilen = field_len(blk, 1+(b_pos));
    int ilen = (k_len)-(oldk_pos);
    if (blk_change_size(blk, b_pos, 2+((k_len)-(k_pos))+1+(v_len), bsiz))
      {
	b_pos = 1+(b_pos);
	b_pos = set_field(blk, b_pos, key_str, oldk_pos, ilen);
	b_pos = set_field(blk, b_pos, val_str, 0, v_len);
	set_field_len(blk, b_pos, k_pos);
	set_field_len(blk, (b_pos)+1, (oldilen)-((k_pos)-(oldk_pos)));
	return !0;
      }
    else return 0;
  }
}


int blk_simple_insert(blk, b_pos, k_pos, key_str, k_len, val_str, v_len, bsiz)
     unsigned char *blk;
     int b_pos;
     int k_pos;
     unsigned char *key_str;
     int k_len;
     unsigned char *val_str;
     int v_len;
     int bsiz;
{
  int ilen = (k_len)-(k_pos);
  if (blk_change_size(blk, b_pos, 3+(v_len)+(ilen), bsiz))
    {
      set_field_len(blk, b_pos, k_pos);
      b_pos = 1+(b_pos);
      b_pos = set_field(blk, b_pos, key_str, k_pos, ilen);
      set_field(blk, b_pos, val_str, 0, v_len);
      return !0;
    }
  else return 0;
}


int blk_change_existing_value(blk, b_pos, key_str, k_len, val_str, v_len, bsiz)
     unsigned char *blk;
     int b_pos;
     unsigned char *key_str;
     int k_len;
     unsigned char *val_str;
     int v_len;
     int bsiz;
{
  int ov_len = 0;
  int v_pos = next_field(blk, 1+(b_pos));
  ov_len = field_len(blk, v_pos);
  if (blk_change_size(blk, (v_pos)+(ov_len)+1, (v_len)-(ov_len), bsiz))
    {
      set_field(blk, v_pos, val_str, 0, v_len);
      return !0;
    }
  else return 0;
}

/*  leaf-splits are called with ACCWRITE on blk and return without it. */

int val_leaf_split(blk, nblk, b_pos, key_str, k_pos, k_len, val_str, v_len)
     unsigned char *blk;
     unsigned char *nblk;
     int b_pos;
     unsigned char *key_str;
     int k_pos;
     int k_len;
     unsigned char *val_str;
     int v_len;
{
  {
    int v_pos = next_field(blk, 1+(b_pos));
    int s_pos = next_field(blk, v_pos);
    int b_end = blk_end(blk);
    set_field_len(nblk, blk_data_start, 0);
    if (((b_end)-(s_pos))>((v_pos)-(blk_data_start)))
      {
	int m_len = field_len(blk, s_pos);
	int f_chr = (((unsigned char*)(blk))[(s_pos)+2]);
	set_field_len(nblk, (blk_data_start)+1, (m_len)+(field_len(blk, 1+(s_pos))));
	subbytes_move(key_str, 0, m_len, nblk, (blk_data_start)+2);
	subbytes_move(blk, (s_pos)+2, b_end, nblk, (blk_data_start)+(m_len)+2);
	blk_set_end(nblk, ((b_end)-(s_pos))+(m_len)+(blk_data_start));
	b_pos = set_field(blk, v_pos, val_str, 0, v_len);
	blk[(b_pos)+2] = f_chr;
	set_field_len(blk, b_pos, m_len);
      }
    else {
      int nb_pos = (blk_data_start)+1;
      nb_pos = set_field(nblk, nb_pos, key_str, 0, k_len);
      nb_pos = set_field(nblk, nb_pos, val_str, 0, v_len);
      subbytes_move(blk, s_pos, b_end, nblk, nb_pos);
      blk_set_end(nblk, (nb_pos)+((b_end)-(s_pos)));
    }
    set_field_len(blk, (b_pos)+1, 1);
    blk_set_end(blk, (b_pos)+3);
    return b_pos;
  }
}


int qpastp_leaf_split(blk, nblk, b_pos, key_str, k_pos, k_len, val_str, v_len)
     unsigned char *blk;
     unsigned char *nblk;
     int b_pos;
     unsigned char *key_str;
     int k_pos;
     int k_len;
     unsigned char *val_str;
     int v_len;
{
  {
    int b_end = blk_end(blk);
    set_field_len(nblk, blk_data_start, 0);
    if (((b_end)-(b_pos))>((b_pos)-(blk_data_start)))
      {
	int m_len = field_len(blk, b_pos);
	int f_chr = (((unsigned char*)(blk))[(b_pos)+2]);
	set_field_len(nblk, (blk_data_start)+1, (m_len)+(field_len(blk, 1+(b_pos))));
	subbytes_move(key_str, 0, m_len, nblk, (blk_data_start)+2);
	subbytes_move(blk, (b_pos)+2, b_end, nblk, (blk_data_start)+(m_len)+2);
	blk_set_end(nblk, ((b_end)-(b_pos))+(m_len)+(blk_data_start));
	set_field_len(blk, b_pos, k_pos);
	b_pos = set_field(blk, (b_pos)+1, key_str, k_pos, (k_len)-(k_pos));
	b_pos = set_field(blk, b_pos, val_str, 0, v_len);
	blk[(b_pos)+2] = f_chr;
	set_field_len(blk, b_pos, m_len);
      }
    else {
      int nb_pos = (blk_data_start)+1;
      nb_pos = set_field(nblk, nb_pos, key_str, 0, k_len);
      nb_pos = set_field(nblk, nb_pos, val_str, 0, v_len);
      subbytes_move(blk, b_pos, b_end, nblk, nb_pos);
      blk_set_end(nblk, (nb_pos)+((b_end)-(b_pos)));
      set_field_len(blk, b_pos, k_pos);
      blk[(b_pos)+2] = (((unsigned char*)(key_str))[k_pos]);
    }
    set_field_len(blk, (b_pos)+1, 1);
    blk_set_end(blk, (b_pos)+3);
    return b_pos;
  }
}


int pastp_leaf_split(blk, nblk, b_pos, key_str, k_pos, k_len, val_str, v_len)
     unsigned char *blk;
     unsigned char *nblk;
     int b_pos;
     unsigned char *key_str;
     int k_pos;
     int k_len;
     unsigned char *val_str;
     int v_len;
{
  {
    int m_len = field_len(blk, b_pos);
    int b_end = blk_end(blk);
    set_field_len(nblk, blk_data_start, 0);
    if (((b_end)-(b_pos))>((b_pos)-(blk_data_start)))
      {
	int f_chr = (((unsigned char*)(blk))[(b_pos)+2+((k_pos)-(field_len(blk, b_pos)))]);
	set_field_len(nblk, (blk_data_start)+1, (m_len)+(field_len(blk, 1+(b_pos))));
	subbytes_move(key_str, 0, m_len, nblk, (blk_data_start)+2);
	subbytes_move(blk, (b_pos)+2, b_end, nblk, (blk_data_start)+(m_len)+2);
	blk_set_end(nblk, ((b_end)-(b_pos))+(m_len)+(blk_data_start));
	set_field_len(blk, b_pos, m_len);
	b_pos = set_field(blk, (b_pos)+1, key_str, m_len, (k_len)-(m_len));
	b_pos = set_field(blk, b_pos, val_str, 0, v_len);
	blk[(b_pos)+2] = f_chr;
	set_field_len(blk, b_pos, k_pos);
      }
    else {
      int nb_pos = (blk_data_start)+1;
      int c_pos = (b_pos)+2+((k_pos)-(m_len));
      nb_pos = set_field(nblk, nb_pos, key_str, 0, k_len);
      nb_pos = set_field(nblk, nb_pos, val_str, 0, v_len);
      set_field_len(nblk, nb_pos, k_pos);
      set_field_len(nblk, (nb_pos)+1, ((field_len(blk, 1+(b_pos)))+(m_len))-(k_pos));
      subbytes_move(blk, c_pos, b_end, nblk, (nb_pos)+2);
      blk_set_end(nblk, (nb_pos)+2+((b_end)-(c_pos)));
    }
    set_field_len(blk, (b_pos)+1, 1);
    blk_set_end(blk, (b_pos)+3);
    return b_pos;
  }
}


int dummy_leaf_split(blk, nblk, b_pos, key_str, k_pos, k_len, val_str, v_len)
     unsigned char *blk;
     unsigned char *nblk;
     int b_pos;
     unsigned char *key_str;
     int k_pos;
     int k_len;
     unsigned char *val_str;
     int v_len;
{
  dprintf((diagout,
	 ">>>>ERROR<<<< %s: bad-MATCH-TYPE blk %ld\n",
	 "dummy_leaf_split",
	 blk_id(blk)));
  return 0;
}


int_function select_split_fun(type)
     int type;
{
  switch (type) {
  case pastp:
    return pastp_leaf_split;
  case qpastp:
    return qpastp_leaf_split;
  case match:
    return val_leaf_split;
  default:
    return dummy_leaf_split;
  }
}


int chain_put(ent, key_str, k_len, val_str, v_len, pkt, xent, wcb)
     ENTRY *ent;
     unsigned char *key_str;
     int k_len;
     unsigned char *val_str;
     int v_len;
     int *pkt;
     ENTRY *xent;
     int wcb;
{
  {
    unsigned char *blk = ent_blk(ent);
    int blklev = blk_level(blk);
    int index_P = (blklev)>(leaf);
    long root_id = blk_top_id(blk);
    ENTRY *nent = 0;
    ENTRY *nrent = 0;
    SEGD *seg = ent_seg(ent);
    int bsiz = seg_bsiz(seg);
    int result_P = 0;
    int split_P = 0;
    ENTRY *nkey_ent = ent;
    int nkey_pos = pkt_match_pos(pkt);
    ENTRY *okey_ent = ent;
    int okey_pos = blk_data_start;
    long n_id = 0x0L;
    int s_pos = 0;
    unsigned char split_str[0x100];
    int s_len = 0;
    pkt_set_blk_to_cache(pkt, ent_id(ent));
    if (((pkt_match_type(pkt))==(pastp))
        && (blk_insert_and_adjust(blk, pkt_match_pos(pkt), pkt_key_pos(pkt), key_str, k_len, val_str, v_len, bsiz)))
      {
	result_P = !0;
      }
    else if (((pkt_match_type(pkt))==(qpastp))
        && (blk_simple_insert(blk, pkt_match_pos(pkt), pkt_key_pos(pkt), key_str, k_len, val_str, v_len, bsiz)))
      {
	result_P = !0;
      }
    else if (((pkt_match_type(pkt))==(match))
        && (blk_change_existing_value(blk, pkt_match_pos(pkt), key_str, k_len, val_str, v_len, bsiz)))
      {
	result_P = !0;
      }
    else if ((nent = create_new_blk_ent(seg),!(nent)))
      ;
    else {
      split_P = !0;
      {
	unsigned char *nblk = ent_blk(nent);
	n_id = ent_id(nent);
	init_next_blk(blk, nblk);
	block_splits = (block_splits)+1;
	s_pos = 
	(*(select_split_fun(pkt_match_type(pkt))))
	  (blk, nblk, pkt_match_pos(pkt), key_str, pkt_key_pos(pkt), k_len, val_str, v_len);
	s_len = 1+(field_len(blk, s_pos));
	subbytes_move(nblk, (blk_data_start)+2, 1+(field_len(blk, s_pos))+((blk_data_start)+2), split_str, 0);
	if (index_P)
	  {
	    okey_ent = nent;
	    if ((pkt_match_pos(pkt))!=(s_pos))
	      {
		split_index_inserts = 1+(split_index_inserts);
	      }
	    else {
	      okey_pos = next_cnvpair(nblk, blk_data_start);
	      nkey_ent = nent;
	      nkey_pos = blk_data_start;
	    }
	  }
	if ((pkt_match_pos(pkt))==(s_pos))
	  pkt_set_blk_to_cache(pkt, ent_id(nent));
	if (root_P(blk))
	  {
	    nrent = create_new_blk_ent(seg);
	    if (nrent)
	      {
		reroot(blk, ent_blk(nrent), ent_id(nrent), seg_bsiz(seg));
		if ((nkey_ent)==(ent))
		  {
		    nkey_ent = nrent;
		    pkt_set_blk_to_cache(pkt, ent_id(nrent));
		  }
	      }
	  }
	result_P = !0;
      }
    }
    if ((result_P)
        && (index_P))
      {
	if (xent)
	  {
	    index_screw_case = 1+(index_screw_case);
	    okey_ent = xent;
	    okey_pos = blk_data_start;
	  }
	else if (!(split_P))
	  okey_pos = next_cnvpair(blk, pkt_match_pos(pkt));
	{
	  unsigned char tmpstr[4];
	  int oldv_pos = (next_field(ent_blk(okey_ent), (okey_pos)+1))+1;
	  int newv_pos = (next_field(ent_blk(nkey_ent), (nkey_pos)+1))+1;
	  subbytes_move_left(ent_blk(okey_ent), oldv_pos, (oldv_pos)+4, tmpstr, 0);
	  subbytes_move_left(ent_blk(nkey_ent), newv_pos, (newv_pos)+4, ent_blk(okey_ent), oldv_pos);
	  subbytes_move_left(tmpstr, 0, 4, ent_blk(nkey_ent), newv_pos);
	}
      }
    if (nrent)
      {
	ents_ent_write(nrent);
	release_ent(nrent, accwrite);
      }
    if (nent)
      {
	ents_ent_write(nent);
	ents_ent_update_access_P(nent, accwrite, accnone);
      }
    if (result_P)
      {
	ent_set_dty(ent, !0);
	if ((split_P)
	    || (xent)
	    || ((wcb_sap)&(wcb)))
	  ents_ent_write(ent);
	release_ent(ent, accwrite);
      }
    if (xent)
      {
	ent_set_dty(xent, !0);
	ents_ent_write(xent);
	release_ent(xent, accwrite);
      }
    if (split_P)
      parent_insert_update(seg, root_id, blklev, split_str, s_len, n_id);
    if (nent)
      release_ent(nent, accnone);
    return result_P;
  }
}
