#include "stdio.h"
#include "setjmp.h"
#include "isamstr.h"
#include "isam.h"

 /* checked good 6-7-84 */

 /***************************************************************
 *                   File ISAM.C                                *
 *      these are the function return type declarations         *
 ***************************************************************/

extern  long    lseek();
extern  char    *calpl2(), *calpl3();
extern  int     read(), write();

 /***************************************************************
           this shows a recursive-call binary search

   M_ELEM mbinsh(upper, lower, key)
   M_ELEM upper, lower;
   char   *key;
   {
       M_ELEM mid;

       if(upper == lower)
          return(upper);

  mid = calpl2((((char *)upper - (char *)lower) / (2*melem)), lower);
  keycmp(key, mid->key) < 0 ? (lower = calpl2(1, mid)) : (upper = mid);
  return(mbinsh(upper, lower, key));
  }
 ***************************************************************/
 /***************************************************************
 *      main binary search routine                              *
 *           searches lower bound to upper bound recursively    *
 *           eof must be checked prior to call                  *
 *                                                              *
 *           returns pointer to element >= last processed key   *
 ***************************************************************/

M_ELEM mbinsh(upper, lower, key)
M_ELEM upper, lower;
char   *key;
{
   M_ELEM  mid;

   while(upper != lower) {

       mid = (M_ELEM)calpl2((((char *)upper - (char *)lower) /
           (2 * melem)), lower);
       keycmp(key, mid->key) < 0 ? (lower = (M_ELEM)calpl2(1, mid))
           : (upper = mid);
   }
   return(upper);

}

 /***************************************************************
 *      L2 binary search routine                                *
 *           searches lower bound to upper bound recursively    *
 *           eof must be checked prior to call                  *
 *                                                              *
 *           returns pointer to element >= last processed key   *
 ***************************************************************/

L2_ELEM    l2binsh(upper, lower, key)
L2_ELEM    upper, lower;
char       *key;
{

   L2_ELEM mid;

   while(upper != lower) {
       mid = (L2_ELEM)calpl2((((char *)upper - (char *)lower) /
           (2 * l2elem)), lower);
       keycmp(key, mid->key) < 0 ? (lower = (L2_ELEM)calpl2(1, mid))
           : (upper = mid);
 }
   return(upper);

}

 /***************************************************************
 *      L3 binary search routine                                *
 *           searches lower bound to upper bound recursively    *
 *           eof must be checked prior to call                  *
 *                                                              *
 *           returns pointer to element >= last processed key   *
 ***************************************************************/

L3_ELEM    l3binsh(upper, lower, key)
L3_ELEM    upper, lower;
char       *key;
{

   L3_ELEM mid;

   while(upper != lower) {
       mid = (L3_ELEM)calpl3((((char *)upper - (char *)lower) /
           (2 * l3elem)), lower);
       keycmp(key, mid->l3key) < 0 ? (lower = (L3_ELEM)calpl3(1, mid))
           : (upper = mid);
 }
   return(upper);

}

 /***************************************************************
 *      group read                                              *
 *           checks to see if currently active l2 group is      *
 *           same as calling group. if not, read new group      *
 ***************************************************************/

void   grread(cgroup)
long   cgroup;
{

   if(l2_group == cgroup)
       return;

   l2read(cgroup);

   l2_group = cgroup;

}

 /***************************************************************
 *      makes room for new entry in main at cama                *
 ***************************************************************/

void   maininsert()
{

   char    *start;

   start = calpl2(cm_ent, bm_ptr) - 1;
   lmove(start, start + melem, start - ((char *)cama) + 1);

}

 /***************************************************************
 *      moves from last to first for len bytes                  *
 ***************************************************************/

void   lmove(start, end, len)
char   *start, *end;
unsigned   len;
{

   while(len--)
       *end-- = *start--;

}

 /***************************************************************
 *      moves from first to last for len bytes                  *
 ***************************************************************/

void   fmove(start, end, len)
char   *start, *end;
unsigned   len;
{

   while(len--)
       *end++ = *start++;

}

 /***************************************************************
 *      if current l2 block is dirty, write to offset disk addr *
 ***************************************************************/

void   l2write(offset)
long   offset;
{

   if(l2_drty) {
       lswrite(offset, l2s_ptr, l2bytes);
       l2_drty = FALSE;
   }
}

 /***************************************************************
 *      first writes current l2 block to disk if dirty,         *
 *            then reads l2 block from offset.                  *
 ***************************************************************/

void   l2read(offset)
long   offset;
{

   if(offset != l2_cur) {
       l2write(l2_cur);
       lsread(offset, l2s_ptr, l2bytes);
       l2_cur = offset;
   }

}

 /***************************************************************
 *      if current l3 block is dirty, write to offset disk addr *
 ***************************************************************/

void   l3write(offset)
long   offset;
{

   if(l3_drty) {
       lswrite(offset, bl3_ptr, l3bytes);
       l3_drty = FALSE;
   }
}

 /***************************************************************
 *      first writes current l3 block to disk if dirty,         *
 *            then reads l3 block from offset.                  *
 ***************************************************************/

void   l3read(offset)
long   offset;
{

   if(offset != l3_cur) {
       l3write(l3_cur);
       lsread(offset, bl3_ptr, l3bytes);
       l3_cur = offset;
   }

}

 /***************************************************************
 *      writes l2 block at work l2 to disk at offset            *
 ***************************************************************/

