/* This file was generated by scm2c from source file "scan.scm" */
/*  "scan.scm" WB-tree File Based Associative String Data Base System. */
/*  Copyright (C) 1991, 1992, 1993, 2000, 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/>. */


#include "wbsys.h"


int bt_scan(han, operation, kstr1, len1, kstr2, len2, func, long_tab, respkt, blk_limit)
     HAND *han;
     int operation;
     unsigned char *kstr1;
     int len1;
     unsigned char *kstr2;
     int len2;
     int_function func;
     long *long_tab;
     int *respkt;
     int blk_limit;
{
L_bt_scan:
  {
    int pkt[pkt_size];
    int opkt[pkt_size];
    ENTRY *ent = 0;
    unsigned char vstr[0x100];
    int accmode = (operation)==(count_scan)
      ?accread
      :accwrite;
    int result = success;
    if (key_error_P(kstr1, len1,  -2, "bt_scan_1"))
      return keyerr;
    else if (key_error_P(kstr2, len2,  -1, "bt_scan_2"))
      return keyerr;
    else if (han_error_P(han, "bt_scan"))
      return argerr;
    else if (((operation)==(modify_scan))
        && (!(func)))
      {
	dprintf((diagout,
	 ">>>>ERROR<<<< %s: MODIFY-SCAN requires func be specified\n",
	 "bt_scan"));
	return argerr;
      }
    else {
      ent = chain_find_ent(han, accmode, kstr1, len1, pkt);
      if ((ent)
	  && (blk_find_pos(ent_blk(ent), kstr2, len2, opkt)))
	{
	  if ((operation)==(count_scan))
	    {
	      ENTRY *nent = allocate_ent();
	      ent_copy(nent, ent);
	      release_ent(ent, accmode);
	      result = chain_scan(nent, operation, pkt, opkt, kstr1, func, long_tab, vstr, respkt, han_wcb(han));
	      recycle_ent(nent);
	    }
	  else {
	    result = chain_scan(ent, operation, pkt, opkt, kstr1, func, long_tab, vstr, respkt, han_wcb(han));
	    release_ent(ent, accmode);
	    if ((result)>0)
	      {
		result = bt_put(han, kstr1, pkt_skey_len(respkt), vstr, result);
		if ((result)==(success))
		  {
		    pkt_set_skey_count(respkt, (pkt_skey_count(respkt))+1);
		    pkt_set_skey_len(respkt, increment_string(kstr1, pkt_skey_len(respkt), 0x100));
		    result = notpres;
		  }
	      }
	  }
	  if (((result)==(notpres))
	      && (0!=(blk_limit)))
	    {
	      len1 = pkt_skey_len(respkt);
	      blk_limit = (blk_limit)-1;
	      goto L_bt_scan;
	    }
	  else return result;
	}
      else {
	if (ent)
	  release_ent(ent, accmode);
	rem_fct = 0x1L+(rem_fct);
	return unkerr;
      }
    }
  }
}

/*  this function increments a string lexicographically */

int increment_string(str, len, maxlen)
     unsigned char *str;
     int len;
     int maxlen;
{
  if ((len)<(maxlen))
    {
      str[len] = 0;
      return (len)+1;
    }
  else {
    int oldval = (((unsigned char*)(str))[(len)-1]);
    str[(len)-1] = 1+(oldval);
    return len;
  }
}

/*  Each call to CHAIN-SCAN scans */
/*  all the keys within the specified range WITHIN block ENT. */
/*  If the scan actually reaches  the end of range, it sets SKEY-LEN=0 */
/*  and returns SUCCESS. If there's more to the range, */
/*  it sets KEY-STR to the key to continue deleting */
/*  from (ie, the split key of ENT), SKEY-LEN to its length, and */
/*  returns NOTPRES (NOTDONE). The caller must then call CHAIN-FIND */
/*  to find the START and END keys and call again. */

