#include "stdio.h"
#include "setjmp.h"
#include "isamstr.h"
#include "isam.h"

 /* checked good 6-7-84 */
 /***************************************************************
 *                      File ISAM3.C                            *
 *      these are the function return type declarations         *
 ***************************************************************/

extern  long    readnext(), insert();

extern  int     open(), close(), read();
extern  int     match(), keycmp();

extern  void    l3write(), l2write();
extern  void    rwrite(), lswrite();
extern  void    keymove(), free();

extern  char    *calloc(), *calpl2(), *calpl3();

 /********************************************************************
 *      index open opens an index file, allocates storate for        *
 *      working blocks in memory and fills in index data locations   *
 ********************************************************************/

char    *ind_open(filename)
char    *filename;
{
        int             j;
        unsigned        i;

        index = (struct global *)0;
        if((j = open(filename, 0x8002)) == EOF) {
                i_errno = FNF;
                return((char *)0);
        }

        if(read(j, &i, sizeof(i)) < sizeof(i)) {
                i_errno = INV;
                return((char *)0);
        }

        if(!(index = (struct global *)calloc(1,i))) {
                i_errno = NEM;
                return((char *)0);
        }

        i = lp_key - (char *)&keylen;
        if(read(j, &keylen, i) != i) {
                free(index);
                i_errno = INV;
                return((char *)(index = (struct global *)0));
        }

        l2elem = sizeof(struct l2_elem) + keylen - 1;
        l2bytes = l2_max * l2elem + sizeof(struct l2_link) + keylen - 1;
        l3elem = sizeof(struct l3_elem) + keylen - 1;
        l3bytes = l3_max * l3elem;
        cama = bm_ptr = (M_ELEM)(lp_key + keylen);
                /* first byte after lp_key */

        l2s_ptr = (struct l2_link *)calpl2(m_max, bm_ptr);
        cal2 = bl2_ptr = (L2_ELEM)((char *)l2s_ptr + sizeof(struct l2_link)
                + keylen - 1);
        cal3 = bl3_ptr = (L3_ELEM)((char *)l2s_ptr + l2bytes + l2elem);
        wbl3_ptr = (L3_ELEM)((char *)bl3_ptr + l3bytes);
        wbl2_ptr = (L2_ELEM)((char *)wbl3_ptr + sizeof(struct l2_link)
                + keylen - 1);
        br_ptr = (struct recov *)((char *)wbl3_ptr + (l2bytes > l3bytes ?
                l2bytes : l3bytes));
        rbytes = sizeof(struct recov) + sizeof(long) * (r_max - 1);
        ifd = j;

        if(cm_ent) {
                j = (unsigned)((char *)l2s_ptr - (char *)bm_ptr);
                if(read(ifd, bm_ptr, j) != j) {
                        free(index);
                        i_errno = INV;
                        index = (struct global *)0;
                }
        }
        return((char *)index);
}
/*
 *********************************************************************
 *      write add writes the key to index and allocates new data     *
 *      storage. returns offset of new storage or -1 on error        *
 ********************************************************************/

long    wa(key)
char    *key;
{

        return(insert(key, _lm1));

}

 /********************************************************************
 *      secondary write add writes key to index using offset and     *
 *      returns offset or -1 on error.                               *
 ********************************************************************/

long    swa(key, offset)
long    offset;
char    *key;
{

        return(insert(key, offset));

}
/*
 *********************************************************************
 *      read key finds first key equal to key and returns offset     *
 *      or -1 if not found or error.                                 *
 ********************************************************************/

long    rk(key)
char    *key;
{

        if(i_errno = setjmp(_ienv))
                return(_lm1);

        if(match(key)) {                /* if zero returned key match */
                i_errno = KNF;
                return(_lm1);
        }
        return(cal3->offset);

}
/*
 *********************************************************************
 *      read next key is used to find duplicate keys.                *
 *      returns offset of next dup key if found, else                *
 *      returns -1, with errno set                                   *
 ********************************************************************/

long    rnk()
{

        long    temp;

        if(i_errno = setjmp(_ienv))
                return(_lm1);

        if((temp = readnext()) < 0 || keycmp(lp_key, cal3->l3key)) {
                i_errno = KNF;
                temp = _lm1;
        }
        keymove(lp_key, cal3->l3key);
        return(temp);

}
/*
 *********************************************************************
 *      read next finds next sequential entry in index.              *
 *      if found returns offset of entry and places key              *
 *      at anskey, else returns -1 with errno set                    *
 ********************************************************************/