void   wl2write(offset)
long   offset;
{

   lswrite(offset, ws_ptr, l2bytes);

}

 /***************************************************************
 *      reads l2 block from disk at offset to work l2           *
 ***************************************************************/

void   wl2read(offset)
long   offset;
{

   lsread(offset, ws_ptr, l2bytes);

}

 /***************************************************************
 *      writes l3 block at work l3 to disk at offset            *
 ***************************************************************/

void   wl3write(offset)
long   offset;
{

   lswrite(offset, wbl3_ptr, l3bytes);

}

 /***************************************************************
 *      reads recovery block from disk at offset, only used     *
 *      with delete code.                                       *
 ***************************************************************/

void   rread(offset)
long   offset;
{
   if(offset != r_cur) {
       rwrite(r_cur);
       lsread(offset, br_ptr, rbytes);
       r_cur = offset;

   }

}

 /***************************************************************
 *      writes recovery block to disk at offset, only used      *
 *      with delete code.                                       *
 ***************************************************************/

void   rwrite(offset)
long   offset;
{
   if(r_drty) {
       lswrite(offset, br_ptr, rbytes);
   }

}

 /*****************************************************************
 *      gets allocation on disk for l2 block, returns disk offset *
 *****************************************************************/

long   l2alloc()
{
   long    i;

   if(i = l2bp) {
       lsread(i, &l2bp, sizeof(long));
   } else {
       i = ieof;
       ieof += l2bytes;
   }
   return(i);

}

 /*****************************************************************
 *      gets allocation on disk for l3 block, returns disk offset *
 *****************************************************************/

long   l3alloc()
{
   long    i;

   if(i = l3bp) {
       lsread(i, &l3bp, sizeof(long));
   } else {
       i = ieof;
       ieof += l3bytes;
   }
   return(i);

}

 /*****************************************************************
 *      gets allocation on disk for recovery block, returns disk  *
 *      offset. used only with delete                             *
 *****************************************************************/

long   ralloc()
{
   long    i;

   if(i = frbp) {
       lsread(i, &frbp, sizeof(long));
   } else {
       i = ieof;
       ieof += rbytes;
   }
   return(i);

}

 /*****************************************************************
 *      gets data allocation for disk. returns disk offset.       *
 *****************************************************************/

long   dalloc()
{

   long    i, j;

   if(rbp) {
       rread(rbp);
       i = br_ptr->roffset[-(br_ptr->rb_ent)];
       if(!br_ptr->rb_ent) {
           j = frbp;
           frbp = rbp;
           rbp = br_ptr->link;
           br_ptr->link = j;
       }
       r_drty = TRUE;
   } else {
       i = deof;
       deof += reclen;
   }
   return(i);

}

 /*****************************************************************
 *      performs all actual disk reads for isam. on error,        *
 *      executes a longjmp with IRE as error code. seeks to       *
 *      offset, reads len bytes to ptr.                           *
 *****************************************************************/

void   lsread(offset, ptr, len)
long   offset;
char   *ptr;
unsigned len;
{

   lseek(ifd, offset, 0);
   if(len != (read(ifd, ptr, len))) {
       longjmp(_ienv, IRE);    /* index read error */
   }

}

 /*****************************************************************
 *      performs all actual disk writes by isam. on error,        *
 *      executes a longjmp with IWE as error code. seeks to       *
 *      offset, writes len bytes from ptr.                        *
 *****************************************************************/

void   lswrite(offset, ptr, len)
long   offset;
char   *ptr;
unsigned len;
{

   lseek(ifd, offset, 0);
   if(len != write(ifd, ptr, len))
       longjmp(_ienv, IWE);    /* index write error */

}

 /*****************************************************************
 *      this compares k2 to k1 and returns >0 if k2>k1,           *
 *      0 if k2==k1, or <0 if k2<k1.                              *
 *****************************************************************/

int    keycmp(k1, k2)
char   *k1, *k2;
{

   int i;

   for(i = keylen; *k2 == *k1 && -i; k1++, k2++)
       ;
   return(*k2 - *k1);

}

 /*****************************************************************
 *      this moves a key for keylen from k2 to k1.                *
 *****************************************************************/

void   keymove(k1, k2)
char   *k1, *k2;
{

   unsigned    i = keylen;

   while(i--)
       *k1++ = *k2++;

}

 /*****************************************************************
 *      sets current index pointers to end-of-file                *
 *****************************************************************/

void   set_eof()
{

   cama = (M_ELEM)calpl2(cm_ent - 1, bm_ptr);
   grread(cama->offset);
   while(highlink)
       l2read(highlink);
   cal2 = (L2_ELEM)calpl2(l2_ent - 1, bl2_ptr);
   l3read(cal2->offset);
   cal3 = (L3_ELEM)calpl3(cal2->group - 1, bl3_ptr);

}

 /*****************************************************************
 *      does pointer arithmetic on main elements and l2 elements. *
 *         adds inc * (length of l2 element in bytes) to ptr.     *
 *****************************************************************/

char   *calpl2(inc, ptr)
char   *ptr;
int    inc;
{

   return(ptr + inc * l2elem);

}

 /*****************************************************************
 *      does pointer arithmetic on l3 elements.                   *
 *         adds inc * (length of l3 element in bytes) to ptr.     *
 *****************************************************************/

char   *calpl3(inc, ptr)
char   *ptr;
int    inc;
{

   return(ptr + inc * l3elem);

}