int chain_scan(ent, operation, pkt, opkt, key_str, func, long_tab, vstr, respkt, wcb)
     ENTRY *ent;
     int operation;
     int *pkt;
     int *opkt;
     unsigned char *key_str;
     int_function func;
     long *long_tab;
     unsigned char *vstr;
     int *respkt;
     int wcb;
{
  {
    unsigned char *blk = ent_blk(ent);
    int result = success;
    if (((operation)==(rem_scan))
        && (!(func))
        && ((pkt_match_pos(opkt))>(pkt_match_pos(pkt)))
        && ((pkt_match_pos(pkt))==(blk_data_start))
        && (at_split_key_pos_P(blk, pkt_match_pos(opkt))))
      {
	{
	  int key_len = recon_this_key(blk, pkt_match_pos(opkt), key_str, 0, 0x100);
	  subbytes_move(key_str, 0, key_len, blk, (blk_data_start)+2);
	  set_field_len(blk, (blk_data_start)+1, key_len);
	  blk_set_end(blk, (blk_data_start)+2+(key_len));
	}
	pkt_set_skey_count(respkt, (pkt_skey_count(respkt))+1);
	rem_ct = 0x1L+(rem_ct);
	ent_set_dty(ent, !0);
	pkt_set_match_pos(opkt, blk_data_start);
      }
    else {
      int oldct = pkt_skey_count(respkt);
      unsigned char ckstr[0x100];
      int clen = 0;
      if (func)
	clen = recon_this_key(blk, pkt_match_pos(pkt), ckstr, 0, 0x100);
      pkt_set_match_type(pkt, match);
      result = scan_loop(ent_blk(ent), operation, pkt, opkt, func, long_tab, respkt, ckstr, clen, vstr, seg_bsiz(ent_seg(ent)));
      if (((operation)!=(count_scan))
	  && ((pkt_skey_count(respkt))>(oldct)))
	ent_set_dty(ent, !0);
    }
    if (((operation)==(rem_scan))
        && (blk_empty_P(blk))
        && (!(end_of_chain_P(blk))))
      {
	del_delete_bck(ent);
      }
    else if (ent_dty_P(ent))
      if ((((operation)==(rem_scan))
	   && (((wcb_sar)&(wcb))
	       || ((blk_level(blk))>(leaf))))
	  || (((operation)==(modify_scan))
	      && ((wcb_sap)&(wcb))))
	ents_ent_write(ent);
    if ((result)!=(success))
      {
	pkt_set_skey_len(respkt, recon_this_key(blk, pkt_match_pos(pkt), key_str, 0, 0x100));
	return result;
      }
    else if (((pkt_match_type(opkt))==(pastend))
        && (!(end_of_chain_P(blk))))
      {
	pkt_set_skey_len(respkt, recon_this_key(blk, pkt_match_pos(pkt), key_str, 0, 0x100));
	return notpres;
      }
    else {
      pkt_set_skey_len(respkt, 0);
      return success;
    }
  }
}

/*  SCAN-LOOP returns SUCCESS if it reaches the end of the range, */
/*  else an ERROR code if terminated before that point, either */
/*  by an error or by FUNC returning TERMINATED. */
/*  SCAN-LOOP returns a value>0 to signal the case of */
/*  a MODIFY that requires a block-split. That value is the */
/*  length of the new value (which must be >0 to have caused an */
/*  increase in block size). SCAN-LOOP NEVER returns NOTPRES. */
/*  Note that (PKT:MATCH-POS pkt) is always the current scan point. */


int scan_loop(blk, operation, pkt, opkt, func, long_tab, respkt, ckstr, clen, vstr, blksize)
     unsigned char *blk;
     int operation;
     int *pkt;
     int *opkt;
     int_function func;
     long *long_tab;
     int *respkt;
     unsigned char *ckstr;
     int clen;
     unsigned char *vstr;
     int blksize;
{
L_scan_loop:
  if ((pkt_match_pos(opkt))>(pkt_match_pos(pkt)))
    {
      int old_bend = blk_end(blk);
      int next_pos = next_cnvpair(blk, pkt_match_pos(pkt));
      int result = success;
      if (func)
	{
	  int vpos = next_field(blk, 1+(pkt_match_pos(pkt)));
	  int vlen = field_len(blk, vpos);
	  subbytes_move(blk, (vpos)+1, (vpos)+(vlen)+1, vstr, 0);
	  result = func(ckstr, clen, vstr, vlen, long_tab);
	}
      if ((result)>=(success))
	{
	  if ((operation)==(rem_scan))
	    {
	      blk_remove_key_and_val(blk, pkt_match_pos(pkt), blksize);
	      pkt_set_skey_count(respkt, (pkt_skey_count(respkt))+1);
	      rem_ct = 0x1L+(rem_ct);
	      if ((pkt_match_pos(opkt))==(next_pos))
		{
		  pkt_set_match_pos(opkt, pkt_match_pos(pkt));
		}
	      else pkt_set_match_pos(opkt, (pkt_match_pos(opkt))-((old_bend)-(blk_end(blk))));
	      next_pos = pkt_match_pos(pkt);
	    }
	  else if ((operation)==(count_scan))
	    {
	      pkt_set_skey_count(respkt, (pkt_skey_count(respkt))+1);
	      pkt_set_match_pos(pkt, next_pos);
	    }
	  else if (blk_change_existing_value(blk, pkt_match_pos(pkt), ckstr, clen, vstr, result, blksize))
	    {
	      pkt_set_skey_count(respkt, (pkt_skey_count(respkt))+1);
	      next_pos = (next_pos)-((old_bend)-(blk_end(blk)));
	      pkt_set_match_pos(opkt, (pkt_match_pos(opkt))-((old_bend)-(blk_end(blk))));
	      pkt_set_match_pos(pkt, next_pos);
	      result = success;
	    }
	  else dprintf((diagout, "%s: hit modify special case\n", "scan_loop"));
	}
      else if ((result)==(notpres))
	pkt_set_match_pos(pkt, next_pos);
      if (((result)==(success))
	  || ((result)==(notpres)))
	{
	  if (func)
	    {
	      clen = (field_len(blk, next_pos))+(field_len(blk, 1+(next_pos)));
	      subbytes_move(blk, (next_pos)+2, (next_pos)+2+(field_len(blk, 1+(next_pos))), ckstr, field_len(blk, next_pos));
	    }
	  goto L_scan_loop;
	}
      else return result;
    }
  else return success;
}