long    rn(anskey)
char    *anskey;
{

        long    temp;

        if(i_errno = setjmp(_ienv))
                return(_lm1);

        if((temp = readnext()) >= 0)
                keymove(anskey, cal3->l3key);
        else
                i_errno = EOF;
        keymove(lp_key, cal3->l3key);
        return(temp);

}
/*
 *********************************************************************
 *      global read key returns offset of first key greater          *
 *      than or equal to key, else -1 with errno set.                *
 *      key found is put at anskey                                   *
 ********************************************************************/

long    grk(key, anskey)
char    *key, *anskey;
{

        if(i_errno = setjmp(_ienv))
                return(_lm1);

        if(match(key) < 0) {
                i_errno = KNF;
                return(_lm1);
        }
        keymove(anskey, cal3->l3key);
        return(cal3->offset);
}
/*
 *********************************************************************
 *      global read next key returns offset of next key greater      *
 *      than or equal to last processed key (if found                *
 *      anskey is set equal to key found), else -1 is                *
 *      returned with errno set.                                     *
 ********************************************************************/

long   grnk(anskey)
char   *anskey;
{

   long    temp;

   if(i_errno = setjmp(_ienv))
           return(_lm1);

   if((temp = readnext()) < 0 || keycmp(lp_key, cal3->l3key) < 0) {
           i_errno = KNF;
           temp = _lm1;
   }
        keymove(anskey, cal3->l3key);
        keymove(lp_key, cal3->l3key);
        return(temp);
}

 /********************************************************************
 *      get index returns current index pointer                      *
 ********************************************************************/

char   *get_ind()
{

   return((char *)index);

}
/*
 *********************************************************************
 *      set index sets current index to iptr                         *
 ********************************************************************/

void   set_ind(iptr)
char   *iptr;
{

   index = (struct global *)iptr;

}

 /********************************************************************
 *                                                                   *
 *      return last found key returns offset and key of current      *
 *      index position                                               *
 *                                                                   *
 ********************************************************************/

long   rlfk(anskey)
char   *anskey;
{

   if(cm_ent) {
           keymove(anskey, lp_key);
                return(cal3->offset);
   }
        i_errno = INE;
        return(_lm1);

}
/*
 *********************************************************************
 *      index close writes any dirty records back to disk,           *
 *      then closes file, returns -1 on error with errno set.        *
 ********************************************************************/

int    ind_close(iptr)
char   *iptr;
{

   char    *isav;
   unsigned i;

   isav = (char *)index;
   index = (struct global *)iptr;

   if(i_errno = setjmp(_ienv)) {
       index = (struct global *)isav;
       return(EOF);
   }

   l2write(l2_cur);
   l3write(l3_cur);
   rwrite(r_cur);
   if(m_drty) {
		lswrite((long)sizeof(unsigned), &keylen,
       	i = lp_key - (char *)&keylen);
       lswrite((long)(i + sizeof(unsigned)), bm_ptr, m_max *
           (sizeof(struct m_elem) + keylen - 1));
   }
        if(close(ifd)) {
           i_errno = ICE;
           index = (struct global *)isav;
           return(EOF);
   }

   free(index);
   index = (struct global *)isav;
   return(0);

}
/*
 *********************************************************************
 *      returns i_errno.                                             *
 ********************************************************************/

int    ind_err()
{

   return(i_errno);

}

 /********************************************************************
 *                                                                   *
 *      sets to end of file                                          *
 *                                                                   *
 ********************************************************************/

long   ind_eof()
{

   if(i_errno = setjmp(_ienv))
		return(_lm1);

   if(cm_ent) {
       set_eof();
       keymove(lp_key, cal3->l3key);
       return(cal3->offset);
   }
   i_errno = INE;
   return(_lm1);

}
/*
 *********************************************************************
 *      set to beginning of file                                     *
 ********************************************************************/

long   ind_bof()
{

   if(i_errno = setjmp(_ienv))
		return(_lm1);

   if(cm_ent) {
       cama = bm_ptr;
       grread(cama->offset);
       while(lowlink)
       	l2read(lowlink);

       cal2 = bl2_ptr;
       l3read(cal2->offset);
       cal3 = bl3_ptr;
       keymove(lp_key, cal3->l3key);
       return(cal3->offset);
   }
   i_errno = INE;
   return(_lm1);

}

/*********************** End of Function ********************/
